lkml.org 
[lkml]   [2004]   [Aug]   [31]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
Subject[PATCH] whole-process CPU usage
From
Date
This looks like it ought to work. Due to undocumented
locking, it may need a bit of work. The two ungreppable
old names are replaced with these six:

->task_sys_time Per-thread CPU usage
->signal->proc_sys_time Per-process CPU usage
->signal->dead_sys_time CPU usage of dead children
(and 3 more, with "usr" in place of "sys")

Some of the changes appear to fix UNIX non-compliance.
For example, times() and getrusage() are per-process.
I assume that the OOM killer wants per-process data too.
BSD accounting appears to be per-thread, so that's what
I gave it for now, but per-process accounting makes more
sense.

Context switch and fault counts can get this treatment
in some future patch.

It's long past time for "signal" to get renamed. Ideas?

diff -Naurd a/arch/alpha/kernel/osf_sys.c b/arch/alpha/kernel/osf_sys.c
--- a/arch/alpha/kernel/osf_sys.c 2004-08-24 03:01:50.000000000 -0400
+++ b/arch/alpha/kernel/osf_sys.c 2004-08-31 00:53:16.000000000 -0400
@@ -1073,21 +1073,21 @@
memset(&r, 0, sizeof(r));
switch (who) {
case RUSAGE_SELF:
- jiffies_to_timeval32(current->utime, &r.ru_utime);
- jiffies_to_timeval32(current->stime, &r.ru_stime);
+ jiffies_to_timeval32(current->signal->proc_usr_time, &r.ru_utime);
+ jiffies_to_timeval32(current->signal->proc_sys_time, &r.ru_stime);
r.ru_minflt = current->min_flt;
r.ru_majflt = current->maj_flt;
break;
case RUSAGE_CHILDREN:
- jiffies_to_timeval32(current->cutime, &r.ru_utime);
- jiffies_to_timeval32(current->cstime, &r.ru_stime);
+ jiffies_to_timeval32(current->signal->dead_usr_time, &r.ru_utime);
+ jiffies_to_timeval32(current->signal->dead_sys_time, &r.ru_stime);
r.ru_minflt = current->cmin_flt;
r.ru_majflt = current->cmaj_flt;
break;
default:
- jiffies_to_timeval32(current->utime + current->cutime,
+ jiffies_to_timeval32(current->signal->proc_usr_time + current->signal->dead_usr_time,
&r.ru_utime);
- jiffies_to_timeval32(current->stime + current->cstime,
+ jiffies_to_timeval32(current->signal->proc_sys_time + current->signal->dead_sys_time,
&r.ru_stime);
r.ru_minflt = current->min_flt + current->cmin_flt;
r.ru_majflt = current->maj_flt + current->cmaj_flt;
diff -Naurd a/arch/i386/kernel/apm.c b/arch/i386/kernel/apm.c
--- a/arch/i386/kernel/apm.c 2004-08-24 03:01:53.000000000 -0400
+++ b/arch/i386/kernel/apm.c 2004-08-31 00:48:38.000000000 -0400
@@ -837,18 +837,18 @@
if (jiffies_since_last_check > IDLE_CALC_LIMIT) {
use_apm_idle = 0;
last_jiffies = jiffies;
- last_stime = current->stime;
+ last_stime = current->task_sys_time;
} else if (jiffies_since_last_check > idle_period) {
unsigned int idle_percentage;

- idle_percentage = current->stime - last_stime;
+ idle_percentage = current->task_sys_time - last_stime;
idle_percentage *= 100;
idle_percentage /= jiffies_since_last_check;
use_apm_idle = (idle_percentage > idle_threshold);
if (apm_info.forbid_idle)
use_apm_idle = 0;
last_jiffies = jiffies;
- last_stime = current->stime;
+ last_stime = current->task_sys_time;
}

bucket = IDLE_LEAKY_MAX;
diff -Naurd a/fs/binfmt_elf.c b/fs/binfmt_elf.c
--- a/fs/binfmt_elf.c 2004-08-24 03:02:33.000000000 -0400
+++ b/fs/binfmt_elf.c 2004-08-30 22:38:48.000000000 -0400
@@ -1176,10 +1176,10 @@
prstatus->pr_ppid = p->parent->pid;
prstatus->pr_pgrp = process_group(p);
prstatus->pr_sid = p->signal->session;
- jiffies_to_timeval(p->utime, &prstatus->pr_utime);
- jiffies_to_timeval(p->stime, &prstatus->pr_stime);
- jiffies_to_timeval(p->cutime, &prstatus->pr_cutime);
- jiffies_to_timeval(p->cstime, &prstatus->pr_cstime);
+ jiffies_to_timeval(p->task_usr_time, &prstatus->pr_utime);
+ jiffies_to_timeval(p->task_sys_time, &prstatus->pr_stime);
+ jiffies_to_timeval(p->signal->dead_usr_time, &prstatus->pr_cutime);
+ jiffies_to_timeval(p->signal->dead_sys_time, &prstatus->pr_cstime);
}

static void fill_psinfo(struct elf_prpsinfo *psinfo, struct task_struct *p,
diff -Naurd a/fs/proc/array.c b/fs/proc/array.c
--- a/fs/proc/array.c 2004-08-24 03:02:58.000000000 -0400
+++ b/fs/proc/array.c 2004-08-31 02:57:25.000000000 -0400
@@ -300,9 +300,10 @@
}

extern unsigned long task_vsize(struct mm_struct *);
-int proc_pid_stat(struct task_struct *task, char * buffer)
+static int do_task_stat(struct task_struct *task, char * buffer, int whole)
{
unsigned long vsize, eip, esp, wchan;
+ unsigned long dead_usr_time, dead_sys_time, usr_time, sys_time;
long priority, nice;
int tty_pgrp = -1, tty_nr = 0;
sigset_t sigign, sigcatch;
@@ -330,10 +331,10 @@
}

get_task_comm(tcomm, task);
- wchan = get_wchan(task);

sigemptyset(&sigign);
sigemptyset(&sigcatch);
+
read_lock(&tasklist_lock);
if (task->sighand) {
spin_lock_irq(&task->sighand->siglock);
@@ -349,6 +350,7 @@
pgid = process_group(task);
sid = task->signal->session;
}
+ ppid = task->pid ? task->real_parent->pid : 0;
read_unlock(&tasklist_lock);

/* scale priority and nice values from timeslices to -20..20 */
@@ -356,16 +358,32 @@
priority = task_prio(task);
nice = task_nice(task);

- read_lock(&tasklist_lock);
- ppid = task->pid ? task->real_parent->pid : 0;
- read_unlock(&tasklist_lock);
+ /* if this is found to need siglock or tasklist_lock, DOCUMENT WHY */
+ dead_usr_time = jiffies_to_clock_t(task->signal->dead_usr_time);
+ dead_sys_time = jiffies_to_clock_t(task->signal->dead_sys_time);
+ if (whole) {
+ usr_time = jiffies_to_clock_t(task->signal->proc_usr_time);
+ sys_time = jiffies_to_clock_t(task->signal->proc_sys_time);
+ } else {
+ usr_time = jiffies_to_clock_t(task->task_usr_time);
+ sys_time = jiffies_to_clock_t(task->task_sys_time);
+ }
+
+ /* compute whole-process wchan only if single-threaded */
+ wchan = (whole && num_threads>1) ? ~0ul : get_wchan(task);

/* Temporary variable needed for gcc-2.96 */
start_time = jiffies_64_to_clock_t(task->start_time - INITIAL_JIFFIES);

- res = sprintf(buffer,"%d (%s) %c %d %d %d %d %d %lu %lu \
-%lu %lu %lu %lu %lu %ld %ld %ld %ld %d %ld %llu %lu %ld %lu %lu %lu %lu %lu \
-%lu %lu %lu %lu %lu %lu %lu %lu %d %d %lu %lu\n",
+ res = sprintf(
+ buffer,
+ "%d (%s) %c %d %d %d %d %d %lu "
+ "%lu %lu %lu %lu %lu %lu %lu %lu "
+ "%ld %ld %d %ld %llu %lu "
+ "%ld %lu %lu %lu %lu %lu %lu "
+ "%lu %lu %lu %lu %lu 0 0 %d %d %lu %lu\n",
+
+ /* arg 3 */
task->pid,
tcomm,
state,
@@ -375,20 +393,26 @@
tty_nr,
tty_pgrp,
task->flags,
+
+ /* arg 12 */
task->min_flt,
task->cmin_flt,
task->maj_flt,
task->cmaj_flt,
- jiffies_to_clock_t(task->utime),
- jiffies_to_clock_t(task->stime),
- jiffies_to_clock_t(task->cutime),
- jiffies_to_clock_t(task->cstime),
+ usr_time,
+ sys_time,
+ dead_usr_time,
+ dead_sys_time,
+
+ /* arg 20 */
priority,
nice,
num_threads,
jiffies_to_clock_t(task->it_real_value),
start_time,
vsize,
+
+ /* arg 26 */
mm ? mm->rss : 0, /* you might want to shift this left 3 */
task->rlim[RLIMIT_RSS].rlim_cur,
mm ? mm->start_code : 0,
@@ -396,26 +420,39 @@
mm ? mm->start_stack : 0,
esp,
eip,
+
/* The signal information here is obsolete.
* It must be decimal for Linux 2.0 compatibility.
* Use /proc/#/status for real-time signals.
*/
+ /* arg 33 */
task->pending.signal.sig[0] & 0x7fffffffUL,
- task->blocked.sig[0] & 0x7fffffffUL,
- sigign .sig[0] & 0x7fffffffUL,
- sigcatch .sig[0] & 0x7fffffffUL,
+ task->blocked .sig[0] & 0x7fffffffUL,
+ sigign .sig[0] & 0x7fffffffUL,
+ sigcatch .sig[0] & 0x7fffffffUL,
wchan,
- 0UL,
- 0UL,
+ /* 0UL, */
+ /* 0UL, */
task->exit_signal,
task_cpu(task),
task->rt_priority,
- task->policy);
+ task->policy
+ );
if(mm)
mmput(mm);
return res;
}

+int proc_tid_stat(struct task_struct *task, char * buffer)
+{
+ return do_task_stat(task, buffer, 0);
+}
+
+int proc_tgid_stat(struct task_struct *task, char * buffer)
+{
+ return do_task_stat(task, buffer, 1);
+}
+
extern int task_statm(struct mm_struct *, int *, int *, int *, int *);
int proc_pid_statm(struct task_struct *task, char *buffer)
{
diff -Naurd a/fs/proc/proc_misc.c b/fs/proc/proc_misc.c
--- a/fs/proc/proc_misc.c 2004-08-24 03:01:55.000000000 -0400
+++ b/fs/proc/proc_misc.c 2004-08-31 01:04:45.000000000 -0400
@@ -136,7 +136,7 @@
struct timespec uptime;
struct timespec idle;
int len;
- u64 idle_jiffies = init_task.utime + init_task.stime;
+ u64 idle_jiffies = init_task.task_usr_time + init_task.task_sys_time;

do_posix_clock_monotonic_gettime(&uptime);
jiffies_to_timespec(idle_jiffies, &idle);
diff -Naurd a/include/linux/sched.h b/include/linux/sched.h
--- a/include/linux/sched.h 2004-08-24 03:01:54.000000000 -0400
+++ b/include/linux/sched.h 2004-08-30 22:20:29.000000000 -0400
@@ -284,6 +284,9 @@
int leader;

struct tty_struct *tty; /* NULL if no tty */
+
+ unsigned long proc_sys_time, proc_usr_time; /* whole process */
+ unsigned long dead_sys_time, dead_usr_time; /* dead children */
};

/*
@@ -460,7 +463,7 @@
unsigned long it_real_value, it_prof_value, it_virt_value;
unsigned long it_real_incr, it_prof_incr, it_virt_incr;
struct timer_list real_timer;
- unsigned long utime, stime, cutime, cstime;
+ unsigned long task_sys_time, task_usr_time;
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 */
diff -Naurd a/kernel/acct.c b/kernel/acct.c
--- a/kernel/acct.c 2004-08-24 03:02:48.000000000 -0400
+++ b/kernel/acct.c 2004-08-30 22:59:30.000000000 -0400
@@ -418,8 +418,14 @@
#endif
do_div(elapsed, AHZ);
ac.ac_btime = xtime.tv_sec - elapsed;
- ac.ac_utime = encode_comp_t(jiffies_to_AHZ(current->utime));
- ac.ac_stime = encode_comp_t(jiffies_to_AHZ(current->stime));
+
+ /*
+ * accounting is called once per thread -- maybe not the best
+ * (if that changes, use current->signal->proc_usr_time, etc.)
+ */
+ ac.ac_utime = encode_comp_t(jiffies_to_AHZ(current->task_usr_time));
+ ac.ac_stime = encode_comp_t(jiffies_to_AHZ(current->task_sys_time));
+
/* we really need to bite the bullet and change layout */
ac.ac_uid = current->uid;
ac.ac_gid = current->gid;
diff -Naurd a/kernel/compat.c b/kernel/compat.c
--- a/kernel/compat.c 2004-08-24 03:02:47.000000000 -0400
+++ b/kernel/compat.c 2004-08-30 23:01:52.000000000 -0400
@@ -160,10 +160,10 @@
*/
if (tbuf) {
struct compat_tms tmp;
- tmp.tms_utime = compat_jiffies_to_clock_t(current->utime);
- tmp.tms_stime = compat_jiffies_to_clock_t(current->stime);
- tmp.tms_cutime = compat_jiffies_to_clock_t(current->cutime);
- tmp.tms_cstime = compat_jiffies_to_clock_t(current->cstime);
+ tmp.tms_utime = compat_jiffies_to_clock_t(current->signal->proc_usr_time);
+ tmp.tms_stime = compat_jiffies_to_clock_t(current->signal->proc_sys_time);
+ tmp.tms_cutime = compat_jiffies_to_clock_t(current->signal->dead_usr_time);
+ tmp.tms_cstime = compat_jiffies_to_clock_t(current->signal->dead_sys_time);
if (copy_to_user(tbuf, &tmp, sizeof(tmp)))
return -EFAULT;
}
diff -Naurd a/kernel/cpu.c b/kernel/cpu.c
--- a/kernel/cpu.c 2004-08-24 03:03:31.000000000 -0400
+++ b/kernel/cpu.c 2004-08-30 23:21:47.000000000 -0400
@@ -49,7 +49,7 @@

write_lock_irq(&tasklist_lock);
for_each_process(p) {
- if (task_cpu(p) == cpu && (p->utime != 0 || p->stime != 0))
+ if (task_cpu(p) == cpu && (p->signal->proc_usr_time || p->signal->proc_sys_time))
printk(KERN_WARNING "Task %s (pid = %d) is on cpu %d\
(state = %ld, flags = %lx) \n",
p->comm, p->pid, cpu, p->state, p->flags);
diff -Naurd a/kernel/exit.c b/kernel/exit.c
--- a/kernel/exit.c 2004-08-24 03:03:31.000000000 -0400
+++ b/kernel/exit.c 2004-08-31 00:04:13.000000000 -0400
@@ -90,12 +90,18 @@
zap_leader = (leader->exit_signal == -1);
}

- p->parent->cutime += p->utime + p->cutime;
- p->parent->cstime += p->stime + p->cstime;
+ /* credit parent's dead-child stats (proper: when parent waits) */
+ if (leader == p && thread_group_empty(leader)) {
+ p->parent->signal->dead_usr_time += p->signal->proc_usr_time + p->signal->dead_usr_time;
+ p->parent->signal->dead_sys_time += p->signal->proc_sys_time + p->signal->dead_sys_time;
+ }
+
+ /* TODO: these should get the same treatment as CPU time */
p->parent->cmin_flt += p->min_flt + p->cmin_flt;
p->parent->cmaj_flt += p->maj_flt + p->cmaj_flt;
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 -Naurd a/kernel/fork.c b/kernel/fork.c
--- a/kernel/fork.c 2004-08-24 03:01:54.000000000 -0400
+++ b/kernel/fork.c 2004-08-31 00:10:31.000000000 -0400
@@ -822,6 +822,8 @@
if (!sig)
return -ENOMEM;
atomic_set(&sig->count, 1);
+ sig->proc_usr_time = sig->proc_sys_time = 0;
+ sig->dead_usr_time = sig->dead_sys_time = 0;
sig->group_exit = 0;
sig->group_exit_code = 0;
sig->group_exit_task = NULL;
@@ -959,8 +961,7 @@
init_timer(&p->real_timer);
p->real_timer.data = (unsigned long) p;

- p->utime = p->stime = 0;
- p->cutime = p->cstime = 0;
+ p->task_usr_time = p->task_sys_time = 0;
p->lock_depth = -1; /* -1 = no lock */
p->start_time = get_jiffies_64();
p->security = NULL;
diff -Naurd a/kernel/signal.c b/kernel/signal.c
--- a/kernel/signal.c 2004-08-24 03:02:32.000000000 -0400
+++ b/kernel/signal.c 2004-08-31 00:19:24.000000000 -0400
@@ -1445,8 +1445,8 @@
info.si_uid = tsk->uid;

/* FIXME: find out whether or not this is supposed to be c*time. */
- info.si_utime = tsk->utime;
- info.si_stime = tsk->stime;
+ info.si_utime = tsk->signal->proc_usr_time + tsk->signal->dead_usr_time;
+ info.si_stime = tsk->signal->proc_sys_time + tsk->signal->dead_sys_time;

status = tsk->exit_code & 0x7f;
why = SI_KERNEL; /* shouldn't happen */
@@ -1534,8 +1534,8 @@
info.si_uid = tsk->uid;

/* FIXME: find out whether or not this is supposed to be c*time. */
- info.si_utime = tsk->utime;
- info.si_stime = tsk->stime;
+ info.si_utime = tsk->signal->proc_usr_time + tsk->signal->dead_usr_time;
+ info.si_stime = tsk->signal->proc_sys_time + tsk->signal->dead_sys_time;

info.si_status = tsk->exit_code & 0x7f;
info.si_code = CLD_STOPPED;
diff -Naurd a/kernel/sys.c b/kernel/sys.c
--- a/kernel/sys.c 2004-08-24 03:01:54.000000000 -0400
+++ b/kernel/sys.c 2004-08-31 00:29:43.000000000 -0400
@@ -944,13 +944,14 @@
* the times increment as we use it. Since the value is an
* atomically safe type this is just fine. Conceptually its
* as if the syscall took an instant longer to occur.
+ * The UNIX spec seems to indicate that these are per-process.
*/
if (tbuf) {
struct tms tmp;
- tmp.tms_utime = jiffies_to_clock_t(current->utime);
- tmp.tms_stime = jiffies_to_clock_t(current->stime);
- tmp.tms_cutime = jiffies_to_clock_t(current->cutime);
- tmp.tms_cstime = jiffies_to_clock_t(current->cstime);
+ tmp.tms_utime = jiffies_to_clock_t(current->signal->proc_usr_time);
+ tmp.tms_stime = jiffies_to_clock_t(current->signal->proc_sys_time);
+ tmp.tms_cutime = jiffies_to_clock_t(current->signal->dead_usr_time);
+ tmp.tms_cstime = jiffies_to_clock_t(current->signal->dead_sys_time);
if (copy_to_user(tbuf, &tmp, sizeof(struct tms)))
return -EFAULT;
}
@@ -1526,12 +1527,9 @@
}

