diff --git a/Process.c b/Process.c index e08ea93b..6ec0d386 100644 --- a/Process.c +++ b/Process.c @@ -28,6 +28,7 @@ in the source distribution for its full text. #include #include #include +#include #ifdef __ANDROID__ #define SYS_ioprio_get __NR_ioprio_get @@ -150,7 +151,7 @@ typedef struct ProcessFieldData_ { const char* name; const char* title; const char* description; - int flags; + uint64_t flags; } ProcessFieldData; // Implemented in platform-specific code: @@ -360,6 +361,21 @@ void Process_outputRate(RichString* str, char* buffer, int n, double rate, int c } } +void Process_printPercentage(float val, char* buffer, int n, int* attr) { + if (val >= 0) { + if (val < 100) { + xSnprintf(buffer, n, "%4.1f ", val); + } else if (val < 1000) { + xSnprintf(buffer, n, "%3d. ", (unsigned int)val); + } else { + xSnprintf(buffer, n, "%4d ", (unsigned int)val); + } + } else { + *attr = CRT_colors[PROCESS_SHADOW]; + xSnprintf(buffer, n, " N/A "); + } +} + void Process_writeField(Process* this, RichString* str, ProcessField field) { char buffer[256]; buffer[255] = '\0'; int attr = CRT_colors[DEFAULT_COLOR]; @@ -368,24 +384,8 @@ void Process_writeField(Process* this, RichString* str, ProcessField field) { bool coloring = this->settings->highlightMegabytes; switch (field) { - case PERCENT_CPU: { - if (this->percent_cpu > 999.9) { - xSnprintf(buffer, n, "%4d ", (unsigned int)this->percent_cpu); - } else if (this->percent_cpu > 99.9) { - xSnprintf(buffer, n, "%3d. ", (unsigned int)this->percent_cpu); - } else { - xSnprintf(buffer, n, "%4.1f ", this->percent_cpu); - } - break; - } - case PERCENT_MEM: { - if (this->percent_mem > 99.9) { - xSnprintf(buffer, n, "100. "); - } else { - xSnprintf(buffer, n, "%4.1f ", this->percent_mem); - } - break; - } + case PERCENT_CPU: Process_printPercentage(this->percent_cpu, buffer, n, &attr); break; + case PERCENT_MEM: Process_printPercentage(this->percent_mem, buffer, n, &attr); break; case COMM: { if (this->settings->highlightThreads && Process_isThread(this)) { attr = CRT_colors[PROCESS_THREAD]; diff --git a/Process.h b/Process.h index 5b8ffdba..708d3362 100644 --- a/Process.h +++ b/Process.h @@ -129,7 +129,7 @@ typedef struct ProcessFieldData_ { const char* name; const char* title; const char* description; - int flags; + uint64_t flags; } ProcessFieldData; // Implemented in platform-specific code: @@ -174,6 +174,8 @@ void Process_printTime(RichString* str, unsigned long long totalHundredths); void Process_outputRate(RichString* str, char* buffer, int n, double rate, int coloring); +void Process_printPercentage(float val, char* buffer, int n, int* attr); + void Process_writeField(Process* this, RichString* str, ProcessField field); void Process_display(Object* cast, RichString* out); diff --git a/ScreensPanel.c b/ScreensPanel.c index 1fe6283f..47ec62b0 100644 --- a/ScreensPanel.c +++ b/ScreensPanel.c @@ -48,6 +48,7 @@ typedef struct ScreenListItem_ { }*/ ObjectClass ScreenListItem_class = { + .extends = Class(ListItem), .display = ListItem_display, .delete = ListItem_delete, .compare = ListItem_compare @@ -319,8 +320,11 @@ void ScreensPanel_update(Panel* super) { this->settings->changed = true; this->settings->screens = xRealloc(this->settings->screens, sizeof(char*) * (size+1)); for (int i = 0; i < size; i++) { - char* name = ((ListItem*) Panel_get(super, i))->value; - this->settings->screens[i]->name = xStrdup(name); + ScreenListItem* item = (ScreenListItem*) Panel_get(super, i); + ScreenSettings* ss = item->ss; + free(ss->name); + this->settings->screens[i] = ss; + ss->name = xStrdup(((ListItem*) item)->value); } this->settings->screens[size] = NULL; } diff --git a/Settings.h b/Settings.h index 80ec9560..a5f3877f 100644 --- a/Settings.h +++ b/Settings.h @@ -9,7 +9,6 @@ Released under the GNU GPL, see the COPYING file in the source distribution for its full text. */ -#define DEFAULT_DELAY 15 #include "Process.h" #include diff --git a/linux/LinuxProcess.c b/linux/LinuxProcess.c index ba42db1f..9fc32a11 100644 --- a/linux/LinuxProcess.c +++ b/linux/LinuxProcess.c @@ -20,12 +20,22 @@ in the source distribution for its full text. #include "PerfCounter.h" -#define PROCESS_FLAG_LINUX_IOPRIO 0x0100 -#define PROCESS_FLAG_LINUX_OPENVZ 0x0200 -#define PROCESS_FLAG_LINUX_VSERVER 0x0400 -#define PROCESS_FLAG_LINUX_CGROUP 0x0800 -#define PROCESS_FLAG_LINUX_OOM 0x1000 -#define PROCESS_FLAG_LINUX_HPC 0x2000 +#define PROCESS_FLAG_LINUX_IOPRIO 0x0100L +#define PROCESS_FLAG_LINUX_OPENVZ 0x0200L +#define PROCESS_FLAG_LINUX_VSERVER 0x0400L +#define PROCESS_FLAG_LINUX_CGROUP 0x0800L +#define PROCESS_FLAG_LINUX_OOM 0x1000L + +#define PROCESS_FLAG_LINUX_HPC 0xff0000L +#define PROCESS_FLAG_LINUX_HPC_CYCLE 0x10000L +#define PROCESS_FLAG_LINUX_HPC_INSN 0x20000L +#define PROCESS_FLAG_LINUX_HPC_MISS 0x40000L +#define PROCESS_FLAG_LINUX_HPC_BMISS 0x80000L + +#define PROCESS_FLAG_LINUX_HPC_L1DR 0x100000L +#define PROCESS_FLAG_LINUX_HPC_L1DW 0x200000L +#define PROCESS_FLAG_LINUX_HPC_L1DRM 0x400000L +#define PROCESS_FLAG_LINUX_HPC_L1DWM 0x800000L typedef enum UnsupportedProcessFields { FLAGS = 9, @@ -91,8 +101,16 @@ typedef enum LinuxProcessFields { #endif #ifdef HAVE_PERFCOUNTERS IPC = 119, + MCYCLE = 120, + MINSTR = 121, + PERCENT_MISS = 122, + PERCENT_BMISS = 123, + L1DREADS = 124, + L1DRMISSES = 125, + L1DWRITES = 126, + L1DWMISSES = 127, #endif - LAST_PROCESSFIELD = 120, + LAST_PROCESSFIELD = 128, } LinuxProcessField; #include "IOPriority.h" @@ -148,7 +166,21 @@ typedef struct LinuxProcess_ { #ifdef HAVE_PERFCOUNTERS PerfCounter* cycleCounter; PerfCounter* insnCounter; - double ipc; + PerfCounter* missCounter; + PerfCounter* brCounter; + PerfCounter* l1drCounter; + PerfCounter* l1drmCounter; + PerfCounter* l1dwCounter; + PerfCounter* l1dwmCounter; + float ipc; + float mcycle; + float minstr; + float pMiss; + float pBMiss; + float l1dr; + float l1drm; + float l1dw; + float l1dwm; #endif } LinuxProcess; @@ -241,12 +273,20 @@ ProcessFieldData Process_fields[] = { [OOM] = { .name = "OOM", .title = " OOM ", .description = "OOM (Out-of-Memory) killer score", .flags = PROCESS_FLAG_LINUX_OOM, }, [IO_PRIORITY] = { .name = "IO_PRIORITY", .title = "IO ", .description = "I/O priority", .flags = PROCESS_FLAG_LINUX_IOPRIO, }, #ifdef HAVE_DELAYACCT - [PERCENT_CPU_DELAY] = { .name = "PERCENT_CPU_DELAY", .title = "CPUD% ", .description = "CPU delay %", .flags = 0, }, + [PERCENT_CPU_DELAY] = { .name = "PERCENT_CPU_DELAY", .title = "CPD% ", .description = "CPU delay %", .flags = 0, }, [PERCENT_IO_DELAY] = { .name = "PERCENT_IO_DELAY", .title = "IOD% ", .description = "Block I/O delay %", .flags = 0, }, - [PERCENT_SWAP_DELAY] = { .name = "PERCENT_SWAP_DELAY", .title = "SWAPD% ", .description = "Swapin delay %", .flags = 0, }, + [PERCENT_SWAP_DELAY] = { .name = "PERCENT_SWAP_DELAY", .title = "SWD% ", .description = "Swapin delay %", .flags = 0, }, #endif #ifdef HAVE_PERFCOUNTERS - [IPC] = { .name = "IPC", .title = " IPC ", .description = "Executed instructions per cycle", .flags = PROCESS_FLAG_LINUX_HPC, }, + [IPC] = { .name = "IPC", .title = " IPC ", .description = "Executed instructions per cycle", .flags = PROCESS_FLAG_LINUX_HPC_CYCLE | PROCESS_FLAG_LINUX_HPC_INSN, }, + [MCYCLE] = { .name = "MCYCLE", .title = " Mcycle ", .description = "Cycles (millions)", .flags = PROCESS_FLAG_LINUX_HPC_CYCLE, }, + [MINSTR] = { .name = "MINSTR", .title = " Minstr ", .description = "Instructions (millions)", .flags = PROCESS_FLAG_LINUX_HPC_INSN, }, + [PERCENT_MISS] = { .name = "PERCENT_MISS", .title = "MIS% ", .description = "Cache misses per 100 instructions", .flags = PROCESS_FLAG_LINUX_HPC_MISS | PROCESS_FLAG_LINUX_HPC_INSN, }, + [PERCENT_BMISS] = { .name = "PERCENT_BMISS", .title = "BrM% ", .description = "Branch misprediction per 100 instructions", .flags = PROCESS_FLAG_LINUX_HPC_BMISS | PROCESS_FLAG_LINUX_HPC_INSN, }, + [L1DREADS] = { .name = "L1DREADS", .title = " L1Dread ", .description = "L1 data cache: reads (thousands)", .flags = PROCESS_FLAG_LINUX_HPC_L1DR, }, + [L1DRMISSES] = { .name = "L1DRMISSES", .title = " R miss ", .description = "L1 data cache: reads misses (thousands)", .flags = PROCESS_FLAG_LINUX_HPC_L1DRM, }, + [L1DWRITES] = { .name = "L1DWRITES", .title = " L1Dwrite ", .description = "L1D data cache: writes (thousands)", .flags = PROCESS_FLAG_LINUX_HPC_L1DW, }, + [L1DWMISSES] = { .name = "L1DWMISSES", .title = " W miss ", .description = "L1D data cache: write misses (thousands)", .flags = PROCESS_FLAG_LINUX_HPC_L1DWM, }, #endif [LAST_PROCESSFIELD] = { .name = "*** report bug! ***", .title = NULL, .description = NULL, .flags = 0, }, }; @@ -324,14 +364,43 @@ bool LinuxProcess_setIOPriority(LinuxProcess* this, IOPriority ioprio) { return (LinuxProcess_updateIOPriority(this) == ioprio); } -#ifdef HAVE_DELAYACCT -void LinuxProcess_printDelay(float delay_percent, char* buffer, int n) { - if (delay_percent == -1LL) { - xSnprintf(buffer, n, " N/A "); - } else { - xSnprintf(buffer, n, "%4.1f ", delay_percent); - } +#if HAVE_DELAYACCT || HAVE_PERFCOUNTERS + +static char* perfFmt[] = { + "%6.2f ", + NULL, + NULL, + NULL, + NULL, + NULL, + "%6.1f ", + "%7.1f ", + "%8.2f ", + "%9.1f ", +}; + +static char* perfNA[] = { + " N/A ", + NULL, + NULL, + NULL, + NULL, + NULL, + " N/A ", + " N/A ", + " N/A ", + " N/A ", +}; + +static inline void LinuxProcess_printPerfCounter(float val, int len, char* buffer, int n, int* attr) { + if (val != -1) { + xSnprintf(buffer, n, perfFmt[len], val); + } else { + xSnprintf(buffer, n, perfNA[len]); + *attr = CRT_colors[PROCESS_SHADOW]; + } } + #endif void LinuxProcess_writeField(Process* this, RichString* str, ProcessField field) { @@ -408,19 +477,20 @@ void LinuxProcess_writeField(Process* this, RichString* str, ProcessField field) break; } #ifdef HAVE_DELAYACCT - case PERCENT_CPU_DELAY: LinuxProcess_printDelay(lp->cpu_delay_percent, buffer, n); break; - 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; + case PERCENT_CPU_DELAY: Process_printPercentage(lp->cpu_delay_percent, buffer, n, &attr); break; + case PERCENT_IO_DELAY: Process_printPercentage(lp->blkio_delay_percent, buffer, n, &attr); break; + case PERCENT_SWAP_DELAY: Process_printPercentage(lp->swapin_delay_percent, buffer, n, &attr); break; #endif #ifdef HAVE_PERFCOUNTERS - case IPC: { - if (lp->ipc == -1) { - attr = CRT_colors[PROCESS_SHADOW]; - xSnprintf(buffer, n, " N/A "); break; - } else { - xSnprintf(buffer, n, "%5.2f ", lp->ipc); break; - } - } + case PERCENT_MISS: Process_printPercentage(lp->pMiss, buffer, n, &attr); break; + case PERCENT_BMISS: Process_printPercentage(lp->pBMiss, buffer, n, &attr); break; + case IPC: LinuxProcess_printPerfCounter(lp->ipc, 0, buffer, n, &attr); break; + case MCYCLE: LinuxProcess_printPerfCounter(lp->mcycle, 8, buffer, n, &attr); break; + case MINSTR: LinuxProcess_printPerfCounter(lp->minstr, 8, buffer, n, &attr); break; + case L1DREADS: LinuxProcess_printPerfCounter(lp->l1dr, 9, buffer, n, &attr); break; + case L1DRMISSES: LinuxProcess_printPerfCounter(lp->l1drm, 9, buffer, n, &attr); break; + case L1DWRITES: LinuxProcess_printPerfCounter(lp->l1dw, 9, buffer, n, &attr); break; + case L1DWMISSES: LinuxProcess_printPerfCounter(lp->l1dwm, 9, buffer, n, &attr); break; #endif default: Process_writeField((Process*)this, str, field); @@ -429,6 +499,8 @@ void LinuxProcess_writeField(Process* this, RichString* str, ProcessField field) RichString_append(str, attr, buffer); } +#define COMPARE_FIELD(_f) return (p2->_f > p1->_f ? 1 : -1) + long LinuxProcess_compare(const void* v1, const void* v2) { LinuxProcess *p1, *p2; Settings *settings = ((Process*)v1)->settings; @@ -484,16 +556,20 @@ long LinuxProcess_compare(const void* v1, const void* v2) { case OOM: return (p2->oom - p1->oom); #ifdef HAVE_DELAYACCT - case PERCENT_CPU_DELAY: - return (p2->cpu_delay_percent > p1->cpu_delay_percent ? 1 : -1); - case PERCENT_IO_DELAY: - return (p2->blkio_delay_percent > p1->blkio_delay_percent ? 1 : -1); - case PERCENT_SWAP_DELAY: - return (p2->swapin_delay_percent > p1->swapin_delay_percent ? 1 : -1); + case PERCENT_CPU_DELAY: COMPARE_FIELD(cpu_delay_percent); + case PERCENT_IO_DELAY: COMPARE_FIELD(blkio_delay_percent); + case PERCENT_SWAP_DELAY: COMPARE_FIELD(swapin_delay_percent); #endif #ifdef HAVE_PERFCOUNTERS - case IPC: - return (p2->ipc > p1->ipc ? 1 : -1); + case PERCENT_MISS: COMPARE_FIELD(pMiss); + case PERCENT_BMISS: COMPARE_FIELD(pBMiss); + case IPC: COMPARE_FIELD(ipc); + case MCYCLE: COMPARE_FIELD(mcycle); + case MINSTR: COMPARE_FIELD(minstr); + case L1DREADS: COMPARE_FIELD(l1dr); + case L1DRMISSES: COMPARE_FIELD(l1drm); + case L1DWRITES: COMPARE_FIELD(l1dw); + case L1DWMISSES: COMPARE_FIELD(l1dwm); #endif case IO_PRIORITY: return LinuxProcess_effectiveIOPriority(p1) - LinuxProcess_effectiveIOPriority(p2); diff --git a/linux/LinuxProcess.h b/linux/LinuxProcess.h index ca22bdda..6abcb127 100644 --- a/linux/LinuxProcess.h +++ b/linux/LinuxProcess.h @@ -12,12 +12,22 @@ in the source distribution for its full text. #include "PerfCounter.h" -#define PROCESS_FLAG_LINUX_IOPRIO 0x0100 -#define PROCESS_FLAG_LINUX_OPENVZ 0x0200 -#define PROCESS_FLAG_LINUX_VSERVER 0x0400 -#define PROCESS_FLAG_LINUX_CGROUP 0x0800 -#define PROCESS_FLAG_LINUX_OOM 0x1000 -#define PROCESS_FLAG_LINUX_HPC 0x2000 +#define PROCESS_FLAG_LINUX_IOPRIO 0x0100L +#define PROCESS_FLAG_LINUX_OPENVZ 0x0200L +#define PROCESS_FLAG_LINUX_VSERVER 0x0400L +#define PROCESS_FLAG_LINUX_CGROUP 0x0800L +#define PROCESS_FLAG_LINUX_OOM 0x1000L + +#define PROCESS_FLAG_LINUX_HPC 0xff0000L +#define PROCESS_FLAG_LINUX_HPC_CYCLE 0x10000L +#define PROCESS_FLAG_LINUX_HPC_INSN 0x20000L +#define PROCESS_FLAG_LINUX_HPC_MISS 0x40000L +#define PROCESS_FLAG_LINUX_HPC_BMISS 0x80000L + +#define PROCESS_FLAG_LINUX_HPC_L1DR 0x100000L +#define PROCESS_FLAG_LINUX_HPC_L1DW 0x200000L +#define PROCESS_FLAG_LINUX_HPC_L1DRM 0x400000L +#define PROCESS_FLAG_LINUX_HPC_L1DWM 0x800000L typedef enum UnsupportedProcessFields { FLAGS = 9, @@ -83,8 +93,16 @@ typedef enum LinuxProcessFields { #endif #ifdef HAVE_PERFCOUNTERS IPC = 119, + MCYCLE = 120, + MINSTR = 121, + PERCENT_MISS = 122, + PERCENT_BMISS = 123, + L1DREADS = 124, + L1DRMISSES = 125, + L1DWRITES = 126, + L1DWMISSES = 127, #endif - LAST_PROCESSFIELD = 120, + LAST_PROCESSFIELD = 128, } LinuxProcessField; #include "IOPriority.h" @@ -140,7 +158,21 @@ typedef struct LinuxProcess_ { #ifdef HAVE_PERFCOUNTERS PerfCounter* cycleCounter; PerfCounter* insnCounter; - double ipc; + PerfCounter* missCounter; + PerfCounter* brCounter; + PerfCounter* l1drCounter; + PerfCounter* l1drmCounter; + PerfCounter* l1dwCounter; + PerfCounter* l1dwmCounter; + float ipc; + float mcycle; + float minstr; + float pMiss; + float pBMiss; + float l1dr; + float l1drm; + float l1dw; + float l1dwm; #endif } LinuxProcess; @@ -177,12 +209,14 @@ IOPriority LinuxProcess_updateIOPriority(LinuxProcess* this); bool LinuxProcess_setIOPriority(LinuxProcess* this, IOPriority ioprio); -#ifdef HAVE_DELAYACCT -void LinuxProcess_printDelay(float delay_percent, char* buffer, int n); +#if HAVE_DELAYACCT || HAVE_PERFCOUNTERS + #endif void LinuxProcess_writeField(Process* this, RichString* str, ProcessField field); +#define COMPARE_FIELD(_f) return (p2->_f > p1->_f ? 1 : -1) + long LinuxProcess_compare(const void* v1, const void* v2); bool Process_isThread(Process* this); diff --git a/linux/LinuxProcessList.c b/linux/LinuxProcessList.c index bba611f0..e72a023d 100644 --- a/linux/LinuxProcessList.c +++ b/linux/LinuxProcessList.c @@ -647,9 +647,9 @@ static void LinuxProcessList_readDelayAcctData(LinuxProcessList* this, LinuxProc } if (nl_send_sync(this->netlink_socket, msg) < 0) { - process->swapin_delay_percent = -1LL; - process->blkio_delay_percent = -1LL; - process->cpu_delay_percent = -1LL; + process->swapin_delay_percent = -1; + process->blkio_delay_percent = -1; + process->cpu_delay_percent = -1; return; } @@ -662,26 +662,71 @@ static void LinuxProcessList_readDelayAcctData(LinuxProcessList* this, LinuxProc #ifdef HAVE_PERFCOUNTERS -static void LinuxProcessList_readPerfCounters(LinuxProcess* lp) { - if (!lp->cycleCounter) { - lp->cycleCounter = PerfCounter_new(lp->super.pid, PERF_TYPE_HARDWARE, PERF_COUNT_HW_CPU_CYCLES); +#define READ_COUNTER(_b, _var, _flag, _type, _config) \ + bool _b ## Ok = false; \ + uint64_t _b ## Delta = 0; \ + if (flags & _flag) { \ + if (!_var) { \ + _var = PerfCounter_new(lp->super.pid, _type, _config); \ + _b ## Ok = PerfCounter_read(_var); \ + _b ## Delta = 0; \ + } else { \ + _b ## Ok = PerfCounter_read(_var); \ + _b ## Delta = PerfCounter_delta(_var); \ + } \ + if (_b ## Ok) { \ + } \ + } else { \ + if (_var) { \ + PerfCounter_delete(_var); \ + _var = NULL; \ + } \ } - if (!lp->insnCounter) { - lp->insnCounter = PerfCounter_new(lp->super.pid, PERF_TYPE_HARDWARE, PERF_COUNT_HW_INSTRUCTIONS); + +#define SET_IF(_ok, _var, _exp) \ + if (_ok) { \ + _var = _exp; \ + } else { \ + _var = -1; \ } - bool cOk = PerfCounter_read(lp->cycleCounter); - bool iOk = PerfCounter_read(lp->insnCounter); - if (cOk && iOk) { - uint64_t i = PerfCounter_delta(lp->insnCounter); - uint64_t c = PerfCounter_delta(lp->cycleCounter); - if (c > 0) { - lp->ipc = (double)i / c; - } else { - lp->ipc = 0; - } - } else { - lp->ipc = -1; + +#define SET_IFNZ(_ok, _z, _var, _exp) \ + if (_ok) { \ + if (_z > 0) { \ + _var = _exp; \ + } else { \ + _var = 0; \ + } \ + } else { \ + _var = -1; \ } + +#define L1DR (PERF_COUNT_HW_CACHE_L1D | (PERF_COUNT_HW_CACHE_OP_READ << 8) | (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16)) +#define L1DRM (PERF_COUNT_HW_CACHE_L1D | (PERF_COUNT_HW_CACHE_OP_READ << 8) | (PERF_COUNT_HW_CACHE_RESULT_MISS << 16)) +#define L1DW (PERF_COUNT_HW_CACHE_L1D | (PERF_COUNT_HW_CACHE_OP_WRITE << 8) | (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16)) +#define L1DWM (PERF_COUNT_HW_CACHE_L1D | (PERF_COUNT_HW_CACHE_OP_WRITE << 8) | (PERF_COUNT_HW_CACHE_RESULT_MISS << 16)) + +static void LinuxProcessList_readPerfCounters(LinuxProcess* lp, uint64_t flags) { + + READ_COUNTER(c, lp->cycleCounter, PROCESS_FLAG_LINUX_HPC_CYCLE, PERF_TYPE_HARDWARE, PERF_COUNT_HW_CPU_CYCLES); + READ_COUNTER(i, lp->insnCounter, PROCESS_FLAG_LINUX_HPC_INSN, PERF_TYPE_HARDWARE, PERF_COUNT_HW_INSTRUCTIONS); + READ_COUNTER(m, lp->missCounter, PROCESS_FLAG_LINUX_HPC_MISS, PERF_TYPE_HARDWARE, PERF_COUNT_HW_CACHE_MISSES); + READ_COUNTER(b, lp->brCounter, PROCESS_FLAG_LINUX_HPC_BMISS, PERF_TYPE_HARDWARE, PERF_COUNT_HW_BRANCH_MISSES); + + READ_COUNTER(r, lp->l1drCounter, PROCESS_FLAG_LINUX_HPC_L1DR, PERF_TYPE_HW_CACHE, L1DR); + READ_COUNTER(R, lp->l1drmCounter, PROCESS_FLAG_LINUX_HPC_L1DRM, PERF_TYPE_HW_CACHE, L1DRM); + READ_COUNTER(w, lp->l1dwCounter, PROCESS_FLAG_LINUX_HPC_L1DW, PERF_TYPE_HW_CACHE, L1DW); + READ_COUNTER(W, lp->l1dwmCounter, PROCESS_FLAG_LINUX_HPC_L1DWM, PERF_TYPE_HW_CACHE, L1DWM); + + SET_IF(cOk, lp->mcycle, (double)cDelta / 1000000); + SET_IF(iOk, lp->minstr, (double)iDelta / 1000000); + SET_IFNZ(cOk && iOk, cDelta, lp->ipc, (double)iDelta / cDelta); + SET_IFNZ(mOk && iOk, iDelta, lp->pMiss, 100 * ((double)mDelta / iDelta)); + SET_IFNZ(bOk && iOk, iDelta, lp->pBMiss, 100 * ((double)bDelta / iDelta)); + SET_IF(rOk, lp->l1dr, (double)rDelta / 1000); + SET_IF(ROk, lp->l1drm, (double)RDelta / 1000); + SET_IF(wOk, lp->l1dw, (double)wDelta / 1000); + SET_IF(WOk, lp->l1dwm, (double)WDelta / 1000); } #endif @@ -899,7 +944,7 @@ static bool LinuxProcessList_recurseProcTree(LinuxProcessList* this, const char* #ifdef HAVE_PERFCOUNTERS if (ss->flags & PROCESS_FLAG_LINUX_HPC) - LinuxProcessList_readPerfCounters(lp); + LinuxProcessList_readPerfCounters(lp, ss->flags); #endif if (proc->state == 'Z' && (proc->basenameOffset == 0)) { diff --git a/linux/LinuxProcessList.h b/linux/LinuxProcessList.h index 06447713..310f5dfd 100644 --- a/linux/LinuxProcessList.h +++ b/linux/LinuxProcessList.h @@ -118,6 +118,50 @@ void ProcessList_delete(ProcessList* pl); #ifdef HAVE_PERFCOUNTERS +#define READ_COUNTER(_b, _var, _flag, _type, _config) \ + bool _b ## Ok = false; \ + uint64_t _b ## Delta = 0; \ + if (flags & _flag) { \ + if (!_var) { \ + _var = PerfCounter_new(lp->super.pid, _type, _config); \ + _b ## Ok = PerfCounter_read(_var); \ + _b ## Delta = 0; \ + } else { \ + _b ## Ok = PerfCounter_read(_var); \ + _b ## Delta = PerfCounter_delta(_var); \ + } \ + if (_b ## Ok) { \ + } \ + } else { \ + if (_var) { \ + PerfCounter_delete(_var); \ + _var = NULL; \ + } \ + } + +#define SET_IF(_ok, _var, _exp) \ + if (_ok) { \ + _var = _exp; \ + } else { \ + _var = -1; \ + } + +#define SET_IFNZ(_ok, _z, _var, _exp) \ + if (_ok) { \ + if (_z > 0) { \ + _var = _exp; \ + } else { \ + _var = 0; \ + } \ + } else { \ + _var = -1; \ + } + +#define L1DR (PERF_COUNT_HW_CACHE_L1D | (PERF_COUNT_HW_CACHE_OP_READ << 8) | (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16)) +#define L1DRM (PERF_COUNT_HW_CACHE_L1D | (PERF_COUNT_HW_CACHE_OP_READ << 8) | (PERF_COUNT_HW_CACHE_RESULT_MISS << 16)) +#define L1DW (PERF_COUNT_HW_CACHE_L1D | (PERF_COUNT_HW_CACHE_OP_WRITE << 8) | (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16)) +#define L1DWM (PERF_COUNT_HW_CACHE_L1D | (PERF_COUNT_HW_CACHE_OP_WRITE << 8) | (PERF_COUNT_HW_CACHE_RESULT_MISS << 16)) + #endif void ProcessList_goThroughEntries(ProcessList* super); diff --git a/linux/Platform.c b/linux/Platform.c index 025abff6..8ce890f8 100644 --- a/linux/Platform.c +++ b/linux/Platform.c @@ -22,6 +22,7 @@ in the source distribution for its full text. #include "ClockMeter.h" #include "HostnameMeter.h" #include "LinuxProcess.h" +#include "CRT.h" #include #include diff --git a/scripts/MakeHeader.py b/scripts/MakeHeader.py index 4841bdac..2393afc2 100755 --- a/scripts/MakeHeader.py +++ b/scripts/MakeHeader.py @@ -12,6 +12,7 @@ ANY=1 COPY=2 SKIP=3 SKIPONE=4 +COPYDEFINE=5 state = ANY static = 0 @@ -49,7 +50,11 @@ for line in file.readlines(): elif len(line) > 1: static = 0 equals = line.find(" = ") - if line[-3:] == "= {": + if line[:7] == "#define": + if line[-1:] == "\\": + state = COPYDEFINE + out.write( line + "\n") + elif line[-3:] == "= {": out.write( "extern " + line[:-4] + ";\n" ) state = SKIP elif equals != -1: @@ -60,7 +65,7 @@ for line in file.readlines(): out.write( line[:-2].replace("inline", "extern") + ";\n" ) state = SKIP else: - out.write( line + "\n") + out.write( line + "\n" ) is_blank = False elif line == "": if not is_blank: @@ -69,6 +74,11 @@ for line in file.readlines(): else: out.write( line + "\n") is_blank = False + elif state == COPYDEFINE: + is_blank = False + out.write( line + "\n") + if line[-1:] != "\\": + state = ANY elif state == COPY: is_blank = False if line == "}*/":