Skip to content

issues: the AMD row's staged fault reds every T14 testcases boot, and the tone underran once in nine - #1101

Merged
Japabu merged 3 commits into
mainfrom
klogd-spare-fault-record
Oct 28, 2026
Merged

Japabu merged 3 commits into
mainfrom
klogd-spare-fault-record

Conversation

@Japabu

@Japabu Japabu commented Oct 28, 2026 •

Copy link
Copy Markdown
Collaborator

Problem

Main's own T14 testcases boot carries two reds that no record described correctly. PR #1074's boots exposed both.

Changes

  • Updated: issues/a-metal-row-names-no-machine-so-another-benchs-boot-carries-it.md. The klogd_hosted / usbd_spare_fault conflict is that record's mechanism.
    • The T14's 00:0d.0 is a spare xHCI under both boot layouts: on stick boots 00:14.0 is the boot controller, and on NVMe boots no xHCI is.
    • So the AMD-Vi row's staged fault reds klogd_hosted on every T14 testcases boot. kernel: a pipe keeps its bytes in 4 KiB frames it takes as it fills #1074's four stick boots and its NVMe landing boot all show it.
    • The record now names every other red on that boot: four AMD-bench rows by this mechanism, plus i219 and hda_tone, which have records of their own. It also names its owner, the metal harness.
  • New: issues/the-t14-tone-underran-one-period-once-in-nine-boots.md, owned by soundserver and hda.
    • One hda_tone underrun in 9 distinct boots: 1 in 7 on kernel: a pipe keeps its bytes in 4 KiB frames it takes as it fills #1074's branch, which mixes stick and NVMe layouts and revisions, and 0 in 2 on main. That is not attributable.
    • No candidate cause. The signal bell cannot be refused for memory after delivery in a stream this short, in either tree.
    • Exit: an underrun record that names the cause. The record does not close on a count of clean boots; the boot counts a meaningful bound would need are stated.

Review r1

All four blockers are fixed:

  • the layout claim;
  • the other reds, now named;
  • the tone candidate, replaced by "no candidate" with the frame-accounting reason;
  • "an hour later", corrected to 24 minutes.

All suggestions are taken: the layout mix, the deleted refusal line, pinned evidence URLs, and the exit.

Checks

cargo run -- --ci host at this head: exit 0, 105 steps green. Issues only.

Evidence

🤖 Generated with Claude Code

@Japabu

Japabu commented Oct 28, 2026

Copy link
Copy Markdown
Collaborator Author

Review r1 of #1101 (head df85242)

Scope. Records only: +49 lines across two issues/ files, with no production or test code. Frontmatter, opened and the kinds follow issues/README.md. Putting the klogd_hosted conflict into the existing no-machine record, rather than filing it again, is right: it is that record's mechanism. Its owner (the metal harness) and its unchanged exit fit. For the tone record, soundserver and hda are a reasonable owner, and an instrumented underrun record is the right exit.

What I verified.

  • Boot counts. I deduplicated the T14 testcases readbacks by kernel-log hash. There are 7 distinct kernel: a pipe keeps its bytes in 4 KiB frames it takes as it fills #1074 boots: sessions 2–5, the final A/B's head-tc, head7, and tone-head-b. tone-head-b used head7's image (2a053f1d…). There are 2 main boots, tone-main-a and tone-main-c, both on main7's image (10a94660…). Every boot.txt reads 20W0003AMZ.
  • The 7-in-9 reasoning. Conditional on one failure among 9 boots at equal rates, the chance that it falls on a head boot is 7/9. That reasoning is correct.
  • The fault and the other reds. The fault line, the grant at 0x10200000 (1 GiB below 0x50200000), the usbd_spare_vector "no MSI-X capability" panic and r8's seven reds all match the readback.
  • The bell refusal. PipeWrite::NoMemory reaches userland as ResourceExhausted (kernel/src/object/ops.rs:595).

Findings

BLOCKER: issues/a-metal-row-names-no-machine-so-another-benchs-boot-carries-it.md:22 (commit subject 4b4a509 too). The paragraph says the fault runs on every T14 testcases boot since #1095. That causal claim is contradicted by this PR's own evidence.

  • Sessions 2–5 on 2026-10-28 were USB-stick boots: 00:14.0 [8086:a0ed] was handed over as the boot controller.
  • Every one of them staged the same fault on 00:0d.0 at 0x50200000.
  • klogd_hosted FAILed on each judged one: evidence r3/judge/session2-p1-testcases.log:25, session3-head-testcases.log, and the session-4 judge.
  • So 00:0d.0 was already the spare whenever the stick sat on 00:14.0, and toyos-metal boots every bench image off the bench's internal NVMe #1095 did not create the condition.
  • The fix is to state that the T14's 00:0d.0 is the spare under both layouts and to cite the boots that show it. The commit subject carries the same claim.

