summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHisham Muhammad <hisham@gobolinux.org>2008-03-09 08:02:22 +0000
committerHisham Muhammad <hisham@gobolinux.org>2008-03-09 08:02:22 +0000
commit12f4f09e6ed288bdedc86e4ef22f3cc34f0e787a (patch)
tree0b3ce5d14fc72ae391378fa178a0a18b69298664
parent460608d6e215dee3d3af822d974f3a36e5f73d3c (diff)
Add support for Linux per-process IO statistics,
enabled with the --enable-taskstats flag, which requires a kernel compiled with taskstats support. Thanks to Tobias Oetiker!
-rw-r--r--ChangeLog4
-rw-r--r--Process.c76
-rw-r--r--Process.h16
-rw-r--r--ProcessList.c48
-rw-r--r--ProcessList.h4
-rw-r--r--configure.ac5
6 files changed, 149 insertions, 4 deletions
diff --git a/ChangeLog b/ChangeLog
index b4ecb17e..11feffef 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,6 +1,10 @@
What's new in version 0.7.1
+* Add support for Linux per-process IO statistics,
+ enabled with the --enable-taskstats flag, which
+ requires a kernel compiled with taskstats support.
+ (thanks to Tobias Oetiker)
* Add Unicode support, enabled with the --enable-unicode
flag, which requires libncursesw.
(thanks to Sergej Pupykin)
diff --git a/Process.c b/Process.c
index 0b551ebb..95bfbade 100644
--- a/Process.c
+++ b/Process.c
@@ -49,6 +49,9 @@ typedef enum ProcessField_ {
#ifdef HAVE_OPENVZ
VEID, VPID,
#endif
+ #ifdef HAVE_TASKSTATS
+ RCHAR, WCHAR, SYSCR, SYSCW, RBYTES, WBYTES, CNCLWB, IO_READ_RATE, IO_WRITE_RATE,
+ #endif
LAST_PROCESSFIELD
} ProcessField;
@@ -121,6 +124,19 @@ typedef struct Process_ {
unsigned int veid;
unsigned int vpid;
#endif
+ #ifdef HAVE_TASKSTATS
+ unsigned long long io_rchar;
+ unsigned long long io_wchar;
+ unsigned long long io_syscr;
+ unsigned long long io_syscw;
+ unsigned long long io_read_bytes;
+ unsigned long long io_write_bytes;
+ unsigned long long io_cancelled_write_bytes;
+ double io_rate_read_bps;
+ unsigned long long io_rate_read_time;
+ double io_rate_write_bps;
+ unsigned long long io_rate_write_time;
+ #endif
} Process;
}*/
@@ -134,7 +150,10 @@ char* PROCESS_CLASS = "Process";
char *Process_fieldNames[] = {
"", "PID", "Command", "STATE", "PPID", "PGRP", "SESSION", "TTY_NR", "TPGID", "FLAGS", "MINFLT", "CMINFLT", "MAJFLT", "CMAJFLT", "UTIME", "STIME", "CUTIME", "CSTIME", "PRIORITY", "NICE", "ITREALVALUE", "STARTTIME", "VSIZE", "RSS", "RLIM", "STARTCODE", "ENDCODE", "STARTSTACK", "KSTKESP", "KSTKEIP", "SIGNAL", "BLOCKED", "SIGIGNORE", "SIGCATCH", "WCHAN", "NSWAP", "CNSWAP", "EXIT_SIGNAL", "PROCESSOR", "M_SIZE", "M_RESIDENT", "M_SHARE", "M_TRS", "M_DRS", "M_LRS", "M_DT", "ST_UID", "PERCENT_CPU", "PERCENT_MEM", "USER", "TIME", "NLWP", "TGID",
#ifdef HAVE_OPENVZ
-"VEID", "VPID",
+ "VEID", "VPID",
+#endif
+#ifdef HAVE_TASKSTATS
+ "RCHAR", "WCHAR", "SYSCR", "SYSCW", "RBYTES", "WBYTES", "CNCLWB", "IO_READ_RATE", "IO_WRITE_RATE",
#endif
"*** report bug! ***"
};
@@ -142,7 +161,7 @@ char *Process_fieldNames[] = {
static int Process_getuid = -1;
Process* Process_new(struct ProcessList_ *pl) {
- Process* this = malloc(sizeof(Process));
+ Process* this = calloc(sizeof(Process), 1);
Object_setClass(this, PROCESS_CLASS);
((Object*)this)->display = Process_display;
((Object*)this)->delete = Process_delete;
@@ -160,6 +179,19 @@ Process* Process_new(struct ProcessList_ *pl) {
Process* Process_clone(Process* this) {
Process* clone = 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(clone, this, sizeof(Process));
this->comm = NULL;
this->pid = 0;
@@ -400,11 +432,22 @@ void Process_writeField(Process* this, RichString* str, ProcessField field) {
case VEID: snprintf(buffer, n, "%5u ", this->veid); break;
case VPID: snprintf(buffer, n, "%5u ", this->vpid); break;
#endif
+ #ifdef HAVE_TASKSTATS
+ case RCHAR: snprintf(buffer, n, "%10llu ", this->io_rchar); break;
+ case WCHAR: snprintf(buffer, n, "%10llu ", this->io_wchar); break;
+ case SYSCR: snprintf(buffer, n, "%10llu ", this->io_syscr); break;
+ case SYSCW: snprintf(buffer, n, "%10llu ", this->io_syscw); break;
+ case RBYTES: snprintf(buffer, n, "%10llu ", this->io_read_bytes); break;
+ case WBYTES: snprintf(buffer, n, "%10llu ", this->io_write_bytes); break;
+ case CNCLWB: snprintf(buffer, n, "%10llu ", this->io_cancelled_write_bytes); break;
+ case IO_READ_RATE: Process_printLargeNumber(this, str, this->io_rate_read_bps / 1024); return;
+ case IO_WRITE_RATE: Process_printLargeNumber(this, str, this->io_rate_write_bps / 1024); return;
+ #endif
+
default:
snprintf(buffer, n, "- ");
}
RichString_append(str, attr, buffer);
- return;
}
int Process_pidCompare(const void* v1, const void* v2) {
@@ -423,6 +466,7 @@ int Process_compare(const void* v1, const void* v2) {
p2 = (Process*)v1;
p1 = (Process*)v2;
}
+ long long diff;
switch (pl->sortKey) {
case PID:
return (p1->pid - p2->pid);
@@ -470,10 +514,23 @@ int Process_compare(const void* v1, const void* v2) {
case VPID:
return (p1->vpid - p2->vpid);
#endif
+ #ifdef HAVE_TASKSTATS
+ case RCHAR: diff = p2->io_rchar - p1->io_rchar; goto test_diff;
+ case WCHAR: diff = p2->io_wchar - p1->io_wchar; goto test_diff;
+ case SYSCR: diff = p2->io_syscr - p1->io_syscr; goto test_diff;
+ case SYSCW: diff = p2->io_syscw - p1->io_syscw; goto test_diff;
+ case RBYTES: diff = p2->io_read_bytes - p1->io_read_bytes; goto test_diff;
+ case WBYTES: diff = p2->io_write_bytes - p1->io_write_bytes; goto test_diff;
+ case CNCLWB: diff = p2->io_cancelled_write_bytes - p1->io_cancelled_write_bytes; goto test_diff;
+ case IO_READ_RATE: diff = p2->io_rate_read_bps - p1->io_rate_read_bps; goto test_diff;
+ case IO_WRITE_RATE: diff = p2->io_rate_write_bps - p1->io_rate_write_bps; goto test_diff;
+ #endif
+
default:
return (p1->pid - p2->pid);
}
-
+ test_diff:
+ return (diff > 0) ? 1 : (diff < 0 ? -1 : 0);
}
char* Process_printField(ProcessField field) {
@@ -509,6 +566,17 @@ char* Process_printField(ProcessField field) {
case VEID: return " VEID ";
case VPID: return " VPID ";
#endif
+ #ifdef HAVE_TASKSTATS
+ case RCHAR: return " RD_CHAR ";
+ case WCHAR: return " WR_CHAR ";
+ case SYSCR: return " RD_SYSC ";
+ case SYSCW: return " WR_SYSC ";
+ case RBYTES: return " IO_RD ";
+ case WBYTES: return " IO_WR ";
+ case CNCLWB: return " IO_CANCEL ";
+ case IO_READ_RATE: return " IORR ";
+ case IO_WRITE_RATE: return " IOWR ";
+ #endif
default: return "- ";
}
}
diff --git a/Process.h b/Process.h
index b107073d..57133380 100644
--- a/Process.h
+++ b/Process.h
@@ -51,6 +51,9 @@ typedef enum ProcessField_ {
#ifdef HAVE_OPENVZ
VEID, VPID,
#endif
+ #ifdef HAVE_TASKSTATS
+ RCHAR, WCHAR, SYSCR, SYSCW, RBYTES, WBYTES, CNCLWB, IO_READ_RATE, IO_WRITE_RATE,
+ #endif
LAST_PROCESSFIELD
} ProcessField;
@@ -123,6 +126,19 @@ typedef struct Process_ {
unsigned int veid;
unsigned int vpid;
#endif
+ #ifdef HAVE_TASKSTATS
+ unsigned long long io_rchar;
+ unsigned long long io_wchar;
+ unsigned long long io_syscr;
+ unsigned long long io_syscw;
+ unsigned long long io_read_bytes;
+ unsigned long long io_write_bytes;
+ unsigned long long io_cancelled_write_bytes;
+ double io_rate_read_bps;
+ unsigned long long io_rate_read_time;
+ double io_rate_write_bps;
+ unsigned long long io_rate_write_time;
+ #endif
} Process;
diff --git a/ProcessList.c b/ProcessList.c
index 04ac6f3e..e0d0939c 100644
--- a/ProcessList.c
+++ b/ProcessList.c
@@ -499,6 +499,50 @@ bool ProcessList_readStatusFile(ProcessList* this, Process* proc, char* dirname,
return true;
}
+#ifdef HAVE_TASKSTATS
+void ProcessList_readIoFile(ProcessList* this, Process* proc, char* dirname, char* name) {
+ char iofilename[MAX_NAME+1];
+ iofilename[MAX_NAME] = '\0';
+
+ char buffer[256];
+ buffer[255] = '\0';
+
+ snprintf(iofilename, MAX_NAME, "%s/%s/io", dirname, name);
+ FILE* io = ProcessList_fopen(this, iofilename, "r");
+ if (io) {
+ struct timeval tv;
+ gettimeofday(&tv,NULL);
+ unsigned long long now = tv.tv_sec*1000+tv.tv_usec/1000;
+
+ unsigned long long last_read = proc->io_read_bytes;
+ unsigned long long last_write = proc->io_write_bytes;
+ while (!feof(io)) {
+ char* ok = fgets(buffer, 255, io);
+ if (!ok)
+ break;
+ if (ProcessList_read(this, buffer, "rchar: %llu", &proc->io_rchar)) continue;
+ if (ProcessList_read(this, buffer, "wchar: %llu", &proc->io_wchar)) continue;
+ if (ProcessList_read(this, buffer, "syscr: %llu", &proc->io_syscr)) continue;
+ if (ProcessList_read(this, buffer, "syscw: %llu", &proc->io_syscw)) continue;
+ if (ProcessList_read(this, buffer, "read_bytes: %llu", &proc->io_read_bytes)) {
+ proc->io_rate_read_bps =
+ ((double)(proc->io_read_bytes - last_read))/(((double)(now - proc->io_rate_read_time))/1000);
+ proc->io_rate_read_time = now;
+ continue;
+ }
+ if (ProcessList_read(this, buffer, "write_bytes: %llu", &proc->io_write_bytes)) {
+ proc->io_rate_write_bps =
+ ((double)(proc->io_write_bytes - last_write))/(((double)(now - proc->io_rate_write_time))/1000);
+ proc->io_rate_write_time = now;
+ continue;
+ }
+ ProcessList_read(this, buffer, "cancelled_write_bytes: %llu", &proc->io_cancelled_write_bytes);
+ }
+ fclose(io);
+ }
+}
+#endif
+
bool ProcessList_processEntries(ProcessList* this, char* dirname, Process* parent, float period) {
DIR* dir;
struct dirent* entry;
@@ -547,6 +591,10 @@ bool ProcessList_processEntries(ProcessList* this, char* dirname, Process* paren
}
}
+ #ifdef HAVE_TASKSTATS
+ ProcessList_readIoFile(this, process, dirname, name);
+ #endif
+
if (showUserlandThreads && (!parent || pid != parent->pid)) {
char subdirname[MAX_NAME+1];
snprintf(subdirname, MAX_NAME, "%s/%s/task", dirname, name);
diff --git a/ProcessList.h b/ProcessList.h
index 34bdc46e..a13d3998 100644
--- a/ProcessList.h
+++ b/ProcessList.h
@@ -165,6 +165,10 @@ void ProcessList_sort(ProcessList* this);
bool ProcessList_readStatusFile(ProcessList* this, Process* proc, char* dirname, char* name);
+#ifdef HAVE_TASKSTATS
+void ProcessList_readIoFile(ProcessList* this, Process* proc, char* dirname, char* name);
+#endif
+
bool ProcessList_processEntries(ProcessList* this, char* dirname, Process* parent, float period);
void ProcessList_scan(ProcessList* this);
diff --git a/configure.ac b/configure.ac
index f82eff9d..a6c1bdc7 100644
--- a/configure.ac
+++ b/configure.ac
@@ -69,6 +69,11 @@ if test "x$enable_openvz" = xyes; then
AC_DEFINE(HAVE_OPENVZ, 1, [Define if openvz support enabled.])
fi
+AC_ARG_ENABLE(taskstats, [AC_HELP_STRING([--enable-taskstats], [enable per-task IO Stats (taskstats kernel sup required)])], ,enable_taskstats="no")
+if test "x$enable_taskstats" = xyes; then
+ AC_DEFINE(HAVE_TASKSTATS, 1, [Define if taskstats support enabled.])
+fi
+
AC_ARG_ENABLE(unicode, [AC_HELP_STRING([--enable-unicode], [enable Unicode support])], ,enable_unicode="no")
if test "x$enable_unicode" = xyes; then
AC_CHECK_LIB([ncursesw], [refresh], [], [missing_libraries="$missing_libraries libncursesw"])

© 2014-2024 Faster IT GmbH | imprint | privacy policy