diff options
Diffstat (limited to 'Process.c')
| -rw-r--r-- | Process.c | 583 |
1 files changed, 423 insertions, 160 deletions
@@ -1,36 +1,35 @@ /* htop - Process.c -(C) 2004-2010 Hisham H. Muhammad +(C) 2004-2011 Hisham H. Muhammad Released under the GNU GPL, see the COPYING file in the source distribution for its full text. */ -#define _GNU_SOURCE +#include "Process.h" + #include "ProcessList.h" -#include "Object.h" #include "CRT.h" #include "String.h" -#include "Process.h" #include "RichString.h" -#include "debug.h" - #include <stdio.h> #include <sys/time.h> #include <sys/resource.h> #include <sys/param.h> -#include <sys/types.h> #include <sys/stat.h> #include <unistd.h> +#include <stdlib.h> #include <signal.h> #include <string.h> #include <stdbool.h> #include <pwd.h> #include <sched.h> #include <time.h> +#include <assert.h> +#include <sys/syscall.h> -#ifdef HAVE_PLPA -#include <plpa.h> +#ifdef HAVE_LIBHWLOC +#include <hwloc/linux.h> #endif // This works only with glibc 2.1+. On earlier versions @@ -41,6 +40,16 @@ in the source distribution for its full text. #define PAGE_SIZE_KB ( PAGE_SIZE / ONE_K ) /*{ +#include "Object.h" +#include "Affinity.h" +#include "IOPriority.h" +#include <sys/types.h> + +#define PROCESS_FLAG_IO 1 +#define PROCESS_FLAG_IOPRIO 2 +#define PROCESS_FLAG_OPENVZ 4 +#define PROCESS_FLAG_VSERVER 8 +#define PROCESS_FLAG_CGROUP 16 #ifndef Process_isKernelThread #define Process_isKernelThread(_process) (_process->pgrp == 0) @@ -72,6 +81,10 @@ typedef enum ProcessField_ { #ifdef HAVE_CGROUP CGROUP, #endif + #ifdef HAVE_OOM + OOM, + #endif + IO_PRIORITY, LAST_PROCESSFIELD } ProcessField; @@ -81,7 +94,6 @@ typedef struct Process_ { Object super; struct ProcessList_ *pl; - bool updated; pid_t pid; char* comm; @@ -97,21 +109,69 @@ typedef struct Process_ { pid_t tgid; int tpgid; unsigned long int flags; - #ifdef DEBUG - unsigned long int minflt; - unsigned long int cminflt; - unsigned long int majflt; - unsigned long int cmajflt; - #endif - unsigned long int utime; - unsigned long int stime; - long int cutime; - long int cstime; + + uid_t st_uid; + float percent_cpu; + float percent_mem; + char* user; + + unsigned long long int utime; + unsigned long long int stime; + unsigned long long int cutime; + unsigned long long int cstime; long int priority; long int nice; long int nlwp; + IOPriority ioPriority; char starttime_show[8]; time_t starttime_ctime; + + #ifdef HAVE_TASKSTATS + unsigned long long io_rchar; + unsigned long long io_wchar; + unsigned long long io_syscr; + unsigned long long io_syscw; + unsigned long long io_read_bytes; + unsigned long long io_write_bytes; + unsigned long long io_cancelled_write_bytes; + double io_rate_read_bps; + unsigned long long io_rate_read_time; + double io_rate_write_bps; + unsigned long long io_rate_write_time; + #endif + + int processor; + long m_size; + long m_resident; + long m_share; + long m_trs; + long m_drs; + long m_lrs; + long m_dt; + + #ifdef HAVE_OPENVZ + unsigned int ctid; + unsigned int vpid; + #endif + #ifdef HAVE_VSERVER + unsigned int vxid; + #endif + + #ifdef HAVE_CGROUP + char* cgroup; + #endif + #ifdef HAVE_OOM + unsigned int oom; + #endif + + int exit_signal; + int basenameOffset; + bool updated; + + unsigned long int minflt; + unsigned long int cminflt; + unsigned long int majflt; + unsigned long int cmajflt; #ifdef DEBUG long int itrealvalue; unsigned long int vsize; @@ -130,52 +190,11 @@ typedef struct Process_ { unsigned long int nswap; unsigned long int cnswap; #endif - int exit_signal; - int processor; - int m_size; - int m_resident; - int m_share; - int m_trs; - int m_drs; - int m_lrs; - int m_dt; - uid_t st_uid; - float percent_cpu; - float percent_mem; - char* user; - #ifdef HAVE_OPENVZ - unsigned int ctid; - unsigned int vpid; - #endif - #ifdef HAVE_VSERVER - unsigned int vxid; - #endif - #ifdef HAVE_TASKSTATS - unsigned long long io_rchar; - unsigned long long io_wchar; - unsigned long long io_syscr; - unsigned long long io_syscw; - unsigned long long io_read_bytes; - unsigned long long io_write_bytes; - unsigned long long io_cancelled_write_bytes; - double io_rate_read_bps; - unsigned long long io_rate_read_time; - double io_rate_write_bps; - unsigned long long io_rate_write_time; - #endif - #ifdef HAVE_CGROUP - char* cgroup; - #endif + } Process; }*/ -#ifdef DEBUG -char* PROCESS_CLASS = "Process"; -#else -#define PROCESS_CLASS NULL -#endif - const char *Process_fieldNames[] = { "", "PID", "Command", "STATE", "PPID", "PGRP", "SESSION", "TTY_NR", "TPGID", "FLAGS", "MINFLT", "CMINFLT", "MAJFLT", "CMAJFLT", @@ -198,18 +217,50 @@ const char *Process_fieldNames[] = { #ifdef HAVE_CGROUP "CGROUP", #endif +#ifdef HAVE_OOM + "OOM", +#endif + "IO_PRIORITY", "*** report bug! ***" }; +const int Process_fieldFlags[] = { + 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, +#ifdef HAVE_OPENVZ + PROCESS_FLAG_OPENVZ, PROCESS_FLAG_OPENVZ, +#endif +#ifdef HAVE_VSERVER + PROCESS_FLAG_VSERVER, +#endif +#ifdef HAVE_TASKSTATS + PROCESS_FLAG_IO, PROCESS_FLAG_IO, PROCESS_FLAG_IO, PROCESS_FLAG_IO, PROCESS_FLAG_IO, PROCESS_FLAG_IO, PROCESS_FLAG_IO, + PROCESS_FLAG_IO, PROCESS_FLAG_IO, PROCESS_FLAG_IO, +#endif +#ifdef HAVE_CGROUP + PROCESS_FLAG_CGROUP, +#endif +#ifdef HAVE_OOM + 0, +#endif + PROCESS_FLAG_IOPRIO +}; + const char *Process_fieldTitles[] = { - "", " PID ", "Command ", "S ", " PPID ", " PGRP ", " SESN ", - " TTY ", "TPGID ", "- ", "- ", "- ", "- ", "- ", - " UTIME+ ", " STIME+ ", "- ", "- ", "PRI ", " NI ", "- ", + "", " PID ", "Command ", "S ", " PPID ", " PGRP ", " SESN ", + " TTY ", " TPGID ", "- ", " MINFLT ", " CMINFLT ", " MAJFLT ", " CMAJFLT ", + " UTIME+ ", " STIME+ ", " CUTIME+ ", " CSTIME+ ", "PRI ", " NI ", "- ", "START ", "- ", "- ", "- ", "- ", "- ", "- ", "- ", "- ", "- ", "- ", "- ", "- ", "- ", "- ", "- ", "- ", "CPU ", " VIRT ", " RES ", " SHR ", " CODE ", " DATA ", " LIB ", " DIRTY ", " UID ", "CPU% ", "MEM% ", - "USER ", " TIME+ ", "NLWP ", " TGID ", + "USER ", " TIME+ ", "NLWP ", " TGID ", #ifdef HAVE_OPENVZ " CTID ", " VPID ", #endif @@ -217,72 +268,167 @@ const char *Process_fieldTitles[] = { " VXID ", #endif #ifdef HAVE_TASKSTATS - " RD_CHAR ", " WR_CHAR ", " RD_SYSC ", " WR_SYSC ", " IO_RBYTES ", " IO_WBYTES ", " IO_CANCEL ", - " IORR ", " IOWR ", " IO ", + " RD_CHAR ", " WR_CHAR ", " RD_SYSC ", " WR_SYSC ", " IO_RBYTES ", " IO_WBYTES ", " IO_CANCEL ", + " IORR ", " IOWR ", " IORW ", #endif #ifdef HAVE_CGROUP " CGROUP ", #endif +#ifdef HAVE_OOM + " OOM ", +#endif + "IO ", "*** report bug! ***" }; static int Process_getuid = -1; -#define ONE_K 1024 +static char* Process_pidFormat = "%7u "; +static char* Process_tpgidFormat = "%7u "; + +void Process_getMaxPid() { + FILE* file = fopen(PROCDIR "/sys/kernel/pid_max", "r"); + if (!file) return; + int maxPid = 4194303; + fscanf(file, "%32d", &maxPid); + fclose(file); + if (maxPid > 99999) { + Process_fieldTitles[PID] = " PID "; + Process_fieldTitles[PPID] = " PPID "; + Process_fieldTitles[TPGID] = " TPGID "; + Process_fieldTitles[TGID] = " TGID "; + Process_fieldTitles[PGRP] = " PGRP "; + Process_fieldTitles[SESSION] = " SESN "; + #ifdef HAVE_OOM + Process_fieldTitles[OOM] = " OOM "; + #endif + Process_pidFormat = "%7u "; + Process_tpgidFormat = "%7d "; + } else { + Process_fieldTitles[PID] = " PID "; + Process_fieldTitles[PPID] = " PPID "; + Process_fieldTitles[TPGID] = "TPGID "; + Process_fieldTitles[TGID] = " TGID "; + Process_fieldTitles[PGRP] = " PGRP "; + Process_fieldTitles[SESSION] = " SESN "; + #ifdef HAVE_OOM + Process_fieldTitles[OOM] = " OOM "; + #endif + Process_pidFormat = "%5u "; + Process_tpgidFormat = "%5d "; + } +} + +#define ONE_K 1024L #define ONE_M (ONE_K * ONE_K) #define ONE_G (ONE_M * ONE_K) -static void Process_printLargeNumber(Process* this, RichString* str, unsigned long number) { +#define ONE_DECIMAL_K 1000L +#define ONE_DECIMAL_M (ONE_DECIMAL_K * ONE_DECIMAL_K) +#define ONE_DECIMAL_G (ONE_DECIMAL_M * ONE_DECIMAL_K) + +static void Process_humanNumber(RichString* str, unsigned long number, bool coloring) { char buffer[11]; int len; - if(number >= (10 * ONE_M)) { - if(number >= (100 * ONE_M)) { + + int largeNumberColor = CRT_colors[LARGE_NUMBER]; + int processMegabytesColor = CRT_colors[PROCESS_MEGABYTES]; + int processColor = CRT_colors[PROCESS]; + if (!coloring) { + largeNumberColor = CRT_colors[PROCESS]; + processMegabytesColor = CRT_colors[PROCESS]; + } + + if(number >= (10 * ONE_DECIMAL_M)) { + #ifdef __LP64__ + if(number >= (100 * ONE_DECIMAL_G)) { + len = snprintf(buffer, 10, "%4ldT ", number / ONE_G); + RichString_appendn(str, largeNumberColor, buffer, len); + return; + } else if (number >= (1000 * ONE_DECIMAL_M)) { + len = snprintf(buffer, 10, "%4.1lfT ", (double)number / ONE_G); + RichString_appendn(str, largeNumberColor, buffer, len); + return; + } + #endif + if(number >= (100 * ONE_DECIMAL_M)) { len = snprintf(buffer, 10, "%4ldG ", number / ONE_M); - RichString_appendn(str, CRT_colors[LARGE_NUMBER], buffer, len); - } else { - len = snprintf(buffer, 10, "%3.1fG ", (float)number / ONE_M); - RichString_appendn(str, CRT_colors[LARGE_NUMBER], buffer, len); + RichString_appendn(str, largeNumberColor, buffer, len); + return; } + len = snprintf(buffer, 10, "%4.1lfG ", (double)number / ONE_M); + RichString_appendn(str, largeNumberColor, buffer, len); + return; } else if (number >= 100000) { len = snprintf(buffer, 10, "%4ldM ", number / ONE_K); - int attr = this->pl->highlightMegabytes - ? CRT_colors[PROCESS_MEGABYTES] - : CRT_colors[PROCESS]; - RichString_appendn(str, attr, buffer, len); - } else if (this->pl->highlightMegabytes && number >= 1000) { + RichString_appendn(str, processMegabytesColor, buffer, len); + return; + } else if (number >= 1000) { len = snprintf(buffer, 10, "%2ld", number/1000); - RichString_appendn(str, CRT_colors[PROCESS_MEGABYTES], buffer, len); + RichString_appendn(str, processMegabytesColor, buffer, len); number %= 1000; - len = snprintf(buffer, 10, "%03ld ", number); - RichString_appendn(str, CRT_colors[PROCESS], buffer, len); + len = snprintf(buffer, 10, "%03lu ", number); + RichString_appendn(str, processColor, buffer, len); + return; + } + len = snprintf(buffer, 10, "%5lu ", number); + RichString_appendn(str, processColor, buffer, len); +} + +static void Process_colorNumber(RichString* str, unsigned long long number, bool coloring) { + char buffer[14]; + + int largeNumberColor = CRT_colors[LARGE_NUMBER]; + int processMegabytesColor = CRT_colors[PROCESS_MEGABYTES]; + int processColor = CRT_colors[PROCESS]; + int processShadowColor = CRT_colors[PROCESS_SHADOW]; + if (!coloring) { + largeNumberColor = CRT_colors[PROCESS]; + processMegabytesColor = CRT_colors[PROCESS]; + processShadowColor = CRT_colors[PROCESS]; + } + + if (number > 10000000000) { + snprintf(buffer, 13, "%11lld ", number / 1000); + RichString_appendn(str, largeNumberColor, buffer, 5); + RichString_appendn(str, processMegabytesColor, buffer+5, 3); + RichString_appendn(str, processColor, buffer+8, 4); } else { - len = snprintf(buffer, 10, "%5ld ", number); - RichString_appendn(str, CRT_colors[PROCESS], buffer, len); + snprintf(buffer, 13, "%11llu ", number); + RichString_appendn(str, largeNumberColor, buffer, 2); + RichString_appendn(str, processMegabytesColor, buffer+2, 3); + RichString_appendn(str, processColor, buffer+5, 3); + RichString_appendn(str, processShadowColor, buffer+8, 4); } } static double jiffy = 0.0; -static void Process_printTime(RichString* str, unsigned long t) { +static void Process_printTime(RichString* str, unsigned long long t) { if(jiffy == 0.0) jiffy = sysconf(_SC_CLK_TCK); double jiffytime = 1.0 / jiffy; double realTime = t * jiffytime; - int iRealTime = (int) realTime; + unsigned long long iRealTime = (unsigned long long) realTime; - int hours = iRealTime / 3600; + unsigned long long hours = iRealTime / 3600; int minutes = (iRealTime / 60) % 60; int seconds = iRealTime % 60; int hundredths = (realTime - iRealTime) * 100; char buffer[11]; - if (hours) { - snprintf(buffer, 10, "%2dh", hours); + if (hours >= 100) { + snprintf(buffer, 10, "%7lluh ", hours); RichString_append(str, CRT_colors[LARGE_NUMBER], buffer); - snprintf(buffer, 10, "%02d:%02d ", minutes, seconds); } else { - snprintf(buffer, 10, "%2d:%02d.%02d ", minutes, seconds, hundredths); + if (hours) { + snprintf(buffer, 10, "%2lluh", hours); + RichString_append(str, CRT_colors[LARGE_NUMBER], buffer); + snprintf(buffer, 10, "%02d:%02d ", minutes, seconds); + } else { + snprintf(buffer, 10, "%2d:%02d.%02d ", minutes, seconds, hundredths); + } + RichString_append(str, CRT_colors[DEFAULT_COLOR], buffer); } - RichString_append(str, CRT_colors[DEFAULT_COLOR], buffer); } static inline void Process_writeCommand(Process* this, int attr, int baseattr, RichString* str) { @@ -290,20 +436,24 @@ static inline void Process_writeCommand(Process* this, int attr, int baseattr, R RichString_append(str, attr, this->comm); if (this->pl->highlightBaseName) { int finish = RichString_size(str) - 1; - int space = RichString_findChar(str, ' ', start); - if (space != -1) - finish = space - 1; - for (;;) { - int slash = RichString_findChar(str, '/', start); - if (slash == -1 || slash > finish) - break; - start = slash + 1; + if (this->basenameOffset != -1) + finish = (start + this->basenameOffset) - 1; + int colon = RichString_findChar(str, ':', start); + if (colon != -1 && colon < finish) { + finish = colon; + } else { + for (int i = finish - start; i >= 0; i--) { + if (this->comm[i] == '/') { + start += i+1; + break; + } + } } RichString_setAttrn(str, baseattr, start, finish); } } -static inline void Process_outputRate(Process* this, RichString* str, int attr, char* buffer, int n, double rate) { +static inline void Process_outputRate(RichString* str, int attr, char* buffer, int n, double rate, int coloring) { rate = rate / 1024; if (rate < 0.01) snprintf(buffer, n, " 0 "); @@ -312,27 +462,32 @@ static inline void Process_outputRate(Process* this, RichString* str, int attr, else if (rate <= 100) snprintf(buffer, n, "%5.1f ", rate); else { - Process_printLargeNumber(this, str, rate); + Process_humanNumber(str, rate, coloring); return; } RichString_append(str, attr, buffer); } static void Process_writeField(Process* this, RichString* str, ProcessField field) { - char buffer[128]; buffer[127] = '\0'; + char buffer[256]; buffer[255] = '\0'; int attr = CRT_colors[DEFAULT_COLOR]; int baseattr = CRT_colors[PROCESS_BASENAME]; int n = sizeof(buffer) - 1; + bool coloring = this->pl->highlightMegabytes; switch (field) { - case PID: snprintf(buffer, n, "%5u ", this->pid); break; - case PPID: snprintf(buffer, n, "%5u ", this->ppid); break; - case PGRP: snprintf(buffer, n, "%5u ", this->pgrp); break; - case SESSION: snprintf(buffer, n, "%5u ", this->session); break; + case PID: snprintf(buffer, n, Process_pidFormat, this->pid); break; + case PPID: snprintf(buffer, n, Process_pidFormat, this->ppid); break; + case PGRP: snprintf(buffer, n, Process_pidFormat, this->pgrp); break; + case SESSION: snprintf(buffer, n, Process_pidFormat, this->session); break; case TTY_NR: snprintf(buffer, n, "%5u ", this->tty_nr); break; - case TGID: snprintf(buffer, n, "%5u ", this->tgid); break; - case TPGID: snprintf(buffer, n, "%5d ", this->tpgid); break; - case PROCESSOR: snprintf(buffer, n, "%3d ", this->processor+1); break; + case TGID: snprintf(buffer, n, Process_pidFormat, this->tgid); break; + case TPGID: snprintf(buffer, n, Process_tpgidFormat, this->tpgid); break; + case MINFLT: Process_colorNumber(str, this->minflt, coloring); return; + case CMINFLT: Process_colorNumber(str, this->cminflt, coloring); return; + case MAJFLT: Process_colorNumber(str, this->majflt, coloring); return; + case CMAJFLT: Process_colorNumber(str, this->cmajflt, coloring); return; + case PROCESSOR: snprintf(buffer, n, "%3d ", ProcessList_cpuId(this->pl, this->processor)); break; case NLWP: snprintf(buffer, n, "%4ld ", this->nlwp); break; case COMM: { if (this->pl->highlightThreads && Process_isThread(this)) { @@ -345,21 +500,26 @@ static void Process_writeField(Process* this, RichString* str, ProcessField fiel } else { char* buf = buffer; int maxIndent = 0; + const char **treeStr = this->pl->treeStr; + bool lastItem = (this->indent < 0); + int indent = (this->indent < 0 ? -this->indent : this->indent); + if (treeStr == NULL) + treeStr = ProcessList_treeStrAscii; + for (int i = 0; i < 32; i++) - if (this->indent & (1 << i)) + if (indent & (1 << i)) maxIndent = i+1; for (int i = 0; i < maxIndent - 1; i++) { - if (this->indent & (1 << i)) - snprintf(buf, n, " | "); + int written; + if (indent & (1 << i)) + written = snprintf(buf, n, "%s ", treeStr[TREE_STR_VERT]); else - snprintf(buf, n, " "); - buf += 4; - n -= 4; + written = snprintf(buf, n, " "); + buf += written; + n -= written; } - if (this->pl->direction == 1) - snprintf(buf, n, " `%s ", this->showChildren ? "-" : "+" ); - else - snprintf(buf, n, " ,%s ", this->showChildren ? "-" : "+" ); + const char* draw = treeStr[lastItem ? (this->pl->direction == 1 ? TREE_STR_BEND : TREE_STR_TEND) : TREE_STR_RTEE]; + snprintf(buf, n, "%s%s ", draw, this->showChildren ? treeStr[TREE_STR_SHUT] : treeStr[TREE_STR_OPEN] ); RichString_append(str, CRT_colors[PROCESS_TREE], buffer); Process_writeCommand(this, attr, baseattr, str); return; @@ -386,25 +546,25 @@ static void Process_writeField(Process* this, RichString* str, ProcessField fiel : attr; break; } - case M_DRS: Process_printLargeNumber(this, str, this->m_drs * PAGE_SIZE_KB); return; - case M_DT: Process_printLargeNumber(this, str, this->m_dt * PAGE_SIZE_KB); return; - case M_LRS: Process_printLargeNumber(this, str, this->m_lrs * PAGE_SIZE_KB); return; - case M_TRS: Process_printLargeNumber(this, str, this->m_trs * PAGE_SIZE_KB); return; - case M_SIZE: Process_printLargeNumber(this, str, this->m_size * PAGE_SIZE_KB); return; - case M_RESIDENT: Process_printLargeNumber(this, str, this->m_resident * PAGE_SIZE_KB); return; - case M_SHARE: Process_printLargeNumber(this, str, this->m_share * PAGE_SIZE_KB); return; + case M_DRS: Process_humanNumber(str, this->m_drs * PAGE_SIZE_KB, coloring); return; + case M_DT: Process_humanNumber(str, this->m_dt * PAGE_SIZE_KB, coloring); return; + case M_LRS: Process_humanNumber(str, this->m_lrs * PAGE_SIZE_KB, coloring); return; + case M_TRS: Process_humanNumber(str, this->m_trs * PAGE_SIZE_KB, coloring); return; + case M_SIZE: Process_humanNumber(str, this->m_size * PAGE_SIZE_KB, coloring); return; + case M_RESIDENT: Process_humanNumber(str, this->m_resident * PAGE_SIZE_KB, coloring); return; + case M_SHARE: Process_humanNumber(str, this->m_share * PAGE_SIZE_KB, coloring); return; case ST_UID: snprintf(buffer, n, "%4d ", this->st_uid); break; case USER: { if (Process_getuid != (int) this->st_uid) attr = CRT_colors[PROCESS_SHADOW]; if (this->user) { - snprintf(buffer, n, "%-8s ", this->user); + snprintf(buffer, n, "%-9s ", this->user); } else { - snprintf(buffer, n, "%-8d ", this->st_uid); + snprintf(buffer, n, "%-9d ", this->st_uid); } - if (buffer[8] != '\0') { - buffer[8] = ' '; - buffer[9] = '\0'; + if (buffer[9] != '\0') { + buffer[9] = ' '; + buffer[10] = '\0'; } break; } @@ -440,21 +600,41 @@ static void Process_writeField(Process* this, RichString* str, ProcessField fiel case VXID: snprintf(buffer, n, "%5u ", this->vxid); break; #endif #ifdef HAVE_TASKSTATS - case RCHAR: snprintf(buffer, n, "%10llu ", this->io_rchar); break; - case WCHAR: snprintf(buffer, n, "%10llu ", this->io_wchar); break; - case SYSCR: snprintf(buffer, n, "%10llu ", this->io_syscr); break; - case SYSCW: snprintf(buffer, n, "%10llu ", this->io_syscw); break; - case RBYTES: snprintf(buffer, n, "%10llu ", this->io_read_bytes); break; - case WBYTES: snprintf(buffer, n, "%10llu ", this->io_write_bytes); break; - case CNCLWB: snprintf(buffer, n, "%10llu ", this->io_cancelled_write_bytes); break; - case IO_READ_RATE: Process_outputRate(this, str, attr, buffer, n, this->io_rate_read_bps); return; - case IO_WRITE_RATE: Process_outputRate(this, str, attr, buffer, n, this->io_rate_write_bps); return; - case IO_RATE: Process_outputRate(this, str, attr, buffer, n, this->io_rate_read_bps + this->io_rate_write_bps); return; + case RCHAR: Process_colorNumber(str, this->io_rchar, coloring); return; + case WCHAR: Process_colorNumber(str, this->io_wchar, coloring); return; + case SYSCR: Process_colorNumber(str, this->io_syscr, coloring); return; + case SYSCW: Process_colorNumber(str, this->io_syscw, coloring); return; + case RBYTES: Process_colorNumber(str, this->io_read_bytes, coloring); return; + case WBYTES: Process_colorNumber(str, this->io_write_bytes, coloring); return; + case CNCLWB: Process_colorNumber(str, this->io_cancelled_write_bytes, coloring); return; + case IO_READ_RATE: Process_outputRate(str, attr, buffer, n, this->io_rate_read_bps, coloring); return; + case IO_WRITE_RATE: Process_outputRate(str, attr, buffer, n, this->io_rate_write_bps, coloring); return; + case IO_RATE: Process_outputRate(str, attr, buffer, n, this->io_rate_read_bps + this->io_rate_write_bps, coloring); return; #endif #ifdef HAVE_CGROUP case CGROUP: snprintf(buffer, n, "%-10s ", this->cgroup); break; #endif - + #ifdef HAVE_OOM + case OOM: snprintf(buffer, n, Process_pidFormat, this->oom); break; + #endif + case IO_PRIORITY: { + int klass = IOPriority_class(this->ioPriority); + if (klass == IOPRIO_CLASS_NONE) { + // see note [1] above + snprintf(buffer, n, "B%1d ", (int) (this->nice + 20) / 5); + } else if (klass == IOPRIO_CLASS_BE) { + snprintf(buffer, n, "B%1d ", IOPriority_data(this->ioPriority)); + } else if (klass == IOPRIO_CLASS_RT) { + attr = CRT_colors[PROCESS_HIGH_PRIORITY]; + snprintf(buffer, n, "R%1d ", IOPriority_data(this->ioPriority)); + } else if (this->ioPriority == IOPriority_Idle) { + attr = CRT_colors[PROCESS_LOW_PRIORITY]; + snprintf(buffer, n, "id "); + } else { + snprintf(buffer, n, "?? "); + } + break; + } default: snprintf(buffer, n, "- "); } @@ -471,7 +651,7 @@ static void Process_display(Object* cast, RichString* out) { RichString_setAttr(out, CRT_colors[PROCESS_SHADOW]); if (this->tag == true) RichString_setAttr(out, CRT_colors[PROCESS_TAG]); - assert(out->len > 0); + assert(out->chlen > 0); } void Process_delete(Object* cast) { @@ -484,11 +664,16 @@ void Process_delete(Object* cast) { free(this); } +ObjectClass Process_class = { + .extends = Class(Object), + .display = Process_display, + .delete = Process_delete, + .compare = Process_compare +}; + Process* Process_new(struct ProcessList_ *pl) { - Process* this = calloc(sizeof(Process), 1); - Object_setClass(this, PROCESS_CLASS); - ((Object*)this)->display = Process_display; - ((Object*)this)->delete = Process_delete; + Process* this = calloc(1, sizeof(Process)); + Object_setClass(this, Class(Process)); this->pid = 0; this->pl = pl; this->tag = false; @@ -498,6 +683,7 @@ Process* Process_new(struct ProcessList_ *pl) { this->utime = 0; this->stime = 0; this->comm = NULL; + this->basenameOffset = -1; this->indent = 0; #ifdef HAVE_CGROUP this->cgroup = NULL; @@ -519,20 +705,92 @@ bool Process_setPriority(Process* this, int priority) { return (err == 0); } -#ifdef HAVE_PLPA -unsigned long Process_getAffinity(Process* this) { - unsigned long mask = 0; - plpa_sched_getaffinity(this->pid, sizeof(unsigned long), (plpa_cpu_set_t*) &mask); - return mask; +bool Process_changePriorityBy(Process* this, size_t delta) { + return Process_setPriority(this, this->nice + delta); +} + +IOPriority Process_updateIOPriority(Process* this) { + IOPriority ioprio = syscall(SYS_ioprio_get, IOPRIO_WHO_PROCESS, this->pid); + this->ioPriority = ioprio; + return ioprio; +} + +bool Process_setIOPriority(Process* this, IOPriority ioprio) { + syscall(SYS_ioprio_set, IOPRIO_WHO_PROCESS, this->pid, ioprio); + return (Process_updateIOPriority(this) == ioprio); +} + +/* +[1] Note that before kernel 2.6.26 a process that has not asked for +an io priority formally uses "none" as scheduling class, but the +io scheduler will treat such processes as if it were in the best +effort class. The priority within the best effort class will be +dynamically derived from the cpu nice level of the process: +io_priority = (cpu_nice + 20) / 5. -- From ionice(1) man page +*/ +#define Process_effectiveIOPriority(p_) (IOPriority_class(p_->ioPriority) == IOPRIO_CLASS_NONE ? IOPriority_tuple(IOPRIO_CLASS_BE, (p_->nice + 20) / 5) : p_->ioPriority) + +#ifdef HAVE_LIBHWLOC + +Affinity* Process_getAffinity(Process* this) { + hwloc_cpuset_t cpuset = hwloc_bitmap_alloc(); + bool ok = (hwloc_linux_get_tid_cpubind(this->pl->topology, this->pid, cpuset) == 0); + Affinity* affinity = NULL; + if (ok) { + affinity = Affinity_new(); + if (hwloc_bitmap_last(cpuset) == -1) { + for (int i = 0; i < this->pl->cpuCount; i++) { + Affinity_add(affinity, i); + } + } else { + unsigned int id; + hwloc_bitmap_foreach_begin(id, cpuset); + Affinity_add(affinity, id); + hwloc_bitmap_foreach_end(); + } + } + hwloc_bitmap_free(cpuset); + return affinity; +} + +bool Process_setAffinity(Process* this, Affinity* affinity) { + hwloc_cpuset_t cpuset = hwloc_bitmap_alloc(); + for (int i = 0; i < affinity->used; i++) { + hwloc_bitmap_set(cpuset, affinity->cpus[i]); + } + bool ok = (hwloc_linux_set_tid_cpubind(this->pl->topology, this->pid, cpuset) == 0); + hwloc_bitmap_free(cpuset); + return ok; +} + +#elif HAVE_NATIVE_AFFINITY + +Affinity* Process_getAffinity(Process* this) { + cpu_set_t cpuset; + bool ok = (sched_getaffinity(this->pid, sizeof(cpu_set_t), &cpuset) == 0); + if (!ok) return NULL; + Affinity* affinity = Affinity_new(); + for (int i = 0; i < this->pl->cpuCount; i++) { + if (CPU_ISSET(i, &cpuset)) + Affinity_add(affinity, i); + } + return affinity; } -bool Process_setAffinity(Process* this, unsigned long mask) { - return (plpa_sched_setaffinity(this->pid, sizeof(unsigned long), (plpa_cpu_set_t*) &mask) == 0); +bool Process_setAffinity(Process* this, Affinity* affinity) { + cpu_set_t cpuset; + CPU_ZERO(&cpuset); + for (int i = 0; i < affinity->used; i++) { + CPU_SET(affinity->cpus[i], &cpuset); + } + bool ok = (sched_setaffinity(this->pid, sizeof(unsigned long), &cpuset) == 0); + return ok; } + #endif -void Process_sendSignal(Process* this, int sgn) { - kill(this->pid, sgn); +void Process_sendSignal(Process* this, size_t sgn) { + kill(this->pid, (int) sgn); } int Process_pidCompare(const void* v1, const void* v2) { @@ -629,7 +887,12 @@ int Process_compare(const void* v1, const void* v2) { case CGROUP: return strcmp(p1->cgroup ? p1->cgroup : "", p2->cgroup ? p2->cgroup : ""); #endif - + #ifdef HAVE_OOM + case OOM: + return (p1->oom - p2->oom); + #endif + case IO_PRIORITY: + return Process_effectiveIOPriority(p1) - Process_effectiveIOPriority(p2); default: return (p1->pid - p2->pid); } |
