The panel paints the cells that moved, and says what it cost - #444
Draft
Japabu wants to merge 5 commits into
Draft
The panel paints the cells that moved, and says what it cost#444Japabu wants to merge 5 commits into
Japabu wants to merge 5 commits into
Conversation
The on-screen console is the one live window a person has into a machine that stopped, and nothing counted what it costs to keep. This adds the count: how often the panel painted, how many pixels it put on the glass, how long it spent inside the painter and the slowest single paint of the boot. The reading is taken in ticks of the cycle counter and converted once, at the census: every boot's first paints happen before `clock::init`, so a panel instrumented in nanoseconds would report the paints it most needs to report as zero. Two channels carry the line, because the panel outlives one of them. A boot that hands the machine back writes it as an ordinary record beside `irq:` and `nvme:`, and `logd` files it; a boot a bound ended has no `logd` left, so the same line goes into the black-box page the next loader pass prints back. It is written into the page's head and not its tail, which is where the page is cut when the ring does not fit. `tests/metal-profile.toml` prices the slowest single paint per boot, under the one ceiling mechanism the suite already has. The ceiling is the widest true bound there is before the machine has answered: two seconds, which is `panic_console`'s own CHECKPOINT budget — past it a process claiming the framebuffer stops waiting for the painter and says so. The other three numbers are printed beside the boot as evidence and are not a gate. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GGQ2H2aCwd1jfiNmjsiUvz
Every paint cleared the whole scanout and drew the text back over it: one framebuffer written per record the panel was asked to show, whatever had changed. On the T14 that is 2,073,600 stores of four bytes each, and the first paints of every boot make them through the mapping the loader left, where nothing combines them. So the panel now keeps the grid it painted. A paint composes each row's cells — its display row's text, ground past the end of it, the footer on the bottom row of a paged report — and writes only the cells whose character or colour moved, ground and ink together, so nothing has to be cleared first. A record added to a screen that is not yet full costs the one row it adds; a scroll costs the cells whose text moved and not the blank right-hand end of any row. The fill is left for the paints that need it: the first of a boot, a change of colour or geometry, and every paint after something else may have reached the glass — a userland claimant, a new framebuffer descriptor, a fatal report taking the screen back, or the report's own probes finding it drawn over. What the panel shows does not change: same font, same grid, same text, same colours. A cell holds the character the font draws and not the byte that asked for it, so what the grid says is on the glass is what the glyph lookup would have put there. `screen_late_panic` gets the assertion the grid owes: on a machine halted for good, with its console whole, every row on the panel is text the log carries — which is what a cell the paint failed to write would not be, past the end of a line that replaced a longer one. The pager cycling a report across that screen is where a screen of long lines becomes one of short lines. `put_pixel` and its per-pixel clamp go: every write to the scanout is now a row of a cell through one bounds-proved pointer, or the fill. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GGQ2H2aCwd1jfiNmjsiUvz
`src/sourcegate.rs` counts them per file so that an added one reds beside a permitted one; the grid the painter diffs against is the third. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014iqcj4jDKpaiDX8B7CMvmK
Run 32 measured the panel's slowest paint at 442-449 ms on every arm of every boot, before the grid and after it: one whole-screen fill of 1920x1080 through the uncacheable 2 MiB pages the loader hands the scanout over in, two million stores nothing combines. The other nine paints of that boot cost about 2 ms each through write-combining, which is the speed this hardware has. The fix kept the first paint as a fill by design, so the fill is what has to stop being uncacheable. So the memory type is decided before the panel paints rather than after `mm::init`. `control_regs::init_cr0` and `pat::init` move to the top of `kernel_main`: two register writes and no memory, before any channel exists, because the panel's own first record is its first paint. Neither logs, so the boot's first record is still the panel's own and every reader of the record order is unchanged; the `PAT:` line stays where the boot's other facts are and reads the live register. `mm::paging::boot_map_write_combining` then switches the scanout's 2 MiB leaves in the tables this CPU is running under — the loader's — to the write-combining PAT entry, both of the windows the loader opened onto it, because one physical page may not hold two memory types. It refuses by name where the walk finds no 2 MiB leaf, and the panel's armed record says which mapping it got. `tests/metal-profile.toml` holds `panel_max_us` to one frame of the panel this bench has: the T14 takes a whole 1080p redraw at 60 Hz, so 16,667 us is what a paint of every cell may cost and still keep pace with the display. The two seconds those rows carried was a bound nothing could ever red on. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014iqcj4jDKpaiDX8B7CMvmK
The two-lines-a-second crawl on the T14 was never the kernel's panel: run 32 measured ten paints on a boot that sat wedged for two minutes, the same ten a 2.7 s boot makes. It is the loader's pass after the reset, which prints the black box's ring tail line by line through the firmware's text console — 187 lines on run 32's `deadlinewedge`, every one of them stamped `[1.xxx cpu0]`, which is why the timings on the glass stood still. The firmware scrolls a 1080p screen by moving the whole frame, about three lines a second, and the wedge boots came back 104 s and 114 s after their own bounds against 37-49 s for a boot with no record to print. So the screen gets the head and the file gets the tail. A line that opens a log record — `toyos_blackbox::RECORD_OPENS_WITH`, the same declaration the kernel cuts the page on — is tail; the reason the boot ended, what was dropped, a fault's registers are head, and the head carries the count of what it does not carry. `loader.log` is unchanged: every line still reaches it, which is where every reader of these lines has always looked. `boot_deadline_ends_a_wedge`'s QEMU half asserted the tail off the console, because in a guest both channels are one wire. It now asserts the count there, and `deadline_wedge_chain` — the metal judge, which reads `loader.log` off the stick — is where the records themselves are still held to `WEDGE_STAGED`. Filed while reading those readbacks: issues/diagnostics/loader-log-stops-at-sixteen-kilobytes.md. Every wedge boot's `loader.log` ends mid-tail near 16 KiB with none of the lines the loader writes after it, and the one statement of why goes to the console alone. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014iqcj4jDKpaiDX8B7CMvmK
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.
Draft. The panel's cost is being measured on the T14 before and after; the
before/after table and the ceilings it sets go here when the machine has
answered.
20c87afcgives the panel a census — paints, pixels, time in the painter,slowest single paint — on both channels a boot can end on, and prices the
slowest paint per boot in
tests/metal-profile.toml.4ab5a65fkeeps the grid the panel painted in RAM and writes only the cellsthat moved, instead of clearing the whole scanout per record.
🤖 Generated with Claude Code