From 98ee833932ad90532246c95daf5859bdcf65dec9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= Date: Fri, 11 Sep 2020 15:02:00 +0200 Subject: [PATCH] Add Linux process column for context switches Displays the incremental sum of voluntary_ctxt_switches and nonvoluntary_ctxt_switches. --- htop.1.in | 3 +++ linux/LinuxProcess.c | 8 ++++++++ linux/LinuxProcess.h | 6 +++++- linux/LinuxProcessList.c | 29 +++++++++++++++++++++++++++++ 4 files changed, 45 insertions(+), 1 deletion(-) diff --git a/htop.1.in b/htop.1.in index c5b131bb..1ae1208f 100644 --- a/htop.1.in +++ b/htop.1.in @@ -386,6 +386,9 @@ Which cgroup the process is in. .B OOM OOM killer score. .TP +.B CTXT +Incremental sum of voluntary and nonvoluntary context switches. +.TP .B IO_PRIORITY (IO) The I/O scheduling class followed by the priority if the class supports it: \fBR\fR for Realtime diff --git a/linux/LinuxProcess.c b/linux/LinuxProcess.c index 377aa5bb..bef648a9 100644 --- a/linux/LinuxProcess.c +++ b/linux/LinuxProcess.c @@ -107,6 +107,7 @@ ProcessFieldData Process_fields[] = { [M_PSS] = { .name = "M_PSS", .title = " PSS ", .description = "proportional set size, same as M_RESIDENT but each page is divided by the number of processes sharing it.", .flags = PROCESS_FLAG_LINUX_SMAPS, }, [M_SWAP] = { .name = "M_SWAP", .title = " SWAP ", .description = "Size of the process's swapped pages", .flags = PROCESS_FLAG_LINUX_SMAPS, }, [M_PSSWP] = { .name = "M_PSSWP", .title = " PSSWP ", .description = "shows proportional swap share of this mapping, Unlike \"Swap\", this does not take into account swapped out page of underlying shmem objects.", .flags = PROCESS_FLAG_LINUX_SMAPS, }, + [CTXT] = { .name = "CTXT", .title = " CTXT ", .description = "Context switches (incremental sum of voluntary_ctxt_switches and nonvoluntary_ctxt_switches)", .flags = PROCESS_FLAG_LINUX_CTXT, }, [LAST_PROCESSFIELD] = { .name = "*** report bug! ***", .title = NULL, .description = NULL, .flags = 0, }, }; @@ -276,6 +277,11 @@ void LinuxProcess_writeField(Process* this, RichString* str, ProcessField field) case PERCENT_IO_DELAY: LinuxProcess_printDelay(lp->blkio_delay_percent, buffer, n); break; case PERCENT_SWAP_DELAY: LinuxProcess_printDelay(lp->swapin_delay_percent, buffer, n); break; #endif + case CTXT: + if (lp->ctxt_diff > 1000) + attr |= A_BOLD; + xSnprintf(buffer, n, "%5lu ", lp->ctxt_diff); + break; default: Process_writeField((Process*)this, str, field); return; @@ -359,6 +365,8 @@ long LinuxProcess_compare(const void* v1, const void* v2) { #endif case IO_PRIORITY: return LinuxProcess_effectiveIOPriority(p1) - LinuxProcess_effectiveIOPriority(p2); + case CTXT: + return ((long)p2->ctxt_diff - (long)p1->ctxt_diff); default: return Process_compare(v1, v2); } diff --git a/linux/LinuxProcess.h b/linux/LinuxProcess.h index 021cae7c..9972ee84 100644 --- a/linux/LinuxProcess.h +++ b/linux/LinuxProcess.h @@ -14,6 +14,7 @@ in the source distribution for its full text. #define PROCESS_FLAG_LINUX_CGROUP 0x0800 #define PROCESS_FLAG_LINUX_OOM 0x1000 #define PROCESS_FLAG_LINUX_SMAPS 0x2000 +#define PROCESS_FLAG_LINUX_CTXT 0x4000 typedef enum UnsupportedProcessFields { FLAGS = 9, @@ -80,7 +81,8 @@ typedef enum LinuxProcessFields { M_PSS = 119, M_SWAP = 120, M_PSSWP = 121, - LAST_PROCESSFIELD = 122, + CTXT = 122, + LAST_PROCESSFIELD = 123, } LinuxProcessField; #include "IOPriority.h" @@ -138,6 +140,8 @@ typedef struct LinuxProcess_ { float blkio_delay_percent; float swapin_delay_percent; #endif + unsigned long ctxt_total; + unsigned long ctxt_diff; } LinuxProcess; #define Process_isKernelThread(_process) (((LinuxProcess*)(_process))->isKernelThread) diff --git a/linux/LinuxProcessList.c b/linux/LinuxProcessList.c index cf91900b..89746e17 100644 --- a/linux/LinuxProcessList.c +++ b/linux/LinuxProcessList.c @@ -588,6 +588,32 @@ static void LinuxProcessList_readOomData(LinuxProcess* process, const char* dirn fclose(file); } +static void LinuxProcessList_readCtxtData(LinuxProcess* process, const char* dirname, const char* name) { + char filename[MAX_NAME+1]; + xSnprintf(filename, MAX_NAME, "%s/%s/status", dirname, name); + FILE* file = fopen(filename, "r"); + if (!file) + return; + char buffer[PROC_LINE_LENGTH + 1]; + unsigned long ctxt = 0; + while (fgets(buffer, PROC_LINE_LENGTH, file)) { + if (String_startsWith(buffer, "voluntary_ctxt_switches:")) { + unsigned long vctxt; + int ok = sscanf(buffer, "voluntary_ctxt_switches:\t%lu", &vctxt); + if (ok >= 1) + ctxt += vctxt; + } else if (String_startsWith(buffer, "nonvoluntary_ctxt_switches:")) { + unsigned long nvctxt; + int ok = sscanf(buffer, "nonvoluntary_ctxt_switches:\t%lu", &nvctxt); + if (ok >= 1) + ctxt += nvctxt; + } + } + fclose(file); + process->ctxt_diff = (ctxt > process->ctxt_total) ? (ctxt - process->ctxt_total) : 0; + process->ctxt_total = ctxt; +} + #ifdef HAVE_DELAYACCT static int handleNetlinkMsg(struct nl_msg *nlmsg, void *linuxProcess) { @@ -885,6 +911,9 @@ static bool LinuxProcessList_recurseProcTree(LinuxProcessList* this, const char* if (settings->flags & PROCESS_FLAG_LINUX_OOM) LinuxProcessList_readOomData(lp, dirname, name); + if (settings->flags & PROCESS_FLAG_LINUX_CTXT) + LinuxProcessList_readCtxtData(lp, dirname, name); + if (proc->state == 'Z' && (proc->basenameOffset == 0)) { proc->basenameOffset = -1; setCommand(proc, command, commLen);