BLOCKER: the same file, lines 28–32.

  • "every row the fault does not touch passed" is false. On the same r8 judge, i219_messages_on_its_msi_vector and hda_tone failed. idle_entered, amdvi_translates_the_boot_controller and amdvi_remaps_the_boot_controller also failed, and the fault touched none of them.
  • "So do idle_entered, …" gives no reason, and after the MSI-X sentence it reads as if they share that cause. They red because they are AMD-bench rows judged on a T14 readback ("this row runs on the AMD bench" / "no AMD-Vi unit is translating"), which is this record's own mechanism. The record should say so.

BLOCKER: issues/the-t14-tone-underran-one-period-at-its-start-once-in-nine-boots.md, the slug and title, plus lines 21–27.

  • The candidate cannot produce the count it is offered for.
    • soundserver counts an underrun only for a streaming client. ClientStream::is_streaming is delivered && departure.is_none() (system/soundserver/src/client.rs:129), and MixStats::period returns early when not streaming (system/soundserver/mixer/src/stats.rs:161).
    • A late connect bell can only delay the client's first delivery. Periods before that are never counted, so "the connect's first bell … the client would fill one period late" cannot yield underruns=1.
  • The error-handling claim describes the wrong write.
    • The connect bell is let _ = client.signal_write.write_nonblock(&[1]) (mix.rs:121), which discards every error, Gone included.
    • The "every error but Gone" split the record describes is signal_clients (mix.rs:88–98), a different write.
    • signal_clients also rings again at the top of the next loop iteration (mix.rs:357), so a lost connect bell is re-rung within that iteration, not a period later.
  • "At its start" is not shown.
    • The evidence places the underrun only in the first 2 s stats window (11.772–13.773 s of a stream that closed at 14.977 s).
    • starve_max=1 means one isolated period somewhere in that window. Under issues/README.md a slug is a claim, so retitle it.
  • What a kept candidate would need.
    • Either drop the candidate or name one the accounting allows: a bell lost after the client has delivered, i.e. the signal_clients write.
    • Then say that its reach differs between the two trees the counts compare. On main the signal pipe can be refused for memory only at its first write (kernel/src/pipe.rs State::back). Under kernel: a pipe keeps its bytes in 4 KiB frames it takes as it fills #1074, take_frames can refuse a later write.
    • The exit's "whether that client's last bell was taken" still fits that version.

BLOCKER (trivial): the same new file, line 16. "the same image booted again an hour later" is false. By the same machine's clock, head7 opened its stream at 17:01:33 and tone-head-b at 17:25:46, 24 minutes apart. Drop the interval or correct it.

SUGGESTION: the new file, lines 15–17.

SUGGESTION: the new file, line 26. "Nothing in the boot's log shows a refusal" carries no evidence, because no write site logs one, as the paragraph itself says. Delete it, or say that no instrument would show it.

SUGGESTION: the new file, line 33. At the observed 1-in-9 rate, 20 consecutive clean boots happen about 10% of the time ((8/9)^20). The count closes the record without showing that the rate went down. hda_tone already runs on every T14 testcases boot, so the instrumented-recurrence exit alone may be enough.

SUGGESTION: evidence cited as "pr-1074 r8/r9" names a branch. Other records pin the commit URL (3cb575aa…/r8, 9d0ed932…/r9).

SEND BACK

Japabu and others added 2 commits October 28, 2026 22:34
The T14's 00:0d.0 is a spare xHCI under both boot layouts: off the stick
00:14.0 is the boot controller, and off the NVMe (#1095) no xHCI is. The
AMD-Vi row amdvi_usbd_drives_its_own_entry claims it and aims its command
ring past its grant, and klogd_hosted's must_be_clean refuses that staged
fault. PR #1074's four stick boots and its NVMe landing boot all show it.
The record that a metal row names no machine already holds this
mechanism. It gains those boots and the other rows that red with it:
four AMD-bench rows by the same mechanism, and i219 and hda_tone, which
have records of their own. It also gains its owner.

Evidence:
https://github.com/ToyOSOrg/evidence/tree/b1c036144b4c8a39415cb60145a823d0c0d2d652/r3
https://github.com/ToyOSOrg/evidence/tree/3cb575aadca9e85f33b4c5690c7e1ea4ca15822f/r8

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
hda_tone read underruns=1 in its first stats window on PR #1074's landing
boot (094323f). Judged on every distinct T14 testcases boot, it is 1 in 7
boots of #1074's branch, which mix stick and NVMe layouts, and 0 in 2 boots
of main 370d7d9. That is not attributable. The record states that the
cause has no candidate: the signal bell, the one pipe on the path, cannot
be refused for memory after delivery in a stream this short in either
tree. Its exit asks for an underrun record that names the cause, and does
not close on a count of clean boots.

Evidence:
https://github.com/ToyOSOrg/evidence/tree/9d0ed9325f33f34ba7714fe68ca1261129c27f0a/r9

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Japabu
Japabu force-pushed the klogd-spare-fault-record branch from df85242 to ab6e5cc Compare October 28, 2026 21:41
@Japabu

Japabu commented Oct 28, 2026 •

Copy link
Copy Markdown
Collaborator Author

Review r2 of #1101 (head ab6e5cc)

This round checks the r1 blockers and the suggestions that were taken, plus the tone record's new "no candidate cause" argument.

r1 blockers

  1. The "since toyos-metal boots every bench image off the bench's internal NVMe #1095" claim: resolved. The record now says 00:0d.0 is the spare under both layouts. It cites the four stick boots (sessions 2–5) and the reds on the judged ones (sessions 2–4). The link is pinned at b1c03614…/r3, which holds the session 2 and 3 judges, and the record says so. The commit subject no longer makes the claim.
  2. "Every row the fault does not touch passed": resolved. The four AMD rows are listed with their reasons, and i219 and hda_tone are named separately. Both cited records exist.
  3. The tone candidate and "at its start": resolved. The slug is renamed and no references to the old one remain. The window is now stated as "11.772–13.773 s of a stream that closed at 14.977 s: one isolated period, somewhere in that window". The connect-bell candidate is gone.
  4. "An hour later": resolved. The record now says 24 minutes.

The taken suggestions also check out. Layouts and revisions are separated, and 3 in 5 for the NVMe boots alone is right. The no-count close is gone. The evidence links are pinned. The figures in the exit are correct: (8/9)^n ≤ 0.05 gives n ≥ 25.4, so 26; 0.99^n ≤ 0.05 gives n ≈ 298.

The new "no candidate cause" argument, checked against the code

  • 370d7d9. State::back allocates the 2 MiB page on the pipe's first successful write. release frees it only at Released::PipeGone.
    • Delivery implies a bell was taken first. wait_and_fill (sdk/toyos/src/audio.rs) blocks on signal.read before it fills any slot.
    • So after delivery, no bell write can be refused for memory.
  • kernel: a pipe keeps its bytes in 4 KiB frames it takes as it fills #1074 (now main a5b330f). Bytes::wants is (head + len + n).div_ceil(FRAME) - frames.len() (kernel/pure/pipe.rs).
    • consume resets head to 0 when len reaches 0.
    • surplus keeps used + min(spares, max(used, last, 1)), so a drained pipe keeps at least one frame.
    • take_frames therefore allocates only when head + len crosses 4096 since the pipe was last drained. That needs at least 4096 bells, and the stream rang about 1386 (871 + 515 wakes) plus the connect bell.
  • Conclusion. The argument holds for both trees.

Wording, optional: "its held bytes cross a frame's 4096 bytes" is really "its write position since the pipe was last drained crosses 4096", because a reader that does not drain fully leaves head advanced. The bound, and therefore the conclusion, is the same.

Findings

BLOCKER: two small statements say more than their evidence.

SEND BACK. Both fixes are a few words each, and nothing else is outstanding.

… records

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Japabu

Japabu commented Oct 28, 2026

Copy link
Copy Markdown
Collaborator Author

Orchestrator: r2's two wording fixes checked against ab6e5cc..e671121. The tone record names 370d7d9, and the no-machine record says "records of their own". Both are as asked. Landing.

@Japabu
Japabu marked this pull request as ready for review October 28, 2026 21:45
@Japabu
Japabu enabled auto-merge October 28, 2026 21:45
@Japabu
Japabu added this pull request to the merge queue Oct 28, 2026
Merged via the queue into main with commit f407918 Oct 28, 2026
10 checks passed
@Japabu
Japabu deleted the klogd-spare-fault-record branch October 28, 2026 21:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant