From 6486229308cf7acc7a4ba7dd5f755cdb969372ef Mon Sep 17 00:00:00 2001 From: Hisham Muhammad Date: Tue, 24 Aug 2010 23:20:38 +0000 Subject: [PATCH] add support for steal/guest CPU time measurement simplify processor data accounting (add CPUData structure) remove Process_clone trick --- AvailableMetersPanel.c | 6 +- CPUMeter.c | 83 +++++++++------- CRT.c | 78 ++++++++++------ CRT.h | 9 +- DisplayOptionsPanel.c | 2 +- Makefile.am | 2 +- OpenFilesScreen.c | 8 +- Process.c | 21 ----- Process.h | 2 - ProcessList.c | 208 +++++++++++++++++++++-------------------- ProcessList.h | 62 ++++++------ TraceScreen.c | 8 +- htop.c | 22 +++-- 13 files changed, 270 insertions(+), 241 deletions(-) diff --git a/AvailableMetersPanel.c b/AvailableMetersPanel.c index 0645eba2..cfed46e6 100644 --- a/AvailableMetersPanel.c +++ b/AvailableMetersPanel.c @@ -91,10 +91,10 @@ AvailableMetersPanel* AvailableMetersPanel_new(Settings* settings, Panel* leftMe } } MeterType* type = &CPUMeter; - int processors = settings->pl->processorCount; - if (processors > 1) { + int cpus = settings->pl->cpuCount; + if (cpus > 1) { Panel_add(super, (Object*) ListItem_new("CPU average", 0)); - for (int i = 1; i <= processors; i++) { + for (int i = 1; i <= cpus; i++) { char buffer[50]; sprintf(buffer, "%s %d", type->uiName, i); Panel_add(super, (Object*) ListItem_new(buffer, i)); diff --git a/CPUMeter.c b/CPUMeter.c index 43d2cfad..bed6266c 100644 --- a/CPUMeter.c +++ b/CPUMeter.c @@ -19,7 +19,7 @@ in the source distribution for its full text. #include int CPUMeter_attributes[] = { - CPU_NICE, CPU_NORMAL, CPU_KERNEL, CPU_IRQ, CPU_SOFTIRQ, CPU_IOWAIT + CPU_NICE, CPU_NORMAL, CPU_KERNEL, CPU_IRQ, CPU_SOFTIRQ, CPU_IOWAIT, CPU_STEAL, CPU_GUEST }; #ifndef MIN @@ -30,10 +30,10 @@ int CPUMeter_attributes[] = { #endif static void CPUMeter_init(Meter* this) { - int processor = this->param; - if (this->pl->processorCount > 1) { + int cpu = this->param; + if (this->pl->cpuCount > 1) { char caption[10]; - sprintf(caption, "%-3d", processor); + sprintf(caption, "%-3d", cpu); Meter_setCaption(this, caption); } if (this->param == 0) @@ -42,37 +42,41 @@ static void CPUMeter_init(Meter* this) { static void CPUMeter_setValues(Meter* this, char* buffer, int size) { ProcessList* pl = this->pl; - int processor = this->param; - if (processor > this->pl->processorCount) { + int cpu = this->param; + if (cpu > this->pl->cpuCount) { snprintf(buffer, size, "absent"); return; } - double total = (double) (pl->totalPeriod[processor] == 0 ? 1 : pl->totalPeriod[processor]); - double cpu; - this->values[0] = pl->nicePeriod[processor] / total * 100.0; - this->values[1] = pl->userPeriod[processor] / total * 100.0; + CPUData* cpuData = &(pl->cpus[cpu]); + double total = (double) ( cpuData->totalPeriod == 0 ? 1 : cpuData->totalPeriod); + double percent; + this->values[0] = cpuData->nicePeriod / total * 100.0; + this->values[1] = cpuData->userPeriod / total * 100.0; if (pl->detailedCPUTime) { - this->values[2] = pl->systemPeriod[processor] / total * 100.0; - this->values[3] = pl->irqPeriod[processor] / total * 100.0; - this->values[4] = pl->softIrqPeriod[processor] / total * 100.0; - this->values[5] = pl->ioWaitPeriod[processor] / total * 100.0; - this->type->items = 6; - cpu = MIN(100.0, MAX(0.0, (this->values[0]+this->values[1]+this->values[2]+ + this->values[2] = cpuData->systemPeriod / total * 100.0; + this->values[3] = cpuData->irqPeriod / total * 100.0; + this->values[4] = cpuData->softIrqPeriod / total * 100.0; + this->values[5] = cpuData->ioWaitPeriod / total * 100.0; + this->values[6] = cpuData->stealPeriod / total * 100.0; + this->values[7] = cpuData->guestPeriod / total * 100.0; + this->type->items = 8; + percent = MIN(100.0, MAX(0.0, (this->values[0]+this->values[1]+this->values[2]+ this->values[3]+this->values[4]))); } else { - this->values[2] = pl->systemAllPeriod[processor] / total * 100.0; - this->type->items = 3; - cpu = MIN(100.0, MAX(0.0, (this->values[0]+this->values[1]+this->values[2]))); + this->values[2] = cpuData->systemAllPeriod / total * 100.0; + this->values[3] = (cpuData->stealPeriod + cpuData->guestPeriod) / total * 100.0; + this->type->items = 4; + percent = MIN(100.0, MAX(0.0, (this->values[0]+this->values[1]+this->values[2]+this->values[3]))); } - if (isnan(cpu)) cpu = 0.0; - snprintf(buffer, size, "%5.1f%%", cpu ); + if (isnan(percent)) percent = 0.0; + snprintf(buffer, size, "%5.1f%%", percent); } static void CPUMeter_display(Object* cast, RichString* out) { char buffer[50]; Meter* this = (Meter*)cast; RichString_init(out); - if (this->param > this->pl->processorCount) { + if (this->param > this->pl->cpuCount) { RichString_append(out, CRT_colors[METER_TEXT], "absent"); return; } @@ -95,6 +99,14 @@ static void CPUMeter_display(Object* cast, RichString* out) { sprintf(buffer, "%5.1f%% ", this->values[5]); RichString_append(out, CRT_colors[METER_TEXT], "wa:"); RichString_append(out, CRT_colors[CPU_IOWAIT], buffer); + sprintf(buffer, "%5.1f%% ", this->values[6]); + RichString_append(out, CRT_colors[METER_TEXT], "st:"); + RichString_append(out, CRT_colors[CPU_STEAL], buffer); + if (this->values[7]) { + sprintf(buffer, "%5.1f%% ", this->values[7]); + RichString_append(out, CRT_colors[METER_TEXT], "gu:"); + RichString_append(out, CRT_colors[CPU_GUEST], buffer); + } } else { sprintf(buffer, "%5.1f%% ", this->values[2]); RichString_append(out, CRT_colors[METER_TEXT], "sys:"); @@ -102,37 +114,42 @@ static void CPUMeter_display(Object* cast, RichString* out) { sprintf(buffer, "%5.1f%% ", this->values[0]); RichString_append(out, CRT_colors[METER_TEXT], "low:"); RichString_append(out, CRT_colors[CPU_NICE], buffer); + if (this->values[3]) { + sprintf(buffer, "%5.1f%% ", this->values[3]); + RichString_append(out, CRT_colors[METER_TEXT], "vir:"); + RichString_append(out, CRT_colors[CPU_GUEST], buffer); + } } } static void AllCPUsMeter_init(Meter* this) { - int processors = this->pl->processorCount; - this->drawBuffer = malloc(sizeof(Meter*) * processors); + int cpus = this->pl->cpuCount; + this->drawBuffer = malloc(sizeof(Meter*) * cpus); Meter** meters = (Meter**) this->drawBuffer; - for (int i = 0; i < processors; i++) + for (int i = 0; i < cpus; i++) meters[i] = Meter_new(this->pl, i+1, &CPUMeter); - this->h = processors; + this->h = cpus; this->mode = BAR_METERMODE; } static void AllCPUsMeter_done(Meter* this) { - int processors = this->pl->processorCount; + int cpus = this->pl->cpuCount; Meter** meters = (Meter**) this->drawBuffer; - for (int i = 0; i < processors; i++) + for (int i = 0; i < cpus; i++) Meter_delete((Object*)meters[i]); } static void AllCPUsMeter_setMode(Meter* this, int mode) { this->mode = mode; - int processors = this->pl->processorCount; + int cpus = this->pl->cpuCount; int h = Meter_modes[this->mode]->h; - this->h = h * processors; + this->h = h * cpus; } static void AllCPUsMeter_draw(Meter* this, int x, int y, int w) { - int processors = this->pl->processorCount; + int cpus = this->pl->cpuCount; Meter** meters = (Meter**) this->drawBuffer; - for (int i = 0; i < processors; i++) { + for (int i = 0; i < cpus; i++) { Meter_setMode(meters[i], this->mode); meters[i]->draw(meters[i], x, y, w); y += meters[i]->h; @@ -143,7 +160,7 @@ MeterType CPUMeter = { .setValues = CPUMeter_setValues, .display = CPUMeter_display, .mode = BAR_METERMODE, - .items = 6, + .items = 8, .total = 100.0, .attributes = CPUMeter_attributes, .name = "CPU", diff --git a/CRT.c b/CRT.c index 22bc248c..a9811aab 100644 --- a/CRT.c +++ b/CRT.c @@ -11,6 +11,7 @@ in the source distribution for its full text. #include #include #include +#include #include "String.h" @@ -93,14 +94,16 @@ typedef enum ColorElements_ { CHECK_MARK, CHECK_TEXT, CLOCK, + HELP_BOLD, + HOSTNAME, CPU_NICE, CPU_NORMAL, CPU_KERNEL, - HELP_BOLD, CPU_IOWAIT, CPU_IRQ, CPU_SOFTIRQ, - HOSTNAME, + CPU_STEAL, + CPU_GUEST, LAST_COLORELEMENT } ColorElements; @@ -116,11 +119,16 @@ int CRT_colors[LAST_COLORELEMENT] = { 0 }; char* CRT_termType; +void *backtraceArray[128]; + static void CRT_handleSIGSEGV(int sgn) { (void) sgn; CRT_done(); - fprintf(stderr, "htop " VERSION " aborted. Please report bug at http://htop.sf.net\n"); - exit(1); + fprintf(stderr, "\n\nhtop " VERSION " aborting. Please report bug at http://htop.sf.net\n"); + size_t size = backtrace(backtraceArray, sizeof(backtraceArray)); + fprintf(stderr, "Backtrace: \n"); + backtrace_symbols_fd(backtraceArray, size, 2); + abort(); } static void CRT_handleSIGTERM(int sgn) { @@ -257,17 +265,19 @@ void CRT_setColors(int colorScheme) { CRT_colors[LOAD_AVERAGE_ONE] = A_BOLD; CRT_colors[LOAD] = A_BOLD; CRT_colors[HELP_BOLD] = A_BOLD; - CRT_colors[CPU_NICE] = A_NORMAL; - CRT_colors[CPU_NORMAL] = A_BOLD; - CRT_colors[CPU_KERNEL] = A_BOLD; CRT_colors[CLOCK] = A_BOLD; CRT_colors[CHECK_BOX] = A_BOLD; CRT_colors[CHECK_MARK] = A_NORMAL; CRT_colors[CHECK_TEXT] = A_NORMAL; + CRT_colors[HOSTNAME] = A_BOLD; + CRT_colors[CPU_NICE] = A_NORMAL; + CRT_colors[CPU_NORMAL] = A_BOLD; + CRT_colors[CPU_KERNEL] = A_BOLD; CRT_colors[CPU_IOWAIT] = A_NORMAL; CRT_colors[CPU_IRQ] = A_BOLD; CRT_colors[CPU_SOFTIRQ] = A_BOLD; - CRT_colors[HOSTNAME] = A_BOLD; + CRT_colors[CPU_STEAL] = A_REVERSE; + CRT_colors[CPU_GUEST] = A_REVERSE; } else if (CRT_colorScheme == COLORSCHEME_BLACKONWHITE) { CRT_colors[RESET_COLOR] = ColorPair(Black,White); CRT_colors[DEFAULT_COLOR] = ColorPair(Black,White); @@ -316,17 +326,19 @@ void CRT_setColors(int colorScheme) { CRT_colors[LOAD_AVERAGE_ONE] = ColorPair(Black,White); CRT_colors[LOAD] = ColorPair(Black,White); CRT_colors[HELP_BOLD] = ColorPair(Blue,White); - CRT_colors[CPU_NICE] = ColorPair(Cyan,White); - CRT_colors[CPU_NORMAL] = ColorPair(Green,White); - CRT_colors[CPU_KERNEL] = ColorPair(Red,White); CRT_colors[CLOCK] = ColorPair(Black,White); CRT_colors[CHECK_BOX] = ColorPair(Blue,White); CRT_colors[CHECK_MARK] = ColorPair(Black,White); CRT_colors[CHECK_TEXT] = ColorPair(Black,White); + CRT_colors[HOSTNAME] = ColorPair(Black,White); + CRT_colors[CPU_NICE] = ColorPair(Cyan,White); + CRT_colors[CPU_NORMAL] = ColorPair(Green,White); + CRT_colors[CPU_KERNEL] = ColorPair(Red,White); CRT_colors[CPU_IOWAIT] = A_BOLD | ColorPair(Black, Black); CRT_colors[CPU_IRQ] = ColorPair(Blue,White); CRT_colors[CPU_SOFTIRQ] = ColorPair(Blue,White); - CRT_colors[HOSTNAME] = ColorPair(Black,White); + CRT_colors[CPU_STEAL] = ColorPair(Cyan,White); + CRT_colors[CPU_GUEST] = ColorPair(Cyan,White); } else if (CRT_colorScheme == COLORSCHEME_BLACKONWHITE2) { CRT_colors[RESET_COLOR] = ColorPair(Black,Black); CRT_colors[DEFAULT_COLOR] = ColorPair(Black,Black); @@ -375,17 +387,19 @@ void CRT_setColors(int colorScheme) { CRT_colors[LOAD_AVERAGE_ONE] = ColorPair(Black,Black); CRT_colors[LOAD] = ColorPair(White,Black); CRT_colors[HELP_BOLD] = ColorPair(Blue,Black); - CRT_colors[CPU_NICE] = ColorPair(Cyan,Black); - CRT_colors[CPU_NORMAL] = ColorPair(Green,Black); - CRT_colors[CPU_KERNEL] = ColorPair(Red,Black); CRT_colors[CLOCK] = ColorPair(White,Black); CRT_colors[CHECK_BOX] = ColorPair(Blue,Black); CRT_colors[CHECK_MARK] = ColorPair(Black,Black); CRT_colors[CHECK_TEXT] = ColorPair(Black,Black); + CRT_colors[HOSTNAME] = ColorPair(White,Black); + CRT_colors[CPU_NICE] = ColorPair(Cyan,Black); + CRT_colors[CPU_NORMAL] = ColorPair(Green,Black); + CRT_colors[CPU_KERNEL] = ColorPair(Red,Black); CRT_colors[CPU_IOWAIT] = A_BOLD | ColorPair(Black, Black); CRT_colors[CPU_IRQ] = A_BOLD | ColorPair(Blue,Black); CRT_colors[CPU_SOFTIRQ] = ColorPair(Blue,Black); - CRT_colors[HOSTNAME] = ColorPair(White,Black); + CRT_colors[CPU_STEAL] = ColorPair(Black,Black); + CRT_colors[CPU_GUEST] = ColorPair(Black,Black); } else if (CRT_colorScheme == COLORSCHEME_MIDNIGHT) { CRT_colors[RESET_COLOR] = ColorPair(White,Blue); CRT_colors[DEFAULT_COLOR] = ColorPair(White,Blue); @@ -434,17 +448,19 @@ void CRT_setColors(int colorScheme) { CRT_colors[LOAD_AVERAGE_ONE] = A_BOLD | ColorPair(White,Blue); CRT_colors[LOAD] = A_BOLD | ColorPair(White,Blue); CRT_colors[HELP_BOLD] = A_BOLD | ColorPair(Cyan,Blue); - CRT_colors[CPU_NICE] = A_BOLD | ColorPair(Cyan,Blue); - CRT_colors[CPU_NORMAL] = A_BOLD | ColorPair(Green,Blue); - CRT_colors[CPU_KERNEL] = A_BOLD | ColorPair(Red,Blue); CRT_colors[CLOCK] = ColorPair(White,Blue); CRT_colors[CHECK_BOX] = ColorPair(Cyan,Blue); CRT_colors[CHECK_MARK] = A_BOLD | ColorPair(White,Blue); CRT_colors[CHECK_TEXT] = A_NORMAL | ColorPair(White,Blue); - CRT_colors[CPU_IOWAIT] = ColorPair(Yellow,Blue); + CRT_colors[HOSTNAME] = ColorPair(White,Blue); + CRT_colors[CPU_NICE] = A_BOLD | ColorPair(Cyan,Blue); + CRT_colors[CPU_NORMAL] = A_BOLD | ColorPair(Green,Blue); + CRT_colors[CPU_KERNEL] = A_BOLD | ColorPair(Red,Blue); + CRT_colors[CPU_IOWAIT] = A_BOLD | ColorPair(Blue,Blue); CRT_colors[CPU_IRQ] = A_BOLD | ColorPair(Black,Blue); CRT_colors[CPU_SOFTIRQ] = ColorPair(Black,Blue); - CRT_colors[HOSTNAME] = ColorPair(White,Blue); + CRT_colors[CPU_STEAL] = ColorPair(White,Blue); + CRT_colors[CPU_GUEST] = ColorPair(White,Blue); } else if (CRT_colorScheme == COLORSCHEME_BLACKNIGHT) { CRT_colors[RESET_COLOR] = ColorPair(Cyan,Black); CRT_colors[DEFAULT_COLOR] = ColorPair(Cyan,Black); @@ -493,17 +509,19 @@ void CRT_setColors(int colorScheme) { CRT_colors[LOAD_AVERAGE_ONE] = A_BOLD | ColorPair(Green,Black); CRT_colors[LOAD] = A_BOLD; CRT_colors[HELP_BOLD] = A_BOLD | ColorPair(Cyan,Black); - CRT_colors[CPU_NICE] = ColorPair(Blue,Black); - CRT_colors[CPU_NORMAL] = ColorPair(Green,Black); - CRT_colors[CPU_KERNEL] = ColorPair(Red,Black); CRT_colors[CLOCK] = ColorPair(Green,Black); CRT_colors[CHECK_BOX] = ColorPair(Green,Black); CRT_colors[CHECK_MARK] = A_BOLD | ColorPair(Green,Black); CRT_colors[CHECK_TEXT] = ColorPair(Cyan,Black); + CRT_colors[HOSTNAME] = ColorPair(Green,Black); + CRT_colors[CPU_NICE] = ColorPair(Blue,Black); + CRT_colors[CPU_NORMAL] = ColorPair(Green,Black); + CRT_colors[CPU_KERNEL] = ColorPair(Red,Black); CRT_colors[CPU_IOWAIT] = ColorPair(Yellow,Black); CRT_colors[CPU_IRQ] = A_BOLD | ColorPair(Blue,Black); CRT_colors[CPU_SOFTIRQ] = ColorPair(Blue,Black); - CRT_colors[HOSTNAME] = ColorPair(Green,Black); + CRT_colors[CPU_STEAL] = ColorPair(Cyan,Black); + CRT_colors[CPU_GUEST] = ColorPair(Cyan,Black); } else { /* Default */ CRT_colors[RESET_COLOR] = ColorPair(White,Black); @@ -553,16 +571,18 @@ void CRT_setColors(int colorScheme) { CRT_colors[LOAD_AVERAGE_ONE] = A_BOLD; CRT_colors[LOAD] = A_BOLD; CRT_colors[HELP_BOLD] = A_BOLD | ColorPair(Cyan,Black); - CRT_colors[CPU_NICE] = ColorPair(Blue,Black); - CRT_colors[CPU_NORMAL] = ColorPair(Green,Black); - CRT_colors[CPU_KERNEL] = ColorPair(Red,Black); CRT_colors[CLOCK] = A_BOLD; CRT_colors[CHECK_BOX] = ColorPair(Cyan,Black); CRT_colors[CHECK_MARK] = A_BOLD; CRT_colors[CHECK_TEXT] = A_NORMAL; + CRT_colors[HOSTNAME] = A_BOLD; + CRT_colors[CPU_NICE] = ColorPair(Blue,Black); + CRT_colors[CPU_NORMAL] = ColorPair(Green,Black); + CRT_colors[CPU_KERNEL] = ColorPair(Red,Black); CRT_colors[CPU_IOWAIT] = A_BOLD | ColorPair(Black, Black); CRT_colors[CPU_IRQ] = ColorPair(Yellow,Black); CRT_colors[CPU_SOFTIRQ] = ColorPair(Magenta,Black); - CRT_colors[HOSTNAME] = A_BOLD; + CRT_colors[CPU_STEAL] = ColorPair(Cyan,Black); + CRT_colors[CPU_GUEST] = ColorPair(Cyan,Black); } } diff --git a/CRT.h b/CRT.h index ef992b59..3a60a0e8 100644 --- a/CRT.h +++ b/CRT.h @@ -14,6 +14,7 @@ in the source distribution for its full text. #include #include #include +#include #include "String.h" @@ -95,14 +96,16 @@ typedef enum ColorElements_ { CHECK_MARK, CHECK_TEXT, CLOCK, + HELP_BOLD, + HOSTNAME, CPU_NICE, CPU_NORMAL, CPU_KERNEL, - HELP_BOLD, CPU_IOWAIT, CPU_IRQ, CPU_SOFTIRQ, - HOSTNAME, + CPU_STEAL, + CPU_GUEST, LAST_COLORELEMENT } ColorElements; @@ -117,6 +120,8 @@ extern int CRT_colors[LAST_COLORELEMENT]; char* CRT_termType; +void *backtraceArray[128]; + // TODO: pass an instance of Settings instead. void CRT_init(int delay, int colorScheme); diff --git a/DisplayOptionsPanel.c b/DisplayOptionsPanel.c index ebaa9953..2f3b9d86 100644 --- a/DisplayOptionsPanel.c +++ b/DisplayOptionsPanel.c @@ -73,6 +73,6 @@ DisplayOptionsPanel* DisplayOptionsPanel_new(Settings* settings, ScreenManager* Panel_add(super, (Object*) CheckItem_new(String_copy("Highlight program \"basename\""), &(settings->pl->highlightBaseName), false)); Panel_add(super, (Object*) CheckItem_new(String_copy("Highlight megabytes in memory counters"), &(settings->pl->highlightMegabytes), false)); Panel_add(super, (Object*) CheckItem_new(String_copy("Leave a margin around header"), &(settings->header->margin), false)); - Panel_add(super, (Object*) CheckItem_new(String_copy("Detailed CPU time (System/IO-Wait/Hard-IRQ/Soft-IRQ)"), &(settings->pl->detailedCPUTime), false)); + Panel_add(super, (Object*) CheckItem_new(String_copy("Detailed CPU time (System/IO-Wait/Hard-IRQ/Soft-IRQ/Steal/Guest)"), &(settings->pl->detailedCPUTime), false)); return this; } diff --git a/Makefile.am b/Makefile.am index cd274394..2dbbd51a 100644 --- a/Makefile.am +++ b/Makefile.am @@ -12,7 +12,7 @@ applications_DATA = htop.desktop pixmapdir = $(datadir)/pixmaps pixmap_DATA = htop.png -htop_CFLAGS = -pedantic -Wall -std=c99 -D_XOPEN_SOURCE_EXTENDED +htop_CFLAGS = -pedantic -Wall -std=c99 -rdynamic -D_XOPEN_SOURCE_EXTENDED AM_CPPFLAGS = -DSYSCONFDIR=\"$(sysconfdir)\" myhtopsources = AvailableMetersPanel.c CategoriesPanel.c CheckItem.c \ diff --git a/OpenFilesScreen.c b/OpenFilesScreen.c index df67f127..7a574707 100644 --- a/OpenFilesScreen.c +++ b/OpenFilesScreen.c @@ -43,17 +43,17 @@ typedef struct OpenFilesScreen_ { }*/ -static const char* tbFunctions[] = {"Refresh", "Done ", NULL}; +static const char* ofsFunctions[] = {"Refresh", "Done ", NULL}; -static const char* tbKeys[] = {"F5", "Esc"}; +static const char* ofsKeys[] = {"F5", "Esc"}; -static int tbEvents[] = {KEY_F(5), 27}; +static int ofsEvents[] = {KEY_F(5), 27}; OpenFilesScreen* OpenFilesScreen_new(Process* process) { OpenFilesScreen* this = (OpenFilesScreen*) malloc(sizeof(OpenFilesScreen)); this->process = process; this->display = Panel_new(0, 1, COLS, LINES-3, LISTITEM_CLASS, true, ListItem_compare); - this->bar = FunctionBar_new(tbFunctions, tbKeys, tbEvents); + this->bar = FunctionBar_new(ofsFunctions, ofsKeys, ofsEvents); this->tracing = true; return this; } diff --git a/Process.c b/Process.c index 6389f741..0fb175ea 100644 --- a/Process.c +++ b/Process.c @@ -471,27 +471,6 @@ Process* Process_new(struct ProcessList_ *pl) { return this; } -Process* Process_clone(Process* this) { - Process* copy = malloc(sizeof(Process)); - #if HAVE_TASKSTATS - this->io_rchar = 0; - this->io_wchar = 0; - this->io_syscr = 0; - this->io_syscw = 0; - this->io_read_bytes = 0; - this->io_rate_read_bps = 0; - this->io_rate_read_time = 0; - this->io_write_bytes = 0; - this->io_rate_write_bps = 0; - this->io_rate_write_time = 0; - this->io_cancelled_write_bytes = 0; - #endif - memcpy(copy, this, sizeof(Process)); - this->comm = NULL; - this->pid = 0; - return copy; -} - void Process_toggleTag(Process* this) { this->tag = this->tag == true ? false : true; } diff --git a/Process.h b/Process.h index d3488165..922afdd6 100644 --- a/Process.h +++ b/Process.h @@ -176,8 +176,6 @@ void Process_delete(Object* cast); Process* Process_new(struct ProcessList_ *pl); -Process* Process_clone(Process* this); - void Process_toggleTag(Process* this); bool Process_setPriority(Process* this, int priority); diff --git a/ProcessList.c b/ProcessList.c index d5af4d05..d65baef5 100644 --- a/ProcessList.c +++ b/ProcessList.c @@ -33,6 +33,7 @@ in the source distribution for its full text. #include /*{ + #ifndef PROCDIR #define PROCDIR "/proc" #endif @@ -53,10 +54,6 @@ in the source distribution for its full text. #define MAX_READ 2048 #endif -#ifndef PER_PROCESSOR_FIELDS -#define PER_PROCESSOR_FIELDS 22 -#endif - }*/ /*{ @@ -65,40 +62,45 @@ in the source distribution for its full text. typedef int(*vxscanf)(void*, const char*, va_list); #endif +typedef struct CPUData_ { + unsigned long long int totalTime; + unsigned long long int userTime; + unsigned long long int systemTime; + unsigned long long int systemAllTime; + unsigned long long int idleAllTime; + unsigned long long int idleTime; + unsigned long long int niceTime; + unsigned long long int ioWaitTime; + unsigned long long int irqTime; + unsigned long long int softIrqTime; + unsigned long long int stealTime; + unsigned long long int guestTime; + + unsigned long long int totalPeriod; + unsigned long long int userPeriod; + unsigned long long int systemPeriod; + unsigned long long int systemAllPeriod; + unsigned long long int idleAllPeriod; + unsigned long long int idlePeriod; + unsigned long long int nicePeriod; + unsigned long long int ioWaitPeriod; + unsigned long long int irqPeriod; + unsigned long long int softIrqPeriod; + unsigned long long int stealPeriod; + unsigned long long int guestPeriod; +} CPUData; + typedef struct ProcessList_ { Vector* processes; Vector* processes2; Hashtable* processTable; - Process* prototype; UsersTable* usersTable; - int processorCount; + int cpuCount; int totalTasks; int runningTasks; - // Must match number of PER_PROCESSOR_FIELDS constant - unsigned long long int* totalTime; - unsigned long long int* userTime; - unsigned long long int* systemTime; - unsigned long long int* systemAllTime; - unsigned long long int* idleAllTime; - unsigned long long int* idleTime; - unsigned long long int* niceTime; - unsigned long long int* ioWaitTime; - unsigned long long int* irqTime; - unsigned long long int* softIrqTime; - unsigned long long int* stealTime; - unsigned long long int* totalPeriod; - unsigned long long int* userPeriod; - unsigned long long int* systemPeriod; - unsigned long long int* systemAllPeriod; - unsigned long long int* idleAllPeriod; - unsigned long long int* idlePeriod; - unsigned long long int* nicePeriod; - unsigned long long int* ioWaitPeriod; - unsigned long long int* irqPeriod; - unsigned long long int* softIrqPeriod; - unsigned long long int* stealPeriod; + CPUData* cpus; unsigned long long int totalMem; unsigned long long int usedMem; @@ -195,23 +197,12 @@ static inline int ProcessList_xread(ProcessList* this, vxscanf fn, void* buffer, #endif -static inline void ProcessList_allocatePerProcessorBuffers(ProcessList* this, int procs) { - unsigned long long int** bufferPtr = &(this->totalTime); - unsigned long long int* buffer = calloc(procs * PER_PROCESSOR_FIELDS, sizeof(unsigned long long int)); - for (int i = 0; i < PER_PROCESSOR_FIELDS; i++) { - *bufferPtr = buffer; - bufferPtr++; - buffer += procs; - } -} - ProcessList* ProcessList_new(UsersTable* usersTable) { ProcessList* this; this = malloc(sizeof(ProcessList)); this->processes = Vector_new(PROCESS_CLASS, true, DEFAULT_SIZE, Process_compare); this->processTable = Hashtable_new(70, false); assert(Hashtable_count(this->processTable) == Vector_count(this->processes)); - this->prototype = Process_new(this); this->usersTable = usersTable; /* tree-view auxiliary buffers */ @@ -224,19 +215,19 @@ ProcessList* ProcessList_new(UsersTable* usersTable) { FILE* status = fopen(PROCSTATFILE, "r"); assert(status != NULL); char buffer[256]; - int procs = -1; + int cpus = -1; do { - procs++; + cpus++; fgets(buffer, 255, status); } while (String_startsWith(buffer, "cpu")); fclose(status); - this->processorCount = procs - 1; + this->cpuCount = cpus - 1; - ProcessList_allocatePerProcessorBuffers(this, procs); + this->cpus = calloc(sizeof(CPUData), cpus); - for (int i = 0; i < procs; i++) { - this->totalTime[i] = 1; - this->totalPeriod[i] = 1; + for (int i = 0; i < cpus; i++) { + this->cpus[i].totalTime = 1; + this->cpus[i].totalPeriod = 1; } this->fields = calloc(sizeof(ProcessField), LAST_PROCESSFIELD+1); @@ -265,11 +256,8 @@ void ProcessList_delete(ProcessList* this) { Hashtable_delete(this->processTable); Vector_delete(this->processes); Vector_delete(this->processes2); - Process_delete((Object*)this->prototype); - // Free first entry only; - // other fields are offsets of the same buffer - free(this->totalTime); + free(this->cpus); #ifdef DEBUG_PROC fclose(this->traceFile); @@ -303,8 +291,10 @@ RichString ProcessList_printHeader(ProcessList* this) { static void ProcessList_add(ProcessList* this, Process* p) { assert(Vector_indexOf(this->processes, p, Process_pidCompare) == -1); assert(Hashtable_get(this->processTable, p->pid) == NULL); + Vector_add(this->processes, p); Hashtable_put(this->processTable, p->pid, p); + assert(Vector_indexOf(this->processes, p, Process_pidCompare) != -1); assert(Hashtable_get(this->processTable, p->pid) != NULL); assert(Hashtable_count(this->processTable) == Vector_count(this->processes)); @@ -357,7 +347,7 @@ static void ProcessList_buildTree(ProcessList* this, pid_t pid, int level, int i ProcessList_buildTree(this, process->pid, level+1, nextIndent, direction, process->showChildren); process->indent = indent | (1 << level); } else { - Hashtable_remove(this->processTable, process->pid); + ProcessList_remove(this, process); } } Vector_delete(children); @@ -532,11 +522,10 @@ static void ProcessList_readIoFile(Process* proc, const char* dirname, char* nam static bool ProcessList_processEntries(ProcessList* this, const char* dirname, Process* parent, pid_t parentPid, float period) { DIR* dir; struct dirent* entry; - Process* prototype = this->prototype; dir = opendir(dirname); if (!dir) return false; - int processors = this->processorCount; + int cpus = this->cpuCount; bool showUserlandThreads = !this->hideUserlandThreads; while ((entry = readdir(dir)) != NULL) { char* name = entry->d_name; @@ -571,7 +560,7 @@ static bool ProcessList_processEntries(ProcessList* this, const char* dirname, P if (parent && parent->pid == pid) { process = parent; } else { - process = prototype; + process = Process_new(this); assert(process->comm == NULL); process->pid = pid; } @@ -703,14 +692,16 @@ static bool ProcessList_processEntries(ProcessList* this, const char* dirname, P } fclose(status); command[PROCESS_COMM_LEN] = '\0'; + free(process->comm); process->comm = String_copy(command); } else if (pid != parentPid && this->showThreadNames) { + free(process->comm); process->comm = String_copy(command); } int percent_cpu = (process->utime + process->stime - lasttimes) / period * 100.0; - process->percent_cpu = MAX(MIN(percent_cpu, processors*100.0), 0.0); + process->percent_cpu = MAX(MIN(percent_cpu, cpus*100.0), 0.0); if (isnan(process->percent_cpu)) process->percent_cpu = 0.0; process->percent_mem = (process->m_resident * PAGE_SIZE_KB) / @@ -723,10 +714,8 @@ static bool ProcessList_processEntries(ProcessList* this, const char* dirname, P } if (!existingProcess) { - process = Process_clone(process); ProcessList_add(this, process); } - continue; // Exception handler. @@ -737,7 +726,8 @@ static bool ProcessList_processEntries(ProcessList* this, const char* dirname, P } if (existingProcess) ProcessList_remove(this, process); - assert(Hashtable_count(this->processTable) == Vector_count(this->processes)); + else + Process_delete((Object*)process); } } } @@ -746,13 +736,13 @@ static bool ProcessList_processEntries(ProcessList* this, const char* dirname, P } void ProcessList_scan(ProcessList* this) { - unsigned long long int usertime, nicetime, systemtime, systemalltime, idlealltime, idletime, totaltime; + unsigned long long int usertime, nicetime, systemtime, systemalltime, idlealltime, idletime, totaltime, virtalltime; unsigned long long int swapFree = 0; FILE* status; status = ProcessList_fopen(this, PROCMEMINFOFILE, "r"); assert(status != NULL); - int processors = this->processorCount; + int cpus = this->cpuCount; { char buffer[128]; while (fgets(buffer, 128, status)) { @@ -791,62 +781,66 @@ void ProcessList_scan(ProcessList* this) { status = ProcessList_fopen(this, PROCSTATFILE, "r"); assert(status != NULL); - for (int i = 0; i <= processors; i++) { + for (int i = 0; i <= cpus; i++) { char buffer[256]; int cpuid; - unsigned long long int ioWait, irq, softIrq, steal; - ioWait = irq = softIrq = steal = 0; + unsigned long long int ioWait, irq, softIrq, steal, guest; + ioWait = irq = softIrq = steal = guest = 0; // Dependending on your kernel version, // 5, 7 or 8 of these fields will be set. // The rest will remain at zero. fgets(buffer, 255, status); if (i == 0) - ProcessList_read(this, buffer, "cpu %llu %llu %llu %llu %llu %llu %llu %llu", &usertime, &nicetime, &systemtime, &idletime, &ioWait, &irq, &softIrq, &steal); + ProcessList_read(this, buffer, "cpu %llu %llu %llu %llu %llu %llu %llu %llu %llu", &usertime, &nicetime, &systemtime, &idletime, &ioWait, &irq, &softIrq, &steal, &guest); else { - ProcessList_read(this, buffer, "cpu%d %llu %llu %llu %llu %llu %llu %llu %llu", &cpuid, &usertime, &nicetime, &systemtime, &idletime, &ioWait, &irq, &softIrq, &steal); + ProcessList_read(this, buffer, "cpu%d %llu %llu %llu %llu %llu %llu %llu %llu %llu", &cpuid, &usertime, &nicetime, &systemtime, &idletime, &ioWait, &irq, &softIrq, &steal, &guest); assert(cpuid == i - 1); } // Fields existing on kernels >= 2.6 // (and RHEL's patched kernel 2.4...) idlealltime = idletime + ioWait; - systemalltime = systemtime + irq + softIrq + steal; - totaltime = usertime + nicetime + systemalltime + idlealltime; - assert (usertime >= this->userTime[i]); - assert (nicetime >= this->niceTime[i]); - assert (systemtime >= this->systemTime[i]); - assert (idletime >= this->idleTime[i]); - assert (totaltime >= this->totalTime[i]); - assert (systemalltime >= this->systemAllTime[i]); - assert (idlealltime >= this->idleAllTime[i]); - assert (ioWait >= this->ioWaitTime[i]); - assert (irq >= this->irqTime[i]); - assert (softIrq >= this->softIrqTime[i]); - assert (steal >= this->stealTime[i]); - this->userPeriod[i] = usertime - this->userTime[i]; - this->nicePeriod[i] = nicetime - this->niceTime[i]; - this->systemPeriod[i] = systemtime - this->systemTime[i]; - this->systemAllPeriod[i] = systemalltime - this->systemAllTime[i]; - this->idleAllPeriod[i] = idlealltime - this->idleAllTime[i]; - this->idlePeriod[i] = idletime - this->idleTime[i]; - this->ioWaitPeriod[i] = ioWait - this->ioWaitTime[i]; - this->irqPeriod[i] = irq - this->irqTime[i]; - this->softIrqPeriod[i] = softIrq - this->softIrqTime[i]; - this->stealPeriod[i] = steal - this->stealTime[i]; - this->totalPeriod[i] = totaltime - this->totalTime[i]; - this->userTime[i] = usertime; - this->niceTime[i] = nicetime; - this->systemTime[i] = systemtime; - this->systemAllTime[i] = systemalltime; - this->idleAllTime[i] = idlealltime; - this->idleTime[i] = idletime; - this->ioWaitTime[i] = ioWait; - this->irqTime[i] = irq; - this->softIrqTime[i] = softIrq; - this->stealTime[i] = steal; - this->totalTime[i] = totaltime; + systemalltime = systemtime + irq + softIrq; + virtalltime = steal + guest; + totaltime = usertime + nicetime + systemalltime + idlealltime + virtalltime; + CPUData* cpuData = &(this->cpus[i]); + assert (usertime >= cpuData->userTime); + assert (nicetime >= cpuData->niceTime); + assert (systemtime >= cpuData->systemTime); + assert (idletime >= cpuData->idleTime); + assert (totaltime >= cpuData->totalTime); + assert (systemalltime >= cpuData->systemAllTime); + assert (idlealltime >= cpuData->idleAllTime); + assert (ioWait >= cpuData->ioWaitTime); + assert (irq >= cpuData->irqTime); + assert (softIrq >= cpuData->softIrqTime); + assert (steal >= cpuData->stealTime); + assert (guest >= cpuData->guestTime); + cpuData->userPeriod = usertime - cpuData->userTime; + cpuData->nicePeriod = nicetime - cpuData->niceTime; + cpuData->systemPeriod = systemtime - cpuData->systemTime; + cpuData->systemAllPeriod = systemalltime - cpuData->systemAllTime; + cpuData->idleAllPeriod = idlealltime - cpuData->idleAllTime; + cpuData->idlePeriod = idletime - cpuData->idleTime; + cpuData->ioWaitPeriod = ioWait - cpuData->ioWaitTime; + cpuData->irqPeriod = irq - cpuData->irqTime; + cpuData->softIrqPeriod = softIrq - cpuData->softIrqTime; + cpuData->stealPeriod = steal - cpuData->stealTime; + cpuData->guestPeriod = guest - cpuData->guestTime; + cpuData->totalPeriod = totaltime - cpuData->totalTime; + cpuData->userTime = usertime; + cpuData->niceTime = nicetime; + cpuData->systemTime = systemtime; + cpuData->systemAllTime = systemalltime; + cpuData->idleAllTime = idlealltime; + cpuData->idleTime = idletime; + cpuData->ioWaitTime = ioWait; + cpuData->irqTime = irq; + cpuData->softIrqTime = softIrq; + cpuData->stealTime = steal; + cpuData->guestTime = guest; + cpuData->totalTime = totaltime; } - float period = (float)this->totalPeriod[0] / processors; - fclose(status); + float period = (float)this->cpus[0].totalPeriod / cpus; fclose(status); // mark all process as "dirty" for (int i = 0; i < Vector_size(this->processes); i++) { @@ -884,3 +878,11 @@ ProcessField ProcessList_keyAt(ProcessList* this, int at) { } return COMM; } + +void ProcessList_expandTree(ProcessList* this) { + int size = Vector_size(this->processes); + for (int i = 0; i < size; i++) { + Process* process = (Process*) Vector_get(this->processes, i); + process->showChildren = true; + } +} diff --git a/ProcessList.h b/ProcessList.h index 509dfce0..48456def 100644 --- a/ProcessList.h +++ b/ProcessList.h @@ -35,6 +35,7 @@ in the source distribution for its full text. #include "debug.h" #include + #ifndef PROCDIR #define PROCDIR "/proc" #endif @@ -55,50 +56,51 @@ in the source distribution for its full text. #define MAX_READ 2048 #endif -#ifndef PER_PROCESSOR_FIELDS -#define PER_PROCESSOR_FIELDS 22 -#endif - #ifdef DEBUG_PROC typedef int(*vxscanf)(void*, const char*, va_list); #endif +typedef struct CPUData_ { + unsigned long long int totalTime; + unsigned long long int userTime; + unsigned long long int systemTime; + unsigned long long int systemAllTime; + unsigned long long int idleAllTime; + unsigned long long int idleTime; + unsigned long long int niceTime; + unsigned long long int ioWaitTime; + unsigned long long int irqTime; + unsigned long long int softIrqTime; + unsigned long long int stealTime; + unsigned long long int guestTime; + + unsigned long long int totalPeriod; + unsigned long long int userPeriod; + unsigned long long int systemPeriod; + unsigned long long int systemAllPeriod; + unsigned long long int idleAllPeriod; + unsigned long long int idlePeriod; + unsigned long long int nicePeriod; + unsigned long long int ioWaitPeriod; + unsigned long long int irqPeriod; + unsigned long long int softIrqPeriod; + unsigned long long int stealPeriod; + unsigned long long int guestPeriod; +} CPUData; + typedef struct ProcessList_ { Vector* processes; Vector* processes2; Hashtable* processTable; - Process* prototype; UsersTable* usersTable; - int processorCount; + int cpuCount; int totalTasks; int runningTasks; - // Must match number of PER_PROCESSOR_FIELDS constant - unsigned long long int* totalTime; - unsigned long long int* userTime; - unsigned long long int* systemTime; - unsigned long long int* systemAllTime; - unsigned long long int* idleAllTime; - unsigned long long int* idleTime; - unsigned long long int* niceTime; - unsigned long long int* ioWaitTime; - unsigned long long int* irqTime; - unsigned long long int* softIrqTime; - unsigned long long int* stealTime; - unsigned long long int* totalPeriod; - unsigned long long int* userPeriod; - unsigned long long int* systemPeriod; - unsigned long long int* systemAllPeriod; - unsigned long long int* idleAllPeriod; - unsigned long long int* idlePeriod; - unsigned long long int* nicePeriod; - unsigned long long int* ioWaitPeriod; - unsigned long long int* irqPeriod; - unsigned long long int* softIrqPeriod; - unsigned long long int* stealPeriod; + CPUData* cpus; unsigned long long int totalMem; unsigned long long int usedMem; @@ -167,4 +169,6 @@ void ProcessList_scan(ProcessList* this); ProcessField ProcessList_keyAt(ProcessList* this, int at); +void ProcessList_expandTree(ProcessList* this); + #endif diff --git a/TraceScreen.c b/TraceScreen.c index 1a896992..3af12e28 100644 --- a/TraceScreen.c +++ b/TraceScreen.c @@ -32,17 +32,17 @@ typedef struct TraceScreen_ { }*/ -static const char* tbFunctions[] = {"AutoScroll ", "Stop Tracing ", "Done ", NULL}; +static const char* tsFunctions[] = {"AutoScroll ", "Stop Tracing ", "Done ", NULL}; -static const char* tbKeys[] = {"F4", "F5", "Esc"}; +static const char* tsKeys[] = {"F4", "F5", "Esc"}; -static int tbEvents[] = {KEY_F(4), KEY_F(5), 27}; +static int tsEvents[] = {KEY_F(4), KEY_F(5), 27}; TraceScreen* TraceScreen_new(Process* process) { TraceScreen* this = (TraceScreen*) malloc(sizeof(TraceScreen)); this->process = process; this->display = Panel_new(0, 1, COLS, LINES-2, LISTITEM_CLASS, true, ListItem_compare); - this->bar = FunctionBar_new(tbFunctions, tbKeys, tbEvents); + this->bar = FunctionBar_new(tsFunctions, tsKeys, tsEvents); this->tracing = true; return this; } diff --git a/htop.c b/htop.c index cd560b52..0e7a84bd 100644 --- a/htop.c +++ b/htop.c @@ -83,13 +83,16 @@ static void showHelp(ProcessList* pl) { addattrstr(CRT_colors[CPU_KERNEL], "kernel"); addstr("/"); addattrstr(CRT_colors[CPU_IRQ], "irq"); addstr("/"); addattrstr(CRT_colors[CPU_SOFTIRQ], "soft-irq"); addstr("/"); - addattrstr(CRT_colors[CPU_IOWAIT], "io-wait"); + addattrstr(CRT_colors[CPU_IOWAIT], "io-wait"); addstr("/"); + addattrstr(CRT_colors[CPU_STEAL], "steal"); addstr("/"); + addattrstr(CRT_colors[CPU_GUEST], "guest"); addattrstr(CRT_colors[BAR_SHADOW], " used%"); } else { addattrstr(CRT_colors[CPU_NICE], "low-priority"); addstr("/"); addattrstr(CRT_colors[CPU_NORMAL], "normal"); addstr("/"); - addattrstr(CRT_colors[CPU_KERNEL], "kernel"); - addattrstr(CRT_colors[BAR_SHADOW], " used%"); + addattrstr(CRT_colors[CPU_KERNEL], "kernel"); addstr("/"); + addattrstr(CRT_colors[CPU_STEAL], "virtualiz"); + addattrstr(CRT_colors[BAR_SHADOW], " used%"); } addattrstr(CRT_colors[BAR_BORDER], "]"); attrset(CRT_colors[DEFAULT_COLOR]); @@ -98,13 +101,13 @@ static void showHelp(ProcessList* pl) { addattrstr(CRT_colors[MEMORY_USED], "used"); addstr("/"); addattrstr(CRT_colors[MEMORY_BUFFERS], "buffers"); addstr("/"); addattrstr(CRT_colors[MEMORY_CACHE], "cache"); - addattrstr(CRT_colors[BAR_SHADOW], " used/total"); + addattrstr(CRT_colors[BAR_SHADOW], " used/total"); addattrstr(CRT_colors[BAR_BORDER], "]"); attrset(CRT_colors[DEFAULT_COLOR]); mvaddstr(5, 0, "Swap bar: "); addattrstr(CRT_colors[BAR_BORDER], "["); addattrstr(CRT_colors[SWAP], "used"); - addattrstr(CRT_colors[BAR_SHADOW], " used/total"); + addattrstr(CRT_colors[BAR_SHADOW], " used/total"); addattrstr(CRT_colors[BAR_BORDER], "]"); attrset(CRT_colors[DEFAULT_COLOR]); mvaddstr(6,0, "Type and layout of header meters are configurable in the setup screen."); @@ -122,7 +125,7 @@ static void showHelp(ProcessList* pl) { mvaddstr(16, 0, " ] F7: higher priority (root only) M: sort by MEM%"); mvaddstr(17, 0, " [ F8: lower priority (+ nice) T: sort by TIME"); #ifdef HAVE_PLPA - if (pl->processorCount > 1) + if (pl->cpuCount > 1) mvaddstr(18, 0, " a: set CPU affinity F4 I: invert sort order"); else #endif @@ -143,7 +146,7 @@ static void showHelp(ProcessList* pl) { mvaddstr(17, 0, " - ] F8"); mvaddstr(17,40, " T"); mvaddstr(18,40, " F4 I"); #if HAVE_PLPA - if (pl->processorCount > 1) + if (pl->cpuCount > 1) mvaddstr(18, 0, " a:"); #endif mvaddstr(19, 0, " F2 S"); mvaddstr(19,40, " F6 >"); @@ -685,12 +688,12 @@ int main(int argc, char** argv) { #ifdef HAVE_PLPA case 'a': { - if (pl->processorCount == 1) + if (pl->cpuCount == 1) break; unsigned long curr = Process_getAffinity((Process*) Panel_getSelected(panel)); - Panel* affinityPanel = AffinityPanel_new(pl->processorCount, curr); + Panel* affinityPanel = AffinityPanel_new(pl->cpuCount, curr); const char* fuFunctions[] = {"Set ", "Cancel ", NULL}; void* set = pickFromVector(panel, affinityPanel, 15, headerHeight, fuFunctions, defaultBar); @@ -782,6 +785,7 @@ int main(int argc, char** argv) { case KEY_F(5): refreshTimeout = 0; pl->treeView = !pl->treeView; + ProcessList_expandTree(pl); settings->changed = true; break; case 'H':