taskstats: add context-switch counters

Make available to the user the following task and process performance
statistics:

	* Involuntary Context Switches (task_struct->nivcsw)
	* Voluntary Context Switches (task_struct->nvcsw)

Statistics information is available from:
	1. taskstats interface (Documentation/accounting/)
	2. /proc/PID/status (task only).

This data is useful for detecting hyperactivity patterns between processes.

[akpm@linux-foundation.org: cleanup]
Signed-off-by: Maxim Uvarov <muvarov@ru.mvista.com>
Cc: Shailabh Nagar <nagar@watson.ibm.com>
Cc: Balbir Singh <balbir@in.ibm.com>
Cc: Jay Lan <jlan@engr.sgi.com>
Cc: Jonathan Lim <jlim@sgi.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
Maxim Uvarov 2007-07-15 23:40:48 -07:00 committed by Linus Torvalds
parent a6c15c2b0f
commit b663a79c19
5 changed files with 41 additions and 3 deletions

View file

@ -49,6 +49,7 @@ char name[100];
int dbg; int dbg;
int print_delays; int print_delays;
int print_io_accounting; int print_io_accounting;
int print_task_context_switch_counts;
__u64 stime, utime; __u64 stime, utime;
#define PRINTF(fmt, arg...) { \ #define PRINTF(fmt, arg...) { \
@ -195,7 +196,7 @@ void print_delayacct(struct taskstats *t)
"IO %15s%15s\n" "IO %15s%15s\n"
" %15llu%15llu\n" " %15llu%15llu\n"
"MEM %15s%15s\n" "MEM %15s%15s\n"
" %15llu%15llu\n\n", " %15llu%15llu\n"
"count", "real total", "virtual total", "delay total", "count", "real total", "virtual total", "delay total",
t->cpu_count, t->cpu_run_real_total, t->cpu_run_virtual_total, t->cpu_count, t->cpu_run_real_total, t->cpu_run_virtual_total,
t->cpu_delay_total, t->cpu_delay_total,
@ -204,6 +205,14 @@ void print_delayacct(struct taskstats *t)
"count", "delay total", t->swapin_count, t->swapin_delay_total); "count", "delay total", t->swapin_count, t->swapin_delay_total);
} }
void task_context_switch_counts(struct taskstats *t)
{
printf("\n\nTask %15s%15s\n"
" %15lu%15lu\n",
"voluntary", "nonvoluntary",
t->nvcsw, t->nivcsw);
}
void print_ioacct(struct taskstats *t) void print_ioacct(struct taskstats *t)
{ {
printf("%s: read=%llu, write=%llu, cancelled_write=%llu\n", printf("%s: read=%llu, write=%llu, cancelled_write=%llu\n",
@ -235,7 +244,7 @@ int main(int argc, char *argv[])
struct msgtemplate msg; struct msgtemplate msg;
while (1) { while (1) {
c = getopt(argc, argv, "diw:r:m:t:p:vl"); c = getopt(argc, argv, "qdiw:r:m:t:p:vl");
if (c < 0) if (c < 0)
break; break;
@ -248,6 +257,10 @@ int main(int argc, char *argv[])
printf("printing IO accounting\n"); printf("printing IO accounting\n");
print_io_accounting = 1; print_io_accounting = 1;
break; break;
case 'q':
printf("printing task/process context switch rates\n");
print_task_context_switch_counts = 1;
break;
case 'w': case 'w':
logfile = strdup(optarg); logfile = strdup(optarg);
printf("write to file %s\n", logfile); printf("write to file %s\n", logfile);
@ -389,6 +402,8 @@ int main(int argc, char *argv[])
print_delayacct((struct taskstats *) NLA_DATA(na)); print_delayacct((struct taskstats *) NLA_DATA(na));
if (print_io_accounting) if (print_io_accounting)
print_ioacct((struct taskstats *) NLA_DATA(na)); print_ioacct((struct taskstats *) NLA_DATA(na));
if (print_task_context_switch_counts)
task_context_switch_counts((struct taskstats *) NLA_DATA(na));
if (fd) { if (fd) {
if (write(fd, NLA_DATA(na), na->nla_len) < 0) { if (write(fd, NLA_DATA(na), na->nla_len) < 0) {
err(1,"write error\n"); err(1,"write error\n");

View file

@ -22,6 +22,8 @@ There are three different groups of fields in the struct taskstats:
/* Extended accounting fields end */ /* Extended accounting fields end */
Their values are collected if CONFIG_TASK_XACCT is set. Their values are collected if CONFIG_TASK_XACCT is set.
4) Per-task and per-thread context switch count statistics
Future extension should add fields to the end of the taskstats struct, and Future extension should add fields to the end of the taskstats struct, and
should not change the relative position of each field within the struct. should not change the relative position of each field within the struct.
@ -158,4 +160,8 @@ struct taskstats {
/* Extended accounting fields end */ /* Extended accounting fields end */
4) Per-task and per-thread statistics
__u64 nvcsw; /* Context voluntary switch counter */
__u64 nivcsw; /* Context involuntary switch counter */
} }

View file

@ -289,6 +289,15 @@ static inline char *task_cap(struct task_struct *p, char *buffer)
cap_t(p->cap_effective)); cap_t(p->cap_effective));
} }
static inline char *task_context_switch_counts(struct task_struct *p,
char *buffer)
{
return buffer + sprintf(buffer, "voluntary_ctxt_switches:\t%lu\n"
"nonvoluntary_ctxt_switches:\t%lu\n",
p->nvcsw,
p->nivcsw);
}
int proc_pid_status(struct task_struct *task, char * buffer) int proc_pid_status(struct task_struct *task, char * buffer)
{ {
char * orig = buffer; char * orig = buffer;
@ -307,6 +316,7 @@ int proc_pid_status(struct task_struct *task, char * buffer)
#if defined(CONFIG_S390) #if defined(CONFIG_S390)
buffer = task_show_regs(task, buffer); buffer = task_show_regs(task, buffer);
#endif #endif
buffer = task_context_switch_counts(task, buffer);
return buffer - orig; return buffer - orig;
} }

View file

@ -31,7 +31,7 @@
*/ */
#define TASKSTATS_VERSION 4 #define TASKSTATS_VERSION 5
#define TS_COMM_LEN 32 /* should be >= TASK_COMM_LEN #define TS_COMM_LEN 32 /* should be >= TASK_COMM_LEN
* in linux/sched.h */ * in linux/sched.h */
@ -149,6 +149,9 @@ struct taskstats {
__u64 read_bytes; /* bytes of read I/O */ __u64 read_bytes; /* bytes of read I/O */
__u64 write_bytes; /* bytes of write I/O */ __u64 write_bytes; /* bytes of write I/O */
__u64 cancelled_write_bytes; /* bytes of cancelled write I/O */ __u64 cancelled_write_bytes; /* bytes of cancelled write I/O */
__u64 nvcsw; /* voluntary_ctxt_switches */
__u64 nivcsw; /* nonvoluntary_ctxt_switches */
}; };

View file

@ -196,6 +196,8 @@ static int fill_pid(pid_t pid, struct task_struct *tsk,
/* fill in basic acct fields */ /* fill in basic acct fields */
stats->version = TASKSTATS_VERSION; stats->version = TASKSTATS_VERSION;
stats->nvcsw = tsk->nvcsw;
stats->nivcsw = tsk->nivcsw;
bacct_add_tsk(stats, tsk); bacct_add_tsk(stats, tsk);
/* fill in extended acct fields */ /* fill in extended acct fields */
@ -242,6 +244,8 @@ static int fill_tgid(pid_t tgid, struct task_struct *first,
*/ */
delayacct_add_tsk(stats, tsk); delayacct_add_tsk(stats, tsk);
stats->nvcsw += tsk->nvcsw;
stats->nivcsw += tsk->nivcsw;
} while_each_thread(first, tsk); } while_each_thread(first, tsk);
unlock_task_sighand(first, &flags); unlock_task_sighand(first, &flags);