From 2417d97ebb68bd397e2efd2aaca22fcb004d259a Mon Sep 17 00:00:00 2001 From: John Baldwin Date: Mon, 18 Jul 2011 17:33:08 +0000 Subject: [PATCH] - Export each thread's individual resource usage in in struct kinfo_proc's ki_rusage member when KERN_PROC_INC_THREAD is passed to one of the process sysctls. - Correctly account for the current thread's cputime in the thread when doing the runtime fixup in calcru(). - Use TIDs as the key to lookup the previous thread to compute IO stat deltas in IO mode in top when thread display is enabled. Reviewed by: kib Approved by: re (kib) --- sys/kern/kern_proc.c | 5 +++++ sys/kern/kern_resource.c | 40 ++++++++++++++++++++++++++++++++++------ sys/sys/resourcevar.h | 1 + usr.bin/top/machine.c | 17 +++++++++++++++-- 4 files changed, 55 insertions(+), 8 deletions(-) diff --git a/sys/kern/kern_proc.c b/sys/kern/kern_proc.c index 4f1dc4567f18..aac8b3937971 100644 --- a/sys/kern/kern_proc.c +++ b/sys/kern/kern_proc.c @@ -848,6 +848,8 @@ fill_kinfo_thread(struct thread *td, struct kinfo_proc *kp, int preferthread) kp->ki_tdaddr = td; PROC_LOCK_ASSERT(p, MA_OWNED); + if (preferthread) + PROC_SLOCK(p); thread_lock(td); if (td->td_wmesg != NULL) strlcpy(kp->ki_wmesg, td->td_wmesg, sizeof(kp->ki_wmesg)); @@ -899,6 +901,7 @@ fill_kinfo_thread(struct thread *td, struct kinfo_proc *kp, int preferthread) kp->ki_pri.pri_user = td->td_user_pri; if (preferthread) { + rufetchtd(td, &kp->ki_rusage); kp->ki_runtime = cputick2usec(td->td_rux.rux_runtime); kp->ki_pctcpu = sched_pctcpu(td); kp->ki_estcpu = td->td_estcpu; @@ -911,6 +914,8 @@ fill_kinfo_thread(struct thread *td, struct kinfo_proc *kp, int preferthread) kp->ki_siglist = td->td_siglist; kp->ki_sigmask = td->td_sigmask; thread_unlock(td); + if (preferthread) + PROC_SUNLOCK(p); } /* diff --git a/sys/kern/kern_resource.c b/sys/kern/kern_resource.c index 1062703b682b..78a25ebaad99 100644 --- a/sys/kern/kern_resource.c +++ b/sys/kern/kern_resource.c @@ -813,7 +813,7 @@ void calcru(struct proc *p, struct timeval *up, struct timeval *sp) { struct thread *td; - uint64_t u; + uint64_t runtime, u; PROC_LOCK_ASSERT(p, MA_OWNED); PROC_SLOCK_ASSERT(p, MA_OWNED); @@ -826,7 +826,9 @@ calcru(struct proc *p, struct timeval *up, struct timeval *sp) td = curthread; if (td->td_proc == p) { u = cpu_ticks(); - p->p_rux.rux_runtime += u - PCPU_GET(switchtime); + runtime = u - PCPU_GET(switchtime); + td->td_runtime += runtime; + td->td_incruntime += runtime; PCPU_SET(switchtime, u); } /* Make sure the per-thread stats are current. */ @@ -838,6 +840,34 @@ calcru(struct proc *p, struct timeval *up, struct timeval *sp) calcru1(p, &p->p_rux, up, sp); } +/* Collect resource usage for a single thread. */ +void +rufetchtd(struct thread *td, struct rusage *ru) +{ + struct proc *p; + uint64_t runtime, u; + + p = td->td_proc; + PROC_SLOCK_ASSERT(p, MA_OWNED); + THREAD_LOCK_ASSERT(td, MA_OWNED); + /* + * If we are getting stats for the current thread, then add in the + * stats that this thread has accumulated in its current time slice. + * We reset the thread and CPU state as if we had performed a context + * switch right here. + */ + if (td == curthread) { + u = cpu_ticks(); + runtime = u - PCPU_GET(switchtime); + td->td_runtime += runtime; + td->td_incruntime += runtime; + PCPU_SET(switchtime, u); + } + ruxagg(p, td); + *ru = td->td_ru; + calcru1(p, &td->td_rux, &ru->ru_utime, &ru->ru_stime); +} + static void calcru1(struct proc *p, struct rusage_ext *ruxp, struct timeval *up, struct timeval *sp) @@ -955,12 +985,10 @@ kern_getrusage(struct thread *td, int who, struct rusage *rup) case RUSAGE_THREAD: PROC_SLOCK(p); - ruxagg(p, td); - PROC_SUNLOCK(p); thread_lock(td); - *rup = td->td_ru; - calcru1(p, &td->td_rux, &rup->ru_utime, &rup->ru_stime); + rufetchtd(td, rup); thread_unlock(td); + PROC_SUNLOCK(p); break; default: diff --git a/sys/sys/resourcevar.h b/sys/sys/resourcevar.h index f17d95f644d0..d091d85e8bfc 100644 --- a/sys/sys/resourcevar.h +++ b/sys/sys/resourcevar.h @@ -136,6 +136,7 @@ void rucollect(struct rusage *ru, struct rusage *ru2); void rufetch(struct proc *p, struct rusage *ru); void rufetchcalc(struct proc *p, struct rusage *ru, struct timeval *up, struct timeval *sp); +void rufetchtd(struct thread *td, struct rusage *ru); void ruxagg(struct proc *p, struct thread *td); int suswintr(void *base, int word); struct uidinfo diff --git a/usr.bin/top/machine.c b/usr.bin/top/machine.c index 02dc8472ad49..1f8a002ba9fc 100644 --- a/usr.bin/top/machine.c +++ b/usr.bin/top/machine.c @@ -235,6 +235,7 @@ static int *pcpu_cpu_states; static int compare_jid(const void *a, const void *b); static int compare_pid(const void *a, const void *b); +static int compare_tid(const void *a, const void *b); static const char *format_nice(const struct kinfo_proc *pp); static void getsysctl(const char *name, void *ptr, size_t len); static int swapmode(int *retavail, int *retfree); @@ -557,7 +558,7 @@ get_old_proc(struct kinfo_proc *pp) * cache it. */ oldpp = bsearch(&pp, previous_pref, previous_proc_count, - sizeof(*previous_pref), compare_pid); + sizeof(*previous_pref), ps.thread ? compare_tid : compare_pid); if (oldpp == NULL) { pp->ki_udata = NOPROC; return (NULL); @@ -652,7 +653,7 @@ get_process_info(struct system_info *si, struct process_select *sel, previous_pref[i] = &previous_procs[i]; bcopy(pbase, previous_procs, nproc * sizeof(*previous_procs)); qsort(previous_pref, nproc, sizeof(*previous_pref), - compare_pid); + ps.thread ? compare_tid : compare_pid); } previous_proc_count = nproc; @@ -1059,6 +1060,18 @@ compare_pid(const void *p1, const void *p2) return ((*pp1)->ki_pid - (*pp2)->ki_pid); } +static int +compare_tid(const void *p1, const void *p2) +{ + const struct kinfo_proc * const *pp1 = p1; + const struct kinfo_proc * const *pp2 = p2; + + if ((*pp2)->ki_tid < 0 || (*pp1)->ki_tid < 0) + abort(); + + return ((*pp1)->ki_tid - (*pp2)->ki_tid); +} + /* * proc_compare - comparison function for "qsort" * Compares the resource consumption of two processes using five