Repository navigation
The interrupt census keeps one word per delivery, so it always adds up - #734
Conversation
Each delivery was two `add`s to the CPU's own block, the machine's total first and the source second, and `irq_census::read` loaded the slots one at a time from whatever CPU prints the census. A reader landing between a CPU's two `add`s saw the total move and the source not, and printed a census whose total was one past its sources. The T14 recorded exactly that: in #728's full Drive-mode suite at 78c21c5, cpu7's process-exit census read cpu1 mid-kick-storm (22906 kicks) as total=24211 against sources summing to 24210, and `irq_census_conservation` named it "a source is not being counted". No source was uncounted: every writer, `irq_took!`, the Ring 0 timer stub and AArch64's `irq_took`, always did both adds. #728's 20 ms wake of every CPU raises the kick rate on the APs around a process exit and so the odds of the read landing in the window; the window is main's. The total is now the sum of the sources, read off the same snapshot, so there is no second word to disagree with and nothing for a torn read to tear. Every delivery costs one `add` instead of two. `taken_here` and `taken_by` sum every source but the NMI; `irq: cpuN` drops its `total=` field and the host's `Census::total` sums the sources. The judge's conservation check, which can no longer fail, goes; its monotonic check now asks every source rather than the total. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WcU2Dsw6mDYtwYfzVHPzM8
|
T14 result at |
|
Review of Net: +78 −111 across 8 files. Production (kernel) is +49 −64, tests +26 −44, and Diagnosis holds. I checked it against the recorded readback, Deleting the total and the conservation check loses nothing a reader needed. Each writer is now one Merge. Measurements. I read the orchestrator's logs in
The negative control is the recorded T14 red, and the independent oracle is the real hardware. For the claim "the census cannot tear between total and sources", no test is possible: there is no total left to tear. BLOCKERNone. NOTE
REMOVENone. LAND AFTER NAMED CHANGES |
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WcU2Dsw6mDYtwYfzVHPzM8
…t cannot fail Review round 1 of #734 found both off this branch's fence: the irq_census judge's per-source monotonic and tlb issuer checks compare lines from two exits that the stamp-merged capture can list in the other order from their reads, and the spurious and unclaimed selftests read their total before the probe that itself raises it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WcU2Dsw6mDYtwYfzVHPzM8
…os-acpi1 tests/toyos.rs conflicted in `counters_on_metal`, in its doc and in its SMI summary line. Both sides are kept: #728's refusal of any line stamped in the idle second, and this branch's ACPI mode with the SMI count flat from `idle0` to `spin`, which replaced main's legacy-mode rise. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WcU2Dsw6mDYtwYfzVHPzM8
The interrupt census keeps one word per delivery: a CPU's total is the sum of its sources, so a census read from another CPU always adds up.
The defect
irq_census_conservationwent red once on the T14, in #728's full Drive-mode suite at78c21c575:cpu1 counted 24211 interrupt(s) and attributed 24210 to sources. The readback'stestcases/kernel.log, line 12102, shows when: cpu7 printed the census attest_rs_counters_metal's exit, and cpu1 was in a kick storm at the time (kick=22906on cpu1, against 1683–5188 on the other APs).Every delivery was two
adds to the CPU's own block, the total first and then the source:irq_took!, the Ring 0 timer stub's inline pair, and AArch64'sirq_took.irq_census::readloaded the slots one at a time withRelaxedloads, from whichever CPU prints. A reader that loads cpu1's total after cpu1's firstaddand thekickslot before its second sees a total one past the sources. Those are the numbers the T14 printed. No source was uncounted: every writer always did both adds, so the judge's message, "a source is not being counted", named the wrong thing. #728's 20 ms wake of every CPU before its idle second does not cause this. It raises the kick rate on the APs around a process exit, so a read is more likely to land in the window. The window was already onmain.The fix, at its owner
kernel/src/irq_census.rs:TOTALandSLOTSare gone, and the block is oneu64perSource.deliveries_total,taken_byandtaken_heresum the same snapshot (taken_*leave out the NMI, as before).irq: cpuNno longer printstotal=.irq_took!(x86-64), the Ring 0 timer stub and AArch64'sirq_tookeach do oneadd. That is one fewer read-modify-write on every interrupt.irq_counts_herereturns the CPU's whole block, onegs:load per slot on x86-64. It is still lock-free and division-free for the NMI path.common::irqcensus::Censusloses itstotalfield and gainstotal(), the sum. The parser now refuses any line whose fields are not exactlySOURCES.tests/toyos.rs,irq_census): the conservation check is deleted. It compared a derived value with itself and can no longer fail. The monotonic check now checks every source, not only the total. That is stronger: with a derived total, one counter going backwards could be hidden by another going up.issues/every-interrupt-lands-on-the-boot-cpu.md: the instrument paragraph now describes the line and the gate as they stand.Why there is no new test
The brief asked for a test at the cheapest tier that reds first, and a loom model if the defect is an ordering race. It is an ordering race, but a race between two words, and this change deletes one of them. With no total stored apart from the sources, no sequence of writes and reads can make the two disagree. That is the type tier: nothing is left for a loom model to explore. A loom model of the old two-word layout would only test a design the tree no longer has.
The defect's red is the recorded T14 failure above. It is a recorded real failure on the base, and it is the independent oracle. The negative control is the base itself: reverting the whole change gives
origin/mainat4d46c8e55, the layout that produced that red. One green T14 run cannot prove a once-in-a-suite race gone, so the T14 run below shows only that the row and its judge still hold on the machine with the new line format.Filed, off this branch's fence
Review round 1 found two defects next to this change and outside it. Both are filed, not fixed:
issues/the-irq-census-judge-reds-on-two-exits-stamped-in-the-other-order.md: the judge's per-source monotonic check and itstlb: shootdowns=checks compare lines from two process exits. The capture is merged by stamp, and a line is stamped after its counters are read, so two exits on two CPUs can be listed in the other order from their reads.issues/the-spurious-and-unclaimed-selftests-took-interrupts-after-check-cannot-fail.md: both selftests readdeliveries_totalbefore the probe, and the probe's own delivery raises it, so "took interrupts after it" holds oncedeliveredholds.Gates
Logs are in the orchestrator's job scratchpad, under
orch/. The code gates ran at27fc30994, the change's commit, with the worktree clean. After them,origin/main(0613f93f7: #729, #732) was merged cleanly and the two issue files were committed. The merge touched no file this change touches excepttests/toyos.rs, where it auto-merged hunks outsideirq_census.cargo test --lib sourcegateran at the pushed head.cargo run -- --build-only27fc30994orch/irqcensus/build.logcargo run -- --build-only --arch aarch6427fc30994orch/irqcensus/build-a64.logcargo run -- --ci host(Host: 75 step(s), all green)27fc30994orch/irqcensus/host.logcargo test(whole guest suite:28 passed, 28 total; the census summary parsed 17 guests' lines in the new format)27fc30994orch/irqcensus/guest.logcargo test --test toyos-build -- --metal --metal-readback <scratch>/metal irq_census_conservation(staging only, exit 2 by design:Verdict::Staged)27fc30994orch/irqcensus/metal-stage.logtestcasesimage, judgeirq_census([metal] 1 passed, 0 failed, 1 boot(s); none of its 72irq: cpulines carriestotal=)27fc30994orch/irqcensus/metal/judge-irq_census.logcargo test --lib sourcegate(10 passed)orch/irqcensus-r2/sourcegate.logWhat I am unsure of
irq: cpuNlines elsewhere in the tree still wantstotal=printed. Old quotations inissues/keep the old format because they are recordings. Every parser in the tree (tests/common/irqcensus.rs, and thetests/checks.rsfixture) now reads the new one.Net against
main: 10 files, the change's 8 at +78 −111 and the two filed issues.🤖 Generated with Claude Code
https://claude.ai/code/session_01WcU2Dsw6mDYtwYfzVHPzM8