Page MenuHomeFreeBSD

x86: hyperv: use Hyper-V time counter (rather than i8254) to calibrate TSC
AbandonedPublic

Authored by decui_microsoft.com on Feb 3 2016, 6:30 AM.
Tags
None
Referenced Files
Unknown Object (File)
Sun, Oct 12, 3:13 PM
Unknown Object (File)
Thu, Sep 25, 10:04 AM
Unknown Object (File)
Wed, Sep 24, 5:54 AM
Unknown Object (File)
Sep 2 2025, 2:17 PM
Unknown Object (File)
Aug 28 2025, 6:56 AM
Unknown Object (File)
Aug 8 2025, 1:31 AM
Unknown Object (File)
Jul 27 2025, 11:41 PM
Unknown Object (File)
Jul 26 2025, 10:06 PM
Subscribers

Details

Summary

The i8254 PIT counter emulated by Hyper-V is not reliable.

In probe_tsc_freq() -> DELAY -> init_ops.early_delay() -> i8254_delay(),
getit() can return these values when it is invoked 10 times:

1 pit count0 = 228
2 pit count0 = 131
3 pit count0 = 34
4 pit count0 = 65473 <-- this is a normal wrap-around.
5 pit count0 = 65375
6 pit count0 = 65278
7 pit count0 = 65180
8 pit count0 = 65388 <-- this is bad!
9 pit count0 = 65290

10 pit count0 = 65193

For the 8th time, the 'delta' in i8254_delay() is < 0 while
it shouldn't, so the later "delta += i8254_max_count;" and
"ticks_left -= delta" will cause i8254_delay() to wait shorter than
expected, and finally probe_tsc_freq() get a smaller 'tsc_freq', e.g.,
a 2.5GHz CPU can be detected as 1.3GHz.

A smaller 'tsc_freq' can cause time inaccuracy in dtrace.
It can also cause warnings like

calcru: runtime went backwards from 50 usec to 25 usec for pid 0 (kernel)
calcru: runtime went backwards from 1471 usec to 743 usec for pid 0 (kernel)
calcru: runtime went backwards from 40 usec to 20 usec for pid 0 (kernel)
calcru: runtime went backwards from 18 usec to 9 usec for pid 0 (kernel)
calcru: runtime went backwards from 46204978 usec to 23362331 usec for pid 0 (kernel)

We should use Hyper-V time counter, which is much more reliable than i8254,
to calibrate TSC.

And, we must use Hyper-V timer counter for Hyper-V Generation-2 (UEFI) VM,
because i8254 doesn't exist for such a VM.

Please suggest how I should improve the patch, e.g., should I move
the new hyperv_delay() to a new file?

Submitted by: Dexuan Cui <decui@microsoft.com>

Test Plan

Boot the kernel with boot_verbose="YES", and check dmesg:

dmesg | grep "TSC clock"

Calibrating TSC clock ... TSC clock: 2500003082 Hz

(Without the patch, the TSC Hz is only ~1.3GHz in my test)

Diff Detail

Repository
rS FreeBSD src repository - subversion
Lint
Lint Passed
Unit
No Test Coverage
Build Status
Buildable 2368
Build 2384: arc lint + arc unit

Event Timeline

decui_microsoft.com retitled this revision from to x86: hyperv: use Hyper-V time counter (rather than i8254) to calibrate TSC.
decui_microsoft.com updated this object.
decui_microsoft.com edited the test plan for this revision. (Show Details)
This revision is now accepted and ready to land.Feb 4 2016, 1:07 AM
adrian edited edge metadata.

hah, good catch!