Repository navigation
feat(obs): export IPI, TLB shootdown and PT_LOCK counters (C3 E1) - #101
Merged
Merged
Conversation
C3 E1 (#90): /proc/schedstat gains reschedule and TLB-shootdown IPIs sent to and handled on each online CPU, the existing targeted and broadcast-fallback shootdown counters with the shootdown IPIs sent, and PT_LOCK acquisitions, contention, try-lock busy returns and wait/hold TSC sums and maxima. Relaxed atomics, observability only. A hosted test covers the PT_LOCK accounting (busy, contended, wait and hold) and a NeedsCpus(2) runtime test checks that the IPI, shootdown and PT_LOCK counters advance on their events.
schedstat_event_counters raises the RuntimeTest total that the hosted kernel-coverage suite pins from 74 to 75.
Receipts are archived in Zero-kernel/Nilix-docs-private#12.
7 tasks
Document sampling skew and LAPIC coalescing; compare separate same-boot counter deltas for C3 analysis. A handled count above the sent count is valid and does not establish a delivery failure. Plan item: N3
8 tasks done
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.
Plan item: N3
Problem and outcome
C3 (#90) has to explain why the
threadstress profile costs about 220 ms of host time per thread at 16 vCPUs, against about 41 ms at 4. Its two leading hypotheses are broadcast TLB shootdowns and contention on the globalPT_LOCK. The counters that would confirm or reject them either exist but are never read (targeted and broadcast-fallback shootdowns) or do not exist (shootdown fanout, IPIs per CPU,PT_LOCKcontention and hold time).This is E1 of the approved C3 design (Zero-kernel/Nilix-docs-private#5,
design/thread-hb-c3-scaling-design.md§3). It exports those counters through/proc/schedstat. The stress runner already samples that file into the serial log, so the E2–E4 diagnostic runs pick them up with no userspace change. Kernel behavior is unchanged.Related issue or audit finding
Related: #90 (C3), #62. Design: Zero-kernel/Nilix-docs-private#5.
Design and scope
/proc/schedstatgains four lines afteridle_rearms. Existing lines are unchanged.(Values from the first sample of a 16-vCPU
threadrun; see validation.)ipis_sent/ipis_handled(kernel_core::process, fed byarch::ipi::send_ipiand the reschedule and TLB-shootdown IPI handlers).ipis_handledmay exceedipis_sent. LAPIC coalescing also means their difference is not an exact pending or dropped IPI count. The handler side readscpu_idfrom the per-CPU slot it already resolves.sent=10, handled=11without unsigned underflow or a delivery-failure verdict.cpuN=fields. That keeps the file small enough forsyscall_test's 2 KiB reader (see compatibility).tlb_shootdowns(mm::tlb_shootdown).targetedandbroadcastare the existingSTATS_TARGETED_SHOOTDOWNSandSTATS_BROADCAST_FALLBACK.ipisis new: shootdown IPIs sent, ACK-timeout resends included. Divided by the other two, it gives the mean fanout of a dispatch.send_ipisinstead of its own identical loop, so resends are counted.pt_lock(mm::page_table).acquired: everylock_ptand successfultry_lock_pt.contended: alock_ptthat found the lock held. It is counted before the lock spins.busy: atry_lock_ptthat returnedNone, which is the #PF Busy path.wait_tscandwait_tsc_max: the spin time of contended acquisitions.hold_tscandhold_tsc_max: acquisition to guard drop. The drop body runs before the inner guard is released.saturating_subkeeps a backward TSC step from poisoning the maximum.SchedstatEventCountersTest(runtime,NeedsCpus(2)). It sends a reschedule IPI and waits for the target's handled count. It issues a CR3-0 shootdown and checks the broadcast and IPI counts. It takesPT_LOCKand checks the acquisition and hold counts.scripts/ci/strict_scope.txt, with its own comment rather than under D1.page_table.rscovers busy, contended, wait and hold.pt_lock_testsare serialized by a test-only lock, because the latter asserts the lock is free at start and end.mmcount goes from 54 to 55, and the pinned RuntimeTest total from 74 to 75.Not in this PR: E2–E4 (diagnostic runs), and any repair. The
PT_LOCKand shootdown paths are not otherwise changed.Kernel safety and invariants
/proc/schedstatstays world-readable and exposes only aggregate counts, as before.unsafe/ MMIO / page-table / usercopy justification: oneunsafefor_rdtscinpage_table.rs, which only reads the time-stamp counter. No new MMIO; the send side deliberately avoids a LAPIC read.lock_ptnow triestry_lockonce beforelock. This is the same acquisition, with one extra uncontended CAS, and no ordering change. ThePT_LOCK_OWNER_CPUpublication is unchanged and still comes first.PT_LOCK_SINCE_TSCis written and read only by the holder.current_cpu()once instead of calling it again.NoSpaceas the existing lines do.TlbShootdownStatsgains fields; its only reader takes named fields.Validation evidence
Public index:
.validation/c3-e1/README.md. Receipts are archived privately in Zero-kernel/Nilix-docs-private#12.Documentation follow-up (2026-11-13): clarified independent IPI sampling in the counter and procfs doc comments and the public validation index.
rustfmt(nightly-2025-12-08) passed for both changed Rust files; byte comparisons confirm that all Rust changes are doc comments and preserve CRLF. No new runtime result is claimed for this clarification.Local (Fedora, nightly-2025-12-08):
Hosted negative controls (local edits, never committed): removing the
contendedincrement or thehold_tscaccumulation failsbusy_contention_wait_and_hold_are_counted.Dev host, QEMU 8.2 (TCG),
e66288b:schedstat_event_countersnot_applicableat 1 vCPU,passat SMP-4f16eb54: 45/29)schedstat_event_counters:CPU 1 IPI counters did not advance: sent 3->4, handled 0->0syscall_test's/proc/schedstatcheck (2 KiB read) passesNILIX_SCHEDSTATPaired ring3-mm runs, side by side on an otherwise idle host:
2e091912e091915d201b3/2e09191The pairs show no slowdown from E1. Ring3-mm at 16 vCPUs is marginal against its 900-second default on this host for every source tried, whenever a second 16-vCPU guest runs beside it. CI's
final-owner-16uses a 2700-second timeout. One run per side does not establish a regression on main.None of these is a strict pass.
The
threadsample above was taken at round 1 and is a format check, not a measurement. It already shows broadcast fallbacks outnumbering targeted dispatches (40 to 26), about 10 IPIs per dispatch, and aPT_LOCKhold of up to 2.1×10⁸ TSC cycles. E2–E4 will measure these properly.Compatibility, performance, and rollout
syscall_testparser and the stress runner ignore lines they do not know.syscall_test's 2048-byte single read, but E1 uses about a fifth of the remaining headroom. No gate runssyscall_testabove 16 vCPUs.PT_LOCKacquisition adds twordtscand three Relaxed atomics. A contended one adds two morerdtsc.rdtscis a helper call. That is small next to the IPI and flush costs C3 is measuring, but it is not free.Checklist
unsafeblocks have localSAFETYreasoning and a minimized unsafe scope. (_rdtsc)generate_schedstatdoc comment)