mirror of https://github.com/xzeldon/htop.git
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.
This commit is contained in:
parent
865b85eb2d
commit
f0ed0fdafb
|
@ -12,6 +12,7 @@ in the source distribution for its full text.
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
#include "CPUMeter.h"
|
#include "CPUMeter.h"
|
||||||
|
#include "DynamicMeter.h"
|
||||||
#include "FunctionBar.h"
|
#include "FunctionBar.h"
|
||||||
#include "Header.h"
|
#include "Header.h"
|
||||||
#include "ListItem.h"
|
#include "ListItem.h"
|
||||||
|
@ -91,6 +92,49 @@ const PanelClass AvailableMetersPanel_class = {
|
||||||
.eventHandler = AvailableMetersPanel_eventHandler
|
.eventHandler = AvailableMetersPanel_eventHandler
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Handle (&CPUMeter_class) entries in the AvailableMetersPanel
|
||||||
|
static void AvailableMetersPanel_addCPUMeters(Panel* super, const MeterClass* type, const ProcessList* pl) {
|
||||||
|
if (pl->cpuCount > 1) {
|
||||||
|
Panel_add(super, (Object*) ListItem_new("CPU average", 0));
|
||||||
|
for (unsigned int i = 1; i <= pl->cpuCount; i++) {
|
||||||
|
char buffer[50];
|
||||||
|
xSnprintf(buffer, sizeof(buffer), "%s %d", type->uiName, Settings_cpuId(pl->settings, i - 1));
|
||||||
|
Panel_add(super, (Object*) ListItem_new(buffer, i));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Panel_add(super, (Object*) ListItem_new(type->uiName, 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
Panel* super;
|
||||||
|
unsigned int id;
|
||||||
|
unsigned int offset;
|
||||||
|
} DynamicIterator;
|
||||||
|
|
||||||
|
static void AvailableMetersPanel_addDynamicMeter(ATTR_UNUSED ht_key_t key, void* value, void* data) {
|
||||||
|
const DynamicMeter* meter = (const DynamicMeter*)value;
|
||||||
|
DynamicIterator* iter = (DynamicIterator*)data;
|
||||||
|
unsigned int identifier = (iter->offset << 16) | iter->id;
|
||||||
|
const char* label = meter->description ? meter->description : meter->caption;
|
||||||
|
if (!label) label = meter->name; /* last fallback to name, guaranteed set */
|
||||||
|
Panel_add(iter->super, (Object*) ListItem_new(label, identifier));
|
||||||
|
iter->id++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle (&DynamicMeter_class) entries in the AvailableMetersPanel
|
||||||
|
static void AvailableMetersPanel_addDynamicMeters(Panel* super, const ProcessList *pl, unsigned int offset) {
|
||||||
|
DynamicIterator iter = { .super = super, .id = 1, .offset = offset };
|
||||||
|
assert(pl->dynamicMeters != NULL);
|
||||||
|
Hashtable_foreach(pl->dynamicMeters, AvailableMetersPanel_addDynamicMeter, &iter);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle remaining Platform Meter entries in the AvailableMetersPanel
|
||||||
|
static void AvailableMetersPanel_addPlatformMeter(Panel* super, const MeterClass* type, unsigned int offset) {
|
||||||
|
const char* label = type->description ? type->description : type->uiName;
|
||||||
|
Panel_add(super, (Object*) ListItem_new(label, offset << 16));
|
||||||
|
}
|
||||||
|
|
||||||
AvailableMetersPanel* AvailableMetersPanel_new(Settings* settings, Header* header, Panel* leftMeters, Panel* rightMeters, ScreenManager* scr, const ProcessList* pl) {
|
AvailableMetersPanel* AvailableMetersPanel_new(Settings* settings, Header* header, Panel* leftMeters, Panel* rightMeters, ScreenManager* scr, const ProcessList* pl) {
|
||||||
AvailableMetersPanel* this = AllocThis(AvailableMetersPanel);
|
AvailableMetersPanel* this = AllocThis(AvailableMetersPanel);
|
||||||
Panel* super = (Panel*) this;
|
Panel* super = (Panel*) this;
|
||||||
|
@ -104,26 +148,19 @@ AvailableMetersPanel* AvailableMetersPanel_new(Settings* settings, Header* heade
|
||||||
this->scr = scr;
|
this->scr = scr;
|
||||||
|
|
||||||
Panel_setHeader(super, "Available meters");
|
Panel_setHeader(super, "Available meters");
|
||||||
// Platform_meterTypes[0] should be always (&CPUMeter_class), which we will
|
// Platform_meterTypes[0] should be always (&CPUMeter_class) which we will
|
||||||
// handle separately in the code below.
|
// handle separately in the code below. Likewise, identifiers for Dynamic
|
||||||
for (int i = 1; Platform_meterTypes[i]; i++) {
|
// Meters are handled separately - similar to CPUs, this allows generation
|
||||||
|
// of multiple different Meters (also using 'param' to distinguish them).
|
||||||
|
for (unsigned int i = 1; Platform_meterTypes[i]; i++) {
|
||||||
const MeterClass* type = Platform_meterTypes[i];
|
const MeterClass* type = Platform_meterTypes[i];
|
||||||
assert(type != &CPUMeter_class);
|
assert(type != &CPUMeter_class);
|
||||||
const char* label = type->description ? type->description : type->uiName;
|
if (type == &DynamicMeter_class)
|
||||||
Panel_add(super, (Object*) ListItem_new(label, i << 16));
|
AvailableMetersPanel_addDynamicMeters(super, pl, i);
|
||||||
}
|
else
|
||||||
// Handle (&CPUMeter_class)
|
AvailableMetersPanel_addPlatformMeter(super, type, i);
|
||||||
const MeterClass* type = &CPUMeter_class;
|
|
||||||
unsigned int cpus = pl->cpuCount;
|
|
||||||
if (cpus > 1) {
|
|
||||||
Panel_add(super, (Object*) ListItem_new("CPU average", 0));
|
|
||||||
for (unsigned int i = 1; i <= cpus; i++) {
|
|
||||||
char buffer[50];
|
|
||||||
xSnprintf(buffer, sizeof(buffer), "%s %d", type->uiName, Settings_cpuId(this->settings, i - 1));
|
|
||||||
Panel_add(super, (Object*) ListItem_new(buffer, i));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Panel_add(super, (Object*) ListItem_new("CPU", 1));
|
|
||||||
}
|
}
|
||||||
|
AvailableMetersPanel_addCPUMeters(super, &CPUMeter_class, pl);
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,6 +50,14 @@ static void CPUMeter_init(Meter* this) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Custom uiName runtime logic to include the param (processor)
|
||||||
|
static void CPUMeter_getUiName(const Meter* this, char* buffer, size_t length) {
|
||||||
|
if (this->param > 0)
|
||||||
|
xSnprintf(buffer, sizeof(length), "%s %u", Meter_uiName(this), this->param);
|
||||||
|
else
|
||||||
|
xSnprintf(buffer, sizeof(length), "%s", Meter_uiName(this));
|
||||||
|
}
|
||||||
|
|
||||||
static void CPUMeter_updateValues(Meter* this) {
|
static void CPUMeter_updateValues(Meter* this) {
|
||||||
unsigned int cpu = this->param;
|
unsigned int cpu = this->param;
|
||||||
if (cpu > this->pl->cpuCount) {
|
if (cpu > this->pl->cpuCount) {
|
||||||
|
@ -326,6 +334,7 @@ const MeterClass CPUMeter_class = {
|
||||||
.display = CPUMeter_display
|
.display = CPUMeter_display
|
||||||
},
|
},
|
||||||
.updateValues = CPUMeter_updateValues,
|
.updateValues = CPUMeter_updateValues,
|
||||||
|
.getUiName = CPUMeter_getUiName,
|
||||||
.defaultMode = BAR_METERMODE,
|
.defaultMode = BAR_METERMODE,
|
||||||
.maxItems = CPU_METER_ITEMCOUNT,
|
.maxItems = CPU_METER_ITEMCOUNT,
|
||||||
.total = 100.0,
|
.total = 100.0,
|
||||||
|
|
56
CRT.c
56
CRT.c
|
@ -195,6 +195,15 @@ static int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = {
|
||||||
[ZFS_COMPRESSED] = ColorPair(Blue, Black),
|
[ZFS_COMPRESSED] = ColorPair(Blue, Black),
|
||||||
[ZFS_RATIO] = ColorPair(Magenta, Black),
|
[ZFS_RATIO] = ColorPair(Magenta, Black),
|
||||||
[ZRAM] = ColorPair(Yellow, Black),
|
[ZRAM] = ColorPair(Yellow, Black),
|
||||||
|
[DYNAMIC_GRAY] = ColorPairGrayBlack,
|
||||||
|
[DYNAMIC_DARKGRAY] = A_BOLD | ColorPairGrayBlack,
|
||||||
|
[DYNAMIC_RED] = ColorPair(Red, Black),
|
||||||
|
[DYNAMIC_GREEN] = ColorPair(Green, Black),
|
||||||
|
[DYNAMIC_BLUE] = ColorPair(Blue, Black),
|
||||||
|
[DYNAMIC_CYAN] = ColorPair(Cyan, Black),
|
||||||
|
[DYNAMIC_MAGENTA] = ColorPair(Magenta, Black),
|
||||||
|
[DYNAMIC_YELLOW] = ColorPair(Yellow, Black),
|
||||||
|
[DYNAMIC_WHITE] = ColorPair(White, Black),
|
||||||
},
|
},
|
||||||
[COLORSCHEME_MONOCHROME] = {
|
[COLORSCHEME_MONOCHROME] = {
|
||||||
[RESET_COLOR] = A_NORMAL,
|
[RESET_COLOR] = A_NORMAL,
|
||||||
|
@ -288,6 +297,15 @@ static int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = {
|
||||||
[ZFS_COMPRESSED] = A_BOLD,
|
[ZFS_COMPRESSED] = A_BOLD,
|
||||||
[ZFS_RATIO] = A_BOLD,
|
[ZFS_RATIO] = A_BOLD,
|
||||||
[ZRAM] = A_NORMAL,
|
[ZRAM] = A_NORMAL,
|
||||||
|
[DYNAMIC_GRAY] = A_DIM,
|
||||||
|
[DYNAMIC_DARKGRAY] = A_DIM,
|
||||||
|
[DYNAMIC_RED] = A_BOLD,
|
||||||
|
[DYNAMIC_GREEN] = A_NORMAL,
|
||||||
|
[DYNAMIC_BLUE] = A_NORMAL,
|
||||||
|
[DYNAMIC_CYAN] = A_BOLD,
|
||||||
|
[DYNAMIC_MAGENTA] = A_NORMAL,
|
||||||
|
[DYNAMIC_YELLOW] = A_NORMAL,
|
||||||
|
[DYNAMIC_WHITE] = A_BOLD,
|
||||||
},
|
},
|
||||||
[COLORSCHEME_BLACKONWHITE] = {
|
[COLORSCHEME_BLACKONWHITE] = {
|
||||||
[RESET_COLOR] = ColorPair(Black, White),
|
[RESET_COLOR] = ColorPair(Black, White),
|
||||||
|
@ -380,7 +398,16 @@ static int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = {
|
||||||
[ZFS_OTHER] = ColorPair(Magenta, White),
|
[ZFS_OTHER] = ColorPair(Magenta, White),
|
||||||
[ZFS_COMPRESSED] = ColorPair(Cyan, White),
|
[ZFS_COMPRESSED] = ColorPair(Cyan, White),
|
||||||
[ZFS_RATIO] = ColorPair(Magenta, White),
|
[ZFS_RATIO] = ColorPair(Magenta, White),
|
||||||
[ZRAM] = ColorPair(Yellow, White)
|
[ZRAM] = ColorPair(Yellow, White),
|
||||||
|
[DYNAMIC_GRAY] = ColorPair(Black, White),
|
||||||
|
[DYNAMIC_DARKGRAY] = A_BOLD | ColorPair(Black, White),
|
||||||
|
[DYNAMIC_RED] = ColorPair(Red, White),
|
||||||
|
[DYNAMIC_GREEN] = ColorPair(Green, White),
|
||||||
|
[DYNAMIC_BLUE] = ColorPair(Blue, White),
|
||||||
|
[DYNAMIC_CYAN] = ColorPair(Yellow, White),
|
||||||
|
[DYNAMIC_MAGENTA] = ColorPair(Magenta, White),
|
||||||
|
[DYNAMIC_YELLOW] = ColorPair(Yellow, White),
|
||||||
|
[DYNAMIC_WHITE] = A_BOLD | ColorPair(Black, White),
|
||||||
},
|
},
|
||||||
[COLORSCHEME_LIGHTTERMINAL] = {
|
[COLORSCHEME_LIGHTTERMINAL] = {
|
||||||
[RESET_COLOR] = ColorPair(Black, Black),
|
[RESET_COLOR] = ColorPair(Black, Black),
|
||||||
|
@ -474,6 +501,15 @@ static int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = {
|
||||||
[ZFS_COMPRESSED] = ColorPair(Cyan, Black),
|
[ZFS_COMPRESSED] = ColorPair(Cyan, Black),
|
||||||
[ZFS_RATIO] = A_BOLD | ColorPair(Magenta, Black),
|
[ZFS_RATIO] = A_BOLD | ColorPair(Magenta, Black),
|
||||||
[ZRAM] = ColorPair(Yellow, Black),
|
[ZRAM] = ColorPair(Yellow, Black),
|
||||||
|
[DYNAMIC_GRAY] = ColorPairGrayBlack,
|
||||||
|
[DYNAMIC_DARKGRAY] = A_BOLD | ColorPairGrayBlack,
|
||||||
|
[DYNAMIC_RED] = ColorPair(Red, Black),
|
||||||
|
[DYNAMIC_GREEN] = ColorPair(Green, Black),
|
||||||
|
[DYNAMIC_BLUE] = ColorPair(Blue, Black),
|
||||||
|
[DYNAMIC_CYAN] = ColorPair(Cyan, Black),
|
||||||
|
[DYNAMIC_MAGENTA] = ColorPair(Magenta, Black),
|
||||||
|
[DYNAMIC_YELLOW] = ColorPair(Yellow, Black),
|
||||||
|
[DYNAMIC_WHITE] = ColorPairWhiteDefault,
|
||||||
},
|
},
|
||||||
[COLORSCHEME_MIDNIGHT] = {
|
[COLORSCHEME_MIDNIGHT] = {
|
||||||
[RESET_COLOR] = ColorPair(White, Blue),
|
[RESET_COLOR] = ColorPair(White, Blue),
|
||||||
|
@ -567,6 +603,15 @@ static int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = {
|
||||||
[ZFS_COMPRESSED] = A_BOLD | ColorPair(White, Blue),
|
[ZFS_COMPRESSED] = A_BOLD | ColorPair(White, Blue),
|
||||||
[ZFS_RATIO] = A_BOLD | ColorPair(Magenta, Blue),
|
[ZFS_RATIO] = A_BOLD | ColorPair(Magenta, Blue),
|
||||||
[ZRAM] = A_BOLD | ColorPair(Yellow, Blue),
|
[ZRAM] = A_BOLD | ColorPair(Yellow, Blue),
|
||||||
|
[DYNAMIC_GRAY] = ColorPairGrayBlack,
|
||||||
|
[DYNAMIC_DARKGRAY] = A_BOLD | ColorPairGrayBlack,
|
||||||
|
[DYNAMIC_RED] = ColorPair(Red, Blue),
|
||||||
|
[DYNAMIC_GREEN] = ColorPair(Green, Blue),
|
||||||
|
[DYNAMIC_BLUE] = ColorPair(Black, Blue),
|
||||||
|
[DYNAMIC_CYAN] = ColorPair(Cyan, Blue),
|
||||||
|
[DYNAMIC_MAGENTA] = ColorPair(Magenta, Blue),
|
||||||
|
[DYNAMIC_YELLOW] = ColorPair(Yellow, Blue),
|
||||||
|
[DYNAMIC_WHITE] = ColorPair(White, Blue),
|
||||||
},
|
},
|
||||||
[COLORSCHEME_BLACKNIGHT] = {
|
[COLORSCHEME_BLACKNIGHT] = {
|
||||||
[RESET_COLOR] = ColorPair(Cyan, Black),
|
[RESET_COLOR] = ColorPair(Cyan, Black),
|
||||||
|
@ -658,6 +703,15 @@ static int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = {
|
||||||
[ZFS_COMPRESSED] = ColorPair(Blue, Black),
|
[ZFS_COMPRESSED] = ColorPair(Blue, Black),
|
||||||
[ZFS_RATIO] = ColorPair(Magenta, Black),
|
[ZFS_RATIO] = ColorPair(Magenta, Black),
|
||||||
[ZRAM] = ColorPair(Yellow, Black),
|
[ZRAM] = ColorPair(Yellow, Black),
|
||||||
|
[DYNAMIC_GRAY] = ColorPairGrayBlack,
|
||||||
|
[DYNAMIC_DARKGRAY] = A_BOLD | ColorPairGrayBlack,
|
||||||
|
[DYNAMIC_RED] = ColorPair(Red, Black),
|
||||||
|
[DYNAMIC_GREEN] = ColorPair(Green, Black),
|
||||||
|
[DYNAMIC_BLUE] = ColorPair(Blue, Black),
|
||||||
|
[DYNAMIC_CYAN] = ColorPair(Cyan, Black),
|
||||||
|
[DYNAMIC_MAGENTA] = ColorPair(Magenta, Black),
|
||||||
|
[DYNAMIC_YELLOW] = ColorPair(Yellow, Black),
|
||||||
|
[DYNAMIC_WHITE] = ColorPair(White, Black),
|
||||||
},
|
},
|
||||||
[COLORSCHEME_BROKENGRAY] = { 0 } // dynamically generated.
|
[COLORSCHEME_BROKENGRAY] = { 0 } // dynamically generated.
|
||||||
};
|
};
|
||||||
|
|
9
CRT.h
9
CRT.h
|
@ -131,6 +131,15 @@ typedef enum ColorElements_ {
|
||||||
ZFS_COMPRESSED,
|
ZFS_COMPRESSED,
|
||||||
ZFS_RATIO,
|
ZFS_RATIO,
|
||||||
ZRAM,
|
ZRAM,
|
||||||
|
DYNAMIC_GRAY,
|
||||||
|
DYNAMIC_DARKGRAY,
|
||||||
|
DYNAMIC_RED,
|
||||||
|
DYNAMIC_GREEN,
|
||||||
|
DYNAMIC_BLUE,
|
||||||
|
DYNAMIC_CYAN,
|
||||||
|
DYNAMIC_MAGENTA,
|
||||||
|
DYNAMIC_YELLOW,
|
||||||
|
DYNAMIC_WHITE,
|
||||||
LAST_COLORELEMENT
|
LAST_COLORELEMENT
|
||||||
} ColorElements;
|
} ColorElements;
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,7 @@ in the source distribution for its full text.
|
||||||
|
|
||||||
#include "Action.h"
|
#include "Action.h"
|
||||||
#include "CRT.h"
|
#include "CRT.h"
|
||||||
|
#include "DynamicMeter.h"
|
||||||
#include "Hashtable.h"
|
#include "Hashtable.h"
|
||||||
#include "Header.h"
|
#include "Header.h"
|
||||||
#include "IncSet.h"
|
#include "IncSet.h"
|
||||||
|
@ -288,7 +289,8 @@ int CommandLine_run(const char* name, int argc, char** argv) {
|
||||||
Process_setupColumnWidths();
|
Process_setupColumnWidths();
|
||||||
|
|
||||||
UsersTable* ut = UsersTable_new();
|
UsersTable* ut = UsersTable_new();
|
||||||
ProcessList* pl = ProcessList_new(ut, flags.pidMatchList, flags.userId);
|
Hashtable* dm = DynamicMeters_new();
|
||||||
|
ProcessList* pl = ProcessList_new(ut, dm, flags.pidMatchList, flags.userId);
|
||||||
|
|
||||||
Settings* settings = Settings_new(pl->cpuCount);
|
Settings* settings = Settings_new(pl->cpuCount);
|
||||||
pl->settings = settings;
|
pl->settings = settings;
|
||||||
|
|
|
@ -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 = "",
|
||||||
|
};
|
|
@ -0,0 +1,25 @@
|
||||||
|
#ifndef HEADER_DynamicMeter
|
||||||
|
#define HEADER_DynamicMeter
|
||||||
|
|
||||||
|
#include "Meter.h"
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct DynamicMeter_ {
|
||||||
|
char name[32]; /* unique name, cannot contain spaces */
|
||||||
|
char* caption;
|
||||||
|
char* description;
|
||||||
|
unsigned int type;
|
||||||
|
double maximum;
|
||||||
|
|
||||||
|
void* dynamicData; /* platform-specific meter data */
|
||||||
|
} DynamicMeter;
|
||||||
|
|
||||||
|
Hashtable* DynamicMeters_new(void);
|
||||||
|
|
||||||
|
const char* DynamicMeter_lookup(const ProcessList* pl, unsigned int param);
|
||||||
|
|
||||||
|
unsigned int DynamicMeter_search(const ProcessList* pl, const char* name);
|
||||||
|
|
||||||
|
extern const MeterClass DynamicMeter_class;
|
||||||
|
|
||||||
|
#endif
|
17
Header.c
17
Header.c
|
@ -13,6 +13,8 @@ in the source distribution for its full text.
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "CRT.h"
|
#include "CRT.h"
|
||||||
|
#include "CPUMeter.h"
|
||||||
|
#include "DynamicMeter.h"
|
||||||
#include "Macros.h"
|
#include "Macros.h"
|
||||||
#include "Object.h"
|
#include "Object.h"
|
||||||
#include "Platform.h"
|
#include "Platform.h"
|
||||||
|
@ -70,7 +72,10 @@ void Header_writeBackToSettings(const Header* this) {
|
||||||
for (int i = 0; i < len; i++) {
|
for (int i = 0; i < len; i++) {
|
||||||
const Meter* meter = (Meter*) Vector_get(vec, i);
|
const Meter* meter = (Meter*) Vector_get(vec, i);
|
||||||
char* name;
|
char* name;
|
||||||
if (meter->param) {
|
if (meter->param && As_Meter(meter) == &DynamicMeter_class) {
|
||||||
|
const char* dynamic = DynamicMeter_lookup(this->pl, meter->param);
|
||||||
|
xAsprintf(&name, "%s(%s)", As_Meter(meter)->name, dynamic);
|
||||||
|
} else if (meter->param && As_Meter(meter) == &CPUMeter_class) {
|
||||||
xAsprintf(&name, "%s(%u)", As_Meter(meter)->name, meter->param);
|
xAsprintf(&name, "%s(%u)", As_Meter(meter)->name, meter->param);
|
||||||
} else {
|
} else {
|
||||||
xAsprintf(&name, "%s", As_Meter(meter)->name);
|
xAsprintf(&name, "%s", As_Meter(meter)->name);
|
||||||
|
@ -87,9 +92,13 @@ MeterModeId Header_addMeterByName(Header* this, const char* name, int column) {
|
||||||
char* paren = strchr(name, '(');
|
char* paren = strchr(name, '(');
|
||||||
unsigned int param = 0;
|
unsigned int param = 0;
|
||||||
if (paren) {
|
if (paren) {
|
||||||
int ok = sscanf(paren, "(%10u)", ¶m);
|
char* end, dynamic[32] = {0};
|
||||||
if (!ok)
|
int ok = sscanf(paren, "(%10u)", ¶m); // CPUMeter
|
||||||
param = 0;
|
if (!ok) {
|
||||||
|
ok = sscanf(paren, "(%30s)", dynamic); // DynamicMeter
|
||||||
|
if (ok && (end = strrchr(dynamic, ')'))) *end = '\0';
|
||||||
|
param = ok ? DynamicMeter_search(this->pl, dynamic) : 0;
|
||||||
|
}
|
||||||
*paren = '\0';
|
*paren = '\0';
|
||||||
}
|
}
|
||||||
MeterModeId mode = TEXT_METERMODE;
|
MeterModeId mode = TEXT_METERMODE;
|
||||||
|
|
|
@ -39,6 +39,7 @@ myhtopsources = \
|
||||||
DateTimeMeter.c \
|
DateTimeMeter.c \
|
||||||
DiskIOMeter.c \
|
DiskIOMeter.c \
|
||||||
DisplayOptionsPanel.c \
|
DisplayOptionsPanel.c \
|
||||||
|
DynamicMeter.c \
|
||||||
EnvScreen.c \
|
EnvScreen.c \
|
||||||
FunctionBar.c \
|
FunctionBar.c \
|
||||||
Hashtable.c \
|
Hashtable.c \
|
||||||
|
@ -93,6 +94,7 @@ myhtopheaders = \
|
||||||
DateTimeMeter.h \
|
DateTimeMeter.h \
|
||||||
DiskIOMeter.h \
|
DiskIOMeter.h \
|
||||||
DisplayOptionsPanel.h \
|
DisplayOptionsPanel.h \
|
||||||
|
DynamicMeter.h \
|
||||||
EnvScreen.h \
|
EnvScreen.h \
|
||||||
FunctionBar.h \
|
FunctionBar.h \
|
||||||
Hashtable.h \
|
Hashtable.h \
|
||||||
|
@ -357,6 +359,7 @@ endif
|
||||||
# --------------------------
|
# --------------------------
|
||||||
|
|
||||||
pcp_platform_headers = \
|
pcp_platform_headers = \
|
||||||
|
pcp/PCPDynamicMeter.h \
|
||||||
pcp/PCPProcess.h \
|
pcp/PCPProcess.h \
|
||||||
pcp/PCPProcessList.h \
|
pcp/PCPProcessList.h \
|
||||||
pcp/Platform.h \
|
pcp/Platform.h \
|
||||||
|
@ -369,6 +372,7 @@ pcp_platform_headers = \
|
||||||
zfs/ZfsCompressedArcMeter.h
|
zfs/ZfsCompressedArcMeter.h
|
||||||
|
|
||||||
pcp_platform_sources = \
|
pcp_platform_sources = \
|
||||||
|
pcp/PCPDynamicMeter.c \
|
||||||
pcp/PCPProcess.c \
|
pcp/PCPProcess.c \
|
||||||
pcp/PCPProcessList.c \
|
pcp/PCPProcessList.c \
|
||||||
pcp/Platform.c \
|
pcp/Platform.c \
|
||||||
|
|
13
Meter.c
13
Meter.c
|
@ -138,14 +138,13 @@ ListItem* Meter_toListItem(const Meter* this, bool moving) {
|
||||||
} else {
|
} else {
|
||||||
mode[0] = '\0';
|
mode[0] = '\0';
|
||||||
}
|
}
|
||||||
char number[10];
|
char name[32];
|
||||||
if (this->param > 0) {
|
if (Meter_getUiNameFn(this))
|
||||||
xSnprintf(number, sizeof(number), " %u", this->param);
|
Meter_getUiName(this, name, sizeof(name));
|
||||||
} else {
|
else
|
||||||
number[0] = '\0';
|
xSnprintf(name, sizeof(name), "%s", Meter_uiName(this));
|
||||||
}
|
|
||||||
char buffer[50];
|
char buffer[50];
|
||||||
xSnprintf(buffer, sizeof(buffer), "%s%s%s", Meter_uiName(this), number, mode);
|
xSnprintf(buffer, sizeof(buffer), "%s%s", name, mode);
|
||||||
ListItem* li = ListItem_new(buffer, 0);
|
ListItem* li = ListItem_new(buffer, 0);
|
||||||
li->moving = moving;
|
li->moving = moving;
|
||||||
return li;
|
return li;
|
||||||
|
|
6
Meter.h
6
Meter.h
|
@ -53,14 +53,16 @@ typedef void(*Meter_Done)(Meter*);
|
||||||
typedef void(*Meter_UpdateMode)(Meter*, int);
|
typedef void(*Meter_UpdateMode)(Meter*, int);
|
||||||
typedef void(*Meter_UpdateValues)(Meter*);
|
typedef void(*Meter_UpdateValues)(Meter*);
|
||||||
typedef void(*Meter_Draw)(Meter*, int, int, int);
|
typedef void(*Meter_Draw)(Meter*, int, int, int);
|
||||||
|
typedef void(*Meter_GetUiName)(const Meter*, char*, size_t);
|
||||||
|
|
||||||
typedef struct MeterClass_ {
|
typedef struct MeterClass_ {
|
||||||
const ObjectClass super;
|
const ObjectClass super;
|
||||||
const Meter_Init init;
|
const Meter_Init init;
|
||||||
const Meter_Done done;
|
const Meter_Done done;
|
||||||
const Meter_UpdateMode updateMode;
|
const Meter_UpdateMode updateMode;
|
||||||
const Meter_Draw draw;
|
|
||||||
const Meter_UpdateValues updateValues;
|
const Meter_UpdateValues updateValues;
|
||||||
|
const Meter_Draw draw;
|
||||||
|
const Meter_GetUiName getUiName;
|
||||||
const int defaultMode;
|
const int defaultMode;
|
||||||
const double total;
|
const double total;
|
||||||
const int* const attributes;
|
const int* const attributes;
|
||||||
|
@ -80,6 +82,8 @@ typedef struct MeterClass_ {
|
||||||
#define Meter_drawFn(this_) As_Meter(this_)->draw
|
#define Meter_drawFn(this_) As_Meter(this_)->draw
|
||||||
#define Meter_doneFn(this_) As_Meter(this_)->done
|
#define Meter_doneFn(this_) As_Meter(this_)->done
|
||||||
#define Meter_updateValues(this_) As_Meter(this_)->updateValues((Meter*)(this_))
|
#define Meter_updateValues(this_) As_Meter(this_)->updateValues((Meter*)(this_))
|
||||||
|
#define Meter_getUiNameFn(this_) As_Meter(this_)->getUiName
|
||||||
|
#define Meter_getUiName(this_,n_,l_) As_Meter(this_)->getUiName((const Meter*)(this_),n_,l_)
|
||||||
#define Meter_defaultMode(this_) As_Meter(this_)->defaultMode
|
#define Meter_defaultMode(this_) As_Meter(this_)->defaultMode
|
||||||
#define Meter_attributes(this_) As_Meter(this_)->attributes
|
#define Meter_attributes(this_) As_Meter(this_)->attributes
|
||||||
#define Meter_name(this_) As_Meter(this_)->name
|
#define Meter_name(this_) As_Meter(this_)->name
|
||||||
|
|
|
@ -19,7 +19,7 @@ in the source distribution for its full text.
|
||||||
#include "XUtils.h"
|
#include "XUtils.h"
|
||||||
|
|
||||||
|
|
||||||
ProcessList* ProcessList_init(ProcessList* this, const ObjectClass* klass, UsersTable* usersTable, Hashtable* pidMatchList, uid_t userId) {
|
ProcessList* ProcessList_init(ProcessList* this, const ObjectClass* klass, UsersTable* usersTable, Hashtable* dynamicMeters, Hashtable* pidMatchList, uid_t userId) {
|
||||||
this->processes = Vector_new(klass, true, DEFAULT_SIZE);
|
this->processes = Vector_new(klass, true, DEFAULT_SIZE);
|
||||||
this->processes2 = Vector_new(klass, true, DEFAULT_SIZE); // tree-view auxiliary buffer
|
this->processes2 = Vector_new(klass, true, DEFAULT_SIZE); // tree-view auxiliary buffer
|
||||||
|
|
||||||
|
@ -29,6 +29,7 @@ ProcessList* ProcessList_init(ProcessList* this, const ObjectClass* klass, Users
|
||||||
|
|
||||||
this->usersTable = usersTable;
|
this->usersTable = usersTable;
|
||||||
this->pidMatchList = pidMatchList;
|
this->pidMatchList = pidMatchList;
|
||||||
|
this->dynamicMeters = dynamicMeters;
|
||||||
|
|
||||||
this->userId = userId;
|
this->userId = userId;
|
||||||
|
|
||||||
|
|
|
@ -50,6 +50,8 @@ typedef struct ProcessList_ {
|
||||||
Hashtable* displayTreeSet;
|
Hashtable* displayTreeSet;
|
||||||
Hashtable* draftingTreeSet;
|
Hashtable* draftingTreeSet;
|
||||||
|
|
||||||
|
Hashtable* dynamicMeters; /* runtime-discovered meters */
|
||||||
|
|
||||||
struct timeval realtime; /* time of the current sample */
|
struct timeval realtime; /* time of the current sample */
|
||||||
uint64_t realtimeMs; /* current time in milliseconds */
|
uint64_t realtimeMs; /* current time in milliseconds */
|
||||||
uint64_t monotonicMs; /* same, but from monotonic clock */
|
uint64_t monotonicMs; /* same, but from monotonic clock */
|
||||||
|
@ -84,12 +86,12 @@ typedef struct ProcessList_ {
|
||||||
unsigned int cpuCount;
|
unsigned int cpuCount;
|
||||||
} ProcessList;
|
} ProcessList;
|
||||||
|
|
||||||
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);
|
void ProcessList_delete(ProcessList* pl);
|
||||||
void ProcessList_goThroughEntries(ProcessList* super, bool pauseProcessUpdate);
|
void ProcessList_goThroughEntries(ProcessList* super, bool pauseProcessUpdate);
|
||||||
|
|
||||||
|
|
||||||
ProcessList* ProcessList_init(ProcessList* this, const ObjectClass* klass, UsersTable* usersTable, Hashtable* pidMatchList, uid_t userId);
|
ProcessList* ProcessList_init(ProcessList* this, const ObjectClass* klass, UsersTable* usersTable, Hashtable* dynamicMeters, Hashtable* pidMatchList, uid_t userId);
|
||||||
|
|
||||||
void ProcessList_done(ProcessList* this);
|
void ProcessList_done(ProcessList* this);
|
||||||
|
|
||||||
|
|
|
@ -128,10 +128,10 @@ static struct kinfo_proc* ProcessList_getKInfoProcs(size_t* count) {
|
||||||
CRT_fatalError("Unable to get kinfo_procs");
|
CRT_fatalError("Unable to get kinfo_procs");
|
||||||
}
|
}
|
||||||
|
|
||||||
ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* pidMatchList, uid_t userId) {
|
ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* dynamicMeters, Hashtable* pidMatchList, uid_t userId) {
|
||||||
DarwinProcessList* this = xCalloc(1, sizeof(DarwinProcessList));
|
DarwinProcessList* this = xCalloc(1, sizeof(DarwinProcessList));
|
||||||
|
|
||||||
ProcessList_init(&this->super, Class(DarwinProcess), usersTable, pidMatchList, userId);
|
ProcessList_init(&this->super, Class(DarwinProcess), usersTable, dynamicMeters, pidMatchList, userId);
|
||||||
|
|
||||||
/* Initialize the CPU information */
|
/* Initialize the CPU information */
|
||||||
this->super.cpuCount = ProcessList_allocateCPULoadInfo(&this->prev_load);
|
this->super.cpuCount = ProcessList_allocateCPULoadInfo(&this->prev_load);
|
||||||
|
|
|
@ -28,7 +28,7 @@ typedef struct DarwinProcessList_ {
|
||||||
ZfsArcStats zfs;
|
ZfsArcStats zfs;
|
||||||
} DarwinProcessList;
|
} DarwinProcessList;
|
||||||
|
|
||||||
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* this);
|
void ProcessList_delete(ProcessList* this);
|
||||||
|
|
||||||
|
|
|
@ -92,4 +92,12 @@ static inline void Platform_gettime_realtime(struct timeval* tv, uint64_t* msec)
|
||||||
|
|
||||||
void Platform_gettime_monotonic(uint64_t* msec);
|
void Platform_gettime_monotonic(uint64_t* msec);
|
||||||
|
|
||||||
|
static inline Hashtable* Platform_dynamicMeters(void) { return NULL; }
|
||||||
|
|
||||||
|
static inline void Platform_dynamicMeterInit(ATTR_UNUSED Meter* meter) { }
|
||||||
|
|
||||||
|
static inline void Platform_dynamicMeterUpdateValues(ATTR_UNUSED Meter* meter) { }
|
||||||
|
|
||||||
|
static inline void Platform_dynamicMeterDisplay(ATTR_UNUSED const Meter* meter, ATTR_UNUSED RichString* out) { }
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -42,12 +42,12 @@ static int MIB_kern_cp_time[2];
|
||||||
static int MIB_kern_cp_times[2];
|
static int MIB_kern_cp_times[2];
|
||||||
static int kernelFScale;
|
static int kernelFScale;
|
||||||
|
|
||||||
ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* pidMatchList, uid_t userId) {
|
ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* dynamicMeters, Hashtable* pidMatchList, uid_t userId) {
|
||||||
size_t len;
|
size_t len;
|
||||||
char errbuf[_POSIX2_LINE_MAX];
|
char errbuf[_POSIX2_LINE_MAX];
|
||||||
DragonFlyBSDProcessList* dfpl = xCalloc(1, sizeof(DragonFlyBSDProcessList));
|
DragonFlyBSDProcessList* dfpl = xCalloc(1, sizeof(DragonFlyBSDProcessList));
|
||||||
ProcessList* pl = (ProcessList*) dfpl;
|
ProcessList* pl = (ProcessList*) dfpl;
|
||||||
ProcessList_init(pl, Class(DragonFlyBSDProcess), usersTable, pidMatchList, userId);
|
ProcessList_init(pl, Class(DragonFlyBSDProcess), usersTable, dynamicMeters, pidMatchList, userId);
|
||||||
|
|
||||||
// physical memory in system: hw.physmem
|
// physical memory in system: hw.physmem
|
||||||
// physical page size: hw.pagesize
|
// physical page size: hw.pagesize
|
||||||
|
|
|
@ -89,4 +89,12 @@ static inline void Platform_gettime_monotonic(uint64_t* msec) {
|
||||||
Generic_gettime_monotonic(msec);
|
Generic_gettime_monotonic(msec);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline Hashtable* Platform_dynamicMeters(void) { return NULL; }
|
||||||
|
|
||||||
|
static inline void Platform_dynamicMeterInit(ATTR_UNUSED Meter* meter) { }
|
||||||
|
|
||||||
|
static inline void Platform_dynamicMeterUpdateValues(ATTR_UNUSED Meter* meter) { }
|
||||||
|
|
||||||
|
static inline void Platform_dynamicMeterDisplay(ATTR_UNUSED const Meter* meter, ATTR_UNUSED RichString* out) { }
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -56,12 +56,12 @@ static int MIB_kern_cp_time[2];
|
||||||
static int MIB_kern_cp_times[2];
|
static int MIB_kern_cp_times[2];
|
||||||
static int kernelFScale;
|
static int kernelFScale;
|
||||||
|
|
||||||
ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* pidMatchList, uid_t userId) {
|
ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* dynamicMeters, Hashtable* pidMatchList, uid_t userId) {
|
||||||
size_t len;
|
size_t len;
|
||||||
char errbuf[_POSIX2_LINE_MAX];
|
char errbuf[_POSIX2_LINE_MAX];
|
||||||
FreeBSDProcessList* fpl = xCalloc(1, sizeof(FreeBSDProcessList));
|
FreeBSDProcessList* fpl = xCalloc(1, sizeof(FreeBSDProcessList));
|
||||||
ProcessList* pl = (ProcessList*) fpl;
|
ProcessList* pl = (ProcessList*) fpl;
|
||||||
ProcessList_init(pl, Class(FreeBSDProcess), usersTable, pidMatchList, userId);
|
ProcessList_init(pl, Class(FreeBSDProcess), usersTable, dynamicMeters, pidMatchList, userId);
|
||||||
|
|
||||||
// physical memory in system: hw.physmem
|
// physical memory in system: hw.physmem
|
||||||
// physical page size: hw.pagesize
|
// physical page size: hw.pagesize
|
||||||
|
|
|
@ -47,7 +47,7 @@ typedef struct FreeBSDProcessList_ {
|
||||||
|
|
||||||
} FreeBSDProcessList;
|
} FreeBSDProcessList;
|
||||||
|
|
||||||
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* this);
|
void ProcessList_delete(ProcessList* this);
|
||||||
|
|
||||||
|
|
|
@ -89,4 +89,12 @@ static inline void Platform_gettime_monotonic(uint64_t* msec) {
|
||||||
Generic_gettime_monotonic(msec);
|
Generic_gettime_monotonic(msec);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline Hashtable* Platform_dynamicMeters(void) { return NULL; }
|
||||||
|
|
||||||
|
static inline void Platform_dynamicMeterInit(ATTR_UNUSED Meter* meter) { }
|
||||||
|
|
||||||
|
static inline void Platform_dynamicMeterUpdateValues(ATTR_UNUSED Meter* meter) { }
|
||||||
|
|
||||||
|
static inline void Platform_dynamicMeterDisplay(ATTR_UNUSED const Meter* meter, ATTR_UNUSED RichString* out) { }
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -184,11 +184,11 @@ static void LinuxProcessList_updateCPUcount(ProcessList* super, FILE* stream) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* pidMatchList, uid_t userId) {
|
ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* dynamicMeters, Hashtable* pidMatchList, uid_t userId) {
|
||||||
LinuxProcessList* this = xCalloc(1, sizeof(LinuxProcessList));
|
LinuxProcessList* this = xCalloc(1, sizeof(LinuxProcessList));
|
||||||
ProcessList* pl = &(this->super);
|
ProcessList* pl = &(this->super);
|
||||||
|
|
||||||
ProcessList_init(pl, Class(LinuxProcess), usersTable, pidMatchList, userId);
|
ProcessList_init(pl, Class(LinuxProcess), usersTable, dynamicMeters, pidMatchList, userId);
|
||||||
LinuxProcessList_initTtyDrivers(this);
|
LinuxProcessList_initTtyDrivers(this);
|
||||||
|
|
||||||
// Initialize page size
|
// Initialize page size
|
||||||
|
|
|
@ -111,7 +111,7 @@ typedef struct LinuxProcessList_ {
|
||||||
#define PROC_LINE_LENGTH 4096
|
#define PROC_LINE_LENGTH 4096
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
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);
|
void ProcessList_delete(ProcessList* pl);
|
||||||
|
|
||||||
|
|
|
@ -105,4 +105,12 @@ static inline void Platform_gettime_monotonic(uint64_t* msec) {
|
||||||
Generic_gettime_monotonic(msec);
|
Generic_gettime_monotonic(msec);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline Hashtable* Platform_dynamicMeters(void) { return NULL; }
|
||||||
|
|
||||||
|
static inline void Platform_dynamicMeterInit(ATTR_UNUSED Meter* meter) { }
|
||||||
|
|
||||||
|
static inline void Platform_dynamicMeterUpdateValues(ATTR_UNUSED Meter* meter) { }
|
||||||
|
|
||||||
|
static inline void Platform_dynamicMeterDisplay(ATTR_UNUSED const Meter* meter, ATTR_UNUSED RichString* out) { }
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -36,7 +36,7 @@ static long fscale;
|
||||||
static int pageSize;
|
static int pageSize;
|
||||||
static int pageSizeKB;
|
static int pageSizeKB;
|
||||||
|
|
||||||
ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* pidMatchList, uid_t userId) {
|
ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* dynamicMeters, Hashtable* pidMatchList, uid_t userId) {
|
||||||
const int nmib[] = { CTL_HW, HW_NCPU };
|
const int nmib[] = { CTL_HW, HW_NCPU };
|
||||||
const int mib[] = { CTL_HW, HW_NCPUONLINE };
|
const int mib[] = { CTL_HW, HW_NCPUONLINE };
|
||||||
const int fmib[] = { CTL_KERN, KERN_FSCALE };
|
const int fmib[] = { CTL_KERN, KERN_FSCALE };
|
||||||
|
@ -48,7 +48,7 @@ ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* pidMatchList, ui
|
||||||
|
|
||||||
OpenBSDProcessList* opl = xCalloc(1, sizeof(OpenBSDProcessList));
|
OpenBSDProcessList* opl = xCalloc(1, sizeof(OpenBSDProcessList));
|
||||||
ProcessList* pl = (ProcessList*) opl;
|
ProcessList* pl = (ProcessList*) opl;
|
||||||
ProcessList_init(pl, Class(OpenBSDProcess), usersTable, pidMatchList, userId);
|
ProcessList_init(pl, Class(OpenBSDProcess), usersTable, dynamicMeters, pidMatchList, userId);
|
||||||
|
|
||||||
size = sizeof(pl->cpuCount);
|
size = sizeof(pl->cpuCount);
|
||||||
r = sysctl(mib, 2, &pl->cpuCount, &size, NULL, 0);
|
r = sysctl(mib, 2, &pl->cpuCount, &size, NULL, 0);
|
||||||
|
|
|
@ -49,7 +49,7 @@ typedef struct OpenBSDProcessList_ {
|
||||||
} OpenBSDProcessList;
|
} OpenBSDProcessList;
|
||||||
|
|
||||||
|
|
||||||
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* this);
|
void ProcessList_delete(ProcessList* this);
|
||||||
|
|
||||||
|
|
|
@ -87,4 +87,12 @@ static inline void Platform_gettime_monotonic(uint64_t* msec) {
|
||||||
Generic_gettime_monotonic(msec);
|
Generic_gettime_monotonic(msec);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline Hashtable* Platform_dynamicMeters(void) { return NULL; }
|
||||||
|
|
||||||
|
static inline void Platform_dynamicMeterInit(ATTR_UNUSED Meter* meter) { }
|
||||||
|
|
||||||
|
static inline void Platform_dynamicMeterUpdateValues(ATTR_UNUSED Meter* meter) { }
|
||||||
|
|
||||||
|
static inline void Platform_dynamicMeterDisplay(ATTR_UNUSED const Meter* meter, ATTR_UNUSED RichString* out) { }
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -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");
|
||||||
|
}
|
|
@ -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
|
|
@ -59,11 +59,11 @@ static char* setUser(UsersTable* this, unsigned int uid, int pid, int offset) {
|
||||||
return name;
|
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));
|
PCPProcessList* this = xCalloc(1, sizeof(PCPProcessList));
|
||||||
ProcessList* super = &(this->super);
|
ProcessList* super = &(this->super);
|
||||||
|
|
||||||
ProcessList_init(super, Class(PCPProcess), usersTable, pidMatchList, userId);
|
ProcessList_init(super, Class(PCPProcess), usersTable, dynamicMeters, pidMatchList, userId);
|
||||||
|
|
||||||
struct timeval timestamp;
|
struct timeval timestamp;
|
||||||
gettimeofday(×tamp, NULL);
|
gettimeofday(×tamp, NULL);
|
||||||
|
|
|
@ -63,7 +63,7 @@ typedef struct PCPProcessList_ {
|
||||||
ZfsArcStats zfs;
|
ZfsArcStats zfs;
|
||||||
} PCPProcessList;
|
} 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);
|
void ProcessList_delete(ProcessList* pl);
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,7 @@ in the source distribution for its full text.
|
||||||
#include "DateMeter.h"
|
#include "DateMeter.h"
|
||||||
#include "DateTimeMeter.h"
|
#include "DateTimeMeter.h"
|
||||||
#include "DiskIOMeter.h"
|
#include "DiskIOMeter.h"
|
||||||
|
#include "DynamicMeter.h"
|
||||||
#include "HostnameMeter.h"
|
#include "HostnameMeter.h"
|
||||||
#include "LoadAverageMeter.h"
|
#include "LoadAverageMeter.h"
|
||||||
#include "Macros.h"
|
#include "Macros.h"
|
||||||
|
@ -41,6 +42,7 @@ in the source distribution for its full text.
|
||||||
#include "linux/PressureStallMeter.h"
|
#include "linux/PressureStallMeter.h"
|
||||||
#include "linux/ZramMeter.h"
|
#include "linux/ZramMeter.h"
|
||||||
#include "linux/ZramStats.h"
|
#include "linux/ZramStats.h"
|
||||||
|
#include "pcp/PCPDynamicMeter.h"
|
||||||
#include "pcp/PCPProcess.h"
|
#include "pcp/PCPProcess.h"
|
||||||
#include "pcp/PCPProcessList.h"
|
#include "pcp/PCPProcessList.h"
|
||||||
#include "zfs/ZfsArcMeter.h"
|
#include "zfs/ZfsArcMeter.h"
|
||||||
|
@ -50,14 +52,14 @@ in the source distribution for its full text.
|
||||||
|
|
||||||
typedef struct Platform_ {
|
typedef struct Platform_ {
|
||||||
int context; /* PMAPI(3) context identifier */
|
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 */
|
const char** names; /* name array indexed by Metric */
|
||||||
pmID* pmids; /* all known metric identifiers */
|
pmID* pmids; /* all known metric identifiers */
|
||||||
pmID* fetch; /* enabled identifiers for sampling */
|
pmID* fetch; /* enabled identifiers for sampling */
|
||||||
pmDesc* descs; /* metric desc array indexed by Metric */
|
pmDesc* descs; /* metric desc array indexed by Metric */
|
||||||
pmResult* result; /* sample values result 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 */
|
struct timeval offset; /* time offset used in archive mode only */
|
||||||
|
|
||||||
long long btime; /* boottime in seconds since the epoch */
|
long long btime; /* boottime in seconds since the epoch */
|
||||||
char* release; /* uname and distro from this context */
|
char* release; /* uname and distro from this context */
|
||||||
int pidmax; /* maximum platform process identifier */
|
int pidmax; /* maximum platform process identifier */
|
||||||
|
@ -78,6 +80,7 @@ const unsigned int Platform_numberOfSignals = ARRAYSIZE(Platform_signals);
|
||||||
|
|
||||||
const MeterClass* const Platform_meterTypes[] = {
|
const MeterClass* const Platform_meterTypes[] = {
|
||||||
&CPUMeter_class,
|
&CPUMeter_class,
|
||||||
|
&DynamicMeter_class,
|
||||||
&ClockMeter_class,
|
&ClockMeter_class,
|
||||||
&DateMeter_class,
|
&DateMeter_class,
|
||||||
&DateTimeMeter_class,
|
&DateTimeMeter_class,
|
||||||
|
@ -244,7 +247,13 @@ static const char *Platform_metricNames[] = {
|
||||||
[PCP_METRIC_COUNT] = NULL
|
[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) {
|
pmAtomValue* Metric_values(Metric metric, pmAtomValue *atom, int count, int type) {
|
||||||
|
if (pcp->result == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
pmValueSet* vset = pcp->result->vset[metric];
|
pmValueSet* vset = pcp->result->vset[metric];
|
||||||
if (!vset || vset->numval <= 0)
|
if (!vset || vset->numval <= 0)
|
||||||
|
@ -374,7 +383,7 @@ bool Metric_fetch(struct timeval *timestamp) {
|
||||||
pmFreeResult(pcp->result);
|
pmFreeResult(pcp->result);
|
||||||
pcp->result = NULL;
|
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 (sts < 0) {
|
||||||
if (pmDebugOptions.appl0)
|
if (pmDebugOptions.appl0)
|
||||||
fprintf(stderr, "Error: cannot fetch metric values: %s\n",
|
fprintf(stderr, "Error: cannot fetch metric values: %s\n",
|
||||||
|
@ -386,12 +395,12 @@ bool Metric_fetch(struct timeval *timestamp) {
|
||||||
return true;
|
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;
|
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 */
|
/* 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->fetch = xRealloc(pcp->fetch, j * sizeof(pmID));
|
||||||
pcp->pmids = xRealloc(pcp->pmids, j * sizeof(pmID));
|
pcp->pmids = xRealloc(pcp->pmids, j * sizeof(pmID));
|
||||||
pcp->names = xRealloc(pcp->names, j * sizeof(char*));
|
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->pmids[i] = pcp->fetch[i] = PM_ID_NULL;
|
||||||
pcp->names[i] = name;
|
pcp->names[i] = name;
|
||||||
return ++pcp->total;
|
return ++pcp->totalMetrics;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* global state from the environment and command line arguments */
|
/* 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++)
|
for (unsigned int i = 0; i < PCP_METRIC_COUNT; i++)
|
||||||
Platform_addMetric(i, Platform_metricNames[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) {
|
if (sts < 0) {
|
||||||
fprintf(stderr, "Error: cannot lookup metric names: %s\n", pmErrStr(sts));
|
fprintf(stderr, "Error: cannot lookup metric names: %s\n", pmErrStr(sts));
|
||||||
exit(1);
|
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 */
|
pcp->fetch[i] = PM_ID_NULL; /* default is to not sample */
|
||||||
|
|
||||||
/* expect some metrics to be missing - e.g. PMDA not available */
|
/* 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;
|
struct timeval* tv = &pcp->result->timestamp;
|
||||||
*msec = ((uint64_t)tv->tv_sec * 1000) + ((uint64_t)tv->tv_usec / 1000);
|
*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);
|
||||||
|
}
|
||||||
|
|
|
@ -24,6 +24,7 @@ in the source distribution for its full text.
|
||||||
#include "Action.h"
|
#include "Action.h"
|
||||||
#include "BatteryMeter.h"
|
#include "BatteryMeter.h"
|
||||||
#include "DiskIOMeter.h"
|
#include "DiskIOMeter.h"
|
||||||
|
#include "Hashtable.h"
|
||||||
#include "Meter.h"
|
#include "Meter.h"
|
||||||
#include "NetworkIOMeter.h"
|
#include "NetworkIOMeter.h"
|
||||||
#include "Process.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);
|
pmAtomValue* Metric_values(Metric metric, pmAtomValue *atom, int count, int type);
|
||||||
|
|
||||||
|
const pmDesc* Metric_desc(Metric metric);
|
||||||
|
|
||||||
int Metric_instanceCount(Metric metric);
|
int Metric_instanceCount(Metric metric);
|
||||||
|
|
||||||
int Metric_instanceOffset(Metric metric, int inst);
|
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_realtime(struct timeval* tv, uint64_t* msec);
|
||||||
|
|
||||||
void Platform_gettime_monotonic(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
|
#endif
|
||||||
|
|
|
@ -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 = %
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -128,4 +128,12 @@ IGNORE_WCASTQUAL_BEGIN
|
||||||
IGNORE_WCASTQUAL_END
|
IGNORE_WCASTQUAL_END
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline Hashtable* Platform_dynamicMeters(void) { return NULL; }
|
||||||
|
|
||||||
|
static inline void Platform_dynamicMeterInit(ATTR_UNUSED Meter* meter) { }
|
||||||
|
|
||||||
|
static inline void Platform_dynamicMeterUpdateValues(ATTR_UNUSED Meter* meter) { }
|
||||||
|
|
||||||
|
static inline void Platform_dynamicMeterDisplay(ATTR_UNUSED const Meter* meter, ATTR_UNUSED RichString* out) { }
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -47,10 +47,10 @@ static char* SolarisProcessList_readZoneName(kstat_ctl_t* kd, SolarisProcess* sp
|
||||||
return zname;
|
return zname;
|
||||||
}
|
}
|
||||||
|
|
||||||
ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* pidMatchList, uid_t userId) {
|
ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* dynamicMeters, Hashtable* pidMatchList, uid_t userId) {
|
||||||
SolarisProcessList* spl = xCalloc(1, sizeof(SolarisProcessList));
|
SolarisProcessList* spl = xCalloc(1, sizeof(SolarisProcessList));
|
||||||
ProcessList* pl = (ProcessList*) spl;
|
ProcessList* pl = (ProcessList*) spl;
|
||||||
ProcessList_init(pl, Class(SolarisProcess), usersTable, pidMatchList, userId);
|
ProcessList_init(pl, Class(SolarisProcess), usersTable, dynamicMeters, pidMatchList, userId);
|
||||||
|
|
||||||
spl->kd = kstat_open();
|
spl->kd = kstat_open();
|
||||||
|
|
||||||
|
|
|
@ -53,7 +53,7 @@ typedef struct SolarisProcessList_ {
|
||||||
ZfsArcStats zfs;
|
ZfsArcStats zfs;
|
||||||
} SolarisProcessList;
|
} SolarisProcessList;
|
||||||
|
|
||||||
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);
|
void ProcessList_delete(ProcessList* pl);
|
||||||
|
|
||||||
|
|
|
@ -78,4 +78,12 @@ static inline void Platform_gettime_monotonic(uint64_t* msec) {
|
||||||
Generic_gettime_monotonic(msec);
|
Generic_gettime_monotonic(msec);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline Hashtable* Platform_dynamicMeters(void) { return NULL; }
|
||||||
|
|
||||||
|
static inline void Platform_dynamicMeterInit(ATTR_UNUSED Meter* meter) { }
|
||||||
|
|
||||||
|
static inline void Platform_dynamicMeterUpdateValues(ATTR_UNUSED Meter* meter) { }
|
||||||
|
|
||||||
|
static inline void Platform_dynamicMeterDisplay(ATTR_UNUSED const Meter* meter, ATTR_UNUSED RichString* out) { }
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -14,9 +14,9 @@ in the source distribution for its full text.
|
||||||
#include "UnsupportedProcess.h"
|
#include "UnsupportedProcess.h"
|
||||||
|
|
||||||
|
|
||||||
ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* pidMatchList, uid_t userId) {
|
ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* dynamicMeters, Hashtable* pidMatchList, uid_t userId) {
|
||||||
ProcessList* this = xCalloc(1, sizeof(ProcessList));
|
ProcessList* this = xCalloc(1, sizeof(ProcessList));
|
||||||
ProcessList_init(this, Class(Process), usersTable, pidMatchList, userId);
|
ProcessList_init(this, Class(Process), usersTable, dynamicMeters, pidMatchList, userId);
|
||||||
|
|
||||||
this->cpuCount = 1;
|
this->cpuCount = 1;
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ in the source distribution for its full text.
|
||||||
#include "ProcessList.h"
|
#include "ProcessList.h"
|
||||||
|
|
||||||
|
|
||||||
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* this);
|
void ProcessList_delete(ProcessList* this);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue