>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:
_______________________________________________
[email protected] mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-bugs
To unsubscribe, send any mail to "[email protected]"

Reply via email to