fix(guest): acpi_init was never 18000 us, it was 18 jiffies - #73
Merged
Conversation
Two things this profiler reported as measurements were not measurements.
**The initcall durations were quantised to 1 ms.** initcall_debug prints what
ktime_get() gives it, and until the TSC clocksource is registered that is served
by the jiffies clocksource: resolution 1/HZ, so 1 ms here (CONFIG_HZ=1000). Every
initcall in the core/postcore/arch/subsys levels runs before that registration
and is therefore rounded to a whole millisecond. Across 42 boots this profiler
reported acpi_init as 2000, 6000, 7000, 17000, 18000, 19000 or 20000 us and never
once anything between, while device-level initcalls in the same boots came back
as 6447, 7003, 2756. The number looked precise to the microsecond and carried
1 ms of quantisation, which is enough to hide any change smaller than itself -
several A/B comparisons were run against that column before it was noticed.
The initcall_start/initcall_finish tracepoints are already enabled at boot for
the level breakdown, and ftrace timestamps come from local_clock(), which is
TSC-backed from very early. So the durations now come from there, with the
initcall_debug values kept as the fallback when the tracepoints are absent. The
header says which was used: `source=tracepoints refined=662/662`.
Same three boots, before and after:
acpi_init 18000 / 18000 / 19000 -> 20252 / 20188 / 18437
pci_subsys_init 0 / 1000 / 0 -> 74 / 105 / 74
The second line is the point: sub-millisecond initcalls were reported as zero.
**And the host was not always idle.** These tests time a boot to the millisecond
on a machine that is also this repository's self-hosted CI runner, where a
`task build:kernel` from an unrelated push takes all 20 cores for minutes. One
such overlap showed up as a pid1-entry of 78 ms against a median of 51 - the only
outlier in twelve runs, and unexplained at the time.
requireQuietHost samples /proc/stat and waits for ambient CPU use to fall below
25%, skipping the test if it has not settled in 30 s. The gate is on measured CPU
rather than on the runner's process: it catches a manual build or a concurrent
benchmark too, and it does not fire merely because these tests are themselves
running inside a CI job, where a Runner.Worker always exists and is idle. The
measured value is logged either way, so a number just under the threshold is
visible next to the timing it produced.
Verified in both directions: an idle host logs `HOST_QUIET host 0.0% busy` and
runs; under 20 spinning cores the test skips with `host 100.0% busy after 30s`.
Full integration suite passes.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014fdjKufitSmytkon6wZDCb
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Two things this profiler reported as measurements were not measurements.
1. The initcall durations were quantised to 1 ms
initcall_debugprints whatktime_get()gives it, and until the TSC clocksource is registered that is served by the jiffies clocksource — resolution 1/HZ, so 1 ms here (CONFIG_HZ=1000). Every initcall in the core/postcore/arch/subsys levels runs before that registration.Across 42 boots this profiler reported
acpi_initas 2000, 6000, 7000, 17000, 18000, 19000 or 20000 µs and never once anything in between, while device-level initcalls in the same boots came back as 6447, 7003, 2756. The number looked precise to the microsecond and carried 1 ms of quantisation — enough to hide any change smaller than itself. Several A/B comparisons were run against that column before it was noticed.The
initcall_start/initcall_finishtracepoints are already enabled at boot for the level breakdown, and ftrace timestamps come fromlocal_clock(), which is TSC-backed from very early boot. Durations now come from there, with theinitcall_debugvalues kept as the fallback when the tracepoints are absent. The header says which was used:source=tracepoints refined=662/662.Same three boots, before and after:
acpi_initpci_subsys_initThe second row is the point: sub-millisecond initcalls were reported as zero.
2. The host was not always idle
These tests time a boot to the millisecond on a machine that is also this repository's self-hosted CI runner, where a
task build:kernelfrom an unrelated push takes all 20 cores for minutes. One such overlap showed up as apid1-entryof 78 ms against a median of 51 — the only outlier in twelve runs, and unexplained at the time.requireQuietHostsamples/proc/statand waits for ambient CPU use to fall below 25%, skipping the test if it has not settled in 30 s. It gates the four measurement tests (TestBootLatency,TestVminitdReady,TestKernelBootProfileComplete,TestUserspaceBootProfile).The gate is on measured CPU rather than on the runner's process, for two reasons: it catches a manual build or a concurrent benchmark too, and it does not fire merely because these tests are themselves running inside a CI job, where a
Runner.Workeralways exists and is idle. The measured value is logged either way, so a number just under the threshold is visible next to the timing it produced.Verified in both directions:
Checks
task lint0 issues,go test -raceon the touched package passes.🤖 Generated with Claude Code