Re: Problem with kernel-pll in 2.0.3x (at least)

Jon Peatfield (
Fri, 01 May 1998 07:33:07 +0100

> I have no alpha, but isn't the tick changed once per second, or
> something like that (no source here...)?

Well looking though various files in linux/kernel/ I don't really understand
all that is going on, sched.c for example has code #ifdef'd on HZ being 100 to
perform some clever fix.

However, taking a trivial belief in the workings (that the clock is updated by
tick uS every timer interrupt (i.e. HZ times per sec)) I estimate the

tick = 1000000 / 1024 = 976.56250
-> tick is actually set to 977, so in 1 second time is updated by
977 * 1024 uS which is 1000448 which is 448ppm too fast.

Running xntpd3-5.93 modified to use the kernel-pll with the MAXFREQ set to
2048 (rather than the default 200ppm) the system stabelised after a few hours
with freq set to -438.308 ppm which is close enough for me to believe this is
really what is happening in the kernel.

Now being fast by 448ppm would mean that unchecked the clock would drift by
~30seconds per day which doesn't seem to happen (though I've probably not left
one up without some ntp daemon for long enough to be sure), so the code may be
different when the kernel-pll is in use.

A bit more digging shows the following definitions in sched.c:

long tick = (1000000 + HZ/2) / HZ; /* timer interrupt period */
int tickadj = 500/HZ; /* microsecs */
long time_freq = ((1000000 + HZ/2) % HZ - HZ/2) << SHIFT_USEC;
/* frequency offset (scaled ppm) */

when HZ is 100 tickadj is 5, but once HZ is over 500 this is zero (is that
right?) The time_freq is very interesting, at HZ=100 it is 0, and at HZ=1024
this sets time_freq to -448 just as I would (though I'd bracket it up a bit to
make it clear that the % binds more tightly than the - since I misread it the
first few times (it is early here, and I'm not wide awake yet).

Looking at another of our machines which is running an xntpd not using
kernel-pll and asking adjtimex() what freq is gives me -448ppm (though xntpd
thinks it has set it to 17.052 ppm, in fact the clock is drifting slowly on
this machine ~1 seconds a day).

Aha, but when using the kernel-pll xntpd starts by setting the pll freq to the
value from ntp.drift which will probably be 0 (or close to it) unless ntp has
already been running. This means that the value for drift is different when
the kernel-pll is used .vs. an external pll xntpd if 1000000 is not divisible
by HZ!

In any case clearly freq needs to be able to reach at least the value it is
set to by default by the kernel which is of order HZ/2, you also need a little
slack in case the clock is jittering between 2 values on either side of
changing tick, hence the original 200ppm for a 100hz clock.

I'm now very happy with why MAXFREQ needs to be able to span more than HZ, if
you know a cleaner way to change the headers to allow this I'd be happy to use

Perhaps HZ + 100 is actually enough for all cases, so the code would be:

#define MAXFREQ ((HZ + 100L) << SHIFT_USEC) /* max frequency error (ppm) */

(or HZ + HZ which at least doesn't have the dreaded multiplication in it).

[ Ian, I'll put this modified kernel on thor lather this morning if no-one is
running big code on it. I'll also finish up my mods to xntpd3-5.93 and put
the RPM up somewhere useful. ]

-- Jon

To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to