From: Peter Chubb Currently, the context switch counters reported by getrusage() are always zero. The appended patch adds fields to struct task_struct to count context switches, and adds code to do the counting. The patch adds 4 longs to struct task struct, and a single addition to the fast path in schedule(). Add context switch counters to struct task_struct; add code to update them in schedule(), initialise them in copy_mm(), and copy them to user space in getrusage(). include/linux/sched.h | 1 + kernel/exit.c | 2 ++ kernel/fork.c | 1 + kernel/sched.c | 3 ++- kernel/sys.c | 6 ++++++ 5 files changed, 12 insertions(+), 1 deletion(-) diff -puN include/linux/sched.h~rusage-context-switch-counters include/linux/sched.h --- 25/include/linux/sched.h~rusage-context-switch-counters 2003-08-26 18:18:54.000000000 -0700 +++ 25-akpm/include/linux/sched.h 2003-08-26 18:19:47.000000000 -0700 @@ -393,6 +393,7 @@ struct task_struct { struct timer_list real_timer; struct list_head posix_timers; /* POSIX.1b Interval Timers */ unsigned long utime, stime, cutime, cstime; + unsigned long nvcsw, nivcsw, cnvcsw, cnivcsw; /* context switch counts */ u64 start_time; /* mm fault and swap info: this can arguably be seen as either mm-specific or thread-specific */ unsigned long min_flt, maj_flt, nswap, cmin_flt, cmaj_flt, cnswap; diff -puN kernel/exit.c~rusage-context-switch-counters kernel/exit.c --- 25/kernel/exit.c~rusage-context-switch-counters 2003-08-26 18:18:54.000000000 -0700 +++ 25-akpm/kernel/exit.c 2003-08-26 18:18:54.000000000 -0700 @@ -80,6 +80,8 @@ void release_task(struct task_struct * p p->parent->cmin_flt += p->min_flt + p->cmin_flt; p->parent->cmaj_flt += p->maj_flt + p->cmaj_flt; p->parent->cnswap += p->nswap + p->cnswap; + p->parent->cnvcsw += p->nvcsw + p->cnvcsw; + p->parent->cnivcsw += p->nivcsw + p->cnivcsw; sched_exit(p); write_unlock_irq(&tasklist_lock); spin_unlock(&p->proc_lock); diff -puN kernel/fork.c~rusage-context-switch-counters kernel/fork.c --- 25/kernel/fork.c~rusage-context-switch-counters 2003-08-26 18:18:54.000000000 -0700 +++ 25-akpm/kernel/fork.c 2003-08-26 18:19:43.000000000 -0700 @@ -461,6 +461,7 @@ static int copy_mm(unsigned long clone_f tsk->min_flt = tsk->maj_flt = 0; tsk->cmin_flt = tsk->cmaj_flt = 0; tsk->nswap = tsk->cnswap = 0; + tsk->nvcsw = tsk->nivcsw = tsk->cnvcsw = tsk->cnivcsw = 0; tsk->mm = NULL; tsk->active_mm = NULL; diff -puN kernel/sched.c~rusage-context-switch-counters kernel/sched.c --- 25/kernel/sched.c~rusage-context-switch-counters 2003-08-26 18:18:54.000000000 -0700 +++ 25-akpm/kernel/sched.c 2003-08-26 18:19:47.000000000 -0700 @@ -1324,8 +1324,9 @@ need_resched: } default: deactivate_task(prev, rq); + prev->nvcsw++; case TASK_RUNNING: - ; + prev->nivcsw++; } pick_next_task: if (unlikely(!rq->nr_running)) { diff -puN kernel/sys.c~rusage-context-switch-counters kernel/sys.c --- 25/kernel/sys.c~rusage-context-switch-counters 2003-08-26 18:18:54.000000000 -0700 +++ 25-akpm/kernel/sys.c 2003-08-26 18:18:54.000000000 -0700 @@ -1321,6 +1321,8 @@ int getrusage(struct task_struct *p, int case RUSAGE_SELF: jiffies_to_timeval(p->utime, &r.ru_utime); jiffies_to_timeval(p->stime, &r.ru_stime); + r.ru_nvcsw = p->nvcsw; + r.ru_nivcsw = p->nivcsw; r.ru_minflt = p->min_flt; r.ru_majflt = p->maj_flt; r.ru_nswap = p->nswap; @@ -1328,6 +1330,8 @@ int getrusage(struct task_struct *p, int case RUSAGE_CHILDREN: jiffies_to_timeval(p->cutime, &r.ru_utime); jiffies_to_timeval(p->cstime, &r.ru_stime); + r.ru_nvcsw = p->cnvcsw; + r.ru_nivcsw = p->cnivcsw; r.ru_minflt = p->cmin_flt; r.ru_majflt = p->cmaj_flt; r.ru_nswap = p->cnswap; @@ -1335,6 +1339,8 @@ int getrusage(struct task_struct *p, int default: jiffies_to_timeval(p->utime + p->cutime, &r.ru_utime); jiffies_to_timeval(p->stime + p->cstime, &r.ru_stime); + r.ru_nvcsw = p->nvcsw + p->cnvcsw; + r.ru_nivcsw = p->nivcsw + p->cnivcsw; r.ru_minflt = p->min_flt + p->cmin_flt; r.ru_majflt = p->maj_flt + p->cmaj_flt; r.ru_nswap = p->nswap + p->cnswap; _