diff --git a/Documentation/accounting/getdelays.c b/Documentation/accounting/getdelays.c index 71acc28ed0d1b8b6b3692362bcf9d6ef4d7fcd02..24c5aade89987998260f956bfc16dacfe3d48841 100644 --- a/Documentation/accounting/getdelays.c +++ b/Documentation/accounting/getdelays.c @@ -49,6 +49,7 @@ char name[100]; int dbg; int print_delays; int print_io_accounting; +int print_task_context_switch_counts; __u64 stime, utime; #define PRINTF(fmt, arg...) { \ @@ -195,7 +196,7 @@ void print_delayacct(struct taskstats *t) "IO %15s%15s\n" " %15llu%15llu\n" "MEM %15s%15s\n" - " %15llu%15llu\n\n", + " %15llu%15llu\n" "count", "real total", "virtual total", "delay total", t->cpu_count, t->cpu_run_real_total, t->cpu_run_virtual_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); } +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) { printf("%s: read=%llu, write=%llu, cancelled_write=%llu\n", @@ -235,7 +244,7 @@ int main(int argc, char *argv[]) struct msgtemplate msg; 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) break; @@ -248,6 +257,10 @@ int main(int argc, char *argv[]) printf("printing IO accounting\n"); print_io_accounting = 1; break; + case 'q': + printf("printing task/process context switch rates\n"); + print_task_context_switch_counts = 1; + break; case 'w': logfile = strdup(optarg); printf("write to file %s\n", logfile); @@ -389,6 +402,8 @@ int main(int argc, char *argv[]) print_delayacct((struct taskstats *) NLA_DATA(na)); if (print_io_accounting) 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 (write(fd, NLA_DATA(na), na->nla_len) < 0) { err(1,"write error\n"); diff --git a/Documentation/accounting/taskstats-struct.txt b/Documentation/accounting/taskstats-struct.txt index 661c797eaf79dc791997fa31a4b3823132735244..8aa7529f8258a12725f6d34b5a7b349aa104a48a 100644 --- a/Documentation/accounting/taskstats-struct.txt +++ b/Documentation/accounting/taskstats-struct.txt @@ -22,6 +22,8 @@ There are three different groups of fields in the struct taskstats: /* Extended accounting fields end */ 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 should not change the relative position of each field within the struct. @@ -158,4 +160,8 @@ struct taskstats { /* Extended accounting fields end */ +4) Per-task and per-thread statistics + __u64 nvcsw; /* Context voluntary switch counter */ + __u64 nivcsw; /* Context involuntary switch counter */ + } diff --git a/fs/proc/array.c b/fs/proc/array.c index 680c913575f0bd41ea7374929258d21cecb5f75d..9cbab7e93557693dce3e83c6d4b3f8c2b3a6c2c6 100644 --- a/fs/proc/array.c +++ b/fs/proc/array.c @@ -289,6 +289,15 @@ static inline char *task_cap(struct task_struct *p, char *buffer) 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) { char * orig = buffer; @@ -307,6 +316,7 @@ int proc_pid_status(struct task_struct *task, char * buffer) #if defined(CONFIG_S390) buffer = task_show_regs(task, buffer); #endif + buffer = task_context_switch_counts(task, buffer); return buffer - orig; } diff --git a/include/linux/taskstats.h b/include/linux/taskstats.h index a46104a28f66db62236b34c587e09a9422213574..dce1ed2049727a9b7a3576abc0c075440bc121e6 100644 --- a/include/linux/taskstats.h +++ b/include/linux/taskstats.h @@ -31,7 +31,7 @@ */ -#define TASKSTATS_VERSION 4 +#define TASKSTATS_VERSION 5 #define TS_COMM_LEN 32 /* should be >= TASK_COMM_LEN * in linux/sched.h */ @@ -149,6 +149,9 @@ struct taskstats { __u64 read_bytes; /* bytes of read I/O */ __u64 write_bytes; /* bytes of write I/O */ __u64 cancelled_write_bytes; /* bytes of cancelled write I/O */ + + __u64 nvcsw; /* voluntary_ctxt_switches */ + __u64 nivcsw; /* nonvoluntary_ctxt_switches */ }; diff --git a/kernel/taskstats.c b/kernel/taskstats.c index 906cae771585f8fe0241375066393a25b7a40cea..059431ed67db4bd10b90bf126b32ff59fd4057f9 100644 --- a/kernel/taskstats.c +++ b/kernel/taskstats.c @@ -196,6 +196,8 @@ static int fill_pid(pid_t pid, struct task_struct *tsk, /* fill in basic acct fields */ stats->version = TASKSTATS_VERSION; + stats->nvcsw = tsk->nvcsw; + stats->nivcsw = tsk->nivcsw; bacct_add_tsk(stats, tsk); /* 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); + stats->nvcsw += tsk->nvcsw; + stats->nivcsw += tsk->nivcsw; } while_each_thread(first, tsk); unlock_task_sighand(first, &flags);