mirror of https://github.com/xzeldon/htop.git
Add IPC performance counter for Linux
This commit is contained in:
parent
fb0b5926d2
commit
f8d6560d71
|
@ -39,10 +39,12 @@ EnvScreen.h InfoScreen.h XAlloc.h
|
||||||
if HTOP_LINUX
|
if HTOP_LINUX
|
||||||
htop_CFLAGS += -rdynamic
|
htop_CFLAGS += -rdynamic
|
||||||
myhtopplatsources = linux/Platform.c linux/IOPriorityPanel.c linux/IOPriority.c \
|
myhtopplatsources = linux/Platform.c linux/IOPriorityPanel.c linux/IOPriority.c \
|
||||||
linux/LinuxProcess.c linux/LinuxProcessList.c linux/LinuxCRT.c linux/Battery.c
|
linux/LinuxProcess.c linux/LinuxProcessList.c linux/LinuxCRT.c linux/Battery.c \
|
||||||
|
linux/PerfCounter.c
|
||||||
|
|
||||||
myhtopplatheaders = linux/Platform.h linux/IOPriorityPanel.h linux/IOPriority.h \
|
myhtopplatheaders = linux/Platform.h linux/IOPriorityPanel.h linux/IOPriority.h \
|
||||||
linux/LinuxProcess.h linux/LinuxProcessList.h linux/LinuxCRT.h linux/Battery.h
|
linux/LinuxProcess.h linux/LinuxProcessList.h linux/LinuxCRT.h linux/Battery.h \
|
||||||
|
linux/PerfCounter.h
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if HTOP_FREEBSD
|
if HTOP_FREEBSD
|
||||||
|
|
|
@ -257,8 +257,10 @@ then
|
||||||
fi
|
fi
|
||||||
|
|
||||||
AC_ARG_ENABLE(perfcounters, [AS_HELP_STRING([--enable-perfcounters], [enable hardware performance counters])],, enable_perfcounters="yes")
|
AC_ARG_ENABLE(perfcounters, [AS_HELP_STRING([--enable-perfcounters], [enable hardware performance counters])],, enable_perfcounters="yes")
|
||||||
if test "x$enable_perfcounters_$my_htop_platform" = xyes_linux
|
if test "x$enable_perfcounters" = "xyes" -a "$my_htop_platform" = "linux"
|
||||||
then
|
then
|
||||||
|
AC_DEFINE(HAVE_PERFCOUNTERS, 1, [Define if hardware performance counter support should be enabled.])
|
||||||
|
|
||||||
AC_CHECK_HEADERS([linux/perf_counter.h], [have_perf_counter=yes],
|
AC_CHECK_HEADERS([linux/perf_counter.h], [have_perf_counter=yes],
|
||||||
[have_perf_counter=no])
|
[have_perf_counter=no])
|
||||||
|
|
||||||
|
|
|
@ -18,11 +18,14 @@ in the source distribution for its full text.
|
||||||
|
|
||||||
/*{
|
/*{
|
||||||
|
|
||||||
|
#include "PerfCounter.h"
|
||||||
|
|
||||||
#define PROCESS_FLAG_LINUX_IOPRIO 0x0100
|
#define PROCESS_FLAG_LINUX_IOPRIO 0x0100
|
||||||
#define PROCESS_FLAG_LINUX_OPENVZ 0x0200
|
#define PROCESS_FLAG_LINUX_OPENVZ 0x0200
|
||||||
#define PROCESS_FLAG_LINUX_VSERVER 0x0400
|
#define PROCESS_FLAG_LINUX_VSERVER 0x0400
|
||||||
#define PROCESS_FLAG_LINUX_CGROUP 0x0800
|
#define PROCESS_FLAG_LINUX_CGROUP 0x0800
|
||||||
#define PROCESS_FLAG_LINUX_OOM 0x1000
|
#define PROCESS_FLAG_LINUX_OOM 0x1000
|
||||||
|
#define PROCESS_FLAG_LINUX_HPC 0x2000
|
||||||
|
|
||||||
typedef enum UnsupportedProcessFields {
|
typedef enum UnsupportedProcessFields {
|
||||||
FLAGS = 9,
|
FLAGS = 9,
|
||||||
|
@ -86,7 +89,10 @@ typedef enum LinuxProcessFields {
|
||||||
PERCENT_IO_DELAY = 117,
|
PERCENT_IO_DELAY = 117,
|
||||||
PERCENT_SWAP_DELAY = 118,
|
PERCENT_SWAP_DELAY = 118,
|
||||||
#endif
|
#endif
|
||||||
LAST_PROCESSFIELD = 119,
|
#ifdef HAVE_PERFCOUNTERS
|
||||||
|
IPC = 119,
|
||||||
|
#endif
|
||||||
|
LAST_PROCESSFIELD = 120,
|
||||||
} LinuxProcessField;
|
} LinuxProcessField;
|
||||||
|
|
||||||
#include "IOPriority.h"
|
#include "IOPriority.h"
|
||||||
|
@ -139,6 +145,11 @@ typedef struct LinuxProcess_ {
|
||||||
float blkio_delay_percent;
|
float blkio_delay_percent;
|
||||||
float swapin_delay_percent;
|
float swapin_delay_percent;
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef HAVE_PERFCOUNTERS
|
||||||
|
PerfCounter* cycleCounter;
|
||||||
|
PerfCounter* insnCounter;
|
||||||
|
double ipc;
|
||||||
|
#endif
|
||||||
} LinuxProcess;
|
} LinuxProcess;
|
||||||
|
|
||||||
#ifndef Process_isKernelThread
|
#ifndef Process_isKernelThread
|
||||||
|
@ -233,6 +244,9 @@ ProcessFieldData Process_fields[] = {
|
||||||
[PERCENT_CPU_DELAY] = { .name = "PERCENT_CPU_DELAY", .title = "CPUD% ", .description = "CPU delay %", .flags = 0, },
|
[PERCENT_CPU_DELAY] = { .name = "PERCENT_CPU_DELAY", .title = "CPUD% ", .description = "CPU delay %", .flags = 0, },
|
||||||
[PERCENT_IO_DELAY] = { .name = "PERCENT_IO_DELAY", .title = "IOD% ", .description = "Block I/O 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 = "SWAPD% ", .description = "Swapin delay %", .flags = 0, },
|
||||||
|
#endif
|
||||||
|
#ifdef HAVE_PERFCOUNTERS
|
||||||
|
[IPC] = { .name = "IPC", .title = " IPC ", .description = "Executed instructions per cycle", .flags = PROCESS_FLAG_LINUX_HPC, },
|
||||||
#endif
|
#endif
|
||||||
[LAST_PROCESSFIELD] = { .name = "*** report bug! ***", .title = NULL, .description = NULL, .flags = 0, },
|
[LAST_PROCESSFIELD] = { .name = "*** report bug! ***", .title = NULL, .description = NULL, .flags = 0, },
|
||||||
};
|
};
|
||||||
|
@ -273,6 +287,10 @@ void Process_delete(Object* cast) {
|
||||||
Process_done((Process*)cast);
|
Process_done((Process*)cast);
|
||||||
#ifdef HAVE_CGROUP
|
#ifdef HAVE_CGROUP
|
||||||
free(this->cgroup);
|
free(this->cgroup);
|
||||||
|
#endif
|
||||||
|
#ifdef HAVE_PERFCOUNTERS
|
||||||
|
PerfCounter_delete(this->cycleCounter);
|
||||||
|
PerfCounter_delete(this->insnCounter);
|
||||||
#endif
|
#endif
|
||||||
free(this->ttyDevice);
|
free(this->ttyDevice);
|
||||||
free(this);
|
free(this);
|
||||||
|
@ -394,6 +412,16 @@ void LinuxProcess_writeField(Process* this, RichString* str, ProcessField field)
|
||||||
case PERCENT_IO_DELAY: LinuxProcess_printDelay(lp->blkio_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_SWAP_DELAY: LinuxProcess_printDelay(lp->swapin_delay_percent, buffer, n); break;
|
||||||
#endif
|
#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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
default:
|
default:
|
||||||
Process_writeField((Process*)this, str, field);
|
Process_writeField((Process*)this, str, field);
|
||||||
return;
|
return;
|
||||||
|
@ -463,6 +491,10 @@ long LinuxProcess_compare(const void* v1, const void* v2) {
|
||||||
case PERCENT_SWAP_DELAY:
|
case PERCENT_SWAP_DELAY:
|
||||||
return (p2->swapin_delay_percent > p1->swapin_delay_percent ? 1 : -1);
|
return (p2->swapin_delay_percent > p1->swapin_delay_percent ? 1 : -1);
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef HAVE_PERFCOUNTERS
|
||||||
|
case IPC:
|
||||||
|
return (p2->ipc > p1->ipc ? 1 : -1);
|
||||||
|
#endif
|
||||||
case IO_PRIORITY:
|
case IO_PRIORITY:
|
||||||
return LinuxProcess_effectiveIOPriority(p1) - LinuxProcess_effectiveIOPriority(p2);
|
return LinuxProcess_effectiveIOPriority(p1) - LinuxProcess_effectiveIOPriority(p2);
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -10,11 +10,14 @@ in the source distribution for its full text.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "PerfCounter.h"
|
||||||
|
|
||||||
#define PROCESS_FLAG_LINUX_IOPRIO 0x0100
|
#define PROCESS_FLAG_LINUX_IOPRIO 0x0100
|
||||||
#define PROCESS_FLAG_LINUX_OPENVZ 0x0200
|
#define PROCESS_FLAG_LINUX_OPENVZ 0x0200
|
||||||
#define PROCESS_FLAG_LINUX_VSERVER 0x0400
|
#define PROCESS_FLAG_LINUX_VSERVER 0x0400
|
||||||
#define PROCESS_FLAG_LINUX_CGROUP 0x0800
|
#define PROCESS_FLAG_LINUX_CGROUP 0x0800
|
||||||
#define PROCESS_FLAG_LINUX_OOM 0x1000
|
#define PROCESS_FLAG_LINUX_OOM 0x1000
|
||||||
|
#define PROCESS_FLAG_LINUX_HPC 0x2000
|
||||||
|
|
||||||
typedef enum UnsupportedProcessFields {
|
typedef enum UnsupportedProcessFields {
|
||||||
FLAGS = 9,
|
FLAGS = 9,
|
||||||
|
@ -78,7 +81,10 @@ typedef enum LinuxProcessFields {
|
||||||
PERCENT_IO_DELAY = 117,
|
PERCENT_IO_DELAY = 117,
|
||||||
PERCENT_SWAP_DELAY = 118,
|
PERCENT_SWAP_DELAY = 118,
|
||||||
#endif
|
#endif
|
||||||
LAST_PROCESSFIELD = 119,
|
#ifdef HAVE_PERFCOUNTERS
|
||||||
|
IPC = 119,
|
||||||
|
#endif
|
||||||
|
LAST_PROCESSFIELD = 120,
|
||||||
} LinuxProcessField;
|
} LinuxProcessField;
|
||||||
|
|
||||||
#include "IOPriority.h"
|
#include "IOPriority.h"
|
||||||
|
@ -131,6 +137,11 @@ typedef struct LinuxProcess_ {
|
||||||
float blkio_delay_percent;
|
float blkio_delay_percent;
|
||||||
float swapin_delay_percent;
|
float swapin_delay_percent;
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef HAVE_PERFCOUNTERS
|
||||||
|
PerfCounter* cycleCounter;
|
||||||
|
PerfCounter* insnCounter;
|
||||||
|
double ipc;
|
||||||
|
#endif
|
||||||
} LinuxProcess;
|
} LinuxProcess;
|
||||||
|
|
||||||
#ifndef Process_isKernelThread
|
#ifndef Process_isKernelThread
|
||||||
|
|
|
@ -660,6 +660,32 @@ static void LinuxProcessList_readDelayAcctData(LinuxProcessList* this, LinuxProc
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#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);
|
||||||
|
}
|
||||||
|
if (!lp->insnCounter) {
|
||||||
|
lp->insnCounter = PerfCounter_new(lp->super.pid, PERF_TYPE_HARDWARE, PERF_COUNT_HW_INSTRUCTIONS);
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
static void setCommand(Process* process, const char* command, int len) {
|
static void setCommand(Process* process, const char* command, int len) {
|
||||||
if (process->comm && process->commLen >= len) {
|
if (process->comm && process->commLen >= len) {
|
||||||
strncpy(process->comm, command, len + 1);
|
strncpy(process->comm, command, len + 1);
|
||||||
|
@ -871,6 +897,11 @@ static bool LinuxProcessList_recurseProcTree(LinuxProcessList* this, const char*
|
||||||
if (ss->flags & PROCESS_FLAG_LINUX_OOM)
|
if (ss->flags & PROCESS_FLAG_LINUX_OOM)
|
||||||
LinuxProcessList_readOomData(lp, dirname, name);
|
LinuxProcessList_readOomData(lp, dirname, name);
|
||||||
|
|
||||||
|
#ifdef HAVE_PERFCOUNTERS
|
||||||
|
if (ss->flags & PROCESS_FLAG_LINUX_HPC)
|
||||||
|
LinuxProcessList_readPerfCounters(lp);
|
||||||
|
#endif
|
||||||
|
|
||||||
if (proc->state == 'Z' && (proc->basenameOffset == 0)) {
|
if (proc->state == 'Z' && (proc->basenameOffset == 0)) {
|
||||||
proc->basenameOffset = -1;
|
proc->basenameOffset = -1;
|
||||||
setCommand(proc, command, commLen);
|
setCommand(proc, command, commLen);
|
||||||
|
|
|
@ -116,6 +116,10 @@ void ProcessList_delete(ProcessList* pl);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_PERFCOUNTERS
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
void ProcessList_goThroughEntries(ProcessList* super);
|
void ProcessList_goThroughEntries(ProcessList* super);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue