diff options
author | Nathan Scott <nathans@redhat.com> | 2021-06-23 17:44:56 +1000 |
---|---|---|
committer | Nathan Scott <nathans@redhat.com> | 2021-07-07 10:59:36 +1000 |
commit | f0ed0fdafb9ecefc9d103ffb8f5d91bf723518f6 (patch) | |
tree | 8f82bf54c96a07d8efa5c9a8bd2c50865bd6757a /pcp/Platform.c | |
parent | 865b85eb2d31321e9c37334838fa514ac348d61a (diff) |
Add a new DynamicMeter class for runtime Meter extension
This commit is based on exploratory work by Sohaib Mohamed.
The end goal is two-fold - to support addition of Meters we
build via configuration files for both the PCP platform and
for scripts ( https://github.com/htop-dev/htop/issues/526 )
Here, we focus on generic code and the PCP support. A new
class DynamicMeter is introduced - it uses the special case
'param' field handling that previously was used only by the
CPUMeter, such that every runtime-configured Meter is given
a unique identifier. Unlike with the CPUMeter this is used
internally only. When reading/writing to htoprc instead of
CPU(N) - where N is an integer param (CPU number) - we use
the string name for each meter. For example, if we have a
configuration for a DynamicMeter for some Redis metrics, we
might read and write "Dynamic(redis)". This identifier is
subsequently matched (back) up to the configuration file so
we're able to re-create arbitrary user configurations.
The PCP platform configuration file format is fairly simple.
We expand configs from several directories, including the
users homedir alongside htoprc (below htop/meters/) and also
/etc/pcp/htop/meters. The format will be described via a
new pcp-htop(5) man page, but its basically ini-style and
each Meter has one or more metric expressions associated, as
well as specifications for labels, color and so on via a dot
separated notation for individual metrics within the Meter.
A few initial sample configuration files are provided below
./pcp/meters that give the general idea. The PCP "derived"
metric specification - see pmRegisterDerived(3) - is used
as the syntax for specifying metrics in PCP DynamicMeters.
Diffstat (limited to 'pcp/Platform.c')
-rw-r--r-- | pcp/Platform.c | 52 |
1 files changed, 43 insertions, 9 deletions
diff --git a/pcp/Platform.c b/pcp/Platform.c index 42db6be1..f10b128b 100644 --- a/pcp/Platform.c +++ b/pcp/Platform.c @@ -20,6 +20,7 @@ in the source distribution for its full text. #include "DateMeter.h" #include "DateTimeMeter.h" #include "DiskIOMeter.h" +#include "DynamicMeter.h" #include "HostnameMeter.h" #include "LoadAverageMeter.h" #include "Macros.h" @@ -41,6 +42,7 @@ in the source distribution for its full text. #include "linux/PressureStallMeter.h" #include "linux/ZramMeter.h" #include "linux/ZramStats.h" +#include "pcp/PCPDynamicMeter.h" #include "pcp/PCPProcess.h" #include "pcp/PCPProcessList.h" #include "zfs/ZfsArcMeter.h" @@ -50,14 +52,14 @@ in the source distribution for its full text. typedef struct Platform_ { int context; /* PMAPI(3) context identifier */ - unsigned int total; /* total number of all metrics */ + unsigned int totalMetrics; /* total number of all metrics */ const char** names; /* name array indexed by Metric */ pmID* pmids; /* all known metric identifiers */ pmID* fetch; /* enabled identifiers for sampling */ pmDesc* descs; /* metric desc array indexed by Metric */ pmResult* result; /* sample values result indexed by Metric */ + PCPDynamicMeters meters; /* dynamic meters via configuration files */ struct timeval offset; /* time offset used in archive mode only */ - long long btime; /* boottime in seconds since the epoch */ char* release; /* uname and distro from this context */ int pidmax; /* maximum platform process identifier */ @@ -78,6 +80,7 @@ const unsigned int Platform_numberOfSignals = ARRAYSIZE(Platform_signals); const MeterClass* const Platform_meterTypes[] = { &CPUMeter_class, + &DynamicMeter_class, &ClockMeter_class, &DateMeter_class, &DateTimeMeter_class, @@ -244,7 +247,13 @@ static const char *Platform_metricNames[] = { [PCP_METRIC_COUNT] = NULL }; +const pmDesc* Metric_desc(Metric metric) { + return &pcp->descs[metric]; +} + pmAtomValue* Metric_values(Metric metric, pmAtomValue *atom, int count, int type) { + if (pcp->result == NULL) + return NULL; pmValueSet* vset = pcp->result->vset[metric]; if (!vset || vset->numval <= 0) @@ -374,7 +383,7 @@ bool Metric_fetch(struct timeval *timestamp) { pmFreeResult(pcp->result); pcp->result = NULL; } - int sts = pmFetch(pcp->total, pcp->fetch, &pcp->result); + int sts = pmFetch(pcp->totalMetrics, pcp->fetch, &pcp->result); if (sts < 0) { if (pmDebugOptions.appl0) fprintf(stderr, "Error: cannot fetch metric values: %s\n", @@ -386,12 +395,12 @@ bool Metric_fetch(struct timeval *timestamp) { return true; } -static int Platform_addMetric(Metric id, const char *name) { +int Platform_addMetric(Metric id, const char *name) { unsigned int i = (unsigned int)id; - if (i >= PCP_METRIC_COUNT && i >= pcp->total) { + if (i >= PCP_METRIC_COUNT && i >= pcp->totalMetrics) { /* added via configuration files */ - unsigned int j = pcp->total + 1; + unsigned int j = pcp->totalMetrics + 1; pcp->fetch = xRealloc(pcp->fetch, j * sizeof(pmID)); pcp->pmids = xRealloc(pcp->pmids, j * sizeof(pmID)); pcp->names = xRealloc(pcp->names, j * sizeof(char*)); @@ -401,7 +410,7 @@ static int Platform_addMetric(Metric id, const char *name) { pcp->pmids[i] = pcp->fetch[i] = PM_ID_NULL; pcp->names[i] = name; - return ++pcp->total; + return ++pcp->totalMetrics; } /* global state from the environment and command line arguments */ @@ -449,14 +458,17 @@ void Platform_init(void) { for (unsigned int i = 0; i < PCP_METRIC_COUNT; i++) Platform_addMetric(i, Platform_metricNames[i]); + pcp->meters.offset = PCP_METRIC_COUNT; - sts = pmLookupName(pcp->total, pcp->names, pcp->pmids); + PCPDynamicMeters_init(&pcp->meters); + + sts = pmLookupName(pcp->totalMetrics, pcp->names, pcp->pmids); if (sts < 0) { fprintf(stderr, "Error: cannot lookup metric names: %s\n", pmErrStr(sts)); exit(1); } - for (unsigned int i = 0; i < pcp->total; i++) { + for (unsigned int i = 0; i < pcp->totalMetrics; i++) { pcp->fetch[i] = PM_ID_NULL; /* default is to not sample */ /* expect some metrics to be missing - e.g. PMDA not available */ @@ -883,3 +895,25 @@ void Platform_gettime_monotonic(uint64_t* msec) { struct timeval* tv = &pcp->result->timestamp; *msec = ((uint64_t)tv->tv_sec * 1000) + ((uint64_t)tv->tv_usec / 1000); } + +Hashtable* Platform_dynamicMeters(void) { + return pcp->meters.table; +} + +void Platform_dynamicMeterInit(Meter* meter) { + PCPDynamicMeter* this = Hashtable_get(pcp->meters.table, meter->param); + if (this) + PCPDynamicMeter_enable(this); +} + +void Platform_dynamicMeterUpdateValues(Meter* meter) { + PCPDynamicMeter* this = Hashtable_get(pcp->meters.table, meter->param); + if (this) + PCPDynamicMeter_updateValues(this, meter); +} + +void Platform_dynamicMeterDisplay(const Meter* meter, RichString* out) { + PCPDynamicMeter* this = Hashtable_get(pcp->meters.table, meter->param); + if (this) + PCPDynamicMeter_display(this, meter, out); +} |