summaryrefslogtreecommitdiffstats
path: root/pcp
diff options
context:
space:
mode:
authorNathan Scott <nathans@redhat.com>2021-06-23 17:44:56 +1000
committerNathan Scott <nathans@redhat.com>2021-07-07 10:59:36 +1000
commitf0ed0fdafb9ecefc9d103ffb8f5d91bf723518f6 (patch)
tree8f82bf54c96a07d8efa5c9a8bd2c50865bd6757a /pcp
parent865b85eb2d31321e9c37334838fa514ac348d61a (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')
-rw-r--r--pcp/PCPDynamicMeter.c368
-rw-r--r--pcp/PCPDynamicMeter.h36
-rw-r--r--pcp/PCPProcessList.c4
-rw-r--r--pcp/PCPProcessList.h2
-rw-r--r--pcp/Platform.c52
-rw-r--r--pcp/Platform.h15
-rw-r--r--pcp/meters/entropy9
-rw-r--r--pcp/meters/freespace11
-rw-r--r--pcp/meters/ipc13
-rw-r--r--pcp/meters/locks15
-rw-r--r--pcp/meters/memcache11
-rw-r--r--pcp/meters/mysql73
-rw-r--r--pcp/meters/postfix21
-rw-r--r--pcp/meters/redis41
-rw-r--r--pcp/meters/tcp22
15 files changed, 680 insertions, 13 deletions
diff --git a/pcp/PCPDynamicMeter.c b/pcp/PCPDynamicMeter.c
new file mode 100644
index 00000000..0dad1ec3
--- /dev/null
+++ b/pcp/PCPDynamicMeter.c
@@ -0,0 +1,368 @@
+/*
+htop - PCPDynamicMeter.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 "pcp/PCPDynamicMeter.h"
+
+#include <math.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "Object.h"
+#include "Platform.h"
+#include "ProcessList.h"
+#include "RichString.h"
+#include "Settings.h"
+#include "XUtils.h"
+
+static PCPDynamicMetric* PCPDynamicMeter_lookupMetric(PCPDynamicMeters* meters, PCPDynamicMeter* meter, const char* name) {
+ size_t bytes = 8 + strlen(meter->super.name) + strlen(name);
+ char* metricName = xMalloc(bytes);
+ xSnprintf(metricName, bytes, "htop.%s.%s", meter->super.name, name);
+
+ PCPDynamicMetric* metric;
+ for (unsigned int i = 0; i < meter->totalMetrics; i++) {
+ metric = &meter->metrics[i];
+ if (String_eq(metric->name, metricName)) {
+ free(metricName);
+ return metric;
+ }
+ }
+
+ /* not an existing metric in this meter - add it */
+ unsigned int n = meter->totalMetrics + 1;
+ meter->metrics = xReallocArray(meter->metrics, n, sizeof(PCPDynamicMetric));
+ meter->totalMetrics = n;
+ metric = &meter->metrics[n-1];
+ memset(metric, 0, sizeof(PCPDynamicMetric));
+ metric->name = metricName;
+ metric->id = meters->offset + meters->cursor;
+ meters->cursor++;
+
+ Platform_addMetric(metric->id, metricName);
+
+ return metric;
+}
+
+static void PCPDynamicMeter_parseMetric(PCPDynamicMeters* meters, PCPDynamicMeter* meter, const char *path, unsigned int line, char* key, char* value) {
+ PCPDynamicMetric *metric;
+ char* p;
+
+ if ((p = strchr(key, '.')) == NULL)
+ return;
+ *p++ = '\0'; /* end the name, p is now the attribute, e.g. 'label' */
+
+ if (String_eq(p, "metric")) {
+ /* lookup a dynamic metric with this name, else create */
+ metric = PCPDynamicMeter_lookupMetric(meters, meter, key);
+
+ /* use derived metrics in dynamic meters for simplicity */
+ char* error;
+ if (pmRegisterDerivedMetric(metric->name, value, &error) < 0) {
+ char note[1024];
+ xSnprintf(note, sizeof(note),
+ "failed to parse expression in %s at line %u\n%s\n%s",
+ path, line, error, pmGetProgname());
+ free(error);
+ errno = EINVAL;
+ CRT_fatalError(note);
+ }
+ } else {
+ /* this is a property of a dynamic metric - the metric expression */
+ /* may not have been observed yet - i.e. we allow for any ordering */
+ metric = PCPDynamicMeter_lookupMetric(meters, meter, key);
+ if (String_eq(p, "color")) {
+ if (String_eq(value, "gray"))
+ metric->color = DYNAMIC_GRAY;
+ else if (String_eq(value, "darkgray"))
+ metric->color = DYNAMIC_DARKGRAY;
+ else if (String_eq(value, "red"))
+ metric->color = DYNAMIC_RED;
+ else if (String_eq(value, "green"))
+ metric->color = DYNAMIC_GREEN;
+ else if (String_eq(value, "blue"))
+ metric->color = DYNAMIC_BLUE;
+ else if (String_eq(value, "cyan"))
+ metric->color = DYNAMIC_CYAN;
+ else if (String_eq(value, "magenta"))
+ metric->color = DYNAMIC_MAGENTA;
+ else if (String_eq(value, "yellow"))
+ metric->color = DYNAMIC_YELLOW;
+ else if (String_eq(value, "white"))
+ metric->color = DYNAMIC_WHITE;
+ } else if (String_eq(p, "label")) {
+ free_and_xStrdup(&metric->label, value);
+ } else if (String_eq(p, "suffix")) {
+ free_and_xStrdup(&metric->suffix, value);
+ }
+ }
+}
+
+// Ensure a valid name for use in a PCP metric name and in htoprc
+static void PCPDynamicMeter_validateMeterName(char* key, const char *path, unsigned int line) {
+ char* p = key;
+ char* end = strrchr(key, ']');
+
+ if (end) {
+ *end = '\0';
+ } else {
+ char note[1024];
+ xSnprintf(note, sizeof(note),
+ "No closing brace on meter name at %s line %u\n\"%s\"",
+ path, line, key);
+ errno = EINVAL;
+ CRT_fatalError(note);
+ }
+
+ while (*p) {
+ if (p == key) {
+ if (!isalpha(*p) && *p != '_')
+ break;
+ } else {
+ if (!isalnum(*p) && *p != '_')
+ break;
+ }
+ p++;
+ }
+ if (*p != '\0') { /* badness */
+ char note[1024];
+ xSnprintf(note, sizeof(note),
+ "Invalid meter name at %s line %u\n\"%s\"",
+ path, line, key);
+ errno = EINVAL;
+ CRT_fatalError(note);
+ } else { /* overwrite closing brace */
+ *p = '\0';
+ }
+}
+
+static PCPDynamicMeter* PCPDynamicMeter_new(PCPDynamicMeters* meters, const char* name) {
+ PCPDynamicMeter* meter = xCalloc(1, sizeof(*meter));
+ String_safeStrncpy(meter->super.name, name, sizeof(meter->super.name));
+ Hashtable_put(meters->table, ++meters->count, meter);
+ return meter;
+}
+
+static void PCPDynamicMeter_parseFile(PCPDynamicMeters* meters, const char* path) {
+ FILE* file = fopen(path, "r");
+ if (!file)
+ return;
+
+ PCPDynamicMeter* meter = NULL;
+ unsigned int lineno = 0;
+ for (;;) {
+ char* line = String_readLine(file);
+ if (!line)
+ break;
+ lineno++;
+
+ /* cleanup whitespace, skip comment lines */
+ char* trimmed = String_trim(line);
+ free(line);
+ if (trimmed[0] == '#' || trimmed[0] == '\0') {
+ free(trimmed);
+ continue;
+ }
+
+ size_t n;
+ char** config = String_split(trimmed, '=', &n);
+ free(trimmed);
+ if (config == NULL)
+ continue;
+
+ char* key = String_trim(config[0]);
+ char* value = n > 1 ? String_trim(config[1]) : NULL;
+ if (key[0] == '[') { /* new section heading - i.e. new meter */
+ PCPDynamicMeter_validateMeterName(key+1, path, lineno);
+ meter = PCPDynamicMeter_new(meters, key+1);
+ } else if (value && String_eq(key, "caption")) {
+ free_and_xStrdup(&meter->super.caption, value);
+ } else if (value && String_eq(key, "description")) {
+ free_and_xStrdup(&meter->super.description, value);
+ } else if (value && String_eq(key, "type")) {
+ if (String_eq(config[1], "bar"))
+ meter->super.type = BAR_METERMODE;
+ else if (String_eq(config[1], "text"))
+ meter->super.type = TEXT_METERMODE;
+ else if (String_eq(config[1], "graph"))
+ meter->super.type = GRAPH_METERMODE;
+ else if (String_eq(config[1], "led"))
+ meter->super.type = LED_METERMODE;
+ } else if (value && String_eq(key, "maximum")) {
+ meter->super.maximum = strtod(value, NULL);
+ } else if (value) {
+ PCPDynamicMeter_parseMetric(meters, meter, path, lineno, key, value);
+ }
+ String_freeArray(config);
+ free(value);
+ free(key);
+ }
+ fclose(file);
+}
+
+static void PCPDynamicMeter_scanDir(PCPDynamicMeters* meters, char* path) {
+ DIR* dir = opendir(path);
+ if (!dir)
+ return;
+
+ struct dirent *dirent;
+ while ((dirent = readdir(dir)) != NULL) {
+ if (dirent->d_name[0] == '.')
+ continue;
+
+ char *file = String_cat(path, dirent->d_name);
+ PCPDynamicMeter_parseFile(meters, file);
+ free(file);
+ }
+ closedir(dir);
+}
+
+void PCPDynamicMeters_init(PCPDynamicMeters* meters) {
+ const char* sysconf = pmGetConfig("PCP_SYSCONF_DIR");
+ const char* xdgConfigHome = getenv("XDG_CONFIG_HOME");
+ const char* home = getenv("HOME");
+ char* path;
+
+ meters->table = Hashtable_new(0, true);
+
+ /* search in the users home directory first of all */
+ if (xdgConfigHome) {
+ path = String_cat(xdgConfigHome, "/htop/meters/");
+ } else {
+ if (!home)
+ home = "";
+ path = String_cat(home, "/.config/htop/meters/");
+ }
+ PCPDynamicMeter_scanDir(meters, path);
+ free(path);
+
+ /* secondly search in the system meters directory */
+ path = String_cat(sysconf, "/htop/meters/");
+ PCPDynamicMeter_scanDir(meters, path);
+ free(path);
+
+ /* check the working directory, as a final option */
+ char cwd[PATH_MAX];
+ if (getcwd(cwd, sizeof(cwd)) != NULL) {
+ path = String_cat(cwd, "/pcp/meters/");
+ PCPDynamicMeter_scanDir(meters, path);
+ free(path);
+ }
+}
+
+void PCPDynamicMeter_enable(PCPDynamicMeter* this) {
+ for (unsigned int i = 0; i < this->totalMetrics; i++)
+ Metric_enable(this->metrics[i].id, true);
+}
+
+void PCPDynamicMeter_updateValues(PCPDynamicMeter* this, Meter* meter) {
+ char* buffer = meter->txtBuffer;
+ size_t size = sizeof(meter->txtBuffer);
+ size_t bytes = 0;
+
+ for (unsigned int i = 0; i < this->totalMetrics; i++) {
+ if (i > 0 && bytes < size - 1)
+ buffer[bytes++] = '/'; /* separator */
+
+ PCPDynamicMetric* metric = &this->metrics[i];
+ const pmDesc* desc = Metric_desc(metric->id);
+ pmAtomValue atom;
+
+ if (!Metric_values(metric->id, &atom, 1, desc->type)) {
+ bytes--; /* clear the separator */
+ continue;
+ }
+ /* TODO: pretty-print the values - pmConvScale, etc */
+ switch (desc->type) {
+ case PM_TYPE_STRING:
+ bytes += xSnprintf(buffer + bytes, size - bytes, "%s", atom.cp);
+ free(atom.cp);
+ break;
+ case PM_TYPE_32:
+ bytes += xSnprintf(buffer + bytes, size - bytes, "%d", atom.l);
+ break;
+ case PM_TYPE_U32:
+ bytes += xSnprintf(buffer + bytes, size - bytes, "%u", atom.ul);
+ break;
+ case PM_TYPE_64:
+ bytes += xSnprintf(buffer + bytes, size - bytes, "%lld", (long long) atom.ll);
+ break;
+ case PM_TYPE_U64:
+ bytes += xSnprintf(buffer + bytes, size - bytes, "%llu", (unsigned long long) atom.ull);
+ break;
+ case PM_TYPE_FLOAT:
+ bytes += xSnprintf(buffer + bytes, size - bytes, "%f", (double) atom.f);
+ break;
+ case PM_TYPE_DOUBLE:
+ bytes += xSnprintf(buffer + bytes, size - bytes, "%f", atom.d);
+ break;
+ default:
+ break;
+ }
+ }
+ if (!bytes)
+ xSnprintf(buffer, size, "no data");
+}
+
+void PCPDynamicMeter_display(PCPDynamicMeter* this, ATTR_UNUSED const Meter* meter, RichString* out) {
+ int nodata = 1;
+
+ for (unsigned int i = 0; i < this->totalMetrics; i++) {
+ PCPDynamicMetric* metric = &this->metrics[i];
+ const pmDesc* desc = Metric_desc(metric->id);
+ pmAtomValue atom;
+ char buffer[64];
+ int len;
+
+ if (!Metric_values(metric->id, &atom, 1, desc->type))
+ continue;
+ nodata = 0;
+
+ if (i > 0)
+ RichString_appendnAscii(out, CRT_colors[metric->color], " ", 1);
+
+ if (metric->label) {
+ len = xSnprintf(buffer, sizeof(buffer), "%s ", metric->label);
+ RichString_appendnAscii(out, CRT_colors[metric->color], buffer, len);
+ }
+
+ /* TODO: pretty-print the values - pmConvScale, etc */
+ len = 0;
+ switch (desc->type) {
+ case PM_TYPE_STRING:
+ len = xSnprintf(buffer, sizeof(buffer), "%s", atom.cp);
+ free(atom.cp);
+ break;
+ case PM_TYPE_32:
+ len = xSnprintf(buffer, sizeof(buffer), "%d", atom.l);
+ break;
+ case PM_TYPE_U32:
+ len = xSnprintf(buffer, sizeof(buffer), "%u", atom.ul);
+ break;
+ case PM_TYPE_64:
+ len = xSnprintf(buffer, sizeof(buffer), "%lld", (long long) atom.ll);
+ break;
+ case PM_TYPE_U64:
+ len = xSnprintf(buffer, sizeof(buffer), "%llu", (unsigned long long) atom.ull);
+ break;
+ case PM_TYPE_FLOAT:
+ len = xSnprintf(buffer, sizeof(buffer), "%f", (double)atom.f);
+ break;
+ case PM_TYPE_DOUBLE:
+ len = xSnprintf(buffer, sizeof(buffer), "%f", atom.d);
+ break;
+ default:
+ break;
+ }
+ if (len)
+ RichString_appendnAscii(out, CRT_colors[metric->color], buffer, len);
+ }
+ if (nodata)
+ RichString_writeAscii(out, CRT_colors[METER_VALUE_ERROR], "no data");
+}
diff --git a/pcp/PCPDynamicMeter.h b/pcp/PCPDynamicMeter.h
new file mode 100644
index 00000000..e73a1bca
--- /dev/null
+++ b/pcp/PCPDynamicMeter.h
@@ -0,0 +1,36 @@
+#ifndef HEADER_PCPDynamicMeter
+#define HEADER_PCPDynamicMeter
+
+#include "CRT.h"
+#include "DynamicMeter.h"
+
+typedef struct {
+ unsigned int id; /* index into metric array */
+ ColorElements color;
+ char* name; /* derived metric name */
+ char* label;
+ char* suffix;
+} PCPDynamicMetric;
+
+typedef struct {
+ DynamicMeter super;
+ PCPDynamicMetric *metrics;
+ unsigned int totalMetrics;
+} PCPDynamicMeter;
+
+typedef struct {
+ Hashtable* table;
+ unsigned int count; /* count of dynamic meters discovered by scan */
+ unsigned int offset; /* start offset into the Platform metric array */
+ unsigned int cursor; /* identifier allocator for each new metric used */
+} PCPDynamicMeters;
+
+void PCPDynamicMeters_init(PCPDynamicMeters* meters);
+
+void PCPDynamicMeter_enable(PCPDynamicMeter* this);
+
+void PCPDynamicMeter_updateValues(PCPDynamicMeter* this, Meter* meter);
+
+void PCPDynamicMeter_display(PCPDynamicMeter* this, const Meter* meter, RichString* out);
+
+#endif
diff --git a/pcp/PCPProcessList.c b/pcp/PCPProcessList.c
index ef37da2d..bece854d 100644
--- a/pcp/PCPProcessList.c
+++ b/pcp/PCPProcessList.c
@@ -59,11 +59,11 @@ static char* setUser(UsersTable* this, unsigned int uid, int pid, int offset) {
return name;
}
-ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* pidMatchList, uid_t userId) {
+ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* dynamicMeters, Hashtable* pidMatchList, uid_t userId) {
PCPProcessList* this = xCalloc(1, sizeof(PCPProcessList));
ProcessList* super = &(this->super);
- ProcessList_init(super, Class(PCPProcess), usersTable, pidMatchList, userId);
+ ProcessList_init(super, Class(PCPProcess), usersTable, dynamicMeters, pidMatchList, userId);
struct timeval timestamp;
gettimeofday(&timestamp, NULL);
diff --git a/pcp/PCPProcessList.h b/pcp/PCPProcessList.h
index 23da6637..f1784904 100644
--- a/pcp/PCPProcessList.h
+++ b/pcp/PCPProcessList.h
@@ -63,7 +63,7 @@ typedef struct PCPProcessList_ {
ZfsArcStats zfs;
} PCPProcessList;
-ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* pidMatchList, uid_t userId);
+ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* dynamicMeters, Hashtable* pidMatchList, uid_t userId);
void ProcessList_delete(ProcessList* pl);
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);
+}
diff --git a/pcp/Platform.h b/pcp/Platform.h
index cd90bc00..7cf3722b 100644
--- a/pcp/Platform.h
+++ b/pcp/Platform.h
@@ -24,6 +24,7 @@ in the source distribution for its full text.
#include "Action.h"
#include "BatteryMeter.h"
#include "DiskIOMeter.h"
+#include "Hashtable.h"
#include "Meter.h"
#include "NetworkIOMeter.h"
#include "Process.h"
@@ -247,14 +248,26 @@ bool Metric_iterate(Metric metric, int* instp, int* offsetp);
pmAtomValue* Metric_values(Metric metric, pmAtomValue *atom, int count, int type);
+const pmDesc* Metric_desc(Metric metric);
+
int Metric_instanceCount(Metric metric);
int Metric_instanceOffset(Metric metric, int inst);
-pmAtomValue *Metric_instance(Metric metric, int inst, int offset, pmAtomValue *atom, int type);
+pmAtomValue* Metric_instance(Metric metric, int inst, int offset, pmAtomValue *atom, int type);
+
+int Platform_addMetric(Metric id, const char *name);
void Platform_gettime_realtime(struct timeval* tv, uint64_t* msec);
void Platform_gettime_monotonic(uint64_t* msec);
+Hashtable* Platform_dynamicMeters(void);
+
+void Platform_dynamicMeterInit(Meter* meter);
+
+void Platform_dynamicMeterUpdateValues(Meter* meter);
+
+void Platform_dynamicMeterDisplay(const Meter* meter, RichString* out);
+
#endif
diff --git a/pcp/meters/entropy b/pcp/meters/entropy
new file mode 100644
index 00000000..0bef0cfc
--- /dev/null
+++ b/pcp/meters/entropy
@@ -0,0 +1,9 @@
+#
+# pcp-htop(1) configuration file - see pcp-htop(5)
+#
+
+[entropy]
+caption = Entropy
+avail.metric = kernel.all.entropy.avail / kernel.all.entropy.poolsize * 100
+avail.label = avail
+avail.suffix = %
diff --git a/pcp/meters/freespace b/pcp/meters/freespace
new file mode 100644
index 00000000..074af6d6
--- /dev/null
+++ b/pcp/meters/freespace
@@ -0,0 +1,11 @@
+#
+# pcp-htop(1) configuration file - see pcp-htop(5)
+#
+
+[freespace]
+caption = Freespace
+description = Filesystem space
+used.metric = sum(filesys.used)
+used.color = blue
+free.metric = sum(filesys.free)
+free.color = green
diff --git a/pcp/meters/ipc b/pcp/meters/ipc
new file mode 100644
index 00000000..4162f392
--- /dev/null
+++ b/pcp/meters/ipc
@@ -0,0 +1,13 @@
+#
+# pcp-htop(1) configuration file - see pcp-htop(5)
+#
+
+[ipc]
+caption = SysV IPC
+description = SysV IPC counts
+msg.metric = ipc.msg.used_queues
+msg.color = blue
+sem.metric = ipc.sem.used_sem
+sem.color = green
+shm.metric = ipc.shm.used_ids
+shm.color = cyan
diff --git a/pcp/meters/locks b/pcp/meters/locks
new file mode 100644
index 00000000..5d095106
--- /dev/null
+++ b/pcp/meters/locks
@@ -0,0 +1,15 @@
+#
+# pcp-htop(1) configuration file - see pcp-htop(5)
+#
+
+[locks]
+caption = File locks
+description = VFS file locks
+posix.metric = vfs.locks.posix.count
+posix.color = blue
+flock.metric = vfs.locks.flock.count
+flock.color = green
+readlock.metric = vfs.locks.posix.read + vfs.locks.flock.read
+readlock.color = red
+writelock.metric = vfs.locks.posix.write + vfs.locks.flock.write
+writelock.color = yellow
diff --git a/pcp/meters/memcache b/pcp/meters/memcache
new file mode 100644
index 00000000..0f2fac23
--- /dev/null
+++ b/pcp/meters/memcache
@@ -0,0 +1,11 @@
+#
+# pcp-htop(1) configuration file - see pcp-htop(5)
+#
+
+[memcache]
+caption = Memcache
+description = Memcache Hits
+hit.metric = sum(memcache.hits)
+hit.color = green
+miss.metric = sum(memcache.misses)
+miss.color = blue
diff --git a/pcp/meters/mysql b/pcp/meters/mysql
new file mode 100644
index 00000000..07ae11e9
--- /dev/null
+++ b/pcp/meters/mysql
@@ -0,0 +1,73 @@
+#
+# pcp-htop(1) configuration file - see pcp-htop(5)
+#
+
+[mysql_io]
+caption = MySQL I/O
+recv.metric = mysql.status.bytes_received
+recv.color = green
+recv.label = recv
+sent.metric = mysql.status.bytes_sent
+sent.color = blue
+sent.label = sent
+
+[mysql_keys]
+caption = MySQL keys
+description = MySQL key status
+key_blocks_used.metric = mysql.status.key_blocks_used
+key_blocks_used.label = color
+key_blocks_used.label = used
+key_reads.metric = mysql.status.key_reads
+key_reads.label = read
+key_reads.color = green
+key_writes.metric = mysql.status.key_writes
+key_writes.label = writ
+key_writes.color = blue
+key_read_requests.metric = mysql.status.key_read_requests
+key_read_requests.label = rreq
+key_read_requests.color = green
+key_write_requests.metric = mysql.status.key_write_requests
+key_write_requests.label = wreq
+key_write_requests.color = blue
+
+[innodb_buffer]
+caption = InnoDB pool
+description = InnoDB buffer pool
+created.metric = mysql.status.innodb_pages_created
+created.label = cr
+created.color = yellow
+read.metric = mysql.status.innodb_pages_read
+read.label = rd
+read.color = greed
+written.metric = mysql.status.innodb_pages_written
+written.label = wr
+written.color = red
+
+[innodb_io]
+caption = InnoDB I/O
+description = InnoDB I/O operations
+read.metric = mysql.status.innodb_data_read
+read.label = rd
+read.color = green
+written.metric = mysql.status.innodb_data.writes
+written.label = wr
+written.color = blue
+sync.metric = mysql.status.innodb_data_fsyncs
+sync.label = sync
+sync.color = cyan
+
+[innodb_ops]
+caption = InnoDB ops
+description = InnoDB operations
+inserted.metric = mysql.status.innodb_rows_inserted
+inserted.label = ins
+inserted.color = blue
+updated.metric = mysql.status.innodb_rows_updated
+updated.label = upd
+updated.color = cyan
+deleted.metric = mysql.status.innodb_rows_deleted
+deleted.label = del
+deleted.color = red
+read.metric = mysql.status.innodb_rows_read
+read.label = rd
+read.color = green
diff --git a/pcp/meters/postfix b/pcp/meters/postfix
new file mode 100644
index 00000000..66876c5a
--- /dev/null
+++ b/pcp/meters/postfix
@@ -0,0 +1,21 @@
+#
+# pcp-htop(1) configuration file - see pcp-htop(5)
+#
+
+[postfix]
+caption = Postfix
+incoming.metric = sum(postfix.queues.incoming)
+incoming.color = green
+incoming.label = in
+active.metric = sum(postfix.queues.active)
+active.color = blue
+active.label = act
+deferred.metric = sum(postfix.queues.deferred)
+deferred.color = cyan
+deferred.label = dfr
+bounce.metric = sum(postfix.queues.maildrop)
+bounce.color = red
+bounce.label = bnc
+hold.metric = sum(postfix.queues.hold)
+hold.color = yellow
+hold.label = hold
diff --git a/pcp/meters/redis b/pcp/meters/redis
new file mode 100644
index 00000000..b9c084be
--- /dev/null
+++ b/pcp/meters/redis
@@ -0,0 +1,41 @@
+#
+# pcp-htop(1) configuration file - see pcp-htop(5)
+#
+
+[redisxact]
+caption = Redis xact
+description = Redis transactions
+tps.metric = redis.instantaneous_ops_per_sec
+tps.color = green
+
+[redismem]
+caption = Redis mem
+description = Redis memory
+lua.metric = redis.used_memory_lua
+lua.color = magenta
+lua.label = lua:
+used.metric = redis.used_memory
+used.color = blue
+used.label = used:
+
+[redisclient]
+caption = Redis clients
+description = Redis clients
+type = bar
+blocked.metric = redis.blocked_clients
+blocked.color = blue
+blocked.label = blk
+clients.metric = redis.connected_clients
+clients.color = green
+clients.label = conn
+
+[redisconn]
+caption = Redis conn
+description = Redis connections
+type = bar
+reject.metric = redis.rejected_connections
+reject.color = magenta
+reject.label = fail/s
+total.metric = redis.total_connections_received
+total.color = blue
+total.label = conn/s
diff --git a/pcp/meters/tcp b/pcp/meters/tcp
new file mode 100644
index 00000000..cebc658d
--- /dev/null
+++ b/pcp/meters/tcp
@@ -0,0 +1,22 @@
+#
+# pcp-htop(1) configuration file - see pcp-htop(5)
+#
+
+[tcp]
+caption = TCP
+description = TCP sockets
+listen.metric = network.tcpconn.listen
+listen.color = green
+listen.label = lis
+active.metric = network.tcpconn.established
+active.color = blue
+active.label = act
+syn.metric = network.tcpconn.syn_sent + network.tcpconn.syn_recv + network.tcpconn.last_ack
+syn.color = cyan
+syn.label = syn
+wait.metric = network.tcpconn.time_wait
+wait.color = red
+wait.label = tim
+close.metric = network.tcpconn.fin_wait1 + network.tcpconn.fin_wait2 + network.tcpconn.close + network.tcpconn.close_wait + network.tcpconn.closing
+close.color = yellow
+close.label = clo

© 2014-2024 Faster IT GmbH | imprint | privacy policy