mirror of https://github.com/xzeldon/htop.git
Compress cgroup names based on some heuristics
This commit is contained in:
parent
ea4282784d
commit
9dc964bb42
|
@ -153,6 +153,7 @@ linux_platform_headers = \
|
||||||
generic/gettime.h \
|
generic/gettime.h \
|
||||||
generic/hostname.h \
|
generic/hostname.h \
|
||||||
generic/uname.h \
|
generic/uname.h \
|
||||||
|
linux/CGroupUtils.h \
|
||||||
linux/HugePageMeter.h \
|
linux/HugePageMeter.h \
|
||||||
linux/IOPriority.h \
|
linux/IOPriority.h \
|
||||||
linux/IOPriorityPanel.h \
|
linux/IOPriorityPanel.h \
|
||||||
|
@ -174,6 +175,7 @@ linux_platform_sources = \
|
||||||
generic/gettime.c \
|
generic/gettime.c \
|
||||||
generic/hostname.c \
|
generic/hostname.c \
|
||||||
generic/uname.c \
|
generic/uname.c \
|
||||||
|
linux/CGroupUtils.c \
|
||||||
linux/HugePageMeter.c \
|
linux/HugePageMeter.c \
|
||||||
linux/IOPriorityPanel.c \
|
linux/IOPriorityPanel.c \
|
||||||
linux/LibSensors.c \
|
linux/LibSensors.c \
|
||||||
|
|
|
@ -0,0 +1,285 @@
|
||||||
|
/*
|
||||||
|
htop - CGroupUtils.h
|
||||||
|
(C) 2021 htop dev team
|
||||||
|
Released under the GNU GPLv2+, see the COPYING file
|
||||||
|
in the source distribution for its full text.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "linux/CGroupUtils.h"
|
||||||
|
|
||||||
|
#include "XUtils.h"
|
||||||
|
|
||||||
|
|
||||||
|
static bool CGroup_filterName_internal(const char *cgroup, char* buf, size_t bufsize) {
|
||||||
|
const char* str_slice_suffix = ".slice";
|
||||||
|
const char* str_system_slice = "system.slice";
|
||||||
|
const char* str_user_slice = "user.slice";
|
||||||
|
const char* str_machine_slice = "machine.slice";
|
||||||
|
const char* str_user_slice_prefix = "/user-";
|
||||||
|
|
||||||
|
const char* str_lxc_monitor_prefix = "lxc.monitor.";
|
||||||
|
const char* str_lxc_payload_prefix = "lxc.payload.";
|
||||||
|
|
||||||
|
const char* str_nspawn_scope_prefix = "machine-";
|
||||||
|
const char* str_nspawn_monitor_label = "/supervisor";
|
||||||
|
|
||||||
|
const char* str_service_suffix = ".service";
|
||||||
|
const char* str_scope_suffix = ".scope";
|
||||||
|
|
||||||
|
while(*cgroup) {
|
||||||
|
if ('/' == *cgroup) {
|
||||||
|
while ('/' == *cgroup)
|
||||||
|
cgroup++;
|
||||||
|
|
||||||
|
if (!bufsize)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
*buf++ = '/';
|
||||||
|
bufsize--;
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* labelStart = cgroup;
|
||||||
|
const char* nextSlash = strchrnul(labelStart, '/');
|
||||||
|
const size_t labelLen = nextSlash - labelStart;
|
||||||
|
|
||||||
|
if (String_startsWith(cgroup, str_system_slice)) {
|
||||||
|
cgroup += strlen(str_system_slice);
|
||||||
|
|
||||||
|
if (*cgroup && *cgroup != '/')
|
||||||
|
goto handle_default;
|
||||||
|
|
||||||
|
if (bufsize < 3)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
*buf++ = '[';
|
||||||
|
*buf++ = 'S';
|
||||||
|
*buf++ = ']';
|
||||||
|
bufsize -= 3;
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (String_startsWith(cgroup, str_machine_slice)) {
|
||||||
|
cgroup += strlen(str_machine_slice);
|
||||||
|
|
||||||
|
if (*cgroup && *cgroup != '/')
|
||||||
|
goto handle_default;
|
||||||
|
|
||||||
|
if (bufsize < 3)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
*buf++ = '[';
|
||||||
|
*buf++ = 'M';
|
||||||
|
*buf++ = ']';
|
||||||
|
bufsize -= 3;
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (String_startsWith(cgroup, str_user_slice)) {
|
||||||
|
cgroup += strlen(str_user_slice);
|
||||||
|
|
||||||
|
if (*cgroup && *cgroup != '/')
|
||||||
|
goto handle_default;
|
||||||
|
|
||||||
|
if (bufsize < 3)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
*buf++ = '[';
|
||||||
|
*buf++ = 'U';
|
||||||
|
*buf++ = ']';
|
||||||
|
bufsize -= 3;
|
||||||
|
|
||||||
|
if (!String_startsWith(cgroup, str_user_slice_prefix))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const char* userSliceSlash = strchrnul(cgroup + strlen(str_user_slice_prefix), '/');
|
||||||
|
const char* sliceSpec = userSliceSlash - strlen(str_slice_suffix);
|
||||||
|
|
||||||
|
if (!String_startsWith(sliceSpec, str_slice_suffix))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const size_t sliceNameLen = sliceSpec - (cgroup + strlen(str_user_slice_prefix));
|
||||||
|
|
||||||
|
if (bufsize < sliceNameLen + 1)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
buf[-1] = ':';
|
||||||
|
|
||||||
|
cgroup += strlen(str_user_slice_prefix);
|
||||||
|
while(cgroup < sliceSpec) {
|
||||||
|
*buf++ = *cgroup++;
|
||||||
|
bufsize--;
|
||||||
|
}
|
||||||
|
cgroup = userSliceSlash;
|
||||||
|
|
||||||
|
*buf++ = ']';
|
||||||
|
bufsize--;
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (labelLen > strlen(str_slice_suffix) && String_startsWith(nextSlash - strlen(str_slice_suffix), str_slice_suffix)) {
|
||||||
|
const size_t sliceNameLen = labelLen - strlen(str_slice_suffix);
|
||||||
|
if (bufsize < 2 + sliceNameLen)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
*buf++ = '[';
|
||||||
|
bufsize--;
|
||||||
|
|
||||||
|
for(size_t i = sliceNameLen; i; i--) {
|
||||||
|
*buf++ = *cgroup++;
|
||||||
|
bufsize--;
|
||||||
|
}
|
||||||
|
|
||||||
|
*buf++ = ']';
|
||||||
|
bufsize--;
|
||||||
|
|
||||||
|
cgroup = nextSlash;
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (String_startsWith(cgroup, str_lxc_payload_prefix)) {
|
||||||
|
const size_t cgroupNameLen = labelLen - strlen(str_lxc_payload_prefix);
|
||||||
|
if (bufsize < 6 + cgroupNameLen)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
*buf++ = '[';
|
||||||
|
*buf++ = 'l';
|
||||||
|
*buf++ = 'x';
|
||||||
|
*buf++ = 'c';
|
||||||
|
*buf++ = ':';
|
||||||
|
bufsize -= 5;
|
||||||
|
|
||||||
|
cgroup += strlen(str_lxc_payload_prefix);
|
||||||
|
while(cgroup < nextSlash) {
|
||||||
|
*buf++ = *cgroup++;
|
||||||
|
bufsize--;
|
||||||
|
}
|
||||||
|
|
||||||
|
*buf++ = ']';
|
||||||
|
bufsize--;
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (String_startsWith(cgroup, str_lxc_monitor_prefix)) {
|
||||||
|
const size_t cgroupNameLen = labelLen - strlen(str_lxc_monitor_prefix);
|
||||||
|
if (bufsize < 6 + cgroupNameLen)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
*buf++ = '[';
|
||||||
|
*buf++ = 'L';
|
||||||
|
*buf++ = 'X';
|
||||||
|
*buf++ = 'C';
|
||||||
|
*buf++ = ':';
|
||||||
|
bufsize -= 5;
|
||||||
|
|
||||||
|
cgroup += strlen(str_lxc_monitor_prefix);
|
||||||
|
while(cgroup < nextSlash) {
|
||||||
|
*buf++ = *cgroup++;
|
||||||
|
bufsize--;
|
||||||
|
}
|
||||||
|
|
||||||
|
*buf++ = ']';
|
||||||
|
bufsize--;
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (labelLen > strlen(str_service_suffix) && String_startsWith(nextSlash - strlen(str_service_suffix), str_service_suffix)) {
|
||||||
|
const size_t serviceNameLen = labelLen - strlen(str_service_suffix);
|
||||||
|
|
||||||
|
if (String_startsWith(cgroup, "user@")) {
|
||||||
|
cgroup = nextSlash;
|
||||||
|
|
||||||
|
while(*cgroup == '/')
|
||||||
|
cgroup++;
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bufsize < serviceNameLen)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for(size_t i = serviceNameLen; i; i--) {
|
||||||
|
*buf++ = *cgroup++;
|
||||||
|
bufsize--;
|
||||||
|
}
|
||||||
|
|
||||||
|
cgroup = nextSlash;
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (labelLen > strlen(str_scope_suffix) && String_startsWith(nextSlash - strlen(str_scope_suffix), str_scope_suffix)) {
|
||||||
|
const size_t scopeNameLen = labelLen - strlen(str_scope_suffix);
|
||||||
|
|
||||||
|
if (String_startsWith(cgroup, str_nspawn_scope_prefix)) {
|
||||||
|
const size_t machineScopeNameLen = scopeNameLen - strlen(str_nspawn_scope_prefix);
|
||||||
|
if (bufsize < 6 + machineScopeNameLen)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const bool is_monitor = String_startsWith(nextSlash, str_nspawn_monitor_label);
|
||||||
|
|
||||||
|
*buf++ = '[';
|
||||||
|
*buf++ = is_monitor ? 'S' : 's';
|
||||||
|
*buf++ = is_monitor ? 'N' : 'n';
|
||||||
|
*buf++ = is_monitor ? 'C' : 'c';
|
||||||
|
*buf++ = ':';
|
||||||
|
bufsize -= 5;
|
||||||
|
|
||||||
|
cgroup += strlen(str_nspawn_scope_prefix);
|
||||||
|
for(size_t i = machineScopeNameLen; i; i--) {
|
||||||
|
*buf++ = *cgroup++;
|
||||||
|
bufsize--;
|
||||||
|
}
|
||||||
|
|
||||||
|
*buf++ = ']';
|
||||||
|
bufsize--;
|
||||||
|
|
||||||
|
cgroup = nextSlash;
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bufsize < 1 + scopeNameLen)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
*buf++ = '!';
|
||||||
|
bufsize--;
|
||||||
|
|
||||||
|
for(size_t i = scopeNameLen; i; i--) {
|
||||||
|
*buf++ = *cgroup++;
|
||||||
|
bufsize--;
|
||||||
|
}
|
||||||
|
|
||||||
|
cgroup = nextSlash;
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
handle_default:
|
||||||
|
// Default behavior: Copy the full label
|
||||||
|
cgroup = labelStart;
|
||||||
|
|
||||||
|
if (bufsize < (size_t)(nextSlash - cgroup))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
while(cgroup < nextSlash) {
|
||||||
|
*buf++ = *cgroup++;
|
||||||
|
bufsize--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CGroup_filterName(const char *cgroup, char* buf, size_t bufsize) {
|
||||||
|
memset(buf, 0, bufsize);
|
||||||
|
|
||||||
|
return CGroup_filterName_internal(cgroup, buf, bufsize - 1);
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
#ifndef HEADER_CGroupUtils
|
||||||
|
#define HEADER_CGroupUtils
|
||||||
|
/*
|
||||||
|
htop - CGroupUtils.h
|
||||||
|
(C) 2021 htop dev team
|
||||||
|
Released under the GNU GPLv2+, see the COPYING file
|
||||||
|
in the source distribution for its full text.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
|
||||||
|
bool CGroup_filterName(const char *cgroup, char* buf, size_t bufsize);
|
||||||
|
|
||||||
|
#endif /* HEADER_CGroupUtils */
|
|
@ -81,7 +81,8 @@ const ProcessFieldData Process_fields[LAST_PROCESSFIELD] = {
|
||||||
[IO_READ_RATE] = { .name = "IO_READ_RATE", .title = " DISK READ ", .description = "The I/O rate of read(2) in bytes per second for the process", .flags = PROCESS_FLAG_IO, .defaultSortDesc = true, },
|
[IO_READ_RATE] = { .name = "IO_READ_RATE", .title = " DISK READ ", .description = "The I/O rate of read(2) in bytes per second for the process", .flags = PROCESS_FLAG_IO, .defaultSortDesc = true, },
|
||||||
[IO_WRITE_RATE] = { .name = "IO_WRITE_RATE", .title = " DISK WRITE ", .description = "The I/O rate of write(2) in bytes per second for the process", .flags = PROCESS_FLAG_IO, .defaultSortDesc = true, },
|
[IO_WRITE_RATE] = { .name = "IO_WRITE_RATE", .title = " DISK WRITE ", .description = "The I/O rate of write(2) in bytes per second for the process", .flags = PROCESS_FLAG_IO, .defaultSortDesc = true, },
|
||||||
[IO_RATE] = { .name = "IO_RATE", .title = " DISK R/W ", .description = "Total I/O rate in bytes per second", .flags = PROCESS_FLAG_IO, .defaultSortDesc = true, },
|
[IO_RATE] = { .name = "IO_RATE", .title = " DISK R/W ", .description = "Total I/O rate in bytes per second", .flags = PROCESS_FLAG_IO, .defaultSortDesc = true, },
|
||||||
[CGROUP] = { .name = "CGROUP", .title = "CGROUP ", .description = "Which cgroup the process is in", .flags = PROCESS_FLAG_LINUX_CGROUP, },
|
[CGROUP] = { .name = "CGROUP", .title = "CGROUP (raw) ", .description = "Which cgroup the process is in", .flags = PROCESS_FLAG_LINUX_CGROUP, },
|
||||||
|
[CCGROUP] = { .name = "CCGROUP", .title = "CGROUP (compressed) ", .description = "Which cgroup the process is in (condensed to essentials)", .flags = PROCESS_FLAG_LINUX_CGROUP, },
|
||||||
[OOM] = { .name = "OOM", .title = " OOM ", .description = "OOM (Out-of-Memory) killer score", .flags = PROCESS_FLAG_LINUX_OOM, .defaultSortDesc = true, },
|
[OOM] = { .name = "OOM", .title = " OOM ", .description = "OOM (Out-of-Memory) killer score", .flags = PROCESS_FLAG_LINUX_OOM, .defaultSortDesc = true, },
|
||||||
[IO_PRIORITY] = { .name = "IO_PRIORITY", .title = "IO ", .description = "I/O priority", .flags = PROCESS_FLAG_LINUX_IOPRIO, },
|
[IO_PRIORITY] = { .name = "IO_PRIORITY", .title = "IO ", .description = "I/O priority", .flags = PROCESS_FLAG_LINUX_IOPRIO, },
|
||||||
#ifdef HAVE_DELAYACCT
|
#ifdef HAVE_DELAYACCT
|
||||||
|
@ -111,6 +112,7 @@ Process* LinuxProcess_new(const Settings* settings) {
|
||||||
void Process_delete(Object* cast) {
|
void Process_delete(Object* cast) {
|
||||||
LinuxProcess* this = (LinuxProcess*) cast;
|
LinuxProcess* this = (LinuxProcess*) cast;
|
||||||
Process_done((Process*)cast);
|
Process_done((Process*)cast);
|
||||||
|
free(this->cgroup_short);
|
||||||
free(this->cgroup);
|
free(this->cgroup);
|
||||||
#ifdef HAVE_OPENVZ
|
#ifdef HAVE_OPENVZ
|
||||||
free(this->ctid);
|
free(this->ctid);
|
||||||
|
@ -247,6 +249,7 @@ static void LinuxProcess_writeField(const Process* this, RichString* str, Proces
|
||||||
case VXID: xSnprintf(buffer, n, "%5u ", lp->vxid); break;
|
case VXID: xSnprintf(buffer, n, "%5u ", lp->vxid); break;
|
||||||
#endif
|
#endif
|
||||||
case CGROUP: xSnprintf(buffer, n, "%-35.35s ", lp->cgroup ? lp->cgroup : "N/A"); break;
|
case CGROUP: xSnprintf(buffer, n, "%-35.35s ", lp->cgroup ? lp->cgroup : "N/A"); break;
|
||||||
|
case CCGROUP: xSnprintf(buffer, n, "%-35.35s ", lp->cgroup_short ? lp->cgroup_short : (lp->cgroup ? lp->cgroup : "N/A")); break;
|
||||||
case OOM: xSnprintf(buffer, n, "%4u ", lp->oom); break;
|
case OOM: xSnprintf(buffer, n, "%4u ", lp->oom); break;
|
||||||
case IO_PRIORITY: {
|
case IO_PRIORITY: {
|
||||||
int klass = IOPriority_class(lp->ioPriority);
|
int klass = IOPriority_class(lp->ioPriority);
|
||||||
|
@ -370,6 +373,8 @@ static int LinuxProcess_compareByKey(const Process* v1, const Process* v2, Proce
|
||||||
#endif
|
#endif
|
||||||
case CGROUP:
|
case CGROUP:
|
||||||
return SPACESHIP_NULLSTR(p1->cgroup, p2->cgroup);
|
return SPACESHIP_NULLSTR(p1->cgroup, p2->cgroup);
|
||||||
|
case CCGROUP:
|
||||||
|
return SPACESHIP_NULLSTR(p1->cgroup_short, p2->cgroup_short);
|
||||||
case OOM:
|
case OOM:
|
||||||
return SPACESHIP_NUMBER(p1->oom, p2->oom);
|
return SPACESHIP_NUMBER(p1->oom, p2->oom);
|
||||||
#ifdef HAVE_DELAYACCT
|
#ifdef HAVE_DELAYACCT
|
||||||
|
|
|
@ -89,6 +89,7 @@ typedef struct LinuxProcess_ {
|
||||||
unsigned int vxid;
|
unsigned int vxid;
|
||||||
#endif
|
#endif
|
||||||
char* cgroup;
|
char* cgroup;
|
||||||
|
char* cgroup_short;
|
||||||
unsigned int oom;
|
unsigned int oom;
|
||||||
#ifdef HAVE_DELAYACCT
|
#ifdef HAVE_DELAYACCT
|
||||||
unsigned long long int delay_read_time;
|
unsigned long long int delay_read_time;
|
||||||
|
|
|
@ -45,6 +45,7 @@ in the source distribution for its full text.
|
||||||
#include "Process.h"
|
#include "Process.h"
|
||||||
#include "Settings.h"
|
#include "Settings.h"
|
||||||
#include "XUtils.h"
|
#include "XUtils.h"
|
||||||
|
#include "linux/CGroupUtils.h"
|
||||||
#include "linux/LinuxProcess.h"
|
#include "linux/LinuxProcess.h"
|
||||||
#include "linux/Platform.h" // needed for GNU/hurd to get PATH_MAX // IWYU pragma: keep
|
#include "linux/Platform.h" // needed for GNU/hurd to get PATH_MAX // IWYU pragma: keep
|
||||||
|
|
||||||
|
@ -860,6 +861,10 @@ static void LinuxProcessList_readCGroupFile(LinuxProcess* process, openat_arg_t
|
||||||
free(process->cgroup);
|
free(process->cgroup);
|
||||||
process->cgroup = NULL;
|
process->cgroup = NULL;
|
||||||
}
|
}
|
||||||
|
if (process->cgroup_short) {
|
||||||
|
free(process->cgroup_short);
|
||||||
|
process->cgroup_short = NULL;
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
char output[PROC_LINE_LENGTH + 1];
|
char output[PROC_LINE_LENGTH + 1];
|
||||||
|
@ -892,7 +897,22 @@ static void LinuxProcessList_readCGroupFile(LinuxProcess* process, openat_arg_t
|
||||||
left -= wrote;
|
left -= wrote;
|
||||||
}
|
}
|
||||||
fclose(file);
|
fclose(file);
|
||||||
|
|
||||||
|
bool changed = !process->cgroup || !String_eq(process->cgroup, output);
|
||||||
|
|
||||||
free_and_xStrdup(&process->cgroup, output);
|
free_and_xStrdup(&process->cgroup, output);
|
||||||
|
|
||||||
|
if (!changed)
|
||||||
|
return;
|
||||||
|
|
||||||
|
char* cgroup_short = xCalloc(strlen(process->cgroup) + 1, 1);
|
||||||
|
if (CGroup_filterName(process->cgroup, cgroup_short, strlen(process->cgroup) + 1)) {
|
||||||
|
free_and_xStrdup(&process->cgroup_short, cgroup_short);
|
||||||
|
} else {
|
||||||
|
free(process->cgroup_short);
|
||||||
|
process->cgroup_short = NULL;
|
||||||
|
}
|
||||||
|
free(cgroup_short);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_VSERVER
|
#ifdef HAVE_VSERVER
|
||||||
|
|
|
@ -45,6 +45,7 @@ in the source distribution for its full text.
|
||||||
SECATTR = 123, \
|
SECATTR = 123, \
|
||||||
AUTOGROUP_ID = 127, \
|
AUTOGROUP_ID = 127, \
|
||||||
AUTOGROUP_NICE = 128, \
|
AUTOGROUP_NICE = 128, \
|
||||||
|
CCGROUP = 129, \
|
||||||
// End of list
|
// End of list
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue