[time-nuts] x86 CPU Timekeeping and clock generation
Tom Van Baak
tvb at LeapSecond.com
Wed Jan 6 20:06:35 UTC 2021
Kasper,
> A short run here using the latest kernel gives an error of < ± 2e-10
> on 14.31818MHz hpet, and 0.5ppm on tsc.
Ah, we know that frequency well
14.31818 MHz is 4x the NTSC colorburst frequency (~3.58 MHz). It is also
3x the original PC CPU clock frequency (~4.77 MHz). And 12x an ISA bus
frequency (~1.19318 MHz). The IBM PC had clock division by 3 and 4 to
generate those frequencies. Even the laptop I'm using to type this has a
high-res timer resolution of 3.579545 MHz. [1] These magic numbers are
everywhere.
Time for a short story. About 30 years ago I was involved with the
development of the Windows NT kernel on a 64-bit machine. NT timekeeping
is pretty much like any OS timekeeping, with ticks and counters and
epochs and stuff. One of the machines had a HAL clock rate of 1.193181
MHz. So how do you set an accurate periodic interrupt timer for that
weird number?
One way is with divisions and shifts and approximations. And I see that
in your Linux code. The guiding principle is usually "close enough" is
good enough. One semi-valid excuse is "the crystal isn't accuracy enough
anyway". Another valid excuse is "NTP will take care of it", so don't worry.
This attitude is enough to make any time nut cringe. It
institutionalizes small errors, excuses rounding and truncation issues.
It's "time abuse" at the nanosecond level. And it means if you do happen
to have a perfect external clock, the OS still cannot keep correct time.
As you and OP now know well.
Anyway, the solution for the NTSC-based HAL was to use pure integers. No
shifts, no rounding, no truncation, ever. Instead modulus arithmetic was
used. You know, the N/M or N/M+R stuff that you see in a phase correct DDS.
Part of the trick was to realize that the 1.19 MHz number was 1/3rd of
the NTSC colorburst frequency. At that is not 3.579 MHz, nor 3.579545
MHz, but instead 315 / 88 MHz. The math (and history) behind NTSC is
really cool. Fun for math- and time-nuts. [2] It always boils down to
integers, vacuum tube friendly small prime factors like 2, 3, 5, 7, 11,
and 13.
If you do your kernel timekeeping in integers and modulus arithmetic you
are essentially doing cycle counting and the kernel will keep perfect
time relative to the external oscillator. So that should be the goal.
Not e-6, not e-9, not e-10, but perfect cycle counting. Consider this a
strong plea for someone in both BSD- and Linux- land to pull that off.
Ironically the first UNIX I worked on was a PDP-11 and it had "cycle
accurate" timekeeping. It was based on a 60 Hz mains interrupt and the
kernel code to increment time used modulus arithmetic. The code was
essentially: if(++lbolt >= HZ) { ... lbolt =- HZ; ... } where HZ is 60.
/tvb
[1] C:\tvb\> qpc
frequency: 0x00000000_00369E99 3579545
3.579545000000000e+006 3.579545000 MHz
counter: 0x00000091_338B6739 623635031865
6.236350318650000e+011 174221.872295222 s
[2] How to become a bit banging, cycle counting, PIC loving, embedded
programming, time nut.
On 1/6/2021 10:39 AM, Kasper Pedersen wrote:
> On 06.01.2021 06.35, Luiz Paulo Damaceno wrote:
>> Hi all,
>>
>> I'm studying computer's timekeeping and i'm on level of remove the base
>> crystal that feeds the entire PLL logic of the motherboard (24 MHz on
>> motherboard that i'm using) and compare system's time with an NTP server.
>>
> (After reading your posts, and your plot, and guessing at PCish
> motherboard and Linux for the board under test)
>
> I did the same thing many moons ago now, and back then it was much
> worse. It turned out to be a painful rounding error in the kernel:
>
> https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=a386b5af8edda1c742ce9f77891e112eefffc005
>
> After that quick-fix there was 5e-9 left, about what your plot shows.
> After later cleanup that should now be be less than 3e-10.
>
>
> What clocksource are you using? see
>
> /sys/devices/system/clocksource/clocksource0/current_clocksource
> and
> /sys/devices/system/clocksource/clocksource0/available_clocksource
>
> You should pick the one that has the least unpredictable
> (rounding-error-prone in hardware) PLL ratios between the crystal
> oscillator and the clocksource. On most PCs that is hpet, which is
> typically driven directly from the crystal, though in your case this may
> be a synthesized 14.31818 MHz (the most common hpet frequency).
>
>
> A short run here using the latest kernel gives an error of < +/- 2e-10
> on 14.31818MHz hpet, and 0.5ppm on tsc.
>
>
> /Kasper Pedersen
>
> _______________________________________________
> time-nuts mailing list -- time-nuts at lists.febo.com
> To unsubscribe, go to http://lists.febo.com/mailman/listinfo/time-nuts_lists.febo.com
> and follow the instructions there.
>
More information about the Time-nuts_lists.febo.com
mailing list