summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--configure.ac11
-rw-r--r--htop.1.in9
-rw-r--r--linux/LinuxProcess.c44
-rw-r--r--linux/LinuxProcess.h20
-rw-r--r--linux/LinuxProcessList.c112
-rw-r--r--linux/LinuxProcessList.h15
6 files changed, 209 insertions, 2 deletions
diff --git a/configure.ac b/configure.ac
index f8af8a96..4b266535 100644
--- a/configure.ac
+++ b/configure.ac
@@ -256,6 +256,17 @@ then
AC_DEFINE(HAVE_SETUID_ENABLED, 1, [Define if setuid support should be enabled.])
fi
+AC_ARG_ENABLE(delayacct, [AS_HELP_STRING([--enable-delayacct], [enable linux delay accounting])],, enable_delayacct="no")
+if test "x$enable_delayacct" = xyes
+then
+ PKG_CHECK_MODULES(LIBNL3, libnl-3.0, [], [missing_libraries="$missing_libraries libnl-3"])
+ PKG_CHECK_MODULES(LIBNL3GENL, libnl-genl-3.0, [], [missing_libraries="$missing_libraries libnl-genl-3"])
+ CFLAGS+=" $LIBNL3_CFLAGS $LIBNL3GENL_CFLAGS"
+ LIBS+=" $LIBNL3_LIBS $LIBNL3GENL_LIBS"
+ AC_DEFINE(HAVE_DELAYACCT, 1, [Define if delay accounting support should be enabled.])
+fi
+
+
# Bail out on errors.
# ----------------------------------------------------------------------
if test ! -z "$missing_libraries"; then
diff --git a/htop.1.in b/htop.1.in
index 4388be12..cb9adb07 100644
--- a/htop.1.in
+++ b/htop.1.in
@@ -370,6 +370,15 @@ The I/O scheduling class followed by the priority if the class supports it:
\fBB\fR for Best-effort
\fBid\fR for Idle
.TP
+.B PERCENT_CPU_DELAY (CPUD%)
+The percentage of time spent waiting for a CPU (while runnable). Requires CAP_NET_ADMIN.
+.TP
+.B PERCENT_IO_DELAY (IOD%)
+The percentage of time spent waiting for the completion of synchronous block I/O. Requires CAP_NET_ADMIN.
+.TP
+.B PERCENT_SWAP_DELAY (SWAPD%)
+The percentage of time spent swapping in pages. Requires CAP_NET_ADMIN.
+.TP
.B All other flags
Currently unsupported (always displays '-').
diff --git a/linux/LinuxProcess.c b/linux/LinuxProcess.c
index bb9e99bb..72408cfa 100644
--- a/linux/LinuxProcess.c
+++ b/linux/LinuxProcess.c
@@ -81,7 +81,12 @@ typedef enum LinuxProcessFields {
#endif
OOM = 114,
IO_PRIORITY = 115,
- LAST_PROCESSFIELD = 116,
+ #ifdef HAVE_DELAYACCT
+ PERCENT_CPU_DELAY = 116,
+ PERCENT_IO_DELAY = 117,
+ PERCENT_SWAP_DELAY = 118,
+ #endif
+ LAST_PROCESSFIELD = 119,
} LinuxProcessField;
#include "IOPriority.h"
@@ -125,6 +130,15 @@ typedef struct LinuxProcess_ {
#endif
unsigned int oom;
char* ttyDevice;
+ #ifdef HAVE_DELAYACCT
+ unsigned long long int delay_read_time;
+ unsigned long long cpu_delay_total;
+ unsigned long long blkio_delay_total;
+ unsigned long long swapin_delay_total;
+ float cpu_delay_percent;
+ float blkio_delay_percent;
+ float swapin_delay_percent;
+ #endif
} LinuxProcess;
#ifndef Process_isKernelThread
@@ -215,6 +229,11 @@ ProcessFieldData Process_fields[] = {
#endif
[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_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, },
+#endif
[LAST_PROCESSFIELD] = { .name = "*** report bug! ***", .title = NULL, .description = NULL, .flags = 0, },
};
@@ -287,6 +306,16 @@ 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);
+ }
+}
+#endif
+
void LinuxProcess_writeField(Process* this, RichString* str, ProcessField field) {
LinuxProcess* lp = (LinuxProcess*) this;
bool coloring = this->settings->highlightMegabytes;
@@ -360,6 +389,11 @@ 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;
+ #endif
default:
Process_writeField((Process*)this, str, field);
return;
@@ -421,6 +455,14 @@ long LinuxProcess_compare(const void* v1, const void* v2) {
#endif
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);
+ #endif
case IO_PRIORITY:
return LinuxProcess_effectiveIOPriority(p1) - LinuxProcess_effectiveIOPriority(p2);
default:
diff --git a/linux/LinuxProcess.h b/linux/LinuxProcess.h
index b42808e1..9400d7be 100644
--- a/linux/LinuxProcess.h
+++ b/linux/LinuxProcess.h
@@ -73,7 +73,12 @@ typedef enum LinuxProcessFields {
#endif
OOM = 114,
IO_PRIORITY = 115,
- LAST_PROCESSFIELD = 116,
+ #ifdef HAVE_DELAYACCT
+ PERCENT_CPU_DELAY = 116,
+ PERCENT_IO_DELAY = 117,
+ PERCENT_SWAP_DELAY = 118,
+ #endif
+ LAST_PROCESSFIELD = 119,
} LinuxProcessField;
#include "IOPriority.h"
@@ -117,6 +122,15 @@ typedef struct LinuxProcess_ {
#endif
unsigned int oom;
char* ttyDevice;
+ #ifdef HAVE_DELAYACCT
+ unsigned long long int delay_read_time;
+ unsigned long long cpu_delay_total;
+ unsigned long long blkio_delay_total;
+ unsigned long long swapin_delay_total;
+ float cpu_delay_percent;
+ float blkio_delay_percent;
+ float swapin_delay_percent;
+ #endif
} LinuxProcess;
#ifndef Process_isKernelThread
@@ -152,6 +166,10 @@ 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);
+#endif
+
void LinuxProcess_writeField(Process* this, RichString* str, ProcessField field);
long LinuxProcess_compare(const void* v1, const void* v2);
diff --git a/linux/LinuxProcessList.c b/linux/LinuxProcessList.c
index 4b585e30..6f2631af 100644
--- a/linux/LinuxProcessList.c
+++ b/linux/LinuxProcessList.c
@@ -27,6 +27,16 @@ in the source distribution for its full text.
#include <sys/types.h>
#include <fcntl.h>
+#ifdef HAVE_DELAYACCT
+#include <netlink/attr.h>
+#include <netlink/netlink.h>
+#include <netlink/genl/genl.h>
+#include <netlink/genl/ctrl.h>
+#include <netlink/socket.h>
+#include <netlink/msg.h>
+#include <linux/taskstats.h>
+#endif
+
/*{
#include "ProcessList.h"
@@ -72,6 +82,10 @@ typedef struct LinuxProcessList_ {
CPUData* cpus;
TtyDriver* ttyDrivers;
+ #ifdef HAVE_DELAYACCT
+ struct nl_sock *netlink_socket;
+ int netlink_family;
+ #endif
} LinuxProcessList;
#ifndef PROCDIR
@@ -192,6 +206,21 @@ static void LinuxProcessList_initTtyDrivers(LinuxProcessList* this) {
this->ttyDrivers = ttyDrivers;
}
+#ifdef HAVE_DELAYACCT
+
+static void LinuxProcessList_initNetlinkSocket(LinuxProcessList* this) {
+ this->netlink_socket = nl_socket_alloc();
+ if (this->netlink_socket == NULL) {
+ return;
+ }
+ if (nl_connect(this->netlink_socket, NETLINK_GENERIC) < 0) {
+ return;
+ }
+ this->netlink_family = genl_ctrl_resolve(this->netlink_socket, TASKSTATS_GENL_NAME);
+}
+
+#endif
+
ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* pidWhiteList, uid_t userId) {
LinuxProcessList* this = xCalloc(1, sizeof(LinuxProcessList));
ProcessList* pl = &(this->super);
@@ -199,6 +228,10 @@ ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* pidWhiteList, ui
LinuxProcessList_initTtyDrivers(this);
+ #ifdef HAVE_DELAYACCT
+ LinuxProcessList_initNetlinkSocket(this);
+ #endif
+
// Update CPU count:
FILE* file = fopen(PROCSTATFILE, "r");
if (file == NULL) {
@@ -234,6 +267,12 @@ void ProcessList_delete(ProcessList* pl) {
}
free(this->ttyDrivers);
}
+ #ifdef HAVE_DELAYACCT
+ if (this->netlink_socket) {
+ nl_close(this->netlink_socket);
+ nl_socket_free(this->netlink_socket);
+ }
+ #endif
free(this);
}
@@ -552,6 +591,75 @@ static void LinuxProcessList_readOomData(LinuxProcess* process, const char* dirn
fclose(file);
}
+#ifdef HAVE_DELAYACCT
+
+static int handleNetlinkMsg(struct nl_msg *nlmsg, void *linuxProcess) {
+ struct nlmsghdr *nlhdr;
+ struct nlattr *nlattrs[TASKSTATS_TYPE_MAX + 1];
+ struct nlattr *nlattr;
+ struct taskstats *stats;
+ int rem;
+ unsigned long long int timeDelta;
+ LinuxProcess* lp = (LinuxProcess*) linuxProcess;
+
+ nlhdr = nlmsg_hdr(nlmsg);
+
+ if (genlmsg_parse(nlhdr, 0, nlattrs, TASKSTATS_TYPE_MAX, NULL) < 0) {
+ return NL_SKIP;
+ }
+
+ if ((nlattr = nlattrs[TASKSTATS_TYPE_AGGR_PID]) || (nlattr = nlattrs[TASKSTATS_TYPE_NULL])) {
+ stats = nla_data(nla_next(nla_data(nlattr), &rem));
+ assert(lp->super.pid == stats->ac_pid);
+ timeDelta = (stats->ac_etime*1000 - lp->delay_read_time);
+ #define BOUNDS(x) isnan(x) ? 0.0 : (x > 100) ? 100.0 : x;
+ #define DELTAPERC(x,y) BOUNDS((float) (x - y) / timeDelta * 100);
+ lp->cpu_delay_percent = DELTAPERC(stats->cpu_delay_total, lp->cpu_delay_total);
+ lp->blkio_delay_percent = DELTAPERC(stats->blkio_delay_total, lp->blkio_delay_total);
+ lp->swapin_delay_percent = DELTAPERC(stats->swapin_delay_total, lp->swapin_delay_total);
+ #undef DELTAPERC
+ #undef BOUNDS
+ lp->swapin_delay_total = stats->swapin_delay_total;
+ lp->blkio_delay_total = stats->blkio_delay_total;
+ lp->cpu_delay_total = stats->cpu_delay_total;
+ lp->delay_read_time = stats->ac_etime*1000;
+ }
+ return NL_OK;
+}
+
+static void LinuxProcessList_readDelayAcctData(LinuxProcessList* this, LinuxProcess* process) {
+ struct nl_msg *msg;
+
+ if (nl_socket_modify_cb(this->netlink_socket, NL_CB_VALID, NL_CB_CUSTOM, handleNetlinkMsg, process) < 0) {
+ return;
+ }
+
+ if (! (msg = nlmsg_alloc())) {
+ return;
+ }
+
+ if (! genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, this->netlink_family, 0, NLM_F_REQUEST, TASKSTATS_CMD_GET, TASKSTATS_VERSION)) {
+ nlmsg_free(msg);
+ }
+
+ if (nla_put_u32(msg, TASKSTATS_CMD_ATTR_PID, process->super.pid) < 0) {
+ nlmsg_free(msg);
+ }
+
+ if (nl_send_sync(this->netlink_socket, msg) < 0) {
+ process->swapin_delay_percent = -1LL;
+ process->blkio_delay_percent = -1LL;
+ process->cpu_delay_percent = -1LL;
+ return;
+ }
+
+ if (nl_recvmsgs_default(this->netlink_socket) < 0) {
+ return;
+ }
+}
+
+#endif
+
static void setCommand(Process* process, const char* command, int len) {
if (process->comm && process->commLen >= len) {
strncpy(process->comm, command, len + 1);
@@ -750,6 +858,10 @@ static bool LinuxProcessList_recurseProcTree(LinuxProcessList* this, const char*
}
}
+ #ifdef HAVE_DELAYACCT
+ LinuxProcessList_readDelayAcctData(this, lp);
+ #endif
+
#ifdef HAVE_CGROUP
if (settings->flags & PROCESS_FLAG_LINUX_CGROUP)
LinuxProcessList_readCGroupFile(lp, dirname, name);
diff --git a/linux/LinuxProcessList.h b/linux/LinuxProcessList.h
index ce39f805..5005220a 100644
--- a/linux/LinuxProcessList.h
+++ b/linux/LinuxProcessList.h
@@ -9,6 +9,9 @@ Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
*/
+#ifdef HAVE_DELAYACCT
+#endif
+
#include "ProcessList.h"
@@ -53,6 +56,10 @@ typedef struct LinuxProcessList_ {
CPUData* cpus;
TtyDriver* ttyDrivers;
+ #ifdef HAVE_DELAYACCT
+ struct nl_sock *netlink_socket;
+ int netlink_family;
+ #endif
} LinuxProcessList;
#ifndef PROCDIR
@@ -80,6 +87,10 @@ typedef struct LinuxProcessList_ {
#define CLAMP(x,low,high) (((x)>(high))?(high):(((x)<(low))?(low):(x)))
#endif
+#ifdef HAVE_DELAYACCT
+
+#endif
+
ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* pidWhiteList, uid_t userId);
void ProcessList_delete(ProcessList* pl);
@@ -101,6 +112,10 @@ void ProcessList_delete(ProcessList* pl);
#endif
+#ifdef HAVE_DELAYACCT
+
+#endif
+
void ProcessList_goThroughEntries(ProcessList* super);
#endif