/*
- * It would make sense to put struct rusage in the task_struct,
- * except that would make the task_struct be *really big*. After
- * task_struct gets moved into malloc'ed memory, it would
- * make sense to do this. It will make moving the rest of the information
- * a lot simpler! (Which we're not doing right now because we're not
- * measuring them yet).
+ * It would make sense to put struct rusage in the signal_struct,
+ * except that would make the signal_struct be *really big*.
+ * TODO: Perhaps a thread-specific rusage value would be useful.
*
* This is SMP safe. Either we are called from sys_getrusage on ourselves
* below (we know we aren't going to exit/disappear and only we change our
@@ -1547,24 +1545,27 @@
memset((char *) &r, 0, sizeof(r));
switch (who) {
case RUSAGE_SELF:
- jiffies_to_timeval(p->utime, &r.ru_utime);
- jiffies_to_timeval(p->stime, &r.ru_stime);
+ jiffies_to_timeval(p->signal->proc_usr_time, &r.ru_utime);
+ jiffies_to_timeval(p->signal->proc_sys_time, &r.ru_stime);
+ /* these are still broken -- should be per-process */
r.ru_nvcsw = p->nvcsw;
r.ru_nivcsw = p->nivcsw;
r.ru_minflt = p->min_flt;
r.ru_majflt = p->maj_flt;
break;
case RUSAGE_CHILDREN:
- jiffies_to_timeval(p->cutime, &r.ru_utime);
- jiffies_to_timeval(p->cstime, &r.ru_stime);
+ jiffies_to_timeval(p->signal->dead_usr_time, &r.ru_utime);
+ jiffies_to_timeval(p->signal->dead_sys_time, &r.ru_stime);
+ /* these are still broken -- should be per-process */
r.ru_nvcsw = p->cnvcsw;
r.ru_nivcsw = p->cnivcsw;
r.ru_minflt = p->cmin_flt;
r.ru_majflt = p->cmaj_flt;
break;
default:
- jiffies_to_timeval(p->utime + p->cutime, &r.ru_utime);
- jiffies_to_timeval(p->stime + p->cstime, &r.ru_stime);
+ jiffies_to_timeval(p->signal->proc_usr_time + p->signal->dead_usr_time, &r.ru_utime);
+ jiffies_to_timeval(p->signal->proc_sys_time + p->signal->dead_sys_time, &r.ru_stime);
+ /* these are still broken -- should be per-process */
r.ru_nvcsw = p->nvcsw + p->cnvcsw;
r.ru_nivcsw = p->nivcsw + p->cnivcsw;
r.ru_minflt = p->min_flt + p->cmin_flt;
diff -Naurd a/kernel/timer.c b/kernel/timer.c
--- a/kernel/timer.c 2004-08-24 03:03:31.000000000 -0400
+++ b/kernel/timer.c 2004-08-31 00:33:25.000000000 -0400
@@ -790,8 +790,10 @@
{
unsigned long psecs;

- psecs = (p->utime += user);
- psecs += (p->stime += system);
+ p->task_usr_time += user;
+ p->task_sys_time += system;
+ psecs = (p->signal->proc_usr_time += user);
+ psecs += (p->signal->proc_sys_time += system);
if (psecs / HZ >= p->rlim[RLIMIT_CPU].rlim_cur) {
/* Send SIGXCPU every second.. */
if (!(psecs % HZ))
diff -Naurd a/mm/oom_kill.c b/mm/oom_kill.c
--- a/mm/oom_kill.c 2004-08-24 03:02:48.000000000 -0400
+++ b/mm/oom_kill.c 2004-08-31 00:43:00.000000000 -0400
@@ -60,7 +60,7 @@
* particular reason for this other than that it turned out to work
* very well in practice.
*/
- cpu_time = (p->utime + p->stime) >> (SHIFT_HZ + 3);
+ cpu_time = (p->signal->proc_usr_time + p->signal->proc_sys_time) >> (SHIFT_HZ + 3);
run_time = (get_jiffies_64() - p->start_time) >> (SHIFT_HZ + 10);

s = int_sqrt(cpu_time);


-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/

\
 
 \ /
  Last update: 2005-03-22 14:05    [W:0.155 / U:0.532 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site