aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMaxim Uvarov <muvarov@ru.mvista.com>2007-07-16 02:40:48 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-07-16 12:05:46 -0400
commitb663a79c191508f27cd885224b592a878c0ba0f6 (patch)
tree270a0472bf1fb0c7323ecb60ec68e40d02dcb1b4
parenta6c15c2b0fbfd5c0a84f5f0e1e3f20f85d2b8692 (diff)
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>
-rw-r--r--Documentation/accounting/getdelays.c19
-rw-r--r--Documentation/accounting/taskstats-struct.txt6
-rw-r--r--fs/proc/array.c10
-rw-r--r--include/linux/taskstats.h5
-rw-r--r--kernel/taskstats.c4
5 files changed, 41 insertions, 3 deletions
diff --git a/Documentation/accounting/getdelays.c b/Documentation/accounting/getdelays.c
index 71acc28ed0d1..24c5aade8998 100644
--- a/Documentation/accounting/getdelays.c
+++ b/Documentation/accounting/getdelays.c
@@ -49,6 +49,7 @@ char name[100];
49int dbg; 49int dbg;
50int print_delays; 50int print_delays;
51int print_io_accounting; 51int print_io_accounting;
52int print_task_context_switch_counts;
52__u64 stime, utime; 53__u64 stime, utime;
53 54
54#define PRINTF(fmt, arg...) { \ 55#define PRINTF(fmt, arg...) { \
@@ -195,7 +196,7 @@ void print_delayacct(struct taskstats *t)
195 "IO %15s%15s\n" 196 "IO %15s%15s\n"
196 " %15llu%15llu\n" 197 " %15llu%15llu\n"
197 "MEM %15s%15s\n" 198 "MEM %15s%15s\n"
198 " %15llu%15llu\n\n", 199 " %15llu%15llu\n"
199 "count", "real total", "virtual total", "delay total", 200 "count", "real total", "virtual total", "delay total",
200 t->cpu_count, t->cpu_run_real_total, t->cpu_run_virtual_total, 201 t->cpu_count, t->cpu_run_real_total, t->cpu_run_virtual_total,
201 t->cpu_delay_total, 202 t->cpu_delay_total,
@@ -204,6 +205,14 @@ void print_delayacct(struct taskstats *t)
204 "count", "delay total", t->swapin_count, t->swapin_delay_total); 205 "count", "delay total", t->swapin_count, t->swapin_delay_total);
205} 206}
206 207
208void task_context_switch_counts(struct taskstats *t)
209{
210 printf("\n\nTask %15s%15s\n"
211 " %15lu%15lu\n",
212 "voluntary", "nonvoluntary",
213 t->nvcsw, t->nivcsw);
214}
215
207void print_ioacct(struct taskstats *t) 216void print_ioacct(struct taskstats *t)
208{ 217{
209 printf("%s: read=%llu, write=%llu, cancelled_write=%llu\n", 218 printf("%s: read=%llu, write=%llu, cancelled_write=%llu\n",
@@ -235,7 +244,7 @@ int main(int argc, char *argv[])
235 struct msgtemplate msg; 244 struct msgtemplate msg;
236 245
237 while (1) { 246 while (1) {
238 c = getopt(argc, argv, "diw:r:m:t:p:vl"); 247 c = getopt(argc, argv, "qdiw:r:m:t:p:vl");
239 if (c < 0) 248 if (c < 0)
240 break; 249 break;
241 250
@@ -248,6 +257,10 @@ int main(int argc, char *argv[])
248 printf("printing IO accounting\n"); 257 printf("printing IO accounting\n");
249 print_io_accounting = 1; 258 print_io_accounting = 1;
250 break; 259 break;
260 case 'q':
261 printf("printing task/process context switch rates\n");
262 print_task_context_switch_counts = 1;
263 break;
251 case 'w': 264 case 'w':
252 logfile = strdup(optarg); 265 logfile = strdup(optarg);
253 printf("write to file %s\n", logfile); 266 printf("write to file %s\n", logfile);
@@ -389,6 +402,8 @@ int main(int argc, char *argv[])
389 print_delayacct((struct taskstats *) NLA_DATA(na)); 402 print_delayacct((struct taskstats *) NLA_DATA(na));
390 if (print_io_accounting) 403 if (print_io_accounting)
391 print_ioacct((struct taskstats *) NLA_DATA(na)); 404 print_ioacct((struct taskstats *) NLA_DATA(na));
405 if (print_task_context_switch_counts)
406 task_context_switch_counts((struct taskstats *) NLA_DATA(na));
392 if (fd) { 407 if (fd) {
393 if (write(fd, NLA_DATA(na), na->nla_len) < 0) { 408 if (write(fd, NLA_DATA(na), na->nla_len) < 0) {
394 err(1,"write error\n"); 409 err(1,"write error\n");
diff --git a/Documentation/accounting/taskstats-struct.txt b/Documentation/accounting/taskstats-struct.txt
index 661c797eaf79..8aa7529f8258 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:
22 /* Extended accounting fields end */ 22 /* Extended accounting fields end */
23 Their values are collected if CONFIG_TASK_XACCT is set. 23 Their values are collected if CONFIG_TASK_XACCT is set.
24 24
254) Per-task and per-thread context switch count statistics
26
25Future extension should add fields to the end of the taskstats struct, and 27Future extension should add fields to the end of the taskstats struct, and
26should not change the relative position of each field within the struct. 28should not change the relative position of each field within the struct.
27 29
@@ -158,4 +160,8 @@ struct taskstats {
158 160
159 /* Extended accounting fields end */ 161 /* Extended accounting fields end */
160 162
1634) Per-task and per-thread statistics
164 __u64 nvcsw; /* Context voluntary switch counter */
165 __u64 nivcsw; /* Context involuntary switch counter */
166
161} 167}
diff --git a/fs/proc/array.c b/fs/proc/array.c
index 680c913575f0..9cbab7e93557 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)
289 cap_t(p->cap_effective)); 289 cap_t(p->cap_effective));
290} 290}
291 291
292static inline char *task_context_switch_counts(struct task_struct *p,
293 char *buffer)
294{
295 return buffer + sprintf(buffer, "voluntary_ctxt_switches:\t%lu\n"
296 "nonvoluntary_ctxt_switches:\t%lu\n",
297 p->nvcsw,
298 p->nivcsw);
299}
300
292int proc_pid_status(struct task_struct *task, char * buffer) 301int proc_pid_status(struct task_struct *task, char * buffer)
293{ 302{
294 char * orig = buffer; 303 char * orig = buffer;
@@ -307,6 +316,7 @@ int proc_pid_status(struct task_struct *task, char * buffer)
307#if defined(CONFIG_S390) 316#if defined(CONFIG_S390)
308 buffer = task_show_regs(task, buffer); 317 buffer = task_show_regs(task, buffer);
309#endif 318#endif
319 buffer = task_context_switch_counts(task, buffer);
310 return buffer - orig; 320 return buffer - orig;
311} 321}
312 322
diff --git a/include/linux/taskstats.h b/include/linux/taskstats.h
index a46104a28f66..dce1ed204972 100644
--- a/include/linux/taskstats.h
+++ b/include/linux/taskstats.h
@@ -31,7 +31,7 @@
31 */ 31 */
32 32
33 33
34#define TASKSTATS_VERSION 4 34#define TASKSTATS_VERSION 5
35#define TS_COMM_LEN 32 /* should be >= TASK_COMM_LEN 35#define TS_COMM_LEN 32 /* should be >= TASK_COMM_LEN
36 * in linux/sched.h */ 36 * in linux/sched.h */
37 37
@@ -149,6 +149,9 @@ struct taskstats {
149 __u64 read_bytes; /* bytes of read I/O */ 149 __u64 read_bytes; /* bytes of read I/O */
150 __u64 write_bytes; /* bytes of write I/O */ 150 __u64 write_bytes; /* bytes of write I/O */
151 __u64 cancelled_write_bytes; /* bytes of cancelled write I/O */ 151 __u64 cancelled_write_bytes; /* bytes of cancelled write I/O */
152
153 __u64 nvcsw; /* voluntary_ctxt_switches */
154 __u64 nivcsw; /* nonvoluntary_ctxt_switches */
152}; 155};
153 156
154 157
diff --git a/kernel/taskstats.c b/kernel/taskstats.c
index 906cae771585..059431ed67db 100644
--- a/kernel/taskstats.c
+++ b/kernel/taskstats.c
@@ -196,6 +196,8 @@ static int fill_pid(pid_t pid, struct task_struct *tsk,
196 196
197 /* fill in basic acct fields */ 197 /* fill in basic acct fields */
198 stats->version = TASKSTATS_VERSION; 198 stats->version = TASKSTATS_VERSION;
199 stats->nvcsw = tsk->nvcsw;
200 stats->nivcsw = tsk->nivcsw;
199 bacct_add_tsk(stats, tsk); 201 bacct_add_tsk(stats, tsk);
200 202
201 /* fill in extended acct fields */ 203 /* fill in extended acct fields */
@@ -242,6 +244,8 @@ static int fill_tgid(pid_t tgid, struct task_struct *first,
242 */ 244 */
243 delayacct_add_tsk(stats, tsk); 245 delayacct_add_tsk(stats, tsk);
244 246
247 stats->nvcsw += tsk->nvcsw;
248 stats->nivcsw += tsk->nivcsw;
245 } while_each_thread(first, tsk); 249 } while_each_thread(first, tsk);
246 250
247 unlock_task_sighand(first, &flags); 251 unlock_task_sighand(first, &flags);