From: Amerigo Wang <amwang@redhat.com> Date: Thu, 10 Dec 2009 08:29:09 -0500 Subject: [fs] getrusage: fill ru_maxrss value Message-id: <20091210083211.4058.98229.sendpatchset@localhost.localdomain> Patchwork-id: 21835 O-Subject: [PATCH RHEL5.x] getrusage: fill ru_maxrss value Bugzilla: 466157 RH-Acked-by: Jiri Pirko <jpirko@redhat.com> RH-Acked-by: Jerome Marchand <jmarchan@redhat.com> BZ: https://bugzilla.redhat.com/show_bug.cgi?id=466157 Description: /usr/bin/time should report meaningful results for ru_maxrss etc. fields. Both Jiri and I tried to fill ru_ixrss etc. fields, but upstream doesn't like this. Also, it is not easy to get a correct value for those fields, because in kernel we don't have such statistics currently. So only for ru_maxrss. Brew: https://brewweb.devel.redhat.com/taskinfo?taskID=2143278 Upstream status: Commit 1f10206cf8e945220f7220a809d8bfc15c21f9a5 Test status: With the testcase from Jiri [1], I can see getrusage() gets a proper value for ru_maxrss field now. 1. http://lkml.org/lkml/2008/12/30/79 Signed-off-by: WANG Cong <amwang@redhat.com> diff --git a/fs/exec.c b/fs/exec.c index 36bf8ad..3ab76d4 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -925,6 +925,9 @@ static int de_thread(struct task_struct *tsk) sig->flags = 0; no_thread_group: + if (current->mm) + setmax_mm_hiwater_rss(&signal_aux(sig)->maxrss, current->mm); + exit_itimers(sig); if (leader) release_task(leader); diff --git a/include/linux/sched.h b/include/linux/sched.h index 49cfe5e..53683be 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -416,6 +416,20 @@ struct mm_struct { struct kioctx *ioctx_list; }; +static inline unsigned long get_mm_hiwater_rss(struct mm_struct *mm) +{ + return max(mm->hiwater_rss, get_mm_rss(mm)); +} + +static inline void setmax_mm_hiwater_rss(unsigned long *maxrss, + struct mm_struct *mm) +{ + unsigned long hiwater_rss = get_mm_hiwater_rss(mm); + + if (*maxrss < hiwater_rss) + *maxrss = hiwater_rss; +} + struct sighand_struct { atomic_t count; struct k_sigaction action[_NSIG]; @@ -538,6 +552,7 @@ struct signal_struct { struct signal_struct_aux { u64 rchar, wchar, syscr, syscw; + unsigned long maxrss, cmaxrss; struct task_io_accounting ioac; u32 it_prof_error, it_prof_incr_error; u32 it_virt_error, it_virt_incr_error; diff --git a/kernel/exit.c b/kernel/exit.c index a68d910..695fbe4 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -887,6 +887,9 @@ fastcall NORET_TYPE void do_exit(long code) if (group_dead) { hrtimer_cancel(&tsk->signal->real_timer); exit_itimers(tsk->signal); + if (tsk->mm) + setmax_mm_hiwater_rss(&signal_aux(tsk->signal)->maxrss, + tsk->mm); } if (current->tux_info) { @@ -1147,6 +1150,7 @@ static int wait_task_zombie(struct task_struct *p, int noreap, if (likely(p->signal)) { struct signal_struct *psig; struct signal_struct *sig; + unsigned long maxrss; /* * The resource counters for the group leader are in its @@ -1192,6 +1196,9 @@ static int wait_task_zombie(struct task_struct *p, int noreap, paux->wchar += p->wchar + aux->wchar; paux->syscr += p->syscr + aux->syscr; paux->syscw += p->syscw + aux->syscw; + maxrss = max(aux->maxrss, aux->cmaxrss); + if (paux->cmaxrss < maxrss) + paux->cmaxrss = maxrss; #ifdef CONFIG_TASK_IO_ACCOUNTING paux->ioac.read_bytes += task_aux(p)->ioac.read_bytes + diff --git a/kernel/sys.c b/kernel/sys.c index 6f7d3f1..98a8608 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -1899,12 +1899,14 @@ static void k_getrusage(struct task_struct *p, int who, struct rusage *r) struct task_struct *t; unsigned long flags; cputime_t utime, stime; + unsigned long maxrss = 0; memset((char *) r, 0, sizeof *r); utime = stime = cputime_zero; if (who == RUSAGE_THREAD) { accumulate_thread_rusage(p, r, &utime, &stime); + maxrss = signal_aux(p->signal)->maxrss; goto out; } @@ -1923,6 +1925,7 @@ static void k_getrusage(struct task_struct *p, int who, struct rusage *r) r->ru_nivcsw = p->signal->cnivcsw; r->ru_minflt = p->signal->cmin_flt; r->ru_majflt = p->signal->cmaj_flt; + maxrss = signal_aux(p->signal)->cmaxrss; if (who == RUSAGE_CHILDREN) break; @@ -1934,6 +1937,8 @@ static void k_getrusage(struct task_struct *p, int who, struct rusage *r) r->ru_nivcsw += p->signal->nivcsw; r->ru_minflt += p->signal->min_flt; r->ru_majflt += p->signal->maj_flt; + if (maxrss < signal_aux(p->signal)->maxrss) + maxrss = signal_aux(p->signal)->maxrss; t = p; do { accumulate_thread_rusage(t, r, &utime, &stime); @@ -1951,6 +1956,15 @@ static void k_getrusage(struct task_struct *p, int who, struct rusage *r) out: cputime_to_timeval(utime, &r->ru_utime); cputime_to_timeval(stime, &r->ru_stime); + + if (who != RUSAGE_CHILDREN) { + struct mm_struct *mm = get_task_mm(p); + if (mm) { + setmax_mm_hiwater_rss(&maxrss, mm); + mmput(mm); + } + } + r->ru_maxrss = maxrss * (PAGE_SIZE / 1024); /* convert pages to KBs */ } int getrusage(struct task_struct *p, int who, struct rusage __user *ru)