kern/145813: [PATCH] RUSAGE_THREAD

Alexander Krizhanovsky ak at natsys-lab.com
Sun Apr 18 20:50:01 UTC 2010


>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:


More information about the freebsd-bugs mailing list