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.)

Reply via email to