Determine TSC frequency on Linux
Asked Answered
C

0

14

Given an x86 with a constant TSC, which is useful for measuring real time, how can one convert between the "units" of TSC reference cycles and normal human real-time units like nanoseconds using the TSC calibration factor calculated by Linux at boot-time?

That is, one can certainly calculate the TSC frequency in user-land by taking TSC and clock measurements (e.g., with CLOCK_MONOTONIC) at both ends of some interval to determine the TSC frequency, but Linux has already made this calculation at boot-time since it internally uses the TSC to help out with time-keeping.

For example, you can see the kernel's result with dmesg | grep tsc:

[    0.000000] tsc: PIT calibration matches HPET. 2 loops
[    0.000000] tsc: Detected 3191.922 MHz processor
[    1.733060] tsc: Refined TSC clocksource calibration: 3192.007 MHz

In a worse-case scenario I guess you could try to grep the result out of dmesg at runtime, but that frankly seems terrible, fragile and all sorts of bad0.

The advantages of using the kernel-determined calibration time are many:

  1. You don't have to write a TSC calibration routine yourself, and you can be pretty sure the Linux one is best-of-breed.
  2. You automatically pick up new techniques in TSC calibration as new kernels come out using your existing binary (e.g., recently chips started advertising their TSC frequency using cpuid leaf 0x15 so calibration isn't always necessary).
  3. You don't slow down your startup with a TSC calibtration.
  4. You use the same TSC value on every run of your process (at least until reboot).
  5. Your TSC frequency is somehow "consistent" with the TSC frequency used by OS time-keeping functions such as gettimeofday and clock_gettime1.
  6. The kernel is able to do the TSC calibration very early at boot, in kernel mode, free from the scourges of interrupts, other processes and is able to access the underlying hardware timers direction as its calibration source.

It's not all gravy though, some downsides of using Linux's TSC calibration include:

  1. It won't work on every Linux installation (e.g., perhaps those that don't use a tsc clocksource) or on other OSes at all, so you may still be stuck writing a fallback calibration method.
  2. There is some reason to believe that a "recent" calibration may be more accurate than an old one, especially one taken right after boot: the crystal behavior may change, especially as temperatures change, so you may get a more accurate frequency by doing it manually close to the point where you'll use it.

0 For example: systems may not have dmesg installed, you may not be able to run it as a regular user, the accumulated output may have wrapped around so the lines are no longer present, you may get false positives on your grep, the kernel messages are English prose and subject to change, it may be hard to launch a sub-process, etc, etc.

1 It is somewhat debatable whether this matters - but if you are mixing rdtsc calls in with code that also uses OS time-keeping, it may increase precision.

Cheryl answered 19/8, 2018 at 15:34 Comment(9)
Maybe it's the tsc_khz symbol exported in tsc.c? Just a guess.Sabrina
@MargaretBloom - it seems like someone tried to expose this, but I guess the patch never made it because I don't see it in the current source.Cheryl
the accumulated output maybe huge,: what actually happens is that the fixed-size kernel log buffer wraps around, so the boot-time messages aren't there anymore in dmesg output.Nicki
find /sys -iname '*tsc*' found /sys/devices/intel_pt/tsc_art_ratio, which says 334:2 on my i7-6700k, so that's maybe usable if it exists, on new enough CPUs.Nicki
@PeterCordes - yeah this value on your box and mine comes from cpuid leaf 0x15 which I could access directly. The problem is that (a) you need to know the "crystal frequency" for your CPU, which varies by model and worse, with Skylake-X varies even within the same model, and (b) it is apparently better to do an actual calibration, on some CPUs like Skylake-X, even if you have the cpuid info, since clock speeds may be different than the ideal by a fair amount, see here for example.Cheryl
In fact, right now I am using the cpuid info to get the TSC frequency, but on Skylake-X I fall back to a user-land calibration, but I'd like to be able to use the Linux value as an option. See here.Cheryl
@PeterCordes - good point about dmesg wraparound - that makes it even less likely for dmesg to work on a system that has been running for a while. You could perhaps parse some on-disk logfile which doesn't wrap around, but that's probably even less portable and the file permissions seem to often be stricter than dmesg. I updated the question to mention wraparound.Cheryl
A more recent attempt at exposing the TSC calibration can be found here. A new vDSO function called __vdso_linux_tsc_calibration is introduced for that purpose. I actually tried to run the code shown at the very end of the message thread, and it indeed failed at vdso_sym.Pascia
Possible duplicate of Getting TSC rate in x86 kernelMonongahela

© 2022 - 2024 — McMap. All rights reserved.