mirror of https://gitee.com/openkylin/linux.git
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:
parent
a6c15c2b0f
commit
b663a79c19
|
@ -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");
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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 */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Reference in New Issue