Date: Sun, 18 Apr 2010 20:46:29 GMT From: Alexander Krizhanovsky <ak@natsys-lab.com> To: freebsd-gnats-submit@FreeBSD.org Subject: kern/145813: [PATCH] RUSAGE_THREAD Message-ID: <201004182046.o3IKkTni067716@www.freebsd.org> Resent-Message-ID: <201004182050.o3IKo1ZD063742@freefall.freebsd.org>
next in thread | raw e-mail | index | archive | help
>Number: 145813 >Category: kern >Synopsis: [PATCH] RUSAGE_THREAD >Confidential: no >Severity: non-critical >Priority: low >Responsible: freebsd-bugs >State: open >Quarter: >Keywords: >Date-Required: >Class: change-request >Submitter-Id: current-users >Arrival-Date: Sun Apr 18 20:50:01 UTC 2010 >Closed-Date: >Last-Modified: >Originator: Alexander Krizhanovsky >Release: 8.0-RELEASE >Organization: NatSys Lab. >Environment: FreeBSD 8.0-RELEASE FreeBSD 8.0-RELEASE #7: Mon Apr 19 00:01:30 UTC 2010 alex@:/usr/obj/usr/src/sys/CUSTOM-RUSAGE amd64 >Description: This patch implements per-thread rusage statistic (like RUSAGE_THREAD in Linux and RUSAGE_LWP in OpenSolaris). Unfortunately, we have to acquire a number of locks to read/update system and user times for current thread rusage information because it's also used for whole process statistic and needs to be zeroed. >How-To-Repeat: struct rusage ruse; getrusage(RUSAGE_THREAD, &ruse); >Fix: Patch attached with submission follows: --- sys/sys/resource.h.orig 2009-10-25 01:10:29.000000000 +0000 +++ sys/sys/resource.h 2010-04-11 23:31:14.000000000 +0000 @@ -56,6 +56,7 @@ #define RUSAGE_SELF 0 #define RUSAGE_CHILDREN -1 +#define RUSAGE_THREAD 1 struct rusage { struct timeval ru_utime; /* user time used */ --- sys/kern/kern_resource.c.orig 2009-10-25 01:10:29.000000000 +0000 +++ sys/kern/kern_resource.c 2010-04-18 23:49:04.000000000 +0000 @@ -76,6 +76,7 @@ static void calcru1(struct proc *p, stru struct timeval *up, struct timeval *sp); static int donice(struct thread *td, struct proc *chgp, int n); static struct uidinfo *uilookup(uid_t uid); +static void ruxagg_tlock(struct proc *p, struct thread *td); /* * Resource controls and accounting. @@ -623,9 +624,7 @@ lim_cb(void *arg) return; PROC_SLOCK(p); FOREACH_THREAD_IN_PROC(p, td) { - thread_lock(td); - ruxagg(&p->p_rux, td); - thread_unlock(td); + ruxagg_tlock(p, td); } PROC_SUNLOCK(p); if (p->p_rux.rux_runtime > p->p_cpulimit * cpu_tickrate()) { @@ -836,9 +835,7 @@ calcru(struct proc *p, struct timeval *u FOREACH_THREAD_IN_PROC(p, td) { if (td->td_incruntime == 0) continue; - thread_lock(td); - ruxagg(&p->p_rux, td); - thread_unlock(td); + ruxagg_tlock(p, td); } calcru1(p, &p->p_rux, up, sp); } @@ -918,6 +915,29 @@ calcru1(struct proc *p, struct rusage_ex sp->tv_usec = su % 1000000; } +static void +calctru(struct thread *td) +{ + u_int64_t tu = cputick2usec(td->td_incruntime); + u_int64_t ut = td->td_uticks; + u_int64_t it = td->td_iticks; + u_int64_t st = td->td_sticks; + u_int64_t tt, uu, su; + + tt = ut + st + it; + if (!tt) { + /* Avoid divide by zero */ + st = 1; + tt = 1; + } + uu = td->td_ru.ru_utime.tv_usec + (ut * tu) / tt; + su = td->td_ru.ru_stime.tv_usec + (st * tu) / tt; + td->td_ru.ru_utime.tv_sec += uu / 1000000; + td->td_ru.ru_utime.tv_usec = uu % 1000000; + td->td_ru.ru_stime.tv_sec += su / 1000000; + td->td_ru.ru_stime.tv_usec = su % 1000000; +} + #ifndef _SYS_SYSPROTO_H_ struct getrusage_args { int who; @@ -939,10 +959,7 @@ getrusage(td, uap) } int -kern_getrusage(td, who, rup) - struct thread *td; - int who; - struct rusage *rup; +kern_getrusage(struct thread *td, int who, struct rusage *rup) { struct proc *p; int error; @@ -961,6 +978,13 @@ kern_getrusage(td, who, rup) calccru(p, &rup->ru_utime, &rup->ru_stime); break; + case RUSAGE_THREAD: + PROC_SLOCK(p); + ruxagg_tlock(p, td); + PROC_SUNLOCK(p); + *rup = td->td_ru; + break; + default: error = EINVAL; } @@ -1010,12 +1034,24 @@ ruxagg(struct rusage_ext *rux, struct th rux->rux_uticks += td->td_uticks; rux->rux_sticks += td->td_sticks; rux->rux_iticks += td->td_iticks; + + /* update thread rusage before ticks counters cleaning */ + calctru(td); + td->td_incruntime = 0; td->td_uticks = 0; td->td_iticks = 0; td->td_sticks = 0; } +static void +ruxagg_tlock(struct proc *p, struct thread *td) +{ + thread_lock(td); + ruxagg(&p->p_rux, td); + thread_unlock(td); +} + /* * Update the rusage_ext structure and fetch a valid aggregate rusage * for proc p if storage for one is supplied. @@ -1030,9 +1066,7 @@ rufetch(struct proc *p, struct rusage *r *ru = p->p_ru; if (p->p_numthreads > 0) { FOREACH_THREAD_IN_PROC(p, td) { - thread_lock(td); - ruxagg(&p->p_rux, td); - thread_unlock(td); + ruxagg_tlock(p, td); rucollect(ru, &td->td_ru); } } >Release-Note: >Audit-Trail: >Unformatted:
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201004182046.o3IKkTni067716>