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 /DynamicMeter.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 'DynamicMeter.c')
-rw-r--r-- | DynamicMeter.c | 98 |
1 files changed, 98 insertions, 0 deletions
diff --git a/DynamicMeter.c b/DynamicMeter.c new file mode 100644 index 00000000..7b39fdaa --- /dev/null +++ b/DynamicMeter.c @@ -0,0 +1,98 @@ +/* +htop - DynamicMeter.c +(C) 2021 htop dev team +(C) 2021 Red Hat, Inc. All Rights Reserved. +Released under the GNU GPLv2, see the COPYING file +in the source distribution for its full text. +*/ +#include "config.h" // IWYU pragma: keep + +#include "DynamicMeter.h" + +#include "CRT.h" +#include "Object.h" +#include "Platform.h" +#include "ProcessList.h" +#include "RichString.h" +#include "XUtils.h" + + +static const int DynamicMeter_attributes[] = { + DYNAMIC_GRAY, + DYNAMIC_DARKGRAY, + DYNAMIC_RED, + DYNAMIC_GREEN, + DYNAMIC_BLUE, + DYNAMIC_CYAN, + DYNAMIC_MAGENTA, + DYNAMIC_YELLOW, + DYNAMIC_WHITE +}; + +Hashtable* DynamicMeters_new(void) { + return Platform_dynamicMeters(); +} + +typedef struct { + unsigned int key; + const char* name; +} DynamicIterator; + +static void DynamicMeter_compare(ht_key_t key, void* value, void* data) { + const DynamicMeter* meter = (const DynamicMeter*)value; + DynamicIterator* iter = (DynamicIterator*)data; + if (String_eq(iter->name, meter->name)) + iter->key = key; +} + +unsigned int DynamicMeter_search(const ProcessList* pl, const char* name) { + DynamicIterator iter = { .key = 0, .name = name }; + if (pl->dynamicMeters) + Hashtable_foreach(pl->dynamicMeters, DynamicMeter_compare, &iter); + return iter.key; +} + +const char* DynamicMeter_lookup(const ProcessList* pl, unsigned int key) { + const DynamicMeter* meter = Hashtable_get(pl->dynamicMeters, key); + return meter ? meter->name : NULL; +} + +static void DynamicMeter_init(Meter* meter) { + Platform_dynamicMeterInit(meter); +} + +static void DynamicMeter_updateValues(Meter* meter) { + Platform_dynamicMeterUpdateValues(meter); +} + +static void DynamicMeter_display(const Object* cast, RichString* out) { + const Meter* meter = (const Meter*)cast; + Platform_dynamicMeterDisplay(meter, out); +} + +static void DynamicMeter_getUiName(const Meter* this, char* name, size_t length) { + const ProcessList* pl = this->pl; + const DynamicMeter* meter = Hashtable_get(pl->dynamicMeters, this->param); + if (meter) { + const char* uiName = meter->caption ? meter->caption : meter->name; + xSnprintf(name, length, "%s", uiName); + } +} + +const MeterClass DynamicMeter_class = { + .super = { + .extends = Class(Meter), + .delete = Meter_delete, + .display = DynamicMeter_display + }, + .init = DynamicMeter_init, + .updateValues = DynamicMeter_updateValues, + .getUiName = DynamicMeter_getUiName, + .defaultMode = TEXT_METERMODE, + .maxItems = 0, + .total = 100.0, + .attributes = DynamicMeter_attributes, + .name = "Dynamic", + .uiName = "Dynamic", + .caption = "", +}; |