diff --git a/CRT.c b/CRT.c index f7861e84..7d2cc10b 100644 --- a/CRT.c +++ b/CRT.c @@ -68,6 +68,8 @@ typedef enum ColorElements_ { PROCESS_BASENAME, PROCESS_HIGH_PRIORITY, PROCESS_LOW_PRIORITY, + PROCESS_THREAD, + PROCESS_THREAD_BASENAME, BAR_BORDER, BAR_SHADOW, GRAPH_1, @@ -210,8 +212,8 @@ void CRT_setColors(int colorScheme) { CRT_colors[FUNCTION_KEY] = A_NORMAL; CRT_colors[PANEL_HEADER_FOCUS] = A_REVERSE; CRT_colors[PANEL_HEADER_UNFOCUS] = A_REVERSE; - CRT_colors[PANEL_HIGHLIGHT_FOCUS] = A_REVERSE | A_BOLD; - CRT_colors[PANEL_HIGHLIGHT_UNFOCUS] = A_REVERSE; + CRT_colors[PANEL_HIGHLIGHT_FOCUS] = A_REVERSE; + CRT_colors[PANEL_HIGHLIGHT_UNFOCUS] = A_BOLD; CRT_colors[FAILED_SEARCH] = A_REVERSE | A_BOLD; CRT_colors[UPTIME] = A_BOLD; CRT_colors[LARGE_NUMBER] = A_BOLD; @@ -228,6 +230,8 @@ void CRT_setColors(int colorScheme) { CRT_colors[PROCESS_R_STATE] = A_BOLD; CRT_colors[PROCESS_HIGH_PRIORITY] = A_BOLD; CRT_colors[PROCESS_LOW_PRIORITY] = A_DIM; + CRT_colors[PROCESS_THREAD] = A_BOLD; + CRT_colors[PROCESS_THREAD_BASENAME] = A_REVERSE; CRT_colors[BAR_BORDER] = A_BOLD; CRT_colors[BAR_SHADOW] = A_DIM; CRT_colors[SWAP] = A_BOLD; @@ -278,11 +282,13 @@ void CRT_setColors(int colorScheme) { CRT_colors[PROCESS_SHADOW] = A_BOLD | ColorPair(Black,White); CRT_colors[PROCESS_TAG] = ColorPair(White,Blue); CRT_colors[PROCESS_MEGABYTES] = ColorPair(Blue,White); - CRT_colors[PROCESS_BASENAME] = ColorPair(Green,White); - CRT_colors[PROCESS_TREE] = ColorPair(Blue,White); + CRT_colors[PROCESS_BASENAME] = ColorPair(Blue,White); + CRT_colors[PROCESS_TREE] = ColorPair(Green,White); CRT_colors[PROCESS_R_STATE] = ColorPair(Green,White); CRT_colors[PROCESS_HIGH_PRIORITY] = ColorPair(Red,White); CRT_colors[PROCESS_LOW_PRIORITY] = ColorPair(Red,White); + CRT_colors[PROCESS_THREAD] = ColorPair(Blue,White); + CRT_colors[PROCESS_THREAD_BASENAME] = A_BOLD | ColorPair(Blue,White); CRT_colors[BAR_BORDER] = ColorPair(Blue,White); CRT_colors[BAR_SHADOW] = ColorPair(Black,White); CRT_colors[SWAP] = ColorPair(Red,White); @@ -338,6 +344,8 @@ void CRT_setColors(int colorScheme) { CRT_colors[PROCESS_R_STATE] = ColorPair(Green,Black); CRT_colors[PROCESS_HIGH_PRIORITY] = ColorPair(Red,Black); CRT_colors[PROCESS_LOW_PRIORITY] = ColorPair(Red,Black); + CRT_colors[PROCESS_THREAD] = ColorPair(Blue,Black); + CRT_colors[PROCESS_THREAD_BASENAME] = A_BOLD | ColorPair(Blue,Black); CRT_colors[BAR_BORDER] = ColorPair(Blue,Black); CRT_colors[BAR_SHADOW] = ColorPair(Black,Black); CRT_colors[SWAP] = ColorPair(Red,Black); @@ -393,6 +401,8 @@ void CRT_setColors(int colorScheme) { CRT_colors[PROCESS_R_STATE] = ColorPair(Green,Blue); CRT_colors[PROCESS_HIGH_PRIORITY] = ColorPair(Red,Blue); CRT_colors[PROCESS_LOW_PRIORITY] = ColorPair(Red,Blue); + CRT_colors[PROCESS_THREAD] = ColorPair(Green,Blue); + CRT_colors[PROCESS_THREAD_BASENAME] = A_BOLD | ColorPair(Green,Blue); CRT_colors[BAR_BORDER] = A_BOLD | ColorPair(Yellow,Blue); CRT_colors[BAR_SHADOW] = ColorPair(Cyan,Blue); CRT_colors[SWAP] = ColorPair(Red,Blue); @@ -445,6 +455,8 @@ void CRT_setColors(int colorScheme) { CRT_colors[PROCESS_MEGABYTES] = A_BOLD | ColorPair(Green,Black); CRT_colors[PROCESS_BASENAME] = A_BOLD | ColorPair(Green,Black); CRT_colors[PROCESS_TREE] = ColorPair(Cyan,Black); + CRT_colors[PROCESS_THREAD] = ColorPair(Green,Black); + CRT_colors[PROCESS_THREAD_BASENAME] = A_BOLD | ColorPair(Blue,Black); CRT_colors[PROCESS_R_STATE] = ColorPair(Green,Black); CRT_colors[PROCESS_HIGH_PRIORITY] = ColorPair(Red,Black); CRT_colors[PROCESS_LOW_PRIORITY] = ColorPair(Red,Black); @@ -471,7 +483,7 @@ void CRT_setColors(int colorScheme) { 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[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); @@ -504,6 +516,8 @@ void CRT_setColors(int colorScheme) { CRT_colors[PROCESS_R_STATE] = ColorPair(Green,Black); CRT_colors[PROCESS_HIGH_PRIORITY] = ColorPair(Red,Black); CRT_colors[PROCESS_LOW_PRIORITY] = ColorPair(Red,Black); + CRT_colors[PROCESS_THREAD] = ColorPair(Green,Black); + CRT_colors[PROCESS_THREAD_BASENAME] = A_BOLD | ColorPair(Green,Black); CRT_colors[BAR_BORDER] = A_BOLD; CRT_colors[BAR_SHADOW] = A_BOLD | ColorPair(Black,Black); CRT_colors[SWAP] = ColorPair(Red,Black); diff --git a/CRT.h b/CRT.h index 41de032f..e455b3b7 100644 --- a/CRT.h +++ b/CRT.h @@ -70,6 +70,8 @@ typedef enum ColorElements_ { PROCESS_BASENAME, PROCESS_HIGH_PRIORITY, PROCESS_LOW_PRIORITY, + PROCESS_THREAD, + PROCESS_THREAD_BASENAME, BAR_BORDER, BAR_SHADOW, GRAPH_1, diff --git a/ChangeLog b/ChangeLog index bf07ac84..1cfbbfb8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,12 @@ What's new in version 0.7.1 +* BUGFIX: Fix display of CPU count for threaded processes. + When user threads are hidden, process now shows the + sum of processor usage for all processors. When user + threads are displayed, each thread shows its own + processor usage, including the root thread. + (thanks to Bert Wesarg for the report) * BUGFIX: avoid crashing when using many meters (thanks to David Cho for the report) diff --git a/DisplayOptionsPanel.c b/DisplayOptionsPanel.c index 2eeeb8aa..ceab53c4 100644 --- a/DisplayOptionsPanel.c +++ b/DisplayOptionsPanel.c @@ -35,6 +35,7 @@ DisplayOptionsPanel* DisplayOptionsPanel_new(Settings* settings, ScreenManager* Panel_add(super, (Object*) CheckItem_new(String_copy("Shadow other users' processes"), &(settings->pl->shadowOtherUsers), false)); Panel_add(super, (Object*) CheckItem_new(String_copy("Hide kernel threads"), &(settings->pl->hideKernelThreads), false)); Panel_add(super, (Object*) CheckItem_new(String_copy("Hide userland threads"), &(settings->pl->hideUserlandThreads), false)); + Panel_add(super, (Object*) CheckItem_new(String_copy("Display threads in a different color"), &(settings->pl->highlightThreads), false)); 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)); diff --git a/Process.c b/Process.c index 8721b73d..ab66d5bb 100644 --- a/Process.c +++ b/Process.c @@ -264,7 +264,7 @@ static void Process_printTime(RichString* str, unsigned long t) { RichString_append(str, CRT_colors[DEFAULT_COLOR], buffer); } -static inline void Process_writeCommand(Process* this, int attr, RichString* str) { +static inline void Process_writeCommand(Process* this, int attr, int baseattr, RichString* str) { if (this->pl->highlightBaseName) { char* firstSpace = strchr(this->comm, ' '); if (firstSpace) { @@ -275,10 +275,10 @@ static inline void Process_writeCommand(Process* this, int attr, RichString* str slash++; RichString_appendn(str, attr, this->comm, slash - this->comm); } - RichString_appendn(str, CRT_colors[PROCESS_BASENAME], slash, firstSpace - slash); + RichString_appendn(str, baseattr, slash, firstSpace - slash); RichString_append(str, attr, firstSpace); } else { - RichString_append(str, CRT_colors[PROCESS_BASENAME], this->comm); + RichString_append(str, baseattr, this->comm); } } else { RichString_append(str, attr, this->comm); @@ -288,6 +288,7 @@ static inline void Process_writeCommand(Process* this, int attr, RichString* str void Process_writeField(Process* this, RichString* str, ProcessField field) { char buffer[PROCESS_COMM_LEN]; int attr = CRT_colors[DEFAULT_COLOR]; + int baseattr = CRT_colors[PROCESS_BASENAME]; int n = PROCESS_COMM_LEN; switch (field) { @@ -301,8 +302,12 @@ void Process_writeField(Process* this, RichString* str, ProcessField field) { case PROCESSOR: snprintf(buffer, n, "%3d ", this->processor+1); break; case NLWP: snprintf(buffer, n, "%4ld ", this->nlwp); break; case COMM: { + if (this->pl->highlightThreads && (this->pid != this->tgid || this->m_size == 0)) { + attr = CRT_colors[PROCESS_THREAD]; + baseattr = CRT_colors[PROCESS_THREAD_BASENAME]; + } if (!this->pl->treeView || this->indent == 0) { - Process_writeCommand(this, attr, str); + Process_writeCommand(this, attr, baseattr, str); return; } else { char* buf = buffer; @@ -323,7 +328,7 @@ void Process_writeField(Process* this, RichString* str, ProcessField field) { else snprintf(buf, n, " ,- "); RichString_append(str, CRT_colors[PROCESS_TREE], buffer); - Process_writeCommand(this, attr, str); + Process_writeCommand(this, attr, baseattr, str); return; } } @@ -376,8 +381,10 @@ void Process_writeField(Process* this, RichString* str, ProcessField field) { case CSTIME: Process_printTime(str, this->cstime); return; case TIME: Process_printTime(str, this->utime + this->stime); return; case PERCENT_CPU: { - if (this->percent_cpu > 99.9) { - snprintf(buffer, n, "100. "); + if (this->percent_cpu > 999.9) { + snprintf(buffer, n, "%4d ", (unsigned int)this->percent_cpu); + } else if (this->percent_cpu > 99.9) { + snprintf(buffer, n, "%3d. ", (unsigned int)this->percent_cpu); } else { snprintf(buffer, n, "%4.1f ", this->percent_cpu); } diff --git a/ProcessList.c b/ProcessList.c index 6b18e04d..66d60949 100644 --- a/ProcessList.c +++ b/ProcessList.c @@ -119,6 +119,7 @@ typedef struct ProcessList_ { bool treeView; bool highlightBaseName; bool highlightMegabytes; + bool highlightThreads; bool detailedCPUTime; #ifdef DEBUG_PROC FILE* traceFile; @@ -498,13 +499,15 @@ bool ProcessList_readStatusFile(ProcessList* this, Process* proc, char* dirname, return true; } -void ProcessList_processEntries(ProcessList* this, char* dirname, int parent, float period) { +bool ProcessList_processEntries(ProcessList* this, char* dirname, Process* parent, float period) { DIR* dir; struct dirent* entry; Process* prototype = this->prototype; dir = opendir(dirname); - if (!dir) return; + if (!dir) return false; + int processors = this->processorCount; + bool showUserlandThreads = !this->hideUserlandThreads; while ((entry = readdir(dir)) != NULL) { char* name = entry->d_name; int pid; @@ -521,34 +524,42 @@ void ProcessList_processEntries(ProcessList* this, char* dirname, int parent, fl isThread = true; } - if (pid > 0 && pid != parent) { - if (!this->hideUserlandThreads) { - char subdirname[MAX_NAME+1]; - snprintf(subdirname, MAX_NAME, "%s/%s/task", dirname, name); - - ProcessList_processEntries(this, subdirname, pid, period); - } + if (pid > 0) { FILE* status; char statusfilename[MAX_NAME+1]; char command[PROCESS_COMM_LEN + 1]; Process* process = NULL; - - assert(Hashtable_count(this->processTable) == Vector_count(this->processes)); Process* existingProcess = (Process*) Hashtable_get(this->processTable, pid); + if (existingProcess) { assert(Vector_indexOf(this->processes, existingProcess, Process_pidCompare) != -1); process = existingProcess; assert(process->pid == pid); } else { - process = prototype; - assert(process->comm == NULL); - process->pid = pid; + if (parent && parent->pid == pid) { + process = parent; + } else { + process = prototype; + assert(process->comm == NULL); + process->pid = pid; + } + } + + if (showUserlandThreads && (!parent || pid != parent->pid)) { + char subdirname[MAX_NAME+1]; + snprintf(subdirname, MAX_NAME, "%s/%s/task", dirname, name); + + if (ProcessList_processEntries(this, subdirname, process, period)) + continue; + } + + process->updated = true; + + if (!existingProcess) if (! ProcessList_readStatusFile(this, process, dirname, name)) goto errorReadingProcess; - } - process->updated = true; snprintf(statusfilename, MAX_NAME, "%s/%s/statm", dirname, name); status = ProcessList_fopen(this, statusfilename, "r"); @@ -573,13 +584,14 @@ void ProcessList_processEntries(ProcessList* this, char* dirname, int parent, fl snprintf(statusfilename, MAX_NAME, "%s/%s/stat", dirname, name); status = ProcessList_fopen(this, statusfilename, "r"); - if (status == NULL) + if (status == NULL) goto errorReadingProcess; int success = ProcessList_readStatFile(this, process, status, command); fclose(status); - if(!success) + if(!success) { goto errorReadingProcess; + } if(!existingProcess) { process->user = UsersTable_getRef(this->usersTable, process->st_uid); @@ -624,8 +636,9 @@ void ProcessList_processEntries(ProcessList* this, char* dirname, int parent, fl fclose(status); } - process->percent_cpu = (process->utime + process->stime - lasttimes) / + 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_mem = (process->m_resident * PAGE_SIZE) / (float)(this->totalMem) * @@ -637,7 +650,8 @@ void ProcessList_processEntries(ProcessList* this, char* dirname, int parent, fl } if (!existingProcess) { - ProcessList_add(this, Process_clone(process)); + process = Process_clone(process); + ProcessList_add(this, process); } continue; @@ -655,6 +669,7 @@ void ProcessList_processEntries(ProcessList* this, char* dirname, int parent, fl } } closedir(dir); + return true; } void ProcessList_scan(ProcessList* this) { @@ -665,6 +680,7 @@ void ProcessList_scan(ProcessList* this) { char buffer[128]; status = ProcessList_fopen(this, PROCMEMINFOFILE, "r"); assert(status != NULL); + int processors = this->processorCount; while (!feof(status)) { fgets(buffer, 128, status); @@ -701,7 +717,7 @@ void ProcessList_scan(ProcessList* this) { status = ProcessList_fopen(this, PROCSTATFILE, "r"); assert(status != NULL); - for (int i = 0; i <= this->processorCount; i++) { + for (int i = 0; i <= processors; i++) { char buffer[256]; int cpuid; unsigned long long int ioWait, irq, softIrq, steal; @@ -755,7 +771,7 @@ void ProcessList_scan(ProcessList* this) { this->stealTime[i] = steal; this->totalTime[i] = totaltime; } - float period = (float)this->totalPeriod[0] / this->processorCount; + float period = (float)this->totalPeriod[0] / processors; fclose(status); // mark all process as "dirty" @@ -766,8 +782,8 @@ void ProcessList_scan(ProcessList* this) { this->totalTasks = 0; this->runningTasks = 0; - - ProcessList_processEntries(this, PROCDIR, 0, period); + + ProcessList_processEntries(this, PROCDIR, NULL, period); for (int i = Vector_size(this->processes) - 1; i >= 0; i--) { Process* p = (Process*) Vector_get(this->processes, i); diff --git a/ProcessList.h b/ProcessList.h index 578edb9e..34bdc46e 100644 --- a/ProcessList.h +++ b/ProcessList.h @@ -119,6 +119,7 @@ typedef struct ProcessList_ { bool treeView; bool highlightBaseName; bool highlightMegabytes; + bool highlightThreads; bool detailedCPUTime; #ifdef DEBUG_PROC FILE* traceFile; @@ -164,7 +165,7 @@ void ProcessList_sort(ProcessList* this); bool ProcessList_readStatusFile(ProcessList* this, Process* proc, char* dirname, char* name); -void ProcessList_processEntries(ProcessList* this, char* dirname, int parent, float period); +bool ProcessList_processEntries(ProcessList* this, char* dirname, Process* parent, float period); void ProcessList_scan(ProcessList* this); diff --git a/Settings.c b/Settings.c index a8ddc456..380bcc76 100644 --- a/Settings.c +++ b/Settings.c @@ -55,6 +55,7 @@ Settings* Settings_new(ProcessList* pl, Header* header) { Header_defaultMeters(this->header); pl->hideKernelThreads = true; pl->highlightMegabytes = true; + pl->highlightThreads = false; } } return this; @@ -137,6 +138,8 @@ bool Settings_read(Settings* this, char* fileName) { this->pl->highlightBaseName = atoi(option[1]); } else if (String_eq(option[0], "highlight_megabytes")) { this->pl->highlightMegabytes = atoi(option[1]); + } else if (String_eq(option[0], "highlight_threads")) { + this->pl->highlightThreads = atoi(option[1]); } else if (String_eq(option[0], "header_margin")) { this->header->margin = atoi(option[1]); } else if (String_eq(option[0], "expand_system_time")) { @@ -198,6 +201,7 @@ bool Settings_write(Settings* this) { fprintf(fd, "shadow_other_users=%d\n", (int) this->pl->shadowOtherUsers); fprintf(fd, "highlight_base_name=%d\n", (int) this->pl->highlightBaseName); fprintf(fd, "highlight_megabytes=%d\n", (int) this->pl->highlightMegabytes); + fprintf(fd, "highlight_threads=%d\n", (int) this->pl->highlightThreads); fprintf(fd, "tree_view=%d\n", (int) this->pl->treeView); fprintf(fd, "header_margin=%d\n", (int) this->header->margin); fprintf(fd, "detailed_cpu_time=%d\n", (int) this->pl->detailedCPUTime);