Repository navigation
Description
Summary
Two runs of NVX microVM tests / Windows / WHP / Runtime adapter failed 14 minutes apart on azure-windows-1, in different scenarios, each because a guest failed time ABI 2 and powered its VM off. Neither head changes any time code.
- In the merge group of ci: run pushes to feature/nvx-refactor #1302, a clone of
vm_clone a_clone_whose_activation_fails_ends_before_it_is_readyended with status 195 before its repair acknowledged the restore. 195 is the time ABI's status for a failed restore repair. The test expects the clone to repair, then fail its activation with 54. This took ci: run pushes to feature/nvx-refactor #1302 out of the merge queue. - In a pull-request run of openvmm: pin the serial socket's read fix and output retention tests #1303, the cold boot of
vm_layered a_denied_network_lets_no_probe_throughfailed check C12, status 193:time sample uncertainty 119213 ns exceeds 100000 ns.
At a cold boot and at a clone's repair alike, the guest takes up to 3 time samples. It accepts one only if OpenVMM paired host UTC with the guest TSC within 100 µs; if none qualifies, the guest powers off (Table 3.10). Incident 2 shows a sample over the bound. Incident 1's status most likely comes from the same check failing during the repair, though no log names the check (see Evidence). In the same two workflow runs, the WHP benchmark runner, azure-windows-5, paired its samples within 136 and 139 ns.
Neither change touches time:
- ci: run pushes to feature/nvx-refactor #1302 changes only CI's workflow, its documentation, and its scripts and their tests.
- openvmm: pin the serial socket's read fix and output retention tests #1303's OpenVMM pin adds 3 commits, in
serial_socketand thevirtio_consoletests only.
#1302's identical tree passed its next merge group on azure-windows-6. azure-windows-1 passed WHP jobs at 01:16Z, before the incidents, and at 02:00Z and 02:11Z, after them.
Incidents
1. Clone repair, merge group of #1302 (2026-11-06 01:34Z)
-
Workflow: CI run 42144050826, attempt 1,
merge_group. -
Head:
c41a9b8c3a52e9fdcfcc8f776c3bf804fc8e2879, ci: run pushes to feature/nvx-refactor #1302's6224fb785ondev's4cfe8330e. OpenVMM14dc4116ec7e57567633c4b7b07892aca3a58522. -
Failed job:
NVX microVM tests / Windows / WHP / Runtime adapteronazure-windows-1, stepRun runtime adapter scenarios on Windows.vm_clonepassed 34 of its 35 tests. -
Failure, at
vm_clone.rs:1492:left: ["repair", "repair-status", "activation", "event", "195", "exited"] right: ["request", "unusable-root", "activation", "activating", "54", "exited"]The start printed:
{"downtime": "10336688075", "failure.code": "exited", "failure.evidence": "repair-status", "failure.outcome": "repair", "failure.progress": "event", "failure.stage": "activation", "failure.status": "195", "failure.teardown": "exited", "generation": "1", "lease": "42197786ea8a4fe185cd79818a8348d5", "pid": "9868", "quarantined": "no", "released": "42197786ea8a4fe185cd79818a8348d5", "source": "monotonic"} -
Downstream:
Required status checkfailed, and the queue removed ci: run pushes to feature/nvx-refactor #1302 at 01:39:08Z (failed_checks).- ci: run pushes to feature/nvx-refactor #1302 was re-queued at 01:58:01Z. Its next group, run 42147285388, had the same tree (
dc5bbe38) and passed the test onazure-windows-6. - ci: run pushes to feature/nvx-refactor #1302 merged at 02:09:13Z, about 30 minutes later than it would have otherwise.
2. Cold boot, pull-request run of #1303 (2026-11-06 01:47Z)
-
Workflow: CI run 42144804527, attempt 1,
pull_request. -
Head:
c96ceaaee37ee97230a2fbc3402c5b9bf88119f4. OpenVMM6fb64731f03314a3c5ee634d3c85d6782a5babe0, incident 1's pin plus 3 commits inserial_socketand thevirtio_consoletests only. -
Failed job:
NVX microVM tests / Windows / WHP / Runtime adapteronazure-windows-1, the same step.vm_layeredpassed 42 of its 43 tests. -
Failure: the launch of
a_denied_network_lets_no_probe_throughexited 1 withcannot attach to the VM: the broker closed the NVXS session. The VMM's log ended:NVX-TIME-ABI-VIOLATION: v=1 code=G_CONFORMANCE_C12 source=conformance phase=boot generation=0 boottime_ns=2251650395 detail="time sample uncertainty 119213 ns exceeds 100000 ns" 3.487992600s INFO openvmm_entry::vm_controller: guest halted reason=PowerOffWithStatus { code: c1 }
Runner validation passed H1 to H4 in both jobs; H4 found azure-windows-1's TSC rate in agreement with QueryPerformanceCounter. No check measures how long OpenVMM takes to pair a sample.
Evidence
- Same bound at boot and at repair. The guest takes at most
SAMPLE_ATTEMPTS, 3, samples, each withinSAMPLE_BOUND_NS, 100 µs.- At a cold boot, an initial sample over the bound fails check C12, status 193.
- At a restore's repair, the guest selects its sample with the same bound. A sample over it fails
G_REPAIR_SAMPLE, status 195.
- Where incident 1's 195 probably came from. This is an inference, not an observation.
- The record's progress,
event, says that the host read OpenVMM's restore-ready event but never saw the repair acknowledge the restore. - Before the acknowledgement, the repair ends a clone with 195 only through
G_REPAIR_PACKET,G_REPAIR_GENERATION,G_REPAIR_SAMPLE, orG_REPAIR_CLOCK.G_REPAIR_SUPPRESSIONcomes from repair step 7, which starts 150 ms after the acknowledgement. - A bad packet or generation would fail every clone, yet the job's other clones passed through the same repair. An
adjtimexfailure has no reason to be intermittent. - That leaves
G_REPAIR_SAMPLE: the same bound that incident 2 exceeded 14 minutes later.
- The record's progress,
- Why no log can confirm it.
- A clone's restore discards the guest's console, so the host sees only the status, which it attributes to the repair.
- A job that runs only the runtime adapter uploads no failure logs.
- Usual values.
- The WHP platform job is the only WHP job whose log routinely shows the latest accepted sample's uncertainty (
NVX-TIME-ABI: … uncertainty_ns=…). Onazure-windows-5it measured 108 to 146 ns in its 17 runs from 2026-11-05 18:35Z to 2026-11-06 01:45Z. - A general runner's log shows the value only when a scenario prints it: 13,024 ns on
azure-windows-4, in a shard of run 41973357177 that failed for another reason (test-microvm: lifecycle intermittently misses its marker when the byte channel's output interleaves with the boot console's #1290). - How close the general runners' parallel suites usually come to 100 µs is unknown.
- The WHP platform job is the only WHP job whose log routinely shows the latest accepted sample's uncertainty (
History
The 300 CI runs from 2026-11-02 08:37Z to 2026-11-06 02:12Z:
- The WHP runtime-adapter job completed 121 times and failed 3.
- Two failures are these, on
azure-windows-1, which passed the job 16 times. - The third was on
azure-windows-4(run 42095876865): a network check,vm_layered an_allow_rule_lets_only_its_destination_through, with no time violation.
- Two failures are these, on
- Of the 33 jobs that failed in those runs, on every backend, only these two logged a time-ABI violation.
Root cause
Probably a transient condition of azure-windows-1 around 01:34Z and 01:47Z on 2026-11-06, in which OpenVMM could not pair host UTC with the guest TSC within 100 µs in 3 tries. The guest and OpenVMM did what time ABI 2 specifies.
What delayed the pairing is unknown. A stall of the runner VM's vCPUs would explain it, whether from contention with the suite's parallel VMs, a noisy neighbor, or host maintenance such as #768's live migration.
Impact
- Any VM that boots or restores on a runner in this state can fail, in any scenario. The scenario reports its own symptom, such as
the broker closed the NVXS session, rather than the time ABI's, unless the VMM's log is printed. - Incident 1 took ci: run pushes to feature/nvx-refactor #1302 out of the merge queue. Incident 2 failed openvmm: pin the serial socket's read fix and output retention tests #1303's pull-request run.
Suggested next steps
- Find what
azure-windows-1went through from 01:30Z to 01:50Z on 2026-11-06: the Azure activity log of its VM (maintenance, live migration), its vCPU wait time, and its load, as ci: track azure-mshv-1's intermittent H4 failures after a live migration to a host with an unstable clock #768 did forazure-mshv-1. - Record the uncertainty of accepted samples on the general runners, as the platform job's log does, to learn how close their suites come to the bound under parallel load.
- Make a clone's 195 attributable:
- Keep the time-ABI violation of a clone's guest where the host can report it.
- Upload the runtime adapter's VMM logs when its job fails.
- If the general runners come close to the bound in normal runs, don't loosen the tests. Instead, either:
- qualify the runners for the bound, as runner validation's H4 does for the TSC rate; or
- revisit the bound or the number of attempts in the time ABI's design.
Related
- test-microvm: time-host-correction fails when the host's time service slews host UTC by more than 75 ppm during a phase (flaky NVX microVM tests / Linux) #1229, fixed by test-microvm: tolerate host time-service slews in time-host-correction #1285:
time-host-correctionfailed by a host time service's slews. It's the same class of failure, the CI host's clock rather than the product, through another mechanism. - ci: track azure-mshv-1's intermittent H4 failures after a live migration to a host with an unstable clock #768:
azure-mshv-1's intermittent H4 failures after a live migration to a host with an unstable clock. - ci: the IMDS deadline tests need the request's worker to reach
connectwithin 0.2 s, so a runner stall fails them (flaky NVX CLI / Windows) #1239, OpenVMM: consomme'stest_tcp_last_ack_restarts_timeout_after_close_waitraces a 1 ms close deadline, so a runner stall hangs it until nextest kills it (flaky OpenVMM unit tests / Windows) #1240: Windows runner stalls that break tight timing bounds. - time ABI: publish the host's clock correction with each time sample #1018, which pins [DO NOT REVIEW] microVM: publish the host's clock correction with each time sample openvmm#4830: time ABI 2, which set the repair's 3 samples within 100 µs.
- nvx-rs: give a clone's failures documented statuses #937, nvx-rs: attribute a clone's failures, record them, and reattach it #951: the statuses of a clone's failures, and their attribution.
Activity
ppenna commentedon Nov 6, 2026
Update on 2026-11-06
A second investigation of incident 2 (run 42144804527) agrees with the root cause above. There's no new occurrence: in the 7 CI runs since 02:00Z, no job failed, and the WHP runtime-adapter job passed 4 times, once on
azure-windows-1at 02:54Z. #1303's head is stillc96ceaae, with no rerun, so itsRequired status checkstays red until the job is rerun.Three corrections to the description, and one addition.
Corrections
azure-windows-5, 136 and 139 ns and the range of 108 to 146 ns, are themax_uncertainty_nsof runner validation's H6 check, the guest warp probe: the uncertainty of its cross-CPU TSC comparisons. Its 18 platform jobs from 2026-11-05 18:35Z to 2026-11-06 02:00Z log noNVX-TIME-ABIline. A time sample's uncertainty can't be under 1,000 ns, since the guest adds a 1 µs skew bound to it. The only sample uncertainty that we have from a general runner is still the 13,024 ns onazure-windows-4, 13% of the bound.%TEMP%, which the sandbox'sDropdeletes once its VM has ended, and the job's log has no message that it kept incident 2's. A failed test has to keep the log, or copy it into the workspace, for an upload to find it.Addition: on WHP, one measurement at a VM's start widens all of its samples
All 3 samples can then exceed 100 µs in two ways:
OpenVMM's log tells them apart. At each start it logs
time ABI: guest TSC offsetwithuncertainty_cycles. For incident 2, about 330,000 cycles (118 µs atazure-windows-1's 2.79 GHz) would mean the offset, and about 24,000 to 35,000 would mean per-sample delays. That line is what step 3 needs to keep.If the offset is the cause, more attempts in the guest (step 4) can't help. The fix would belong in OpenVMM, for example measuring the offset again while its tightest read is still wide.
openvmm: pin measuring the guest TSC offset until it is not wide
doc: describe the reads of a wide guest TSC offset in the clock design
virt: read on while the guest TSC's offset is wide
openvmm: pin measuring the guest TSC offset until it is not wide
doc: describe the reads of a wide guest TSC offset in the clock design
virt: read the guest TSC offset until it is within its bound
openvmm: pin waiting for a guest TSC offset within its bound