From c214a378f8d3ec45423ef985d76c28dbee48f958 Mon Sep 17 00:00:00 2001 From: Nathan Scott Date: Wed, 25 Sep 2024 16:09:57 +1000 Subject: [PATCH] treetop: improve handling of local SHAP values tab --- src/treetop/pcp/Feature.c | 44 +++++++++---------- src/treetop/pcp/Feature.h | 4 +- src/treetop/pcp/FeatureTable.c | 50 ++++++++++++++++++++-- src/treetop/pcp/FeatureTable.h | 11 ++++- src/treetop/pcp/Metric.h | 1 - src/treetop/pcp/TreeTop.c | 25 +++++++---- src/treetop/pcp/TreeTop.h | 6 +-- vendor/github.com/htop-dev/htop/Settings.c | 2 +- 8 files changed, 97 insertions(+), 46 deletions(-) diff --git a/src/treetop/pcp/Feature.c b/src/treetop/pcp/Feature.c index 1743a985bc..828b126ea0 100644 --- a/src/treetop/pcp/Feature.c +++ b/src/treetop/pcp/Feature.c @@ -29,12 +29,10 @@ const FeatureFieldData Feature_fields[] = { [LOCAL_FEATURE] = { .name = "LOCAL_FEATURE", .title = " Important Metrics ", .description = "Most important metrics (features) from local SHAP" }, [LOCAL_IMPORTANCE] = { .name = "LOCAL_IMPORTANCE", .title = "SHAP VALUE ", .description = "SHAP value importance measure" }, [LOCAL_MUTUALINFO] = { .name = "LOCAL_MUTUALINFO", .title = "MUTUALINFO ", .description = "Mutual information for high SHAP value features" }, - [OPTMIN_FEATURE] = { .name = "OPTMIN_FEATURE", .title = " Key Metrics for Optimisation ", .description = "Important metrics for optimisation based on minima perturbations" }, - [OPTMIN_CHANGE] = { .name = "OPTMIN_CHANGE", .title = "DELTA ", .description = "Change in prediction with minima perturbations" }, - [OPTMIN_DIRECTION] = { .name = "OPTMIN_DIRECTION", .title = "DIRECTION", .description = "Direction of change with minima perturbations" }, - [OPTMAX_FEATURE] = { .name = "OPTMAXFEATURE", .title = " Key Metrics for Optimisation ", .description = "Important metrics for optimisation based on maxima perturbations" }, - [OPTMAX_CHANGE] = { .name = "OPTMAX_CHANGE", .title = "DELTA ", .description = "Change in prediction with maxima perturbations" }, - [OPTMAX_DIRECTION] = { .name = "OPTMAX_DIRECTION", .title = "DIRECTION", .description = "Direction of change with maxima perturbations" }, + [OPTIM_FEATURE] = { .name = "OPTMIN_FEATURE", .title = " Key Metrics for Optimisation ", .description = "Important metrics for optimisation based on minima perturbations" }, + [OPTIM_MIN_MAX] = { .name = "OPTIM_MIN_MAX", .title = "MIN/MAX", .description = "Used minimum or maximum for perturbation" }, + [OPTIM_DIFFERENCE] = { .name = "OPTIM_DIFFERENCE", .title = "DELTA ", .description = "Change in prediction from perturbation" }, + [OPTIM_MUTUALINFO] = { .name = "OPTIM_MUTUALINFO", .title = "MUTUALINFO ", .description = "Mutual information with the target variable" }, // End of list }; @@ -47,8 +45,6 @@ Feature* Feature_new(const Machine* host) { void Feature_done(Feature* this) { Row_done(&this->super); - free(this->direction); - free(this->change); } static void Feature_delete(Object* cast) { @@ -62,10 +58,12 @@ static const char* Feature_name(Row* rp) { return fp->name; } -static void Feature_writeChange(const Feature* fp, RichString* str) { -} - -static void Feature_writeDirection(const Feature* fp, RichString* str) { +static void Feature_writeMinMax(const Feature* fp, RichString* str) { + char buffer[16]; buffer[16] = '\0'; + int shadow = CRT_colors[PROCESS_SHADOW]; + size_t n = sizeof(buffer) - 1; + snprintf(buffer, n, "%8s ", fp->min_max); + RichString_appendWide(str, shadow, buffer); } static void Feature_writeName(const Feature* fp, RichString* str) { @@ -112,31 +110,29 @@ static void Feature_writeField(const Row* super, RichString* str, RowField field const Feature* fp = (const Feature*) super; switch ((int)field) { + case LOCAL_MUTUALINFO: + case MODEL_MUTUALINFO: + case OPTIM_MUTUALINFO: + Feature_writeValue(str, fp->mutualinfo); + return; case LOCAL_IMPORTANCE: case MODEL_IMPORTANCE: Feature_writeValue(str, fp->importance); return; - case LOCAL_MUTUALINFO: - case MODEL_MUTUALINFO: - Feature_writeValue(str, fp->mutualinfo); + case OPTIM_DIFFERENCE: + Feature_writeValue(str, fp->difference); return; - case OPTMAX_DIRECTION: - case OPTMIN_DIRECTION: - Feature_writeDirection(fp, str); - case OPTMAX_CHANGE: - case OPTMIN_CHANGE: - Feature_writeChange(fp, str); + case OPTIM_MIN_MAX: + Feature_writeMinMax(fp, str); return; case LOCAL_FEATURE: case MODEL_FEATURE: - case OPTMAX_FEATURE: - case OPTMIN_FEATURE: + case OPTIM_FEATURE: Feature_writeName(fp, str); return; default: break; } - Feature_writeField(&fp->super, str, field); } static int Feature_compareByKey(const Row* v1, const Row* v2, int key) { diff --git a/src/treetop/pcp/Feature.h b/src/treetop/pcp/Feature.h index 4c72d3c61e..6f005a9f3d 100644 --- a/src/treetop/pcp/Feature.h +++ b/src/treetop/pcp/Feature.h @@ -21,10 +21,10 @@ typedef struct Feature_ { /* default result offset to use for searching metrics */ unsigned int offset; - char* change; - char* direction; float importance; float mutualinfo; + float difference; + char min_max[16]; } Feature; typedef struct FeatureFieldData_ { diff --git a/src/treetop/pcp/FeatureTable.c b/src/treetop/pcp/FeatureTable.c index 0d4e7e5dfa..c7de6f3e3e 100644 --- a/src/treetop/pcp/FeatureTable.c +++ b/src/treetop/pcp/FeatureTable.c @@ -29,13 +29,21 @@ in the source distribution for its full text. #include "pcp/Feature.h" -FeatureTable* FeatureTable_new(Machine* host) { +FeatureTable* FeatureTable_new(Machine* host, FeatureTableType type) { FeatureTable* this = xCalloc(1, sizeof(FeatureTable)); Object_setClass(this, Class(FeatureTable)); Table* super = &this->super; Table_init(super, Class(Row), host); + if (type == TABLE_LOCAL_IMPORTANCE) + this->feature = PCP_LOCAL_FEATURES; + else if (type == TABLE_OPTIM_IMPORTANCE) + this->feature = PCP_OPTIM_FEATURES; + else /* (type == TABLE_MODEL_IMPORTANCE) */ + this->feature = PCP_MODEL_FEATURES; + this->table_type = type; + return this; } @@ -56,7 +64,7 @@ static inline float Feature_float(int metric, int id, int offset, float fallback return fallback; } -static void FeatureTable_updateInfo(Feature* fp, int id, int offset) { +static void FeatureTable_updateModelInfo(Feature* fp, int id, int offset) { pmAtomValue value; if (!Metric_instance(PCP_MODEL_FEATURES, id, offset, &value, PM_TYPE_STRING)) @@ -68,6 +76,35 @@ static void FeatureTable_updateInfo(Feature* fp, int id, int offset) { fp->mutualinfo = Feature_float(PCP_MODEL_MUTUALINFO, id, offset, 0); } +static void FeatureTable_updateLocalInfo(Feature* fp, int id, int offset) { + pmAtomValue value; + + if (!Metric_instance(PCP_LOCAL_FEATURES, id, offset, &value, PM_TYPE_STRING)) + value.cp = xStrdup(""); + String_safeStrncpy(fp->name, value.cp, sizeof(fp->name)); + free(value.cp); + + fp->importance = Feature_float(PCP_LOCAL_IMPORTANCE, id, offset, 0); + fp->mutualinfo = Feature_float(PCP_LOCAL_MUTUALINFO, id, offset, 0); +} + +static void FeatureTable_updateOptimInfo(Feature* fp, int id, int offset) { + pmAtomValue value; + + if (!Metric_instance(PCP_OPTIM_FEATURES, id, offset, &value, PM_TYPE_STRING)) + value.cp = xStrdup(""); + String_safeStrncpy(fp->name, value.cp, sizeof(fp->name)); + free(value.cp); + + if (Metric_instance(PCP_OPTIM_MIN_MAX, id, offset, &value, PM_TYPE_STRING)) + value.cp = xStrdup(""); + String_safeStrncpy(fp->min_max, value.cp, sizeof(fp->min_max)); + free(value.cp); + + fp->difference = Feature_float(PCP_OPTIM_DIFFERENCE, id, offset, 0); + fp->mutualinfo = Feature_float(PCP_OPTIM_MUTUALINFO, id, offset, 0); +} + static Feature* FeatureTable_getFeature(FeatureTable* this, int id, bool* preExisting) { const Table* super = &this->super; Feature* fp = (Feature*) Hashtable_get(super->table, id); @@ -87,12 +124,17 @@ static void FeatureTable_goThroughEntries(FeatureTable* this) { int id = -1, offset = -1; /* for every important feature from the model ... */ - while (Metric_iterate(PCP_MODEL_FEATURES, &id, &offset)) { + while (Metric_iterate(this->feature, &id, &offset)) { bool preExisting; Feature* fp = FeatureTable_getFeature(this, id, &preExisting); fp->offset = offset >= 0 ? offset : 0; - FeatureTable_updateInfo(fp, id, offset); + if (this->table_type == TABLE_LOCAL_IMPORTANCE) + FeatureTable_updateLocalInfo(fp, id, offset); + else if (this->table_type == TABLE_OPTIM_IMPORTANCE) + FeatureTable_updateOptimInfo(fp, id, offset); + else /* (this->table_type == TABLE_MODEL_IMPORTANCE) */ + FeatureTable_updateModelInfo(fp, id, offset); Row* row = (Row*) fp; if (!preExisting) diff --git a/src/treetop/pcp/FeatureTable.h b/src/treetop/pcp/FeatureTable.h index 4f0e4e1432..cece05a9bd 100644 --- a/src/treetop/pcp/FeatureTable.h +++ b/src/treetop/pcp/FeatureTable.h @@ -10,15 +10,24 @@ in the source distribution for its full text. #include #include +#include "Metric.h" #include "Table.h" +typedef enum FeatureTableType_ { + TABLE_MODEL_IMPORTANCE, + TABLE_LOCAL_IMPORTANCE, + TABLE_OPTIM_IMPORTANCE, +} FeatureTableType; + typedef struct FeatureTable_ { Table super; + Metric feature; + FeatureTableType table_type; } FeatureTable; extern const TableClass FeatureTable_class; -FeatureTable* FeatureTable_new(struct Machine_* host); +FeatureTable* FeatureTable_new(struct Machine_* host, FeatureTableType type); void FeatureTable_done(FeatureTable* this); diff --git a/src/treetop/pcp/Metric.h b/src/treetop/pcp/Metric.h index 79b6e4eec1..71cf6667f7 100644 --- a/src/treetop/pcp/Metric.h +++ b/src/treetop/pcp/Metric.h @@ -50,7 +50,6 @@ typedef enum Metric_ { PCP_LOCAL_MUTUALINFO, /* treetop.server.explaining.local.mutual_information */ PCP_LOCAL_ELAPSED, /* treetop.server.explaining.shap.elapsed_time */ PCP_OPTIM_FEATURES, /* treetop.server.optimising.features */ - PCP_OPTIM_INC_DEC, /* treetop.server.optimising.inc_dec */ PCP_OPTIM_MIN_MAX, /* treetop.server.optimising.min_max */ PCP_OPTIM_DIFFERENCE, /* treetop.server.optimising.difference */ PCP_OPTIM_MUTUALINFO, /* treetop.server.optimising.mutual_information */ diff --git a/src/treetop/pcp/TreeTop.c b/src/treetop/pcp/TreeTop.c index 40e5b88978..5bb95d2fc1 100644 --- a/src/treetop/pcp/TreeTop.c +++ b/src/treetop/pcp/TreeTop.c @@ -119,7 +119,6 @@ static const char* Platform_metricNames[] = { [PCP_LOCAL_ELAPSED] = "mmv.treetop.server.explaining.local.elapsed_time", [PCP_OPTIM_FEATURES] = "mmv.treetop.server.optimising.features", [PCP_OPTIM_MIN_MAX] = "mmv.treetop.server.optimising.min_max", - [PCP_OPTIM_INC_DEC] = "mmv.treetop.server.optimising.inc_dec", [PCP_OPTIM_DIFFERENCE] = "mmv.treetop.server.optimising.difference", [PCP_OPTIM_MUTUALINFO] = "mmv.treetop.server.optimising.mutual_infomation", [PCP_OPTIM_ELAPSED] = "mmv.treetop.server.optimising.elapsed_time", @@ -444,10 +443,6 @@ void Platform_getHostname(char* buffer, size_t size) { String_safeStrncpy(buffer, hostname, size); } -void Platform_getRelease(char** string) { - *string = NULL; -} - void Platform_longOptionsUsage(ATTR_UNUSED const char* name) { printf( " --host=HOSTSPEC metrics source is PMCD at HOSTSPEC [see PCPIntro(1)]\n" @@ -562,13 +557,27 @@ void Platform_addDynamicScreenAvailableColumns(Panel* availableColumns, const ch ProcessTable* ProcessTable_new(Machine* host, Hashtable* idMatchList) { (void)idMatchList; - pcp->model_features = FeatureTable_new(host); + pcp->model_features = FeatureTable_new(host, TABLE_MODEL_IMPORTANCE); return (ProcessTable*) pcp->model_features; } void Platform_updateTables(Machine* host) { - pcp->local_features = FeatureTable_new(host); - pcp->optim_features = FeatureTable_new(host); + pcp->local_features = FeatureTable_new(host, TABLE_LOCAL_IMPORTANCE); + pcp->optim_features = FeatureTable_new(host, TABLE_OPTIM_IMPORTANCE); +} + +Table* Platform_getTable(const char* name) { + for (unsigned int i = 0; i < Platform_numberOfDefaultScreens; i++) { + if (!String_eq(name, Platform_defaultScreens[i].name)) + continue; + if (i == TABLE_LOCAL_IMPORTANCE) + return &pcp->local_features->super; + if (i == TABLE_OPTIM_IMPORTANCE) + return &pcp->optim_features->super; + break; + } + /* default: TABLE_MODEL_IMPORTANCE */ + return &pcp->model_features->super; } void Platform_updateMap(void) { diff --git a/src/treetop/pcp/TreeTop.h b/src/treetop/pcp/TreeTop.h index 0edddc7a53..e750fee7e5 100644 --- a/src/treetop/pcp/TreeTop.h +++ b/src/treetop/pcp/TreeTop.h @@ -105,13 +105,9 @@ pid_t Platform_getMaxPid(void); double Platform_setCPUValues(Meter* this, int cpu); -char* Platform_getProcessEnv(pid_t pid); - -void Platform_getPressureStall(const char* file, bool some, double* ten, double* sixty, double* threehundred); - void Platform_getHostname(char* buffer, size_t size); -void Platform_getRelease(char** string); +Table* Platform_getTable(const char* name); enum { PLATFORM_LONGOPT_HOST = 128, diff --git a/vendor/github.com/htop-dev/htop/Settings.c b/vendor/github.com/htop-dev/htop/Settings.c index ab95b77059..b9fa2dfc57 100644 --- a/vendor/github.com/htop-dev/htop/Settings.c +++ b/vendor/github.com/htop-dev/htop/Settings.c @@ -315,7 +315,7 @@ ScreenSettings* Settings_newScreen(Settings* this, const ScreenDefaults* default *ss = (ScreenSettings) { .heading = xStrdup(defaults->name), .dynamic = NULL, - .table = NULL, + .table = Platform_getTable(defaults->name), .fields = xCalloc(LAST_PROCESSFIELD, sizeof(ProcessField)), .flags = 0, .direction = sortDesc ? -1 : 1,