瀏覽代碼

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>
Maxim Uvarov 18 年之前
父節點
當前提交
b663a79c19

+ 17 - 2
Documentation/accounting/getdelays.c

@@ -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");

+ 6 - 0
Documentation/accounting/taskstats-struct.txt

@@ -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 */
+
 }
 }

+ 10 - 0
fs/proc/array.c

@@ -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;
 }
 }
 
 

+ 4 - 1
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
 #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 */
 };
 };
 
 
 
 

+ 4 - 0
kernel/taskstats.c

@@ -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);