Commit b663a79c authored by Maxim Uvarov's avatar Maxim Uvarov Committed by Linus Torvalds

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: default avatarMaxim 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: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent a6c15c2b
...@@ -49,6 +49,7 @@ char name[100]; ...@@ -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) ...@@ -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) ...@@ -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[]) ...@@ -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[]) ...@@ -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[]) ...@@ -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");
......
...@@ -22,6 +22,8 @@ There are three different groups of fields in the struct taskstats: ...@@ -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 { ...@@ -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 */
} }
...@@ -289,6 +289,15 @@ static inline char *task_cap(struct task_struct *p, char *buffer) ...@@ -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) ...@@ -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;
} }
......
...@@ -31,7 +31,7 @@ ...@@ -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 { ...@@ -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 */
}; };
......
...@@ -196,6 +196,8 @@ static int fill_pid(pid_t pid, struct task_struct *tsk, ...@@ -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, ...@@ -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);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment