mirror of
https://github.com/xzeldon/htop.git
synced 2024-12-23 22:55:46 +00:00
Merge branch 'dynamic-columns' of https://github.com/smalinux/htop into smalinux-dynamic-columns
This commit is contained in:
commit
f839095e3b
13
Action.c
13
Action.c
@ -13,9 +13,10 @@ in the source distribution for its full text.
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "CRT.h"
|
||||
#include "CategoriesPanel.h"
|
||||
#include "CommandScreen.h"
|
||||
#include "CRT.h"
|
||||
#include "DynamicColumn.h"
|
||||
#include "EnvScreen.h"
|
||||
#include "FunctionBar.h"
|
||||
#include "Hashtable.h"
|
||||
@ -168,8 +169,16 @@ static Htop_Reaction actionSetSortColumn(State* st) {
|
||||
Panel* sortPanel = Panel_new(0, 0, 0, 0, Class(ListItem), true, FunctionBar_newEnterEsc("Sort ", "Cancel "));
|
||||
Panel_setHeader(sortPanel, "Sort by");
|
||||
const ProcessField* fields = st->settings->fields;
|
||||
Hashtable* dynamicColumns = st->settings->dynamicColumns;
|
||||
for (int i = 0; fields[i]; i++) {
|
||||
char* name = String_trim(Process_fields[fields[i]].name);
|
||||
char* name = NULL;
|
||||
if (fields[i] >= LAST_PROCESSFIELD) {
|
||||
DynamicColumn* column = Hashtable_get(dynamicColumns, fields[i]);
|
||||
if (column)
|
||||
name = xStrdup(column->caption ? column->caption : column->name);
|
||||
} else {
|
||||
name = String_trim(Process_fields[fields[i]].name);
|
||||
}
|
||||
Panel_add(sortPanel, (Object*) ListItem_new(name, fields[i]));
|
||||
if (fields[i] == Settings_getActiveSortKey(st->settings))
|
||||
Panel_setSelected(sortPanel, i);
|
||||
|
@ -7,15 +7,20 @@ in the source distribution for its full text.
|
||||
|
||||
#include "AvailableColumnsPanel.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "ColumnsPanel.h"
|
||||
#include "DynamicColumn.h"
|
||||
#include "FunctionBar.h"
|
||||
#include "Hashtable.h"
|
||||
#include "ListItem.h"
|
||||
#include "Macros.h"
|
||||
#include "Object.h"
|
||||
#include "Process.h"
|
||||
#include "ProcessList.h"
|
||||
#include "ProvideCurses.h"
|
||||
#include "XUtils.h"
|
||||
|
||||
@ -29,6 +34,15 @@ static void AvailableColumnsPanel_delete(Object* object) {
|
||||
free(this);
|
||||
}
|
||||
|
||||
static void AvailableColumnsPanel_insert(AvailableColumnsPanel* this, int at, int key) {
|
||||
const char* name;
|
||||
if (key >= LAST_PROCESSFIELD)
|
||||
name = DynamicColumn_init(key);
|
||||
else
|
||||
name = Process_fields[key].name;
|
||||
Panel_insert(this->columns, at, (Object*) ListItem_new(name, key));
|
||||
}
|
||||
|
||||
static HandlerResult AvailableColumnsPanel_eventHandler(Panel* super, int ch) {
|
||||
AvailableColumnsPanel* this = (AvailableColumnsPanel*) super;
|
||||
HandlerResult result = IGNORED;
|
||||
@ -42,10 +56,9 @@ static HandlerResult AvailableColumnsPanel_eventHandler(Panel* super, int ch) {
|
||||
if (!selected)
|
||||
break;
|
||||
|
||||
int key = selected->key;
|
||||
int at = Panel_getSelectedIndex(this->columns);
|
||||
Panel_insert(this->columns, at, (Object*) ListItem_new(Process_fields[key].name, key));
|
||||
Panel_setSelected(this->columns, at+1);
|
||||
AvailableColumnsPanel_insert(this, at, selected->key);
|
||||
Panel_setSelected(this->columns, at + 1);
|
||||
ColumnsPanel_update(this->columns);
|
||||
result = HANDLED;
|
||||
break;
|
||||
@ -68,14 +81,25 @@ const PanelClass AvailableColumnsPanel_class = {
|
||||
.eventHandler = AvailableColumnsPanel_eventHandler
|
||||
};
|
||||
|
||||
AvailableColumnsPanel* AvailableColumnsPanel_new(Panel* columns) {
|
||||
AvailableColumnsPanel* this = AllocThis(AvailableColumnsPanel);
|
||||
Panel* super = (Panel*) this;
|
||||
FunctionBar* fuBar = FunctionBar_new(AvailableColumnsFunctions, NULL, NULL);
|
||||
Panel_init(super, 1, 1, 1, 1, Class(ListItem), true, fuBar);
|
||||
static void AvailableColumnsPanel_addDynamicColumn(ht_key_t key, void* value, void* data) {
|
||||
const DynamicColumn* column = (const DynamicColumn*) value;
|
||||
Panel* super = (Panel*) data;
|
||||
const char* title = column->caption ? column->caption : column->heading;
|
||||
if (!title)
|
||||
title = column->name; // fallback to the only mandatory field
|
||||
char description[256];
|
||||
xSnprintf(description, sizeof(description), "%s - %s", title, column->description);
|
||||
Panel_add(super, (Object*) ListItem_new(description, key));
|
||||
}
|
||||
|
||||
Panel_setHeader(super, "Available Columns");
|
||||
// Handle DynamicColumns entries in the AvailableColumnsPanel
|
||||
static void AvailableColumnsPanel_addDynamicColumns(Panel* super, Hashtable* dynamicColumns) {
|
||||
assert(dynamicColumns);
|
||||
Hashtable_foreach(dynamicColumns, AvailableColumnsPanel_addDynamicColumn, super);
|
||||
}
|
||||
|
||||
// Handle remaining Platform Meter entries in the AvailableColumnsPanel
|
||||
static void AvailableColumnsPanel_addPlatformColumn(Panel* super) {
|
||||
for (int i = 1; i < LAST_PROCESSFIELD; i++) {
|
||||
if (i != COMM && Process_fields[i].description) {
|
||||
char description[256];
|
||||
@ -83,6 +107,18 @@ AvailableColumnsPanel* AvailableColumnsPanel_new(Panel* columns) {
|
||||
Panel_add(super, (Object*) ListItem_new(description, i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AvailableColumnsPanel* AvailableColumnsPanel_new(Panel* columns, Hashtable* dynamicColumns) {
|
||||
AvailableColumnsPanel* this = AllocThis(AvailableColumnsPanel);
|
||||
Panel* super = (Panel*) this;
|
||||
FunctionBar* fuBar = FunctionBar_new(AvailableColumnsFunctions, NULL, NULL);
|
||||
Panel_init(super, 1, 1, 1, 1, Class(ListItem), true, fuBar);
|
||||
|
||||
Panel_setHeader(super, "Available Columns");
|
||||
AvailableColumnsPanel_addPlatformColumn(super);
|
||||
AvailableColumnsPanel_addDynamicColumns(super, dynamicColumns);
|
||||
|
||||
this->columns = columns;
|
||||
return this;
|
||||
}
|
||||
|
@ -7,7 +7,9 @@ Released under the GNU GPLv2, see the COPYING file
|
||||
in the source distribution for its full text.
|
||||
*/
|
||||
|
||||
#include "Hashtable.h"
|
||||
#include "Panel.h"
|
||||
#include "ProcessList.h"
|
||||
|
||||
|
||||
typedef struct AvailableColumnsPanel_ {
|
||||
@ -17,6 +19,6 @@ typedef struct AvailableColumnsPanel_ {
|
||||
|
||||
extern const PanelClass AvailableColumnsPanel_class;
|
||||
|
||||
AvailableColumnsPanel* AvailableColumnsPanel_new(Panel* columns);
|
||||
AvailableColumnsPanel* AvailableColumnsPanel_new(Panel* columns, Hashtable* dynamicColumns);
|
||||
|
||||
#endif
|
||||
|
@ -14,8 +14,10 @@ in the source distribution for its full text.
|
||||
#include "CPUMeter.h"
|
||||
#include "DynamicMeter.h"
|
||||
#include "FunctionBar.h"
|
||||
#include "Hashtable.h"
|
||||
#include "Header.h"
|
||||
#include "ListItem.h"
|
||||
#include "Macros.h"
|
||||
#include "Meter.h"
|
||||
#include "MetersPanel.h"
|
||||
#include "Object.h"
|
||||
|
@ -56,7 +56,7 @@ static void CategoriesPanel_makeColorsPage(CategoriesPanel* this) {
|
||||
|
||||
static void CategoriesPanel_makeColumnsPage(CategoriesPanel* this) {
|
||||
Panel* columns = (Panel*) ColumnsPanel_new(this->settings);
|
||||
Panel* availableColumns = (Panel*) AvailableColumnsPanel_new(columns);
|
||||
Panel* availableColumns = (Panel*) AvailableColumnsPanel_new(columns, this->settings->dynamicColumns);
|
||||
ScreenManager_add(this->scr, columns, 20);
|
||||
ScreenManager_add(this->scr, availableColumns, -1);
|
||||
}
|
||||
|
@ -11,7 +11,9 @@ in the source distribution for its full text.
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "CRT.h"
|
||||
#include "DynamicColumn.h"
|
||||
#include "FunctionBar.h"
|
||||
#include "Hashtable.h"
|
||||
#include "ListItem.h"
|
||||
#include "Object.h"
|
||||
#include "Process.h"
|
||||
@ -115,6 +117,32 @@ const PanelClass ColumnsPanel_class = {
|
||||
.eventHandler = ColumnsPanel_eventHandler
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
Panel* super;
|
||||
unsigned int id;
|
||||
unsigned int offset;
|
||||
} DynamicIterator;
|
||||
|
||||
static void ColumnsPanel_add(Panel* super, unsigned int key, Hashtable* columns) {
|
||||
const char* name;
|
||||
if (key < LAST_PROCESSFIELD) {
|
||||
name = Process_fields[key].name;
|
||||
} else {
|
||||
const DynamicColumn* column = Hashtable_get(columns, key);
|
||||
assert(column);
|
||||
if (!column) {
|
||||
name = NULL;
|
||||
} else {
|
||||
name = column->caption ? column->caption : column->heading;
|
||||
if (!name)
|
||||
name = column->name; /* name is a mandatory field */
|
||||
}
|
||||
}
|
||||
if (name == NULL)
|
||||
name = "- ";
|
||||
Panel_add(super, (Object*) ListItem_new(name, key));
|
||||
}
|
||||
|
||||
ColumnsPanel* ColumnsPanel_new(Settings* settings) {
|
||||
ColumnsPanel* this = AllocThis(ColumnsPanel);
|
||||
Panel* super = (Panel*) this;
|
||||
@ -125,12 +153,11 @@ ColumnsPanel* ColumnsPanel_new(Settings* settings) {
|
||||
this->moving = false;
|
||||
Panel_setHeader(super, "Active Columns");
|
||||
|
||||
const ProcessField* fields = this->settings->fields;
|
||||
for (; *fields; fields++) {
|
||||
if (Process_fields[*fields].name) {
|
||||
Panel_add(super, (Object*) ListItem_new(Process_fields[*fields].name, *fields));
|
||||
}
|
||||
}
|
||||
Hashtable* dynamicColumns = settings->dynamicColumns;
|
||||
const ProcessField* fields = settings->fields;
|
||||
for (; *fields; fields++)
|
||||
ColumnsPanel_add(super, *fields, dynamicColumns);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -143,7 +170,8 @@ void ColumnsPanel_update(Panel* super) {
|
||||
for (int i = 0; i < size; i++) {
|
||||
int key = ((ListItem*) Panel_get(super, i))->key;
|
||||
this->settings->fields[i] = key;
|
||||
this->settings->flags |= Process_fields[key].flags;
|
||||
if (key < LAST_PROCESSFIELD)
|
||||
this->settings->flags |= Process_fields[key].flags;
|
||||
}
|
||||
this->settings->fields[size] = 0;
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ in the source distribution for its full text.
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "Panel.h"
|
||||
#include "ProcessList.h"
|
||||
#include "Settings.h"
|
||||
|
||||
|
||||
|
@ -22,6 +22,7 @@ in the source distribution for its full text.
|
||||
|
||||
#include "Action.h"
|
||||
#include "CRT.h"
|
||||
#include "DynamicColumn.h"
|
||||
#include "DynamicMeter.h"
|
||||
#include "Hashtable.h"
|
||||
#include "Header.h"
|
||||
@ -292,10 +293,14 @@ int CommandLine_run(const char* name, int argc, char** argv) {
|
||||
Process_setupColumnWidths();
|
||||
|
||||
UsersTable* ut = UsersTable_new();
|
||||
Hashtable* dc = DynamicColumns_new();
|
||||
Hashtable* dm = DynamicMeters_new();
|
||||
ProcessList* pl = ProcessList_new(ut, dm, flags.pidMatchList, flags.userId);
|
||||
if (!dc)
|
||||
dc = Hashtable_new(0, true);
|
||||
|
||||
Settings* settings = Settings_new(pl->activeCPUs);
|
||||
ProcessList* pl = ProcessList_new(ut, dm, dc, flags.pidMatchList, flags.userId);
|
||||
|
||||
Settings* settings = Settings_new(pl->activeCPUs, dc);
|
||||
pl->settings = settings;
|
||||
|
||||
Header* header = Header_new(pl, settings, 2);
|
||||
@ -384,8 +389,12 @@ int CommandLine_run(const char* name, int argc, char** argv) {
|
||||
if (flags.pidMatchList)
|
||||
Hashtable_delete(flags.pidMatchList);
|
||||
|
||||
/* Delete Settings last, since it can get accessed in the crash handler */
|
||||
/* Delete these last, since they can get accessed in the crash handler */
|
||||
Settings_delete(settings);
|
||||
if (dc)
|
||||
Hashtable_delete(dc);
|
||||
if (dm)
|
||||
Hashtable_delete(dm);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
60
DynamicColumn.c
Normal file
60
DynamicColumn.c
Normal file
@ -0,0 +1,60 @@
|
||||
/*
|
||||
htop - DynamicColumn.c
|
||||
(C) 2021 Sohaib Mohammed
|
||||
(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 "DynamicColumn.h"
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "Platform.h"
|
||||
#include "ProcessList.h"
|
||||
#include "RichString.h"
|
||||
#include "XUtils.h"
|
||||
|
||||
|
||||
Hashtable* DynamicColumns_new(void) {
|
||||
return Platform_dynamicColumns();
|
||||
}
|
||||
|
||||
const char* DynamicColumn_init(unsigned int key) {
|
||||
return Platform_dynamicColumnInit(key);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
const char* name;
|
||||
const DynamicColumn* data;
|
||||
unsigned int key;
|
||||
} DynamicIterator;
|
||||
|
||||
static void DynamicColumn_compare(ht_key_t key, void* value, void* data) {
|
||||
const DynamicColumn* column = (const DynamicColumn*)value;
|
||||
DynamicIterator* iter = (DynamicIterator*)data;
|
||||
if (String_eq(iter->name, column->name)) {
|
||||
iter->data = column;
|
||||
iter->key = key;
|
||||
}
|
||||
}
|
||||
|
||||
const DynamicColumn* DynamicColumn_search(Hashtable* dynamics, const char* name, unsigned int* key) {
|
||||
DynamicIterator iter = { .key = 0, .data = NULL, .name = name };
|
||||
if (dynamics)
|
||||
Hashtable_foreach(dynamics, DynamicColumn_compare, &iter);
|
||||
if (key)
|
||||
*key = iter.key;
|
||||
return iter.data;
|
||||
}
|
||||
|
||||
const DynamicColumn* DynamicColumn_lookup(Hashtable* dynamics, unsigned int key) {
|
||||
return (const DynamicColumn*) Hashtable_get(dynamics, key);
|
||||
}
|
||||
|
||||
bool DynamicColumn_writeField(const Process* proc, RichString* str, unsigned int key) {
|
||||
return Platform_dynamicColumnWriteField(proc, str, key);
|
||||
}
|
31
DynamicColumn.h
Normal file
31
DynamicColumn.h
Normal file
@ -0,0 +1,31 @@
|
||||
#ifndef HEADER_DynamicColumn
|
||||
#define HEADER_DynamicColumn
|
||||
|
||||
#include "Hashtable.h"
|
||||
#include "Process.h"
|
||||
#include "ProcessList.h"
|
||||
#include "RichString.h"
|
||||
|
||||
|
||||
#define DYNAMIC_MAX_COLUMN_WIDTH 28
|
||||
#define DYNAMIC_DEFAULT_COLUMN_WIDTH -5
|
||||
|
||||
typedef struct DynamicColumn_ {
|
||||
char name[32]; /* unique, internal-only name */
|
||||
char* heading; /* displayed in main screen */
|
||||
char* caption; /* displayed in setup menu (short name) */
|
||||
char* description; /* displayed in setup menu (detail) */
|
||||
int width; /* display width +/- for value alignment */
|
||||
} DynamicColumn;
|
||||
|
||||
Hashtable* DynamicColumns_new(void);
|
||||
|
||||
const char* DynamicColumn_init(unsigned int key);
|
||||
|
||||
const DynamicColumn* DynamicColumn_lookup(Hashtable* dynamics, unsigned int key);
|
||||
|
||||
const DynamicColumn* DynamicColumn_search(Hashtable* dynamics, const char* name, unsigned int* field);
|
||||
|
||||
bool DynamicColumn_writeField(const Process* proc, RichString* str, unsigned int key);
|
||||
|
||||
#endif
|
@ -1,6 +1,8 @@
|
||||
#ifndef HEADER_DynamicMeter
|
||||
#define HEADER_DynamicMeter
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "Hashtable.h"
|
||||
#include "Meter.h"
|
||||
|
||||
@ -11,8 +13,6 @@ typedef struct DynamicMeter_ {
|
||||
char* description;
|
||||
unsigned int type;
|
||||
double maximum;
|
||||
|
||||
void* dynamicData; /* platform-specific meter data */
|
||||
} DynamicMeter;
|
||||
|
||||
Hashtable* DynamicMeters_new(void);
|
||||
|
14
Makefile.am
14
Makefile.am
@ -39,6 +39,7 @@ myhtopsources = \
|
||||
DateTimeMeter.c \
|
||||
DiskIOMeter.c \
|
||||
DisplayOptionsPanel.c \
|
||||
DynamicColumn.c \
|
||||
DynamicMeter.c \
|
||||
EnvScreen.c \
|
||||
FunctionBar.c \
|
||||
@ -94,6 +95,7 @@ myhtopheaders = \
|
||||
DateTimeMeter.h \
|
||||
DiskIOMeter.h \
|
||||
DisplayOptionsPanel.h \
|
||||
DynamicColumn.h \
|
||||
DynamicMeter.h \
|
||||
EnvScreen.h \
|
||||
FunctionBar.h \
|
||||
@ -359,25 +361,27 @@ endif
|
||||
# --------------------------
|
||||
|
||||
pcp_platform_headers = \
|
||||
linux/PressureStallMeter.h \
|
||||
linux/ZramMeter.h \
|
||||
linux/ZramStats.h \
|
||||
pcp/PCPDynamicColumn.h \
|
||||
pcp/PCPDynamicMeter.h \
|
||||
pcp/PCPProcess.h \
|
||||
pcp/PCPProcessList.h \
|
||||
pcp/Platform.h \
|
||||
pcp/ProcessField.h \
|
||||
linux/PressureStallMeter.h \
|
||||
linux/ZramMeter.h \
|
||||
linux/ZramStats.h \
|
||||
zfs/ZfsArcMeter.h \
|
||||
zfs/ZfsArcStats.h \
|
||||
zfs/ZfsCompressedArcMeter.h
|
||||
|
||||
pcp_platform_sources = \
|
||||
linux/PressureStallMeter.c \
|
||||
linux/ZramMeter.c \
|
||||
pcp/PCPDynamicColumn.c \
|
||||
pcp/PCPDynamicMeter.c \
|
||||
pcp/PCPProcess.c \
|
||||
pcp/PCPProcessList.c \
|
||||
pcp/Platform.c \
|
||||
linux/PressureStallMeter.c \
|
||||
linux/ZramMeter.c \
|
||||
zfs/ZfsArcMeter.c \
|
||||
zfs/ZfsCompressedArcMeter.c
|
||||
|
||||
|
@ -26,6 +26,7 @@ in the source distribution for its full text.
|
||||
#include "Macros.h"
|
||||
#include "Platform.h"
|
||||
#include "ProcessList.h"
|
||||
#include "DynamicColumn.h"
|
||||
#include "RichString.h"
|
||||
#include "Settings.h"
|
||||
#include "XUtils.h"
|
||||
@ -905,8 +906,11 @@ void Process_writeField(const Process* this, RichString* str, ProcessField field
|
||||
xSnprintf(buffer, n, "%-9d ", this->st_uid);
|
||||
break;
|
||||
default:
|
||||
if (DynamicColumn_writeField(this, str, field))
|
||||
return;
|
||||
assert(0 && "Process_writeField: default key reached"); /* should never be reached */
|
||||
xSnprintf(buffer, n, "- ");
|
||||
break;
|
||||
}
|
||||
RichString_appendAscii(str, attr, buffer);
|
||||
}
|
||||
|
@ -56,6 +56,7 @@ typedef enum ProcessField_ {
|
||||
/* Platform specific fields, defined in ${platform}/ProcessField.h */
|
||||
PLATFORM_PROCESS_FIELDS
|
||||
|
||||
/* Do not add new fields after this entry (dynamic entries follow) */
|
||||
LAST_PROCESSFIELD
|
||||
} ProcessField;
|
||||
|
||||
@ -267,7 +268,7 @@ typedef struct ProcessFieldData_ {
|
||||
/* Scan flag to enable scan-method otherwise not run */
|
||||
uint32_t flags;
|
||||
|
||||
/* Whether the values are process identifies; adjusts the width of title and values if true */
|
||||
/* Whether the values are process identifiers; adjusts the width of title and values if true */
|
||||
bool pidColumn;
|
||||
|
||||
/* Whether the column should be sorted in descending order by default */
|
||||
|
@ -12,6 +12,7 @@ in the source distribution for its full text.
|
||||
#include <string.h>
|
||||
|
||||
#include "CRT.h"
|
||||
#include "DynamicColumn.h"
|
||||
#include "Hashtable.h"
|
||||
#include "Macros.h"
|
||||
#include "Platform.h"
|
||||
@ -19,7 +20,7 @@ in the source distribution for its full text.
|
||||
#include "XUtils.h"
|
||||
|
||||
|
||||
ProcessList* ProcessList_init(ProcessList* this, const ObjectClass* klass, UsersTable* usersTable, Hashtable* dynamicMeters, Hashtable* pidMatchList, uid_t userId) {
|
||||
ProcessList* ProcessList_init(ProcessList* this, const ObjectClass* klass, UsersTable* usersTable, Hashtable* dynamicMeters, Hashtable* dynamicColumns, Hashtable* pidMatchList, uid_t userId) {
|
||||
this->processes = Vector_new(klass, true, DEFAULT_SIZE);
|
||||
this->processes2 = Vector_new(klass, true, DEFAULT_SIZE); // tree-view auxiliary buffer
|
||||
|
||||
@ -30,6 +31,7 @@ ProcessList* ProcessList_init(ProcessList* this, const ObjectClass* klass, Users
|
||||
this->usersTable = usersTable;
|
||||
this->pidMatchList = pidMatchList;
|
||||
this->dynamicMeters = dynamicMeters;
|
||||
this->dynamicColumns = dynamicColumns;
|
||||
|
||||
this->userId = userId;
|
||||
|
||||
@ -83,7 +85,22 @@ void ProcessList_setPanel(ProcessList* this, Panel* panel) {
|
||||
this->panel = panel;
|
||||
}
|
||||
|
||||
static const char* alignedProcessFieldTitle(ProcessField field) {
|
||||
static const char* alignedDynamicColumnTitle(const ProcessList* this, int key) {
|
||||
const DynamicColumn* column = Hashtable_get(this->dynamicColumns, key);
|
||||
if (column == NULL)
|
||||
return "- ";
|
||||
static char titleBuffer[DYNAMIC_MAX_COLUMN_WIDTH + /* space */ 1 + /* null terminator */ + 1];
|
||||
int width = column->width;
|
||||
if (!width || abs(width) > DYNAMIC_MAX_COLUMN_WIDTH)
|
||||
width = DYNAMIC_DEFAULT_COLUMN_WIDTH;
|
||||
xSnprintf(titleBuffer, sizeof(titleBuffer), "%*s", width, column->heading);
|
||||
return titleBuffer;
|
||||
}
|
||||
|
||||
static const char* alignedProcessFieldTitle(const ProcessList* this, ProcessField field) {
|
||||
if (field >= LAST_PROCESSFIELD)
|
||||
return alignedDynamicColumnTitle(this, field);
|
||||
|
||||
const char* title = Process_fields[field].title;
|
||||
if (!title)
|
||||
return "- ";
|
||||
@ -115,7 +132,7 @@ void ProcessList_printHeader(const ProcessList* this, RichString* header) {
|
||||
color = CRT_colors[PANEL_HEADER_FOCUS];
|
||||
}
|
||||
|
||||
RichString_appendWide(header, color, alignedProcessFieldTitle(fields[i]));
|
||||
RichString_appendWide(header, color, alignedProcessFieldTitle(this, fields[i]));
|
||||
if (key == fields[i] && RichString_getCharVal(*header, RichString_size(header) - 1) == ' ') {
|
||||
RichString_rewind(header, 1); // rewind to override space
|
||||
RichString_appendnWide(header,
|
||||
@ -478,7 +495,7 @@ ProcessField ProcessList_keyAt(const ProcessList* this, int at) {
|
||||
const ProcessField* fields = this->settings->fields;
|
||||
ProcessField field;
|
||||
for (int i = 0; (field = fields[i]); i++) {
|
||||
int len = strlen(alignedProcessFieldTitle(field));
|
||||
int len = strlen(alignedProcessFieldTitle(this, field));
|
||||
if (at >= x && at <= x + len) {
|
||||
return field;
|
||||
}
|
||||
|
@ -51,6 +51,7 @@ typedef struct ProcessList_ {
|
||||
Hashtable* draftingTreeSet;
|
||||
|
||||
Hashtable* dynamicMeters; /* runtime-discovered meters */
|
||||
Hashtable* dynamicColumns; /* runtime-discovered Columns */
|
||||
|
||||
struct timeval realtime; /* time of the current sample */
|
||||
uint64_t realtimeMs; /* current time in milliseconds */
|
||||
@ -88,13 +89,13 @@ typedef struct ProcessList_ {
|
||||
} ProcessList;
|
||||
|
||||
/* Implemented by platforms */
|
||||
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);
|
||||
void ProcessList_goThroughEntries(ProcessList* super, bool pauseProcessUpdate);
|
||||
bool ProcessList_isCPUonline(const ProcessList* super, unsigned int id);
|
||||
|
||||
|
||||
ProcessList* ProcessList_init(ProcessList* this, const ObjectClass* klass, UsersTable* usersTable, Hashtable* dynamicMeters, Hashtable* pidMatchList, uid_t userId);
|
||||
ProcessList* ProcessList_init(ProcessList* this, const ObjectClass* klass, UsersTable* usersTable, Hashtable* dynamicMeters, Hashtable* dynamicColumns, Hashtable* pidMatchList, uid_t userId);
|
||||
|
||||
void ProcessList_done(ProcessList* this);
|
||||
|
||||
|
58
Settings.c
58
Settings.c
@ -8,12 +8,14 @@ in the source distribution for its full text.
|
||||
#include "Settings.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "CRT.h"
|
||||
#include "DynamicColumn.h"
|
||||
#include "Macros.h"
|
||||
#include "Meter.h"
|
||||
#include "Platform.h"
|
||||
@ -106,22 +108,42 @@ static void Settings_defaultMeters(Settings* this, unsigned int initialCpuCount)
|
||||
this->columns[1].modes[r++] = TEXT_METERMODE;
|
||||
}
|
||||
|
||||
static void readFields(ProcessField* fields, uint32_t* flags, const char* line) {
|
||||
static void Settings_readFields(Settings* settings, const char* line) {
|
||||
char* trim = String_trim(line);
|
||||
char** ids = String_split(trim, ' ', NULL);
|
||||
free(trim);
|
||||
int i, j;
|
||||
*flags = 0;
|
||||
for (j = 0, i = 0; i < LAST_PROCESSFIELD && ids[i]; i++) {
|
||||
|
||||
settings->flags = 0;
|
||||
|
||||
unsigned int i, j;
|
||||
for (j = 0, i = 0; ids[i]; i++) {
|
||||
if (j >= UINT_MAX / sizeof(ProcessField))
|
||||
continue;
|
||||
if (j >= LAST_PROCESSFIELD) {
|
||||
settings->fields = xRealloc(settings->fields, j * sizeof(ProcessField));
|
||||
memset(&settings->fields[j], 0, sizeof(ProcessField));
|
||||
}
|
||||
|
||||
// Dynamically-defined columns are always stored by-name.
|
||||
char* end, dynamic[32] = {0};
|
||||
if (sscanf(ids[i], "Dynamic(%30s)", dynamic)) {
|
||||
if ((end = strrchr(dynamic, ')')) == NULL)
|
||||
continue;
|
||||
*end = '\0';
|
||||
unsigned int key;
|
||||
if (!DynamicColumn_search(settings->dynamicColumns, dynamic, &key))
|
||||
continue;
|
||||
settings->fields[j++] = key;
|
||||
continue;
|
||||
}
|
||||
// This "+1" is for compatibility with the older enum format.
|
||||
int id = atoi(ids[i]) + 1;
|
||||
if (id > 0 && id < LAST_PROCESSFIELD && Process_fields[id].name) {
|
||||
fields[j] = id;
|
||||
*flags |= Process_fields[id].flags;
|
||||
j++;
|
||||
settings->flags |= Process_fields[id].flags;
|
||||
settings->fields[j++] = id;
|
||||
}
|
||||
}
|
||||
fields[j] = NULL_PROCESSFIELD;
|
||||
settings->fields[j] = NULL_PROCESSFIELD;
|
||||
String_freeArray(ids);
|
||||
}
|
||||
|
||||
@ -145,7 +167,7 @@ static bool Settings_read(Settings* this, const char* fileName, unsigned int ini
|
||||
continue;
|
||||
}
|
||||
if (String_eq(option[0], "fields")) {
|
||||
readFields(this->fields, &(this->flags), option[1]);
|
||||
Settings_readFields(this, option[1]);
|
||||
didReadFields = true;
|
||||
} else if (String_eq(option[0], "sort_key")) {
|
||||
// This "+1" is for compatibility with the older enum format.
|
||||
@ -256,12 +278,17 @@ static bool Settings_read(Settings* this, const char* fileName, unsigned int ini
|
||||
return didReadFields;
|
||||
}
|
||||
|
||||
static void writeFields(FILE* fd, const ProcessField* fields, const char* name) {
|
||||
static void writeFields(FILE* fd, const ProcessField* fields, Hashtable* columns, const char* name) {
|
||||
fprintf(fd, "%s=", name);
|
||||
const char* sep = "";
|
||||
for (int i = 0; fields[i]; i++) {
|
||||
// This "-1" is for compatibility with the older enum format.
|
||||
fprintf(fd, "%s%d", sep, (int) fields[i] - 1);
|
||||
for (unsigned int i = 0; fields[i]; i++) {
|
||||
if (fields[i] >= LAST_PROCESSFIELD) {
|
||||
const DynamicColumn* column = DynamicColumn_lookup(columns, fields[i]);
|
||||
fprintf(fd, "%sDynamic(%s)", sep, column->name);
|
||||
} else {
|
||||
// This "-1" is for compatibility with the older enum format.
|
||||
fprintf(fd, "%s%d", sep, (int) fields[i] - 1);
|
||||
}
|
||||
sep = " ";
|
||||
}
|
||||
fprintf(fd, "\n");
|
||||
@ -299,7 +326,7 @@ int Settings_write(const Settings* this, bool onCrash) {
|
||||
fprintf(fd, "# Beware! This file is rewritten by htop when settings are changed in the interface.\n");
|
||||
fprintf(fd, "# The parser is also very primitive, and not human-friendly.\n");
|
||||
}
|
||||
writeFields(fd, this->fields, "fields");
|
||||
writeFields(fd, this->fields, this->dynamicColumns, "fields");
|
||||
// This "-1" is for compatibility with the older enum format.
|
||||
fprintf(fd, "sort_key=%d\n", (int) this->sortKey - 1);
|
||||
fprintf(fd, "sort_direction=%d\n", (int) this->direction);
|
||||
@ -361,9 +388,10 @@ int Settings_write(const Settings* this, bool onCrash) {
|
||||
return r;
|
||||
}
|
||||
|
||||
Settings* Settings_new(unsigned int initialCpuCount) {
|
||||
Settings* Settings_new(unsigned int initialCpuCount, Hashtable* dynamicColumns) {
|
||||
Settings* this = xCalloc(1, sizeof(Settings));
|
||||
|
||||
this->dynamicColumns = dynamicColumns;
|
||||
this->sortKey = PERCENT_CPU;
|
||||
this->treeSortKey = PID;
|
||||
this->direction = -1;
|
||||
|
@ -12,6 +12,7 @@ in the source distribution for its full text.
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "Hashtable.h"
|
||||
#include "Process.h"
|
||||
|
||||
|
||||
@ -26,6 +27,7 @@ typedef struct {
|
||||
typedef struct Settings_ {
|
||||
char* filename;
|
||||
MeterColumnSettings columns[2];
|
||||
Hashtable* dynamicColumns;
|
||||
|
||||
ProcessField* fields;
|
||||
uint32_t flags;
|
||||
@ -92,7 +94,7 @@ void Settings_delete(Settings* this);
|
||||
|
||||
int Settings_write(const Settings* this, bool onCrash);
|
||||
|
||||
Settings* Settings_new(unsigned int initialCpuCount);
|
||||
Settings* Settings_new(unsigned int initialCpuCount, Hashtable* dynamicColumns);
|
||||
|
||||
void Settings_invertSortOrder(Settings* this);
|
||||
|
||||
|
@ -128,10 +128,10 @@ static struct kinfo_proc* ProcessList_getKInfoProcs(size_t* count) {
|
||||
CRT_fatalError("Unable to get kinfo_procs");
|
||||
}
|
||||
|
||||
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) {
|
||||
DarwinProcessList* this = xCalloc(1, sizeof(DarwinProcessList));
|
||||
|
||||
ProcessList_init(&this->super, Class(DarwinProcess), usersTable, dynamicMeters, pidMatchList, userId);
|
||||
ProcessList_init(&this->super, Class(DarwinProcess), usersTable, dynamicMeters, dynamicColumns, pidMatchList, userId);
|
||||
|
||||
/* Initialize the CPU information */
|
||||
this->super.activeCPUs = ProcessList_allocateCPULoadInfo(&this->prev_load);
|
||||
|
@ -28,7 +28,7 @@ typedef struct DarwinProcessList_ {
|
||||
ZfsArcStats zfs;
|
||||
} DarwinProcessList;
|
||||
|
||||
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* this);
|
||||
|
||||
|
@ -15,6 +15,7 @@ in the source distribution for its full text.
|
||||
#include "BatteryMeter.h"
|
||||
#include "CPUMeter.h"
|
||||
#include "DiskIOMeter.h"
|
||||
#include "Hashtable.h"
|
||||
#include "NetworkIOMeter.h"
|
||||
#include "ProcessLocksScreen.h"
|
||||
#include "SignalsPanel.h"
|
||||
@ -92,9 +93,7 @@ static inline void Platform_gettime_realtime(struct timeval* tv, uint64_t* msec)
|
||||
|
||||
void Platform_gettime_monotonic(uint64_t* msec);
|
||||
|
||||
static inline Hashtable* Platform_dynamicMeters(void) {
|
||||
return NULL;
|
||||
}
|
||||
static inline Hashtable* Platform_dynamicMeters(void) { return NULL; }
|
||||
|
||||
static inline void Platform_dynamicMeterInit(ATTR_UNUSED Meter* meter) { }
|
||||
|
||||
@ -102,4 +101,10 @@ static inline void Platform_dynamicMeterUpdateValues(ATTR_UNUSED Meter* meter) {
|
||||
|
||||
static inline void Platform_dynamicMeterDisplay(ATTR_UNUSED const Meter* meter, ATTR_UNUSED RichString* out) { }
|
||||
|
||||
static inline Hashtable* Platform_dynamicColumns(void) { return NULL; }
|
||||
|
||||
static inline const char* Platform_dynamicColumnInit(ATTR_UNUSED unsigned int key) { return NULL; }
|
||||
|
||||
static inline bool Platform_dynamicColumnWriteField(ATTR_UNUSED const Process* proc, ATTR_UNUSED RichString* str, ATTR_UNUSED unsigned int key) { return false; }
|
||||
|
||||
#endif
|
||||
|
@ -42,12 +42,12 @@ static int MIB_kern_cp_time[2];
|
||||
static int MIB_kern_cp_times[2];
|
||||
static int kernelFScale;
|
||||
|
||||
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) {
|
||||
size_t len;
|
||||
char errbuf[_POSIX2_LINE_MAX];
|
||||
DragonFlyBSDProcessList* dfpl = xCalloc(1, sizeof(DragonFlyBSDProcessList));
|
||||
ProcessList* pl = (ProcessList*) dfpl;
|
||||
ProcessList_init(pl, Class(DragonFlyBSDProcess), usersTable, dynamicMeters, pidMatchList, userId);
|
||||
ProcessList_init(pl, Class(DragonFlyBSDProcess), usersTable, dynamicMeters, dynamicColumns, pidMatchList, userId);
|
||||
|
||||
// physical memory in system: hw.physmem
|
||||
// physical page size: hw.pagesize
|
||||
|
@ -53,7 +53,7 @@ typedef struct DragonFlyBSDProcessList_ {
|
||||
Hashtable* jails;
|
||||
} DragonFlyBSDProcessList;
|
||||
|
||||
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* this);
|
||||
|
||||
|
@ -16,6 +16,7 @@ in the source distribution for its full text.
|
||||
#include "Action.h"
|
||||
#include "BatteryMeter.h"
|
||||
#include "DiskIOMeter.h"
|
||||
#include "Hashtable.h"
|
||||
#include "Macros.h"
|
||||
#include "Meter.h"
|
||||
#include "NetworkIOMeter.h"
|
||||
@ -89,9 +90,7 @@ static inline void Platform_gettime_monotonic(uint64_t* msec) {
|
||||
Generic_gettime_monotonic(msec);
|
||||
}
|
||||
|
||||
static inline Hashtable* Platform_dynamicMeters(void) {
|
||||
return NULL;
|
||||
}
|
||||
static inline Hashtable* Platform_dynamicMeters(void) { return NULL; }
|
||||
|
||||
static inline void Platform_dynamicMeterInit(ATTR_UNUSED Meter* meter) { }
|
||||
|
||||
@ -99,4 +98,10 @@ static inline void Platform_dynamicMeterUpdateValues(ATTR_UNUSED Meter* meter) {
|
||||
|
||||
static inline void Platform_dynamicMeterDisplay(ATTR_UNUSED const Meter* meter, ATTR_UNUSED RichString* out) { }
|
||||
|
||||
static inline Hashtable* Platform_dynamicColumns(void) { return NULL; }
|
||||
|
||||
static inline const char* Platform_dynamicColumnInit(ATTR_UNUSED unsigned int key) { return NULL; }
|
||||
|
||||
static inline bool Platform_dynamicColumnWriteField(ATTR_UNUSED const Process* proc, ATTR_UNUSED RichString* str, ATTR_UNUSED unsigned int key) { return false; }
|
||||
|
||||
#endif
|
||||
|
@ -56,12 +56,12 @@ static int MIB_kern_cp_time[2];
|
||||
static int MIB_kern_cp_times[2];
|
||||
static int kernelFScale;
|
||||
|
||||
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) {
|
||||
size_t len;
|
||||
char errbuf[_POSIX2_LINE_MAX];
|
||||
FreeBSDProcessList* fpl = xCalloc(1, sizeof(FreeBSDProcessList));
|
||||
ProcessList* pl = (ProcessList*) fpl;
|
||||
ProcessList_init(pl, Class(FreeBSDProcess), usersTable, dynamicMeters, pidMatchList, userId);
|
||||
ProcessList_init(pl, Class(FreeBSDProcess), usersTable, dynamicMeters, DynamicColumns, pidMatchList, userId);
|
||||
|
||||
// physical memory in system: hw.physmem
|
||||
// physical page size: hw.pagesize
|
||||
|
@ -47,7 +47,7 @@ typedef struct FreeBSDProcessList_ {
|
||||
|
||||
} FreeBSDProcessList;
|
||||
|
||||
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* this);
|
||||
|
||||
|
@ -13,6 +13,7 @@ in the source distribution for its full text.
|
||||
#include "Action.h"
|
||||
#include "BatteryMeter.h"
|
||||
#include "DiskIOMeter.h"
|
||||
#include "Hashtable.h"
|
||||
#include "Meter.h"
|
||||
#include "NetworkIOMeter.h"
|
||||
#include "Process.h"
|
||||
@ -89,9 +90,7 @@ static inline void Platform_gettime_monotonic(uint64_t* msec) {
|
||||
Generic_gettime_monotonic(msec);
|
||||
}
|
||||
|
||||
static inline Hashtable* Platform_dynamicMeters(void) {
|
||||
return NULL;
|
||||
}
|
||||
static inline Hashtable* Platform_dynamicMeters(void) { return NULL; }
|
||||
|
||||
static inline void Platform_dynamicMeterInit(ATTR_UNUSED Meter* meter) { }
|
||||
|
||||
@ -99,4 +98,10 @@ static inline void Platform_dynamicMeterUpdateValues(ATTR_UNUSED Meter* meter) {
|
||||
|
||||
static inline void Platform_dynamicMeterDisplay(ATTR_UNUSED const Meter* meter, ATTR_UNUSED RichString* out) { }
|
||||
|
||||
static inline Hashtable* Platform_dynamicColumns(void) { return NULL; }
|
||||
|
||||
static inline const char* Platform_dynamicColumnInit(ATTR_UNUSED unsigned int key) { return NULL; }
|
||||
|
||||
static inline bool Platform_dynamicColumnWriteField(ATTR_UNUSED const Process* proc, ATTR_UNUSED RichString* str, ATTR_UNUSED unsigned int key) { return false; }
|
||||
|
||||
#endif
|
||||
|
@ -240,11 +240,11 @@ static void LinuxProcessList_updateCPUcount(ProcessList* super) {
|
||||
super->existingCPUs = currExisting;
|
||||
}
|
||||
|
||||
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) {
|
||||
LinuxProcessList* this = xCalloc(1, sizeof(LinuxProcessList));
|
||||
ProcessList* pl = &(this->super);
|
||||
|
||||
ProcessList_init(pl, Class(LinuxProcess), usersTable, dynamicMeters, pidMatchList, userId);
|
||||
ProcessList_init(pl, Class(LinuxProcess), usersTable, dynamicMeters, dynamicColumns, pidMatchList, userId);
|
||||
LinuxProcessList_initTtyDrivers(this);
|
||||
|
||||
// Initialize page size
|
||||
|
@ -115,7 +115,7 @@ typedef struct LinuxProcessList_ {
|
||||
#define PROC_LINE_LENGTH 4096
|
||||
#endif
|
||||
|
||||
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);
|
||||
|
||||
|
@ -17,6 +17,7 @@ in the source distribution for its full text.
|
||||
#include "Action.h"
|
||||
#include "BatteryMeter.h"
|
||||
#include "DiskIOMeter.h"
|
||||
#include "Hashtable.h"
|
||||
#include "Meter.h"
|
||||
#include "NetworkIOMeter.h"
|
||||
#include "Process.h"
|
||||
@ -105,9 +106,7 @@ static inline void Platform_gettime_monotonic(uint64_t* msec) {
|
||||
Generic_gettime_monotonic(msec);
|
||||
}
|
||||
|
||||
static inline Hashtable* Platform_dynamicMeters(void) {
|
||||
return NULL;
|
||||
}
|
||||
static inline Hashtable* Platform_dynamicMeters(void) { return NULL; }
|
||||
|
||||
static inline void Platform_dynamicMeterInit(ATTR_UNUSED Meter* meter) { }
|
||||
|
||||
@ -115,4 +114,10 @@ static inline void Platform_dynamicMeterUpdateValues(ATTR_UNUSED Meter* meter) {
|
||||
|
||||
static inline void Platform_dynamicMeterDisplay(ATTR_UNUSED const Meter* meter, ATTR_UNUSED RichString* out) { }
|
||||
|
||||
static inline Hashtable* Platform_dynamicColumns(void) { return NULL; }
|
||||
|
||||
static inline const char* Platform_dynamicColumnInit(ATTR_UNUSED unsigned int key) { return NULL; }
|
||||
|
||||
static inline bool Platform_dynamicColumnWriteField(ATTR_UNUSED const Process* proc, ATTR_UNUSED RichString* str, ATTR_UNUSED unsigned int key) { return false; }
|
||||
|
||||
#endif
|
||||
|
@ -94,9 +94,7 @@ static inline void Platform_gettime_monotonic(uint64_t* msec) {
|
||||
Generic_gettime_monotonic(msec);
|
||||
}
|
||||
|
||||
static inline Hashtable* Platform_dynamicMeters(void) {
|
||||
return NULL;
|
||||
}
|
||||
static inline Hashtable* Platform_dynamicMeters(void) { return NULL; }
|
||||
|
||||
static inline void Platform_dynamicMeterInit(ATTR_UNUSED Meter* meter) { }
|
||||
|
||||
@ -104,4 +102,10 @@ static inline void Platform_dynamicMeterUpdateValues(ATTR_UNUSED Meter* meter) {
|
||||
|
||||
static inline void Platform_dynamicMeterDisplay(ATTR_UNUSED const Meter* meter, ATTR_UNUSED RichString* out) { }
|
||||
|
||||
static inline Hashtable* Platform_dynamicColumns(void) { return NULL; }
|
||||
|
||||
static inline const char* Platform_dynamicColumnInit(ATTR_UNUSED unsigned int key) { return NULL; }
|
||||
|
||||
static inline bool Platform_dynamicColumnWriteField(ATTR_UNUSED const Process* proc, ATTR_UNUSED RichString* str, ATTR_UNUSED unsigned int key) { return false; }
|
||||
|
||||
#endif
|
||||
|
@ -94,14 +94,14 @@ static void OpenBSDProcessList_updateCPUcount(ProcessList* super) {
|
||||
}
|
||||
|
||||
|
||||
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) {
|
||||
const int fmib[] = { CTL_KERN, KERN_FSCALE };
|
||||
size_t size;
|
||||
char errbuf[_POSIX2_LINE_MAX];
|
||||
|
||||
OpenBSDProcessList* opl = xCalloc(1, sizeof(OpenBSDProcessList));
|
||||
ProcessList* pl = (ProcessList*) opl;
|
||||
ProcessList_init(pl, Class(OpenBSDProcess), usersTable, dynamicMeters, pidMatchList, userId);
|
||||
ProcessList_init(pl, Class(OpenBSDProcess), usersTable, dynamicMeters, dynamicColumns, pidMatchList, userId);
|
||||
|
||||
OpenBSDProcessList_updateCPUcount(pl);
|
||||
|
||||
|
@ -49,7 +49,7 @@ typedef struct OpenBSDProcessList_ {
|
||||
} OpenBSDProcessList;
|
||||
|
||||
|
||||
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* this);
|
||||
|
||||
|
@ -14,6 +14,7 @@ in the source distribution for its full text.
|
||||
#include "Action.h"
|
||||
#include "BatteryMeter.h"
|
||||
#include "DiskIOMeter.h"
|
||||
#include "Hashtable.h"
|
||||
#include "Meter.h"
|
||||
#include "NetworkIOMeter.h"
|
||||
#include "Process.h"
|
||||
@ -87,9 +88,7 @@ static inline void Platform_gettime_monotonic(uint64_t* msec) {
|
||||
Generic_gettime_monotonic(msec);
|
||||
}
|
||||
|
||||
static inline Hashtable* Platform_dynamicMeters(void) {
|
||||
return NULL;
|
||||
}
|
||||
static inline Hashtable* Platform_dynamicMeters(void) { return NULL; }
|
||||
|
||||
static inline void Platform_dynamicMeterInit(ATTR_UNUSED Meter* meter) { }
|
||||
|
||||
@ -97,4 +96,10 @@ static inline void Platform_dynamicMeterUpdateValues(ATTR_UNUSED Meter* meter) {
|
||||
|
||||
static inline void Platform_dynamicMeterDisplay(ATTR_UNUSED const Meter* meter, ATTR_UNUSED RichString* out) { }
|
||||
|
||||
static inline Hashtable* Platform_dynamicColumns(void) { return NULL; }
|
||||
|
||||
static inline const char* Platform_dynamicColumnInit(ATTR_UNUSED unsigned int key) { return NULL; }
|
||||
|
||||
static inline bool Platform_dynamicColumnWriteField(ATTR_UNUSED const Process* proc, ATTR_UNUSED RichString* str, ATTR_UNUSED unsigned int key) { return false; }
|
||||
|
||||
#endif
|
||||
|
326
pcp/PCPDynamicColumn.c
Normal file
326
pcp/PCPDynamicColumn.c
Normal file
@ -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(¬e,
|
||||
"%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;
|
||||
}
|
32
pcp/PCPDynamicColumn.h
Normal file
32
pcp/PCPDynamicColumn.h
Normal file
@ -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
|
@ -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) {
|
||||
path = String_cat(xdgConfigHome, "/htop/meters/");
|
||||
} else {
|
||||
if (!home)
|
||||
home = "";
|
||||
path = String_cat(home, "/.config/htop/meters/");
|
||||
/* developer paths - PCP_HTOP_DIR=./pcp ./pcp-htop */
|
||||
if (override) {
|
||||
path = String_cat(override, "/meters/");
|
||||
PCPDynamicMeter_scanDir(meters, path);
|
||||
free(path);
|
||||
}
|
||||
PCPDynamicMeter_scanDir(meters, path);
|
||||
free(path);
|
||||
|
||||
/* secondly search in the system meters directory */
|
||||
/* next, search in home directory alongside htoprc */
|
||||
if (xdgConfigHome)
|
||||
path = String_cat(xdgConfigHome, "/htop/meters/");
|
||||
else if (home)
|
||||
path = String_cat(home, "/.config/htop/meters/");
|
||||
else
|
||||
path = NULL;
|
||||
if (path) {
|
||||
PCPDynamicMeter_scanDir(meters, path);
|
||||
free(path);
|
||||
}
|
||||
|
||||
/* 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;
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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(×tamp, 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
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
10
pcp/columns/container
Normal file
10
pcp/columns/container
Normal file
@ -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
|
10
pcp/columns/delayacct
Normal file
10
pcp/columns/delayacct
Normal file
@ -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
|
10
pcp/columns/fdcount
Normal file
10
pcp/columns/fdcount
Normal file
@ -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
|
17
pcp/columns/guest
Normal file
17
pcp/columns/guest
Normal file
@ -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
|
39
pcp/columns/memory
Normal file
39
pcp/columns/memory
Normal file
@ -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
|
10
pcp/columns/sched
Normal file
10
pcp/columns/sched
Normal file
@ -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
|
15
pcp/columns/swap
Normal file
15
pcp/columns/swap
Normal file
@ -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
|
31
pcp/columns/tcp
Normal file
31
pcp/columns/tcp
Normal file
@ -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
|
31
pcp/columns/udp
Normal file
31
pcp/columns/udp
Normal file
@ -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
|
17
pcp/columns/wchan
Normal file
17
pcp/columns/wchan
Normal file
@ -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
|
@ -31,6 +31,7 @@ in the source distribution for its full text.
|
||||
#include "Action.h"
|
||||
#include "BatteryMeter.h"
|
||||
#include "DiskIOMeter.h"
|
||||
#include "Hashtable.h"
|
||||
#include "NetworkIOMeter.h"
|
||||
#include "ProcessLocksScreen.h"
|
||||
#include "SignalsPanel.h"
|
||||
@ -128,9 +129,7 @@ IGNORE_WCASTQUAL_BEGIN
|
||||
IGNORE_WCASTQUAL_END
|
||||
}
|
||||
|
||||
static inline Hashtable* Platform_dynamicMeters(void) {
|
||||
return NULL;
|
||||
}
|
||||
static inline Hashtable* Platform_dynamicMeters(void) { return NULL; }
|
||||
|
||||
static inline void Platform_dynamicMeterInit(ATTR_UNUSED Meter* meter) { }
|
||||
|
||||
@ -138,4 +137,10 @@ static inline void Platform_dynamicMeterUpdateValues(ATTR_UNUSED Meter* meter) {
|
||||
|
||||
static inline void Platform_dynamicMeterDisplay(ATTR_UNUSED const Meter* meter, ATTR_UNUSED RichString* out) { }
|
||||
|
||||
static inline Hashtable* Platform_dynamicColumns(void) { return NULL; }
|
||||
|
||||
static inline const char* Platform_dynamicColumnInit(ATTR_UNUSED unsigned int key) { return NULL; }
|
||||
|
||||
static inline bool Platform_dynamicColumnWriteField(ATTR_UNUSED const Process* proc, ATTR_UNUSED RichString* str, ATTR_UNUSED unsigned int key) { return false; }
|
||||
|
||||
#endif
|
||||
|
@ -89,10 +89,10 @@ static void SolarisProcessList_updateCPUcount(ProcessList* super) {
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
SolarisProcessList* spl = xCalloc(1, sizeof(SolarisProcessList));
|
||||
ProcessList* pl = (ProcessList*) spl;
|
||||
ProcessList_init(pl, Class(SolarisProcess), usersTable, dynamicMeters, pidMatchList, userId);
|
||||
ProcessList_init(pl, Class(SolarisProcess), usersTable, dynamicMeters, dynamicColumns, pidMatchList, userId);
|
||||
|
||||
spl->kd = kstat_open();
|
||||
if (!spl->kd)
|
||||
|
@ -54,7 +54,7 @@ typedef struct SolarisProcessList_ {
|
||||
ZfsArcStats zfs;
|
||||
} SolarisProcessList;
|
||||
|
||||
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);
|
||||
|
||||
|
@ -11,6 +11,7 @@ in the source distribution for its full text.
|
||||
#include "Action.h"
|
||||
#include "BatteryMeter.h"
|
||||
#include "DiskIOMeter.h"
|
||||
#include "Hashtable.h"
|
||||
#include "NetworkIOMeter.h"
|
||||
#include "ProcessLocksScreen.h"
|
||||
#include "SignalsPanel.h"
|
||||
@ -78,9 +79,7 @@ static inline void Platform_gettime_monotonic(uint64_t* msec) {
|
||||
Generic_gettime_monotonic(msec);
|
||||
}
|
||||
|
||||
static inline Hashtable* Platform_dynamicMeters(void) {
|
||||
return NULL;
|
||||
}
|
||||
static inline Hashtable* Platform_dynamicMeters(void) { return NULL; }
|
||||
|
||||
static inline void Platform_dynamicMeterInit(ATTR_UNUSED Meter* meter) { }
|
||||
|
||||
@ -88,4 +87,10 @@ static inline void Platform_dynamicMeterUpdateValues(ATTR_UNUSED Meter* meter) {
|
||||
|
||||
static inline void Platform_dynamicMeterDisplay(ATTR_UNUSED const Meter* meter, ATTR_UNUSED RichString* out) { }
|
||||
|
||||
static inline Hashtable* Platform_dynamicColumns(void) { return NULL; }
|
||||
|
||||
static inline const char* Platform_dynamicColumnInit(ATTR_UNUSED unsigned int key) { return NULL; }
|
||||
|
||||
static inline bool Platform_dynamicColumnWriteField(ATTR_UNUSED const Process* proc, ATTR_UNUSED RichString* str, ATTR_UNUSED unsigned int key) { return false; }
|
||||
|
||||
#endif
|
||||
|
@ -14,9 +14,9 @@ in the source distribution for its full text.
|
||||
#include "UnsupportedProcess.h"
|
||||
|
||||
|
||||
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) {
|
||||
ProcessList* this = xCalloc(1, sizeof(ProcessList));
|
||||
ProcessList_init(this, Class(Process), usersTable, dynamicMeters, pidMatchList, userId);
|
||||
ProcessList_init(this, Class(Process), usersTable, dynamicMeters, dynamicColumns, pidMatchList, userId);
|
||||
|
||||
this->existingCPUs = 1;
|
||||
this->activeCPUs = 1;
|
||||
|
Loading…
Reference in New Issue
Block a user