Skip to content

Restore the guest TSC exactly on WHP - #2022

Merged
ludfjig merged 1 commit into
hyperlight-dev:mainfrom
ludfjig:whp-tsc-restore
Nov 11, 2026
Merged

ludfjig merged 1 commit into
hyperlight-dev:mainfrom
ludfjig:whp-tsc-restore

Conversation

@ludfjig

@ludfjig ludfjig commented Nov 4, 2026 •

Copy link
Copy Markdown
Contributor

On WHP hosts with TscAdjustSupport, restore does not rewind the guest TSC. Writing TSC shifts TSC_ADJUST by the same amount, and writing TSC_ADJUST shifts TSC back, so restoring both keeps the time since the snapshot.

This clears TscAdjustSupport when creating the partition, as the MSHV driver does. restore_rewinds_tsc now runs on WHP. CI hosts lack the feature, so I tested on a host that has it. The test fails without the fix and passes with it.

Fixes #2021

@ludfjig
ludfjig requested a review from danbugs as a code owner November 4, 2026 00:26
@ludfjig ludfjig added the C-bug For PRs that fix bugs label Nov 4, 2026
Copilot AI balanced review requested due to automatic review settings November 4, 2026 00:26
@ludfjig ludfjig added the C-bug For PRs that fix bugs label Nov 4, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

The hard-coded SDK bit controlling WHP partition feature exposure remains unverified because authoritative header retrieval failed and independent runtime validation requires a Windows host with TscAdjustSupport.

No open issues 🎉

What changed in this PR

This PR makes snapshot restore rewind the guest time-stamp counter (TSC) on WHP hosts with TscAdjustSupport. It also includes the KVM restore fix from #2015, aligning guest-time behavior across Hyperlight’s backends.

Changes:

  • Disable TscAdjustSupport during WHP partition creation.
  • Include KVM’s decoy TSC write and regression tests for rewind and zero-value restore.
  • Document TSC restore behavior and record both fixes in the changelog.
File Description
src/​tests/​rust_guests/​simpleguest/​src/​main.rs Add a guest function for reading the TSC.
src/​hyperlight_host/​src/​sandbox/​initialized.rs Test TSC rewind and KVM zero-value restore.
src/​hyperlight_host/​src/​hypervisor/​virtual_machine/​whp/​x86_64.rs Disable TSC adjustment support during partition creation.
src/​hyperlight_host/​src/​hypervisor/​virtual_machine/​kvm/​x86_64.rs Prepend a decoy write to force TSC restoration.
src/​hyperlight_host/​src/​hypervisor/​regs/​x86_64/​msrs.rs Remove an inaccurate comment about Hyper-V TSC storage.
docs/​msr.md Explain TSC rewind behavior and disabled adjustment support.
CHANGELOG.md Record the KVM and WHP TSC restore fixes.

Review effort: Balanced

@hyperlight-gh-bot

This comment has been minimized.

On WHP hosts with TscAdjustSupport, restore does not rewind the guest
TSC. Writing TSC shifts TSC_ADJUST by the same amount, and writing
TSC_ADJUST shifts TSC back, so restoring both keeps the time since the
snapshot.

Clear TscAdjustSupport in the partition's processor feature banks, as
the MSHV driver does. The probe then drops TSC_ADJUST from the reset
set, and restore_rewinds_tsc runs on WHP too.

Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com>
@hyperlight-gh-bot

Copy link
Copy Markdown

Benchmark Results

Measured commit: 3245e4248354
Baseline commit: a03088470d82

kvm / amd (Linux) (➖ stable)

No benchmark improved or regressed.

Benchmark Results

function_call_codec

encode_control decode_vec_bytes_copy
byte_chunks 780.34 ns (➖ 1.02x slower)
vec_bytes 595.37 ns (➖ 1.01x slower)
374.47 µs (➖ 1.00x faster)

payload_allocation

slot_pool_segmented
262144 526.61 ns (➖ 1.01x slower)
65536 146.56 ns (➖ 1.04x slower)

sandboxes

create_initialized_and_drop
medium 13.64 ms (➖ 1.02x faster)

slot_pool

alloc_dealloc_128 alloc_dealloc_4096 alloc_dealloc_1500
7.69 ns (➖ 1.00x faster) 7.68 ns (➖ 1.00x faster) 7.68 ns (➖ 1.00x faster)

snapshot_files

load_snapshot_unverified
small 99.31 µs (➖ 1.01x slower)

virtq_readonly

slot_pool_segmented slot_pool_segmented_fragmented
262144 7.67 µs (➖ 1.01x slower) 7.07 µs (➖ 1.03x faster)
65536 1.94 µs (➖ 1.10x faster) 2.05 µs (➖ 1.05x slower)

virtq_readwrite

slot_pool_segmented slot_pool_segmented_fragmented
262144 28.29 µs (➖ 1.04x slower)
65536 6.12 µs (➖ 1.07x faster) 6.17 µs (➖ 1.02x faster)
8192 1.03 µs (➖ 1.00x faster) 1.14 µs (➖ 1.12x slower)
kvm / intel (Linux) (➖ stable)

No benchmark improved or regressed.

Benchmark Results

function_call_codec

encode_control decode_vec_bytes_copy
byte_chunks 758.35 ns (➖ 1.12x slower)
vec_bytes 503.17 ns (➖ 1.06x faster)
679.83 µs (➖ 1.00x slower)

payload_allocation

slot_pool_segmented
262144 495.69 ns (➖ 1.00x slower)
65536 155.52 ns (➖ 1.00x slower)

sandboxes

create_initialized_and_drop
medium 15.05 ms (➖ 1.03x faster)

slot_pool

alloc_dealloc_128 alloc_dealloc_4096 alloc_dealloc_1500
6.76 ns (➖ 1.00x faster) 6.78 ns (➖ 1.01x faster) 6.81 ns (➖ 1.00x slower)

snapshot_files

load_snapshot_unverified
small 48.59 µs (➖ 1.01x faster)

virtq_readonly

slot_pool_segmented slot_pool_segmented_fragmented
262144 7.53 µs (➖ 1.00x slower) 7.50 µs (➖ 1.01x slower)
65536 2.12 µs (➖ 1.00x slower) 2.12 µs (➖ 1.01x faster)

virtq_readwrite

slot_pool_segmented slot_pool_segmented_fragmented
262144 29.02 µs (➖ 1.09x faster)
65536 7.01 µs (➖ 1.01x faster) 7.02 µs (➖ 1.00x faster)
8192 713.96 ns (➖ 1.01x slower) 710.64 ns (➖ 1.02x faster)
mshv3 / amd (Linux) (➖ stable)

No benchmark improved or regressed.

Benchmark Results

function_call_codec

encode_control decode_vec_bytes_copy
byte_chunks 911.44 ns (➖ 1.00x slower)
vec_bytes 702.67 ns (➖ 1.01x slower)
315.95 µs (➖ 1.02x faster)

payload_allocation

slot_pool_segmented
262144 672.68 ns (➖ 1.00x faster)
65536 182.11 ns (➖ 1.00x faster)

sandboxes

create_initialized_and_drop
medium 70.04 ms (➖ 1.01x faster)

slot_pool

alloc_dealloc_128 alloc_dealloc_4096 alloc_dealloc_1500
9.91 ns (➖ 1.00x faster) 9.86 ns (➖ 1.21x faster) 9.88 ns (➖ 1.01x faster)

snapshot_files

load_snapshot_unverified
small 111.40 µs (➖ 1.04x slower)

virtq_readonly

slot_pool_segmented slot_pool_segmented_fragmented
262144 9.23 µs (➖ 1.00x slower) 9.22 µs (➖ 1.02x slower)
65536 2.47 µs (➖ 1.00x slower) 2.67 µs (➖ 1.00x slower)

virtq_readwrite

slot_pool_segmented slot_pool_segmented_fragmented
262144 34.73 µs (➖ 1.01x faster)
65536 7.94 µs (➖ 1.03x faster) 8.01 µs (➖ 1.02x faster)
8192 1.26 µs (➖ 1.01x slower) 1.32 µs (➖ 1.03x slower)
mshv3 / intel (Linux) (➖ stable)

No benchmark improved or regressed.

Benchmark Results

function_call_codec

encode_control decode_vec_bytes_copy
byte_chunks 915.99 ns (➖ 1.02x faster)
vec_bytes 654.81 ns (➖ 1.01x faster)
663.82 µs (➖ 1.03x slower)

payload_allocation

slot_pool_segmented
262144 662.17 ns (➖ 1.00x faster)
65536 241.19 ns (➖ 1.07x faster)

sandboxes

create_initialized_and_drop
medium 56.64 ms (➖ 1.46x faster)

slot_pool

alloc_dealloc_128 alloc_dealloc_4096 alloc_dealloc_1500
8.69 ns (➖ 1.00x faster) 8.69 ns (➖ 1.00x faster) 8.71 ns (➖ 1.00x faster)

snapshot_files

load_snapshot_unverified
small 54.83 µs (➖ 1.01x slower)

virtq_readonly

slot_pool_segmented slot_pool_segmented_fragmented
262144 7.97 µs (➖ 1.00x slower) 7.98 µs (➖ 1.00x slower)
65536 2.31 µs (➖ 1.01x slower) 2.30 µs (➖ 1.00x slower)

virtq_readwrite

slot_pool_segmented slot_pool_segmented_fragmented
262144 39.38 µs (➖ 1.02x slower)
65536 7.41 µs (➖ 1.02x faster) 7.53 µs (➖ 1.06x faster)
8192 902.70 ns (➖ 1.02x faster) 901.93 ns (➖ 1.02x faster)
hyperv-ws2025 / amd (Windows) (➖ stable)

No benchmark improved or regressed.

Benchmark Results

function_call_codec

encode_control decode_vec_bytes_copy
byte_chunks 1.19 µs (➖ 1.02x slower)
vec_bytes 803.74 ns (➖ 1.02x slower)
2.05 ms (➖ 1.05x slower)

payload_allocation

slot_pool_segmented
262144 784.83 ns (➖ 1.00x slower)
65536 229.56 ns (➖ 1.01x faster)

sandboxes

create_initialized_and_drop
medium 12.81 ms (➖ 1.04x faster)

slot_pool

alloc_dealloc_128 alloc_dealloc_4096 alloc_dealloc_1500
10.21 ns (➖ 1.03x faster) 9.99 ns (➖ 1.03x faster) 9.89 ns (➖ 1.05x faster)

snapshot_files

load_snapshot_unverified
small 756.30 µs (➖ 1.01x faster)

virtq_readonly

slot_pool_segmented slot_pool_segmented_fragmented
262144 9.25 µs (➖ 1.21x faster) 9.36 µs (➖ 1.04x faster)
65536 2.31 µs (➖ 1.10x faster) 2.36 µs (➖ 1.00x slower)

virtq_readwrite

slot_pool_segmented slot_pool_segmented_fragmented
262144 38.81 µs (➖ 1.01x faster)
65536 8.86 µs (➖ 1.03x faster) 9.30 µs (➖ 1.01x slower)
8192 1.28 µs (➖ 1.05x faster) 1.32 µs (➖ 1.01x slower)
hyperv-ws2025 / intel (Windows) (➖ stable)

No benchmark improved or regressed.

Benchmark Results

function_call_codec

encode_control decode_vec_bytes_copy
byte_chunks 1.31 µs (➖ 1.10x slower)
vec_bytes 754.02 ns (➖ 1.09x faster)
3.13 ms (➖ 1.01x slower)

payload_allocation

slot_pool_segmented
262144 742.08 ns (➖ 1.02x faster)
65536 208.71 ns (➖ 1.02x faster)

sandboxes

create_initialized_and_drop
medium 14.69 ms (➖ 1.01x slower)

slot_pool

alloc_dealloc_128 alloc_dealloc_4096 alloc_dealloc_1500
9.72 ns (➖ 1.00x slower) 10.25 ns (➖ 1.02x slower) 9.64 ns (➖ 1.00x slower)

snapshot_files

load_snapshot_unverified
small 674.55 µs (➖ 1.01x slower)

virtq_readonly

slot_pool_segmented slot_pool_segmented_fragmented
262144 7.76 µs (➖ 1.01x slower) 7.85 µs (➖ 1.05x slower)
65536 2.39 µs (➖ 1.03x slower) 2.39 µs (➖ 1.05x slower)

virtq_readwrite

slot_pool_segmented slot_pool_segmented_fragmented
262144 42.73 µs (➖ 1.06x slower)
65536 8.83 µs (➖ 1.06x slower) 8.23 µs (➖ 1.01x faster)
8192 1.15 µs (➖ 1.07x slower) 1.11 µs (➖ 1.05x slower)

Reported by cargo ci bench-report --candidate run:42104899724 --config-file bench_report.toml.

@ludfjig
ludfjig merged commit 6635b69 into hyperlight-dev:main Nov 11, 2026
63 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

C-bug For PRs that fix bugs

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Restore does not rewind the guest TSC on WHP

3 participants