pmtimer and nanouptime
Matthew Dillon
dillon at apollo.backplane.com
Tue Jul 20 11:45:40 PDT 2004
:On my PC, getnanotime() starts to return non-normalized value
:(tv_nsec not between 0 and 999999999) after resuming from S3 state.
:This breaks programs relying on the timespec value returned by
:clock_gettime() to be normalized, and libc_r is one of them.
:After inserting printf() in several places, I found the following things:
:
:- nanouptime() returns non-normalized value when it's called from
: set_timeofday() called from pmtimer_resume(), because of overflow
: in multiplication. The following is modified version of nanouptime()
: I'm using to print out each value used in multiplication.
:
: do {
: tsp->tv_sec = gd->gd_time_seconds;
: count = cputimer_count();
: base = gd->gd_cpuclock_base;
: delta = count - base;
: } while (tsp->tv_sec != gd->gd_time_seconds);
: nsec = (cputimer_freq64_nsec * delta) >> 32;
:..
What it comes down to is that the calculated delta from the 8254
cannot safely exceed approximately 2 seconds. This is not usually
a problem, because gd_cpuclock_base is updated in hardclock() once
a second.
However, when you go into sleep the hardclock is turned off.
set_timeofday() uses nanouptime() in order to set the basetime
offset. In DragonFly the 'uptime' is the basis for the time in
the system and a base offset is added to get to the time of day.
When you go into sleep, though, the basis for calculating the uptime
gets messed up. The clock stops happening but the 8254 keeps ticking,
and various calls to cputimer_count() causes the software to continue to
update the 32 bit cputimer counter. When you wake up again, nanoputime()
gets a big delta.
:And it printed out the following message on the console:
: nanouptime: nsec went negative;delta: 8697958, count: 55705685, base: 470077
:27, freq64_nsec: 3599591090043
The 8254 delta you've printed here is 8.6 million ticks. The 8254 runs
at 1.19MHz so we are talking around 8 seconds worth of delta here. This
easily overflows the pot, so to speak.
There are two possible solutions. First, we can put a cap on the delta
in the various micro/nanotime routines. I'd prefer not to do this
because those routines are in the critical path. Second, we can add a
procedure to pmtimer_resume() which resets the deltas.
This isn't entirely trivial since MP boxes need special care. I will have
a patch set for you to try in a moment.
-Matt
More information about the Bugs
mailing list