Subject: Re: getrusage() problem in hp300 port??
To: None <Havard.Eidnes@runit.sintef.no>
From: Greg Oster <oster@cs.usask.ca>
List: port-hp300
Date: 11/20/1997 17:21:19
Havard.Eidnes@runit.sintef.no writes:
> Hi,
> 
> I've found at least one explanation to why the ru_utime time
> returned by getrusage() isn't monotonically increasing.
> 
> The basic problem is that the implementation of getrusage() pretends
> to have more resolution in the resource accounting than what is
> actually the case...
> 
> The process accounting is done in 'ticks', and each tick is counted
> as either "user time", "system time" or "interrupt time" (the latter
> is always zero on at least NetBSD/i386 and NetBSD/hp300).
> 
> calcru() inside /sys/kern/kern_resource.c shows what is going on.
> It sums up how much time this process has used, sums up the ticks,
> and distributes the total time over the ticks.  Thus, if you get a
> clock tick accounted to system time and at the same time not one to
> user time and the total time consumed hasn't changed much, the user
> time proportion can decrease.

Ahh.. Yup, I believe that's correct. 
Allow me to attempt to do a little of the math (which I probably shouldn't be 
doing thisafternoon, as my brain is already mush, but here goes anyways...)
For those who care to follow along, and/or make sure I'm not completely off 
track, the relevant code is calcru() in /src/sys/kern/kern_resource.c.
Apologies for the length of this post, but I'm hoping this analysis will be 
useful... 

Say we are at the *end* of the current timeslice, but the tick counters and 
such have *NOT* been updated:

  st=80
  ut=20
  it=0
  tot=100
  rtime.tv_sec=1
  rtime.tv_usec=0

(I hope that's right... 100 ticks total, at 100 ticks/second is 1 second)
At this point (the end of the quantum), the number of usecs run should be 
equal to (at most) 1/100 of a second, so that's 10000 usecs.

 Thus we get:

 sec = rtime.tv_sec + (tv.tv_sec - runtime.tv_sec) = 1 + 0 = 1
 usec = rtime.tv_usec + (tv.tv_usec - runtime.tv_usec) = 0 + 10000 = 10000
 u = sec * 1000000 + usec = 1 * 1000000 + 10000 = 1010000
 st = (u * st) / tot = (1010000 * 80) / 100 = 808000
 ut = (u * ut) / tot = (1010000 * 20) / 100 = 202000

and hence:
 sp->tv_sec = 0
 sp->tv_usec = 808000
 up->tv_sec = 0
 up->tv_usec = 202000

So that's at the *end* of the quantum, and *before* the tick counters have 
been updated.  
Now consider that the quantum is done, and we update one of the tick counters 
(lets say it was p_sticks that was updated, for sake of argument) and the 
amount of accumulated running time.  Our updated values are now:

  st=81
  ut=20
  it=0
  tot=101
  rtime.tv_sec=1
  rtime.tv_usec=10000  

At the very beginning of this quantum, we have:
(Note that both (tv.tv_sec - runtime.tv_sec) and (tv.tv_usec - 
runtime.tv_usec) are 0 -- might not be very likely, but it's worst-case...)

 sec = rtime.tv_sec + (tv.tv_sec - runtime.tv_sec) = 1 + 0 = 1
 usec = rtime.tv_usec +  = 10000 + 0 = 10000

 u = sec * 1000000 + usec = 1 * 1000000 + 10000 = 1010000
 st = (u * st) / tot = (1010000 * 81) / 101 = 810000
 ut = (u * ut) / tot = (1010000 * 20) / 101 = 200000

Woah!!! what's this?? Our "ut" value is now 200000, which is 2000 usec
*LOWER* than what it was before...  Thus our user resource usage time appears 
to have actually decreased...  

Thus unless I'm very much wrong somewhere above it would appear quite possible 
to end up with the "erratic" usage times that I've been seeing...

I'm not sure if/how this can be fixed, except perhaps by adjusting "st" or 
"ut" to the appropriate value once the time used (tv.tv_usec - 
runtime.tv_usec) is greater than 1/2 of the time it takes to complete the 
quantum (or get to the next "tick").  "better" still would be to weight the 
values of "st" or "ut" as to how far through the quantum the measurement is 
being taken.  All of this just gets plain ugly though...

> For a while I thought that the sum of the system time and the user
> time would monotonically increase, but that appears not to be the
> case either, at least on NetBSD/hp300. 

Now that's *really* curious... Even with my math above I'd expect the sum of 
the two to be the same... That certainly does point to "something else" 
contributing to the problem...

> I tweaked your original
> program and ran it for a while, and suddenly it printed:
> 
> 0 + 303763
> 0 + 305256
> 0 + 306344
> 0 + 297427
> Decreasing time: 0 + 306344 vs 0 + 297427
> 0 + 299611
> 0 + 300696
> 0 + 301752
> 
> The tweaked program can be found below.

Hmm.. I've run that program a number of times, and have been unable 
to get this behaviour... (I suspect it's something to do with the nature 
of the "bug"(s)...)

> Strange...  I wonder: can it be that microtime() and thus
> gettimeofday() isn't always monotonically increasing? (...)  Yep,
> that appears to be the problem.  It appears that NetBSD/hp300's
> microtime is slightly broken, I get lots of these from my test
> program which I've included below when I run it on one of our
> hp433's:
> 
> Whoa! Decreasing time: 880054445 + 499972 vs 880054445 + 490000
> Whoa! Decreasing time: 880054445 + 529972 vs 880054445 + 520000
> Whoa! Decreasing time: 880054446 + 149972 vs 880054446 + 140000
> Whoa! Decreasing time: 880054447 + 779972 vs 880054447 + 770000
> Whoa! Decreasing time: 880054448 + 279972 vs 880054448 + 270000
> Whoa! Decreasing time: 880054448 + 299972 vs 880054448 + 290000

I see much the same thing on our hp300's.. 

> Oh, well, more work for our beloved portmaster, I think... (Yes,
> I've UTSL'ed /sys/arch/hp300/hp300/clock.c, but the source isn't
> quite with me today, I think...  ;-)

:-) I havn't made it out of calcru() yet... microtime() may be this 
evenings project, if I get some other stuff taken care of first...

> Anyway, this latter problem with gettimeofday() returning non-
> monotonically increasing values doesn't appear to exist on either of
> NetBSD/sparc, NetBSD/i386, NetBSD/pmax(1.2) or NetBSD/vax.

Later...

Greg Oster

oster@cs.usask.ca
Department of Computer Science
University of Saskatchewan, Saskatoon, Saskatchewan, CANADA