On Thu, Oct 14, 2021 at 11:37:44PM +0200, Mark Kettenis wrote:
> > Date: Thu, 14 Oct 2021 16:13:17 -0500
> > From: Scott Cheloha <[email protected]>
> >
> > [...]
> >
> > Thoughts?
>
> I never understood this code. But I don't understand that if our
> timecounters are only 32 bits, we need more than 64 bits to store a
> time difference on the order of seconds...
Let's use the TSC on my laptop as a practical example.
We have a 64-bit register, so it provides a 32-bit counter. The
maximum value tc_delta() can return is UINT_MAX, i.e. UINT32_MAX.
What is the frequency of my TSC?
$ sysctl machdep.tscfreq
machdep.tscfreq=2112000000
Given that frequency, the unadjusted scale for the counter is:
scale = 2^64 / frequency = 2 ^64 / 2112000000 = 8734253822
Of course, we can't do that math with 64-bit integers, so we
approximate (see tc_windup() in kern_tc.c):
scale = (1 << 63) / frequency * 2 = 8734253822
(In this case it makes no difference, the scale is the same.)
Assuming the unadjusted scale, the maximum possible product is:
UINT32_MAX * 8734253822 = 4294967295 * 8734253822 = 37513334511718751490
Recall that UINT64_MAX is 18446744073709551615. It's considerably
smaller than 37513334511718751490.
If we capture the full 96-bit result we can handle a blackout of
37513334511718751490 / 19066590438009199874 = 2.033601938739046
or roughly 2 seconds on the primary CPU.
If we don't handle the full 96-bit result we overflow after 1 second.
(It follows, then, that lower frequency timecounters yield longer grace
periods before we lose time.)