summaryrefslogtreecommitdiffstats
path: root/pcp
diff options
context:
space:
mode:
authorNathan Scott <nathans@redhat.com>2021-08-13 15:56:01 +1000
committerNathan Scott <nathans@redhat.com>2021-08-13 15:56:01 +1000
commitf839095e3b29668d080c89f3b32fb6dccff54030 (patch)
tree7ef2d9359dea6e171c882f5b6ec5620eb4555396 /pcp
parent6974ce8e7982d061f26dbbe7c5ca48d7aa6f4dbc (diff)
parent6f2021f3d95e02fc54e59fdeeb006e34c209b9c3 (diff)
Merge branch 'dynamic-columns' of https://github.com/smalinux/htop into smalinux-dynamic-columns
Diffstat (limited to 'pcp')
-rw-r--r--pcp/PCPDynamicColumn.c326
-rw-r--r--pcp/PCPDynamicColumn.h32
-rw-r--r--pcp/PCPDynamicMeter.c65
-rw-r--r--pcp/PCPDynamicMeter.h17
-rw-r--r--pcp/PCPProcess.c17
-rw-r--r--pcp/PCPProcess.h8
-rw-r--r--pcp/PCPProcessList.c13
-rw-r--r--pcp/PCPProcessList.h10
-rw-r--r--pcp/Platform.c78
-rw-r--r--pcp/Platform.h13
-rw-r--r--pcp/columns/container10
-rw-r--r--pcp/columns/delayacct10
-rw-r--r--pcp/columns/fdcount10
-rw-r--r--pcp/columns/guest17
-rw-r--r--pcp/columns/memory39
-rw-r--r--pcp/columns/sched10
-rw-r--r--pcp/columns/swap15
-rw-r--r--pcp/columns/tcp31
-rw-r--r--pcp/columns/udp31
-rw-r--r--pcp/columns/wchan17
20 files changed, 692 insertions, 77 deletions
diff --git a/pcp/PCPDynamicColumn.c b/pcp/PCPDynamicColumn.c
new file mode 100644
index 00000000..2848490e
--- /dev/null
+++ b/pcp/PCPDynamicColumn.c
@@ -0,0 +1,326 @@
+/*
+htop - PCPDynamicColumn.c
+(C) 2021 Sohaib Mohammed
+(C) 2021 htop dev team
+(C) 2021 Red Hat, Inc.
+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/PCPDynamicColumn.h"
+
+#include <ctype.h>
+#include <dirent.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "CRT.h"
+#include "Macros.h"
+#include "Platform.h"
+#include "Process.h"
+#include "RichString.h"
+#include "XUtils.h"
+
+#include "pcp/PCPProcess.h"
+
+
+static bool PCPDynamicColumn_addMetric(PCPDynamicColumns* columns, PCPDynamicColumn* column) {
+ if (!column->super.name[0])
+ return false;
+
+ size_t bytes = 16 + strlen(column->super.name);
+ char* metricName = xMalloc(bytes);
+ xSnprintf(metricName, bytes, "htop.column.%s", column->super.name);
+
+ column->metricName = metricName;
+ column->id = columns->offset + columns->cursor;
+ columns->cursor++;
+
+ Platform_addMetric(column->id, metricName);
+ return true;
+}
+
+static void PCPDynamicColumn_parseMetric(PCPDynamicColumns* columns, PCPDynamicColumn* column, const char* path, unsigned int line, char* value) {
+ /* lookup a dynamic metric with this name, else create */
+ if (PCPDynamicColumn_addMetric(columns, column) == false)
+ return;
+
+ /* derived metrics in all dynamic columns for simplicity */
+ char* error;
+ if (pmRegisterDerivedMetric(column->metricName, value, &error) < 0) {
+ char* note;
+ xAsprintf(&note,
+ "%s: failed to parse expression in %s at line %u\n%s\n",
+ pmGetProgname(), path, line, error);
+ free(error);
+ errno = EINVAL;
+ CRT_fatalError(note);
+ free(note);
+ }
+}
+
+// Ensure a valid name for use in a PCP metric name and in htoprc
+static bool PCPDynamicColumn_validateColumnName(char* key, const char* path, unsigned int line) {
+ char* p = key;
+ char* end = strrchr(key, ']');
+
+ if (end) {
+ *end = '\0';
+ } else {
+ fprintf(stderr,
+ "%s: no closing brace on column name at %s line %u\n\"%s\"",
+ pmGetProgname(), path, line, key);
+ return false;
+ }
+
+ while (*p) {
+ if (p == key) {
+ if (!isalpha(*p) && *p != '_')
+ break;
+ } else {
+ if (!isalnum(*p) && *p != '_')
+ break;
+ }
+ p++;
+ }
+ if (*p != '\0') { /* badness */
+ fprintf(stderr,
+ "%s: invalid column name at %s line %u\n\"%s\"",
+ pmGetProgname(), path, line, key);
+ return false;
+ }
+ return true;
+}
+
+// Ensure a column name has not been defined previously
+static bool PCPDynamicColumn_uniqueName(char* key, PCPDynamicColumns* columns) {
+ return DynamicColumn_search(columns->table, key, NULL) == NULL;
+}
+
+static PCPDynamicColumn* PCPDynamicColumn_new(PCPDynamicColumns* columns, const char* name) {
+ PCPDynamicColumn* column = xCalloc(1, sizeof(*column));
+ String_safeStrncpy(column->super.name, name, sizeof(column->super.name));
+
+ size_t id = columns->count + LAST_PROCESSFIELD;
+ Hashtable_put(columns->table, id, column);
+ columns->count++;
+
+ return column;
+}
+
+static void PCPDynamicColumn_parseFile(PCPDynamicColumns* columns, const char* path) {
+ FILE* file = fopen(path, "r");
+ if (!file)
+ return;
+
+ PCPDynamicColumn* column = NULL;
+ unsigned int lineno = 0;
+ bool ok = true;
+ for (;;) {
+ char* line = String_readLine(file);
+ if (!line)
+ break;
+ lineno++;
+
+ /* cleanup whitespace, skip comment lines */
+ char* trimmed = String_trim(line);
+ free(line);
+ if (!trimmed || !trimmed[0] || trimmed[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 column */
+ ok = PCPDynamicColumn_validateColumnName(key + 1, path, lineno);
+ if (ok)
+ ok = PCPDynamicColumn_uniqueName(key + 1, columns);
+ if (ok)
+ column = PCPDynamicColumn_new(columns, key + 1);
+ } else if (value && column && String_eq(key, "caption")) {
+ free_and_xStrdup(&column->super.caption, value);
+ } else if (value && column && String_eq(key, "heading")) {
+ free_and_xStrdup(&column->super.heading, value);
+ } else if (value && column && String_eq(key, "description")) {
+ free_and_xStrdup(&column->super.description, value);
+ } else if (value && column && String_eq(key, "width")) {
+ column->super.width = strtoul(value, NULL, 10);
+ } else if (value && column && String_eq(key, "metric")) {
+ PCPDynamicColumn_parseMetric(columns, column, path, lineno, value);
+ }
+ String_freeArray(config);
+ free(value);
+ free(key);
+ }
+ fclose(file);
+}
+
+static void PCPDynamicColumn_scanDir(PCPDynamicColumns* columns, 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);
+ PCPDynamicColumn_parseFile(columns, file);
+ free(file);
+ }
+ closedir(dir);
+}
+
+void PCPDynamicColumns_init(PCPDynamicColumns* columns) {
+ const char* share = pmGetConfig("PCP_SHARE_DIR");
+ const char* sysconf = pmGetConfig("PCP_SYSCONF_DIR");
+ const char* xdgConfigHome = getenv("XDG_CONFIG_HOME");
+ const char* override = getenv("PCP_HTOP_DIR");
+ const char* home = getenv("HOME");
+ char* path;
+
+ columns->table = Hashtable_new(0, true);
+
+ /* developer paths - PCP_HTOP_DIR=./pcp ./pcp-htop */
+ if (override) {
+ path = String_cat(override, "/columns/");
+ PCPDynamicColumn_scanDir(columns, path);
+ free(path);
+ }
+
+ /* next, search in home directory alongside htoprc */
+ if (xdgConfigHome)
+ path = String_cat(xdgConfigHome, "/htop/columns/");
+ else if (home)
+ path = String_cat(home, "/.config/htop/columns/");
+ else
+ path = NULL;
+ if (path) {
+ PCPDynamicColumn_scanDir(columns, path);
+ free(path);
+ }
+
+ /* next, search in the system columns directory */
+ path = String_cat(sysconf, "/htop/columns/");
+ PCPDynamicColumn_scanDir(columns, path);
+ free(path);
+
+ /* next, try the readonly system columns directory */
+ path = String_cat(share, "/htop/columns/");
+ PCPDynamicColumn_scanDir(columns, path);
+ free(path);
+}
+
+void PCPDynamicColumn_writeField(PCPDynamicColumn* this, const Process* proc, RichString* str) {
+ const PCPProcess* pp = (const PCPProcess*) proc;
+ unsigned int type = Metric_type(this->id);
+
+ pmAtomValue atom;
+ if (!Metric_instance(this->id, proc->pid, pp->offset, &atom, type)) {
+ RichString_appendAscii(str, CRT_colors[METER_VALUE_ERROR], "no data");
+ return;
+ }
+
+ int width = this->super.width;
+ if (!width || abs(width) > DYNAMIC_MAX_COLUMN_WIDTH)
+ width = DYNAMIC_DEFAULT_COLUMN_WIDTH;
+ int abswidth = abs(width);
+ if (abswidth > DYNAMIC_MAX_COLUMN_WIDTH) {
+ abswidth = DYNAMIC_MAX_COLUMN_WIDTH;
+ width = -abswidth;
+ }
+
+ char buffer[DYNAMIC_MAX_COLUMN_WIDTH + /* space */ 1 + /* null terminator */ + 1];
+ int attr = CRT_colors[DEFAULT_COLOR];
+ switch (type) {
+ case PM_TYPE_STRING:
+ attr = CRT_colors[PROCESS_SHADOW];
+ Process_printLeftAlignedField(str, attr, atom.cp, abswidth);
+ free(atom.cp);
+ break;
+ case PM_TYPE_32:
+ xSnprintf(buffer, sizeof(buffer), "%*d ", width, atom.l);
+ RichString_appendAscii(str, attr, buffer);
+ break;
+ case PM_TYPE_U32:
+ xSnprintf(buffer, sizeof(buffer), "%*u ", width, atom.ul);
+ RichString_appendAscii(str, attr, buffer);
+ break;
+ case PM_TYPE_64:
+ xSnprintf(buffer, sizeof(buffer), "%*lld ", width, (long long) atom.ll);
+ RichString_appendAscii(str, attr, buffer);
+ break;
+ case PM_TYPE_U64:
+ xSnprintf(buffer, sizeof(buffer), "%*llu ", width, (unsigned long long) atom.ull);
+ RichString_appendAscii(str, attr, buffer);
+ break;
+ case PM_TYPE_FLOAT:
+ xSnprintf(buffer, sizeof(buffer), "%*.2f ", width, (double) atom.f);
+ RichString_appendAscii(str, attr, buffer);
+ break;
+ case PM_TYPE_DOUBLE:
+ xSnprintf(buffer, sizeof(buffer), "%*.2f ", width, atom.d);
+ RichString_appendAscii(str, attr, buffer);
+ break;
+ default:
+ attr = CRT_colors[METER_VALUE_ERROR];
+ RichString_appendAscii(str, attr, "no type");
+ break;
+ }
+}
+
+int PCPDynamicColumn_compareByKey(const PCPProcess* p1, const PCPProcess* p2, ProcessField key) {
+ const PCPDynamicColumn* column = Hashtable_get(p1->super.processList->dynamicColumns, key);
+
+ size_t metric = column->id;
+ unsigned int type = Metric_type(metric);
+
+ pmAtomValue atom1 = {0}, atom2 = {0};
+ if (!Metric_instance(metric, p1->super.pid, p1->offset, &atom1, type) ||
+ !Metric_instance(metric, p2->super.pid, p2->offset, &atom2, type)) {
+ if (type == PM_TYPE_STRING) {
+ free(atom1.cp);
+ free(atom2.cp);
+ }
+ return -1;
+ }
+
+ switch (type) {
+ case PM_TYPE_STRING: {
+ int cmp = SPACESHIP_NULLSTR(atom2.cp, atom1.cp);
+ free(atom2.cp);
+ free(atom1.cp);
+ return cmp;
+ }
+ case PM_TYPE_32:
+ return SPACESHIP_NUMBER(atom2.l, atom1.l);
+ case PM_TYPE_U32:
+ return SPACESHIP_NUMBER(atom2.ul, atom1.ul);
+ case PM_TYPE_64:
+ return SPACESHIP_NUMBER(atom2.ll, atom1.ll);
+ case PM_TYPE_U64:
+ return SPACESHIP_NUMBER(atom2.ull, atom1.ull);
+ case PM_TYPE_FLOAT:
+ return SPACESHIP_NUMBER(atom2.f, atom1.f);
+ case PM_TYPE_DOUBLE:
+ return SPACESHIP_NUMBER(atom2.d, atom1.d);
+ default:
+ break;
+ }
+ return -1;
+}
diff --git a/pcp/PCPDynamicColumn.h b/pcp/PCPDynamicColumn.h
new file mode 100644
index 00000000..39f79358
--- /dev/null
+++ b/pcp/PCPDynamicColumn.h
@@ -0,0 +1,32 @@
+#ifndef HEADER_PCPDynamicColumn
+#define HEADER_PCPDynamicColumn
+
+#include "CRT.h"
+#include "DynamicColumn.h"
+#include "Hashtable.h"
+#include "Process.h"
+#include "RichString.h"
+
+#include "pcp/PCPProcess.h"
+
+
+typedef struct PCPDynamicColumn_ {
+ DynamicColumn super;
+ char* metricName;
+ size_t id; /* identifier for metric array lookups */
+} PCPDynamicColumn;
+
+typedef struct PCPDynamicColumns_ {
+ Hashtable* table;
+ size_t count; /* count of dynamic meters discovered by scan */
+ size_t offset; /* start offset into the Platform metric array */
+ size_t cursor; /* identifier allocator for each new metric used */
+} PCPDynamicColumns;
+
+void PCPDynamicColumns_init(PCPDynamicColumns* columns);
+
+void PCPDynamicColumn_writeField(PCPDynamicColumn* this, const Process* proc, RichString* str);
+
+int PCPDynamicColumn_compareByKey(const PCPProcess* p1, const PCPProcess* p2, ProcessField key);
+
+#endif
diff --git a/pcp/PCPDynamicMeter.c b/pcp/PCPDynamicMeter.c
index ffde2b4f..b90511ec 100644
--- a/pcp/PCPDynamicMeter.c
+++ b/pcp/PCPDynamicMeter.c
@@ -1,7 +1,7 @@
/*
htop - PCPDynamicMeter.c
(C) 2021 htop dev team
-(C) 2021 Red Hat, Inc. All Rights Reserved.
+(C) 2021 Red Hat, Inc.
Released under the GNU GPLv2, see the COPYING file
in the source distribution for its full text.
*/
@@ -18,13 +18,14 @@ in the source distribution for its full text.
#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);
+ size_t bytes = 16 + strlen(meter->super.name) + strlen(name);
char* metricName = xMalloc(bytes);
- xSnprintf(metricName, bytes, "htop.%s.%s", meter->super.name, name);
+ xSnprintf(metricName, bytes, "htop.meter.%s.%s", meter->super.name, name);
PCPDynamicMetric* metric;
- for (unsigned int i = 0; i < meter->totalMetrics; i++) {
+ for (size_t i = 0; i < meter->totalMetrics; i++) {
metric = &meter->metrics[i];
if (String_eq(metric->name, metricName)) {
free(metricName);
@@ -33,7 +34,7 @@ static PCPDynamicMetric* PCPDynamicMeter_lookupMetric(PCPDynamicMeters* meters,
}
/* not an existing metric in this meter - add it */
- unsigned int n = meter->totalMetrics + 1;
+ size_t n = meter->totalMetrics + 1;
meter->metrics = xReallocArray(meter->metrics, n, sizeof(PCPDynamicMetric));
meter->totalMetrics = n;
metric = &meter->metrics[n - 1];
@@ -139,13 +140,8 @@ static bool PCPDynamicMeter_validateMeterName(char* key, const char* path, unsig
}
// Ensure a meter name has not been defined previously
-static bool PCPDynamicMeter_uniqueName(char* key, const char* path, unsigned int line, PCPDynamicMeters* meters) {
- if (DynamicMeter_search(meters->table, key, NULL) == false)
- return true;
-
- fprintf(stderr, "%s: duplicate name at %s line %u: \"%s\", ignored\n",
- pmGetProgname(), path, line, key);
- return false;
+static bool PCPDynamicMeter_uniqueName(char* key, PCPDynamicMeters* meters) {
+ return !DynamicMeter_search(meters->table, key, NULL);
}
static PCPDynamicMeter* PCPDynamicMeter_new(PCPDynamicMeters* meters, const char* name) {
@@ -188,7 +184,7 @@ static void PCPDynamicMeter_parseFile(PCPDynamicMeters* meters, const char* path
if (key[0] == '[') { /* new section heading - i.e. new meter */
ok = PCPDynamicMeter_validateMeterName(key + 1, path, lineno);
if (ok)
- ok = PCPDynamicMeter_uniqueName(key + 1, path, lineno, meters);
+ ok = PCPDynamicMeter_uniqueName(key + 1, meters);
if (ok)
meter = PCPDynamicMeter_new(meters, key + 1);
} else if (!ok) {
@@ -241,40 +237,47 @@ static void PCPDynamicMeter_scanDir(PCPDynamicMeters* meters, char* path) {
}
void PCPDynamicMeters_init(PCPDynamicMeters* meters) {
+ const char* share = pmGetConfig("PCP_SHARE_DIR");
const char* sysconf = pmGetConfig("PCP_SYSCONF_DIR");
const char* xdgConfigHome = getenv("XDG_CONFIG_HOME");
+ const char* override = getenv("PCP_HTOP_DIR");
const char* home = getenv("HOME");
char* path;
meters->table = Hashtable_new(0, true);
- /* search in the users home directory first of all */
- if (xdgConfigHome) {
+ /* developer paths - PCP_HTOP_DIR=./pcp ./pcp-htop */
+ if (override) {
+ path = String_cat(override, "/meters/");
+ PCPDynamicMeter_scanDir(meters, path);
+ free(path);
+ }
+
+ /* next, search in home directory alongside htoprc */
+ if (xdgConfigHome)
path = String_cat(xdgConfigHome, "/htop/meters/");
- } else {
- if (!home)
- home = "";
+ else if (home)
path = String_cat(home, "/.config/htop/meters/");
+ else
+ path = NULL;
+ if (path) {
+ PCPDynamicMeter_scanDir(meters, path);
+ free(path);
}
- PCPDynamicMeter_scanDir(meters, path);
- free(path);
- /* secondly search in the system meters directory */
+ /* next, 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);
- }
+ /* next, try the readonly system meters directory */
+ path = String_cat(share, "/htop/meters/");
+ PCPDynamicMeter_scanDir(meters, path);
+ free(path);
}
void PCPDynamicMeter_enable(PCPDynamicMeter* this) {
- for (unsigned int i = 0; i < this->totalMetrics; i++)
+ for (size_t i = 0; i < this->totalMetrics; i++)
Metric_enable(this->metrics[i].id, true);
}
@@ -283,7 +286,7 @@ void PCPDynamicMeter_updateValues(PCPDynamicMeter* this, Meter* meter) {
size_t size = sizeof(meter->txtBuffer);
size_t bytes = 0;
- for (unsigned int i = 0; i < this->totalMetrics; i++) {
+ for (size_t i = 0; i < this->totalMetrics; i++) {
if (i > 0 && bytes < size - 1)
buffer[bytes++] = '/'; /* separator */
@@ -357,7 +360,7 @@ void PCPDynamicMeter_updateValues(PCPDynamicMeter* this, Meter* meter) {
void PCPDynamicMeter_display(PCPDynamicMeter* this, ATTR_UNUSED const Meter* meter, RichString* out) {
int nodata = 1;
- for (unsigned int i = 0; i < this->totalMetrics; i++) {
+ for (size_t i = 0; i < this->totalMetrics; i++) {
PCPDynamicMetric* metric = &this->metrics[i];
const pmDesc* desc = Metric_desc(metric->id);
pmAtomValue atom, raw;
diff --git a/pcp/PCPDynamicMeter.h b/pcp/PCPDynamicMeter.h
index a7390e61..cfe488e5 100644
--- a/pcp/PCPDynamicMeter.h
+++ b/pcp/PCPDynamicMeter.h
@@ -4,25 +4,26 @@
#include "CRT.h"
#include "DynamicMeter.h"
-typedef struct {
- unsigned int id; /* index into metric array */
+
+typedef struct PCPDynamicMetric_ {
+ size_t id; /* index into metric array */
ColorElements color;
char* name; /* derived metric name */
char* label;
char* suffix;
} PCPDynamicMetric;
-typedef struct {
+typedef struct PCPDynamicMeter_ {
DynamicMeter super;
PCPDynamicMetric* metrics;
- unsigned int totalMetrics;
+ size_t totalMetrics;
} PCPDynamicMeter;
-typedef struct {
+typedef struct PCPDynamicMeters_ {
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 */
+ size_t count; /* count of dynamic meters discovered by scan */
+ size_t offset; /* start offset into the Platform metric array */
+ size_t cursor; /* identifier allocator for each new metric used */
} PCPDynamicMeters;
void PCPDynamicMeters_init(PCPDynamicMeters* meters);
diff --git a/pcp/PCPProcess.c b/pcp/PCPProcess.c
index de709110..5407a021 100644
--- a/pcp/PCPProcess.c
+++ b/pcp/PCPProcess.c
@@ -1,8 +1,8 @@
/*
htop - PCPProcess.c
(C) 2014 Hisham H. Muhammad
-(C) 2020 htop dev team
-(C) 2020-2021 Red Hat, Inc. All Rights Reserved.
+(C) 2020-2021 htop dev team
+(C) 2020-2021 Red Hat, Inc.
Released under the GNU GPLv2, see the COPYING file
in the source distribution for its full text.
*/
@@ -12,15 +12,18 @@ in the source distribution for its full text.
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
-#include <string.h>
-#include <syscall.h>
-#include <unistd.h>
#include "CRT.h"
+#include "Macros.h"
+#include "Platform.h"
#include "Process.h"
#include "ProvideCurses.h"
+#include "RichString.h"
#include "XUtils.h"
+#include "pcp/PCPDynamicColumn.h"
+
+
const ProcessFieldData Process_fields[] = {
[0] = { .name = "", .title = NULL, .description = NULL, .flags = 0, },
[PID] = { .name = "PID", .title = "PID", .description = "Process/thread ID", .flags = 0, .pidColumn = true, },
@@ -271,7 +274,9 @@ static int PCPProcess_compareByKey(const Process* v1, const Process* v2, Process
case AUTOGROUP_NICE:
return SPACESHIP_NUMBER(p1->autogroup_nice, p2->autogroup_nice);
default:
- return Process_compareByKey_Base(v1, v2, key);
+ if (key < LAST_PROCESSFIELD)
+ return Process_compareByKey_Base(v1, v2, key);
+ return PCPDynamicColumn_compareByKey(p1, p2, key);
}
}
diff --git a/pcp/PCPProcess.h b/pcp/PCPProcess.h
index 2d1a8b6c..3593255b 100644
--- a/pcp/PCPProcess.h
+++ b/pcp/PCPProcess.h
@@ -12,13 +12,13 @@ in the source distribution for its full text.
#include "config.h" // IWYU pragma: keep
#include <stdbool.h>
-#include <sys/types.h>
#include "Object.h"
#include "Process.h"
-#include "RichString.h"
#include "Settings.h"
+#include "pcp/Platform.h"
+
#define PROCESS_FLAG_LINUX_CGROUP 0x00000800
#define PROCESS_FLAG_LINUX_OOM 0x00001000
@@ -29,6 +29,10 @@ in the source distribution for its full text.
typedef struct PCPProcess_ {
Process super;
+
+ /* default result offset to use for searching proc metrics */
+ unsigned int offset;
+
unsigned long int cminflt;
unsigned long int cmajflt;
unsigned long long int utime;
diff --git a/pcp/PCPProcessList.c b/pcp/PCPProcessList.c
index 638ece21..8e644b07 100644
--- a/pcp/PCPProcessList.c
+++ b/pcp/PCPProcessList.c
@@ -2,7 +2,7 @@
htop - PCPProcessList.c
(C) 2014 Hisham H. Muhammad
(C) 2020-2021 htop dev team
-(C) 2020-2021 Red Hat, Inc. All Rights Reserved.
+(C) 2020-2021 Red Hat, Inc.
Released under the GNU GPLv2, see the COPYING file
in the source distribution for its full text.
*/
@@ -11,11 +11,15 @@ in the source distribution for its full text.
#include "pcp/PCPProcessList.h"
+#include <limits.h>
#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
-#include "CRT.h"
#include "Macros.h"
#include "Object.h"
+#include "Platform.h"
#include "Process.h"
#include "Settings.h"
#include "XUtils.h"
@@ -57,11 +61,11 @@ static char* setUser(UsersTable* this, unsigned int uid, int pid, int offset) {
return name;
}
-ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* dynamicMeters, Hashtable* pidMatchList, uid_t userId) {
+ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* dynamicMeters, Hashtable* dynamicColumns, Hashtable* pidMatchList, uid_t userId) {
PCPProcessList* this = xCalloc(1, sizeof(PCPProcessList));
ProcessList* super = &(this->super);
- ProcessList_init(super, Class(PCPProcess), usersTable, dynamicMeters, pidMatchList, userId);
+ ProcessList_init(super, Class(PCPProcess), usersTable, dynamicMeters, dynamicColumns, pidMatchList, userId);
struct timeval timestamp;
gettimeofday(&timestamp, NULL);
@@ -334,6 +338,7 @@ static bool PCPProcessList_updateProcesses(PCPProcessList* this, double period,
PCPProcess* pp = (PCPProcess*) proc;
PCPProcessList_updateID(proc, pid, offset);
proc->isUserlandThread = proc->pid != proc->tgid;
+ pp->offset = offset >= 0 ? offset : 0;
/*
* These conditions will not trigger on first occurrence, cause we need to
diff --git a/pcp/PCPProcessList.h b/pcp/PCPProcessList.h
index 7f0f6fe4..07f6c399 100644
--- a/pcp/PCPProcessList.h
+++ b/pcp/PCPProcessList.h
@@ -56,14 +56,14 @@ typedef enum CPUMetric_ {
typedef struct PCPProcessList_ {
ProcessList super;
- double timestamp; /* previous sample timestamp */
- pmAtomValue* cpu; /* aggregate values for each metric */
- pmAtomValue** percpu; /* per-processor values for each metric */
- pmAtomValue* values; /* per-processor buffer for just one metric */
+ double timestamp; /* previous sample timestamp */
+ pmAtomValue* cpu; /* aggregate values for each metric */
+ pmAtomValue** percpu; /* per-processor values for each metric */
+ pmAtomValue* values; /* per-processor buffer for just one metric */
ZfsArcStats zfs;
} PCPProcessList;
-ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* dynamicMeters, Hashtable* pidMatchList, uid_t userId);
+ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* dynamicMeters, Hashtable* dynamicColumns, Hashtable* pidMatchList, uid_t userId);
void ProcessList_delete(ProcessList* pl);
diff --git a/pcp/Platform.c b/pcp/Platform.c
index 63ff50a7..5c7e6c34 100644
--- a/pcp/Platform.c
+++ b/pcp/Platform.c
@@ -2,7 +2,7 @@
htop - linux/Platform.c
(C) 2014 Hisham H. Muhammad
(C) 2020-2021 htop dev team
-(C) 2020-2021 Red Hat, Inc. All Rights Reserved.
+(C) 2020-2021 Red Hat, Inc.
Released under the GNU GPLv2, see the COPYING file
in the source distribution for its full text.
*/
@@ -42,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/PCPDynamicColumn.h"
#include "pcp/PCPDynamicMeter.h"
#include "pcp/PCPProcess.h"
#include "pcp/PCPProcessList.h"
@@ -51,19 +52,20 @@ in the source distribution for its full text.
typedef struct Platform_ {
- int context; /* PMAPI(3) context identifier */
- 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 */
- int ncpu; /* maximum processor count configured */
+ int context; /* PMAPI(3) context identifier */
+ size_t 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 */
+ PCPDynamicColumns columns; /* dynamic columns 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 */
+ int ncpu; /* maximum processor count configured */
} Platform;
Platform* pcp;
@@ -253,6 +255,10 @@ const pmDesc* Metric_desc(Metric metric) {
return &pcp->descs[metric];
}
+int Metric_type(Metric metric) {
+ return pcp->descs[metric].type;
+}
+
pmAtomValue* Metric_values(Metric metric, pmAtomValue* atom, int count, int type) {
if (pcp->result == NULL)
return NULL;
@@ -400,12 +406,12 @@ bool Metric_fetch(struct timeval* timestamp) {
return true;
}
-int Platform_addMetric(Metric id, const char* name) {
+size_t Platform_addMetric(Metric id, const char* name) {
unsigned int i = (unsigned int)id;
if (i >= PCP_METRIC_COUNT && i >= pcp->totalMetrics) {
/* added via configuration files */
- unsigned int j = pcp->totalMetrics + 1;
+ size_t 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*));
@@ -467,14 +473,17 @@ void Platform_init(void) {
PCPDynamicMeters_init(&pcp->meters);
+ pcp->columns.offset = PCP_METRIC_COUNT + pcp->meters.cursor;
+ PCPDynamicColumns_init(&pcp->columns);
+
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->totalMetrics; i++) {
- pcp->fetch[i] = PM_ID_NULL; /* default is to not sample */
+ for (size_t 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 */
if (pcp->pmids[i] == PM_ID_NULL)
@@ -503,11 +512,14 @@ void Platform_init(void) {
Metric_enable(PCP_UNAME_MACHINE, true);
Metric_enable(PCP_UNAME_DISTRO, true);
+ for (size_t i = pcp->columns.offset; i < pcp->columns.offset + pcp->columns.count; i++)
+ Metric_enable(i, true);
+
Metric_fetch(NULL);
for (Metric metric = 0; metric < PCP_PROC_PID; metric++)
Metric_enable(metric, true);
- Metric_enable(PCP_PID_MAX, false); /* needed one time only */
+ Metric_enable(PCP_PID_MAX, false); /* needed one time only */
Metric_enable(PCP_BOOTTIME, false);
Metric_enable(PCP_UNAME_SYSNAME, false);
Metric_enable(PCP_UNAME_RELEASE, false);
@@ -629,7 +641,7 @@ static double Platform_setOneCPUValues(Meter* this, pmAtomValue* values) {
double Platform_setCPUValues(Meter* this, int cpu) {
const PCPProcessList* pl = (const PCPProcessList*) this->pl;
- if (cpu <= 0) /* use aggregate values */
+ if (cpu <= 0) /* use aggregate values */
return Platform_setOneCPUValues(this, pl->cpu);
return Platform_setOneCPUValues(this, pl->percpu[cpu - 1]);
}
@@ -926,3 +938,29 @@ void Platform_dynamicMeterDisplay(const Meter* meter, RichString* out) {
if (this)
PCPDynamicMeter_display(this, meter, out);
}
+
+Hashtable* Platform_dynamicColumns(void) {
+ return pcp->columns.table;
+}
+
+const char* Platform_dynamicColumnInit(unsigned int key) {
+ PCPDynamicColumn* this = Hashtable_get(pcp->columns.table, key);
+ if (this) {
+ Metric_enable(this->id, true);
+ if (this->super.caption)
+ return this->super.caption;
+ if (this->super.heading)
+ return this->super.heading;
+ return this->super.name;
+ }
+ return NULL;
+}
+
+bool Platform_dynamicColumnWriteField(const Process* proc, RichString* str, unsigned int key) {
+ PCPDynamicColumn* this = Hashtable_get(pcp->columns.table, key);
+ if (this) {
+ PCPDynamicColumn_writeField(this, proc, str);
+ return true;
+ }
+ return false;
+}
diff --git a/pcp/Platform.h b/pcp/Platform.h
index 527bef29..3f98a733 100644
--- a/pcp/Platform.h
+++ b/pcp/Platform.h
@@ -11,6 +11,8 @@ in the source distribution for its full text.
#include <ctype.h>
#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
#include <pcp/pmapi.h>
/* use htop config.h values for these macros, not pcp values */
@@ -29,6 +31,7 @@ in the source distribution for its full text.
#include "NetworkIOMeter.h"
#include "Process.h"
#include "ProcessLocksScreen.h"
+#include "RichString.h"
#include "SignalsPanel.h"
#include "SysArchMeter.h"
@@ -253,13 +256,15 @@ pmAtomValue* Metric_values(Metric metric, pmAtomValue* atom, int count, int type
const pmDesc* Metric_desc(Metric metric);
+int Metric_type(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);
-int Platform_addMetric(Metric id, const char* name);
+size_t Platform_addMetric(Metric id, const char* name);
void Platform_gettime_realtime(struct timeval* tv, uint64_t* msec);
@@ -273,4 +278,10 @@ void Platform_dynamicMeterUpdateValues(Meter* meter);
void Platform_dynamicMeterDisplay(const Meter* meter, RichString* out);
+Hashtable* Platform_dynamicColumns(void);
+
+const char* Platform_dynamicColumnInit(unsigned int key);
+
+bool Platform_dynamicColumnWriteField(const Process* proc, RichString* str, unsigned int key);
+
#endif
diff --git a/pcp/columns/container b/pcp/columns/container
new file mode 100644
index 00000000..519288f4
--- /dev/null
+++ b/pcp/columns/container
@@ -0,0 +1,10 @@
+#
+# pcp-htop(1) configuration file - see pcp-htop(5)
+#
+
+[container]
+heading = Container
+caption = CONTAINER
+width = -12
+metric = proc.id.container
+description = Name of processes container via cgroup heuristics
diff --git a/pcp/columns/delayacct b/pcp/columns/delayacct
new file mode 100644
index 00000000..016904c6
--- /dev/null
+++ b/pcp/columns/delayacct
@@ -0,0 +1,10 @@
+#
+# pcp-htop(1) configuration file - see pcp-htop(5)
+#
+
+[blkio]
+heading = BLKIOD
+caption = BLKIO_TIME
+width = 6
+metric = proc.psinfo.delayacct_blkio_time
+description = Aggregated block I/O delays
diff --git a/pcp/columns/fdcount b/pcp/columns/fdcount
new file mode 100644
index 00000000..e6794803
--- /dev/null
+++ b/pcp/columns/fdcount
@@ -0,0 +1,10 @@
+#
+# pcp-htop(1) configuration file - see pcp-htop(5)
+#
+
+[fds]
+heading = FDS
+caption = FDCOUNT
+width = 4
+metric = proc.fd.count
+description = Open file descriptors
diff --git a/pcp/columns/guest b/pcp/columns/guest
new file mode 100644
index 00000000..89bb926b
--- /dev/null
+++ b/pcp/columns/guest
@@ -0,0 +1,17 @@
+#
+# pcp-htop(1) configuration file - see pcp-htop(5)
+#
+
+[guest]
+heading = GUEST
+caption = GUEST_TIME
+width = 6
+metric = proc.psinfo.guest_time
+description = Guest time for the process
+
+[cguest]
+heading = CGUEST
+caption = CGUEST_TIME
+width = 6
+metric = proc.psinfo.guest_time + proc.psinfo.cguest_time
+description = Cumulative guest time for the process and its children
diff --git a/pcp/columns/memory b/pcp/columns/memory
new file mode 100644
index 00000000..305a654a
--- /dev/null
+++ b/pcp/columns/memory
@@ -0,0 +1,39 @@
+#
+# pcp-htop(1) configuration file - see pcp-htop(5)
+#
+
+[vmdata]
+heading = VDATA
+width = 6
+metric = proc.memory.vmdata
+description = Virtual memory used for data
+
+[vmstack]
+heading = VSTACK
+width = -6
+metric = proc.memory.vmstack
+description = Virtual memory used for stack
+
+[vmexe]
+heading = VEXEC
+width = 6
+metric = proc.memory.vmexe
+description = Virtual memory used for non-library executable code
+
+[vmlib]
+heading = VLIBS
+width = 6
+metric = proc.memory.vmlib
+description = Virtual memory used for libraries
+
+[vmswap]
+heading = VSWAP
+width = 6
+metric = proc.memory.vmswap
+description = Virtual memory size currently swapped out
+
+[vmlock]
+heading = VLOCK
+width = 6
+metric = proc.memory.vmlock
+description = Locked virtual memory
diff --git a/pcp/columns/sched b/pcp/columns/sched
new file mode 100644
index 00000000..36b8b551
--- /dev/null
+++ b/pcp/columns/sched
@@ -0,0 +1,10 @@
+#
+# pcp-htop(1) configuration file - see pcp-htop(5)
+#
+
+[rundelay]
+heading = RUNQ
+caption = RUN_DELAY
+width = 4
+metric = proc.schedstat.run_delay
+description = Run queue time
diff --git a/pcp/columns/swap b/pcp/columns/swap
new file mode 100644
index 00000000..234b3db3
--- /dev/null
+++ b/pcp/columns/swap
@@ -0,0 +1,15 @@
+#
+# pcp-htop(1) configuration file - see pcp-htop(5)
+#
+
+[swap]
+heading = SWAP
+width = 5
+metric = proc.psinfo.nswap
+description = Count of swap operations for the process
+
+[cswap]
+heading = CSWAP
+width = 5
+metric = proc.psinfo.nswap + proc.psinfo.cnswap
+description = Cumulative swap operations for the process and its children
diff --git a/pcp/columns/tcp b/pcp/columns/tcp
new file mode 100644
index 00000000..f9a18196
--- /dev/null
+++ b/pcp/columns/tcp
@@ -0,0 +1,31 @@
+#
+# pcp-htop(1) configuration file - see pcp-htop(5)
+#
+
+[tcp_send_calls]
+heading = TCPS
+caption = TCP_SEND
+width = 6
+metric = bcc.proc.net.tcp.send.calls
+description = Count of TCP send calls
+
+[tcp_send_bytes]
+heading = TCPSB
+caption = TCP_SEND_BYTES
+width = 6
+metric = bcc.proc.net.tcp.send.bytes
+description = Cumulative bytes sent via TCP
+
+[tcp_recv_calls]
+heading = TCPR
+caption = TCP_RECV
+width = 6
+metric = bcc.proc.net.tcp.recv.calls
+description = Count of TCP recv calls
+
+[tcp_recv_bytes]
+heading = TCPRB
+caption = TCP_RECV_BYTES
+width = 6
+metric = bcc.proc.net.tcp.recv.bytes
+description = Cumulative bytes received via TCP
diff --git a/pcp/columns/udp b/pcp/columns/udp
new file mode 100644
index 00000000..060f0486
--- /dev/null
+++ b/pcp/columns/udp
@@ -0,0 +1,31 @@
+#
+# pcp-htop(1) configuration file - see pcp-htop(5)
+#
+
+[udp_send_calls]
+heading = UDPS
+caption = UDP_SEND
+width = 6
+metric = bcc.proc.net.udp.send.calls
+description = Count of UDP send calls
+
+[udp_send_bytes]
+heading = UDPSB
+caption = UDP_SEND_BYTES
+width = 6
+metric = bcc.proc.net.udp.send.bytes
+description = Cumulative bytes sent via UDP
+
+[udp_recv_calls]
+heading = UDPR
+caption = UDP_RECV
+width = 6
+metric = bcc.proc.net.udp.recv.calls
+description = Count of UDP recv calls
+
+[udp_recv_bytes]
+heading = UDPRB
+caption = UDP_RECV_BYTES
+width = 6
+metric = bcc.proc.net.udp.recv.bytes
+description = Cumulative bytes received via UDP
diff --git a/pcp/columns/wchan b/pcp/columns/wchan
new file mode 100644
index 00000000..893de587
--- /dev/null
+++ b/pcp/columns/wchan
@@ -0,0 +1,17 @@
+#
+# pcp-htop(1) configuration file - see pcp-htop(5)
+#
+
+[wchan]
+heading = WCHAN
+caption = WCHAN_ADDRESS
+width = 8
+metric = proc.psinfo.wchan
+description = Wait channel, kernel address process is blocked or sleeping on
+
+[wchans]
+heading = WCHANS
+caption = WCHAN_SYMBOL
+width = -12
+metric = proc.psinfo.wchan_s
+description = Wait channel, kernel symbol process is blocked or sleeping on

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