Repository navigation
Conversation
Review of #1270 at 14bc8a0 (own commits de14b11, 14bc8a0)ArchitectureThe ownership is right and matches the orchestrator's decisions recorded in #1265:
Promising the whole region at creation keeps refusal at The manual needs no edit. Net size:
No caller holds the allocator's lock, which is taken only inside Promise accounting is correct at creation, at a region's end and for a partly touched region. At the end, drawn frames go back through FindingsBLOCKER 1: a toucher that loses the race draws against a promise that is not its page's.
BLOCKER 2: the batched draw of a run's holes is recorded only as conditional on a metal reading. My recommendation on the author's risk: do not batch in this PR; record the batch as owed to the object fault-around.
SUGGESTION 1: SUGGESTION 2: EvidenceI ran these checks in a detached worktree at 14bc8a0. Every clippy run used the adopted lints and
The author's
SEND BACK |
… lock Two touches of a hole both drew before racing to install, so the loser drew against a promise its page did not hold, and the machine's promised count fell short of the promises outstanding until it gave the frame back. Each region now has a first-touch lock (`sync::Lock`): a touch takes an installed frame with one Acquire load, and a hole is drawn by the touch that, holding the lock, still finds it a hole, and installed with a Release store. Every draw is the page's own promise's; `discard` keeps #1250's caller and Safety text. The lock order is space, region, allocator, and nothing else takes the region's lock. The loom model asserts one draw a page, and `slot-install-relaxed` still reds the publication. The batched draw of an object run's holes is recorded without condition, owed by the object fault-around (#1259): whichever of #1259 and this lands second draws a run's holes in one hold. The free batch is a superframe's worth by name, and the promise doc is rewrapped. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review of #1270, round 2, at 71b2f15 (code changed since 14bc8a0)ArchitectureRound 2 builds the design the orchestrator decided for blocker 1:
Net size:
Round-1 findingsBlocker 1: resolved. Each case below is checked at this head.
Blocker 2: resolved as the orchestrator decided.
Suggestions 1 and 2: both taken ( Loom model
FindingsNo blockers. SUGGESTION:
Cutting the header to its first sentence plus the loom line would remove the repetition. EvidenceMy runs were in a detached worktree at 71b2f15 with a clean tree. Every clippy run used the adopted lints and
VerdictNo code blocker remains. Round 1's condition still holds: run 43098612390, or a replacement at this head, must finish green before landing. It had not started at the time of this review. LAND |
71b2f15 to
0c76f7a
Compare
… lock Two touches of a hole both drew before racing to install, so the loser drew against a promise its page did not hold, and the machine's promised count fell short of the promises outstanding until it gave the frame back. Each region now has a first-touch lock (`sync::Lock`): a touch takes an installed frame with one Acquire load, and a hole is drawn by the touch that, holding the lock, still finds it a hole, and installed with a Release store. Every draw is the page's own promise's; `discard` keeps #1250's caller and Safety text. The lock order is space, region, allocator, and nothing else takes the region's lock. The loom model asserts one draw a page, and `slot-install-relaxed` still reds the publication. The batched draw of an object run's holes is recorded without condition, owed by the object fault-around (#1259): whichever of #1259 and this lands second draws a run's holes in one hold. The free batch is a superframe's worth by name, and the promise doc is rewrapped. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review of #1270, round 3, at 4c68367 (base
|
| Check | Result |
|---|---|
cargo test --manifest-path kernel/loom/Cargo.toml --test shm_slot |
exit 0, 4 passed |
The same with --features slot-install-relaxed |
exit 101. two_touches_draw_once_and_are_handed_one_frame and a_frame_is_handed_over_with_what_its_drawer_wrote fail on loom's causality violation. two_runs_draw_each_page_once and a_touch_after_the_first_draws_nothing pass. |
cargo test -p kernel --lib --features sched-check |
exit 0, 465 passed |
Kernel library clippy, --lib --tests: sched-check, and sched-check,protocol-port with the kernel controls |
exit 0 each |
| x86-64 kernel clippy: default, boot+test actuators, boot actuators, instruments, both heap-band shapes | exit 0 each |
| aarch64 kernel clippy: default, boot+test actuators, boot actuators, instruments | exit 0 each |
kernel-loom clippy --all-targets, with and without the control |
exit 0 each |
cargo run -- --ci host models |
exit 0. 84 steps, all green. Control slot-install-relaxed: 2 verdicts reached. |
- Author's evidence:
checks-4.logat 4c68367, with a clean tree, agrees with my runs. It ran no--ci host modelsat this head, and the body says so. My run above supplies it. - Guest rows: no result exists yet for 4c68367.
- Run 43116588754 is queued at this head.
- 43113647566 passed at 0c76f7a. That covers rounds 1 and 2's code, not the batch.
- Metal: not a landing condition while the benches are down. The owed A/B is recorded in the first-touch record, with its rows and what main must show.
SEND BACK
…e install zips holes with draws The frame allocator's record named `pmm::alloc_promised_many`, which this PR deletes, as how a region is drawn; it now says a region's untouched pages are drawn a run at a time, at first touch. `slot::frames` installs by zipping the holes with what was drawn, with no check that cannot fail, and the loom header says what the model asserts and names both tests its control reds. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Orchestrator verification of round 3's fixes at 917b8ef: the record clause no longer names the deleted |
… lock Two touches of a hole both drew before racing to install, so the loser drew against a promise its page did not hold, and the machine's promised count fell short of the promises outstanding until it gave the frame back. Each region now has a first-touch lock (`sync::Lock`): a touch takes an installed frame with one Acquire load, and a hole is drawn by the touch that, holding the lock, still finds it a hole, and installed with a Release store. Every draw is the page's own promise's; `discard` keeps #1250's caller and Safety text. The lock order is space, region, allocator, and nothing else takes the region's lock. The loom model asserts one draw a page, and `slot-install-relaxed` still reds the publication. The batched draw of an object run's holes is recorded without condition, owed by the object fault-around (#1259): whichever of #1259 and this lands second draws a run's holes in one hold. The free batch is a superframe's worth by name, and the promise doc is rewrapped. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
917b8ef to
ea10107
Compare
…e install zips holes with draws The frame allocator's record named `pmm::alloc_promised_many`, which this PR deletes, as how a region is drawn; it now says a region's untouched pages are drawn a run at a time, at first touch. `slot::frames` installs by zipping the holes with what was drawn, with no check that cannot fail, and the loom header says what the model asserts and names both tests its control reds. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… lock Two touches of a hole both drew before racing to install, so the loser drew against a promise its page did not hold, and the machine's promised count fell short of the promises outstanding until it gave the frame back. Each region now has a first-touch lock (`sync::Lock`): a touch takes an installed frame with one Acquire load, and a hole is drawn by the touch that, holding the lock, still finds it a hole, and installed with a Release store. Every draw is the page's own promise's; `discard` keeps #1250's caller and Safety text. The lock order is space, region, allocator, and nothing else takes the region's lock. The loom model asserts one draw a page, and `slot-install-relaxed` still reds the publication. The batched draw of an object run's holes is recorded without condition, owed by the object fault-around (#1259): whichever of #1259 and this lands second draws a run's holes in one hold. The free batch is a superframe's worth by name, and the promise doc is rewrapped. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ea10107 to
4765676
Compare
…e install zips holes with draws The frame allocator's record named `pmm::alloc_promised_many`, which this PR deletes, as how a region is drawn; it now says a region's untouched pages are drawn a run at a time, at first touch. `slot::frames` installs by zipping the holes with what was drawn, with no check that cannot fail, and the loom header says what the model asserts and names both tests its control reds. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
4765676 to
5a372f4
Compare
… lock Two touches of a hole both drew before racing to install, so the loser drew against a promise its page did not hold, and the machine's promised count fell short of the promises outstanding until it gave the frame back. Each region now has a first-touch lock (`sync::Lock`): a touch takes an installed frame with one Acquire load, and a hole is drawn by the touch that, holding the lock, still finds it a hole, and installed with a Release store. Every draw is the page's own promise's; `discard` keeps #1250's caller and Safety text. The lock order is space, region, allocator, and nothing else takes the region's lock. The loom model asserts one draw a page, and `slot-install-relaxed` still reds the publication. The batched draw of an object run's holes is recorded without condition, owed by the object fault-around (#1259): whichever of #1259 and this lands second draws a run's holes in one hold. The free batch is a superframe's worth by name, and the promise doc is rewrapped. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e install zips holes with draws The frame allocator's record named `pmm::alloc_promised_many`, which this PR deletes, as how a region is drawn; it now says a region's untouched pages are drawn a run at a time, at first touch. `slot::frames` installs by zipping the holes with what was drawn, with no check that cannot fail, and the loom header says what the model asserts and names both tests its control reds. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`SharedMemObject::create` drew and zeroed every frame of a region before it returned, so a region cost its whole size however little of it a process touched: a served directory's 2 MiB window, four of them a build child, was 95 us a window on the T14 and 133 us on the AMD bench with one child at a time, and most of what the all-CPU build's children add in CPU, by the spawn diagnosis. The orchestrator decided (recorded in #1265): promised whole at creation, drawn at first touch, with a device's run and an inbox's rings drawn whole. A region's pages are slots (`shm::slot::Slot`), each a hole until its first touch. `SharedMemObject::page()`, which every consumer of a page's frame goes through (an object range's fault, the kernel's reads and writes, an inbox's words), draws a hole's zeroed frame with `pmm::alloc_promised()` against the promise `create` made, and installs it with one compare-exchange; a toucher that loses the race gives its frame and its promise back (`pmm::discard`) and is handed the winner's. That draw is the one map7b's N4 calls for a MEMORY volume's hole, into its pager's index. `page()` states who may call it: never in interrupt context, never holding the allocator's lock. An inbox's rings are made with `create_whole`, which touches every page at once, since the kernel writes them in interrupt context; the clock page's one page is drawn by the boot's own `page(0)`. A region's end frees what was drawn, 512 at a time, and gives back the promises of the pages never touched. `pmm::alloc_promised_many` and `pmm::free_all` lose their only callers and go. The slot is compiled a second time by `kernel-loom`: `shm_slot` models two touches racing for one page (one frame each is handed, every other draw goes back once, a frame comes with its zeros), and `slot-install-relaxed` is its negative control. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The benches are down, so its A/B is owed rather than run: the window record names the rows, benches and what main must show. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… lock Two touches of a hole both drew before racing to install, so the loser drew against a promise its page did not hold, and the machine's promised count fell short of the promises outstanding until it gave the frame back. Each region now has a first-touch lock (`sync::Lock`): a touch takes an installed frame with one Acquire load, and a hole is drawn by the touch that, holding the lock, still finds it a hole, and installed with a Release store. Every draw is the page's own promise's; `discard` keeps #1250's caller and Safety text. The lock order is space, region, allocator, and nothing else takes the region's lock. The loom model asserts one draw a page, and `slot-install-relaxed` still reds the publication. The batched draw of an object run's holes is recorded without condition, owed by the object fault-around (#1259): whichever of #1259 and this lands second draws a run's holes in one hold. The free batch is a superframe's worth by name, and the promise doc is rewrapped. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…cator's lock Main's populate already fills an object range's whole run (#1245), so a region written whole after it is made, such as a 32 MiB spawn image, drew a frame a page, one hold of the frame allocator's lock each: 8,192 where drawing the region whole took 16. The orchestrator decided to build the batch here rather than wait for #1259. `SharedMemObject::pages()` answers a run of pages at once, at most a fault's run, and `page()` goes through it. For a region, `slot::frames` takes every frame installed with one Acquire load each; if any page it was asked for is a hole it takes the region's first-touch lock, looks again, and has the holes still left drawn by one call, `pmm::alloc_promised_zeroed_into`: one hold of the allocator's lock for the draw, zeroing outside it, and one Release store a page to install. The object arm of `populate` asks for its run this way, and `create_whole` draws an inbox's rings a run at a time. The loom model gains two runs sharing a page: each page draws once, the shared page's one frame is handed to both, and each run draws in one call at most; `slot-install-relaxed` still reds the hand-over models. The first-touch record says it is built and carries what it owes on metal; the window record's two bullets go, the batch being built and the reading moved to the record of the change it measures. The slot's comments are trimmed as review r2 suggested. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e install zips holes with draws The frame allocator's record named `pmm::alloc_promised_many`, which this PR deletes, as how a region is drawn; it now says a region's untouched pages are drawn a run at a time, at first touch. `slot::frames` installs by zipping the holes with what was drawn, with no check that cannot fail, and the loom header says what the model asserts and names both tests its control reds. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
5a372f4 to
e37586c
Compare
Stacked on #1268 (base
pmm-batch, itself on #1250, on main 29c5f2d): this PR's diff is five commits, the code,what it owes on metal, review r1, the batched object run and review r3, head e37586c. It is retargeted to main once those land.
Problem
SharedMemObject::createdrew and zeroed every frame of a region before it returned, so a region cost its whole sizein time and memory however little of it a process touched, where private memory takes a frame at each page's first
touch. On the spawn path that is a build child's four
SHM_CREATEs, by inference from the SDK its directory windows(2 MiB each): 95 us a call on the T14 and 133 us on the AMD bench with one child at a time, 17 and 19 % of a child's
CPU, and most of what the all-CPU build's children add in CPU (#1265's diagnosis).
Behavior
The orchestrator's decision (recorded in #1265,
a-shared-memory-region-draws-and-zeroes-every-frame-when-it-is-made):createmakes a slota page (
shm::slot::Slot), each a hole, and promises them all, so a region is still refused at creation(
ResourceExhausted) and never at a touch.SharedMemObject::pages(), a run of at most afault's 16 pages, or
page(), which asks it for one: an object range's fault (its whole run), the kernel'sreadand
write(a copied range's source among them), an inbox's ring words, the clock page. A touch takes eachinstalled frame with one Acquire load. If any page it asks for is a hole, it takes the region's first-touch lock
(
sync::Lock), looks again, and has the holes still left drawn by one call ofpmm::alloc_promised_zeroed_into:one hold of the frame allocator's lock for the draw, the zeroing outside it, and one Release store a page to
install, all under the region's lock. So a page draws exactly once, against its own promise, and a fault's run
takes one hold of the allocator's lock, not one a page. The lock order is space, region, allocator, and nothing
else takes the region's lock.
pmm::alloc_promised_zeroed_into, the batched form of the promiseddraw
pmm::alloc_promised()that map7b's N4 (A served file is mapped read-only and shared, and a fault on its absent page waits for its pager #1269) calls for a MEMORY volume's hole, into its pager's index underthe pager's lock; both draw through
Frames::alloc_promised. Two stores, since a pager's page is revocable and aregion's never is.
page()is stated there: it may draw, so never in interrupt context and never holding theregion's or the allocator's lock. Audited at this head: the fault path holds the space lock, where private faults already draw; a
copied range's source is read under it too; the clock page's one page is drawn by the boot's own
page(0); aninbox's rings are written in interrupt context, so they are made with
create_whole, which draws every page, arun at a time. A device's run is unchanged (
create_run).PER_SUPER) to a hold of the allocator's lock aftertheir futex waits end, and gives back the promises of the pages never touched.
pmm::alloc_promised_many(from A draw of many promised frames takes the allocator's lock once #1268) andpmm::free_alllose their only callers and go; a fault's run keepsA draw of many promised frames takes the allocator's lock once #1268's batch.
Checks
head), pending:
testcases_members_exit_0andshared_debug_members_exit_0(every shared member,abuse_spawn_mapsamong them) and
a_spawn_from_an_image_frees_it_when_the_child_ends,osbench_capability_groups_exit_0,virt_user_mode,virt_smp. The earlier row runs no longer cover the landed heads.abuse_spawn_maps's past-the-objectrange names
backing: SpawnBacking::Copy, the field A memory object's range is mapped where the caller says, and an immutable one is shared and executable: /system text is ROOT's own pages #1259 added after the case was written (no earlier runcompiled it: it is a shared member). At each head the testcases image builds,
vm::andframes::pass and thekernel's clippy shapes exit 0; every guest member compiles (
rebase5-checks.login the evidence).its root" to the doc on
impl Drop for AddressSpace, which A spawn reserves its stack once, and a committed page's frame is written once #1250 rewrote; both stand. Every other commit isunchanged (
rebase4-range-diff.txtin the evidence).kernel/loom/src/lib.rs's contextconflicted (A poll belongs to the handle it was made through, and a ring to its one submitter #1261 removed the poll modules beside
shm_slot);--test shm_slotexit 0 (4 passed), withslot-install-relaxedexit 101. At 4765676:vm::andframes::exit 0, kernel clippy for
x86_64-unknown-none, withboot-actuators,test-actuators, foraarch64-unknown-none-softfloatand the library's tests, exit 0 each (rebase3-*in the evidence).kernel/pure/vm.rs's tests: A memory object's range is mapped where the caller says, and an immutable one is shared and executable: /system text is ROOT's own pages #1259'san_object_maps_as_what_it_isand this stack's copied-page tests both stay. At ea10107:vm::andframes::exit 0,kernel clippy for
x86_64-unknown-none, withboot-actuators,test-actuators, foraarch64-unknown-none-softfloatand the library's tests, exit 0 each.
--test shm_slotexit 0(4 passed), with
slot-install-relaxedexit 101 (the two hand-over models). No record owes the batch to A memory object's range is mapped where the caller says, and an immutable one is shared and executable: /system text is ROOT's own pages #1259 anymore: it is built here.
kernel-loomcompilesobject/shm/slot.rsbeside the kernel, andkernel/loom/tests/shm_slot.rsmodelstouches and runs of a three-page region from every interleaving, the region's lock a loom mutex: two touches of a
page draw once and are both handed that frame; two runs sharing a page draw each page once, in one draw a run at
most, and are both handed the shared page's frame; a frame comes with what its drawer wrote; a later touch draws
none. At 4c68367
--test shm_slotpasses all four, and the negative control (--features slot-install-relaxed:the install and the one load
Relaxed) reds the two that hand a frame over the one load, on loom's causalityviolation. Registered in CI's control table (its verdicts unchanged since
--ci host modelsran green at71b2f15).
cargo test -p kernel --lib --features sched-checkexit 0 (465 passed); clippy with the adoptedlints and
-D warnings, exit 0 each, for the kernel onx86_64-unknown-none(default,boot-actuators,test-actuators,boot-actuators), onaarch64-unknown-none-softfloat(default,boot-actuators,test-actuators), the library's tests withsched-check, andkernel-loomwith and without thecontrol.
the install zips the holes with what was drawn, and the loom header names both tests the control reds. At 917b8ef:
--test shm_slotexit 0 (4 passed), withslot-install-relaxedexit 101 (the two hand-over models); kernel clippyfor
x86_64-unknown-none,aarch64-unknown-none-softfloatand the library's tests, andkernel-loomclippy, exit 0each.
hold-*), pending (43113647566 resolved to 0c76f7a and 43116588754 at4c68367 was cancelled for this head): x86
a_spawn_from_an_image_frees_it_when_the_child_endsandosbench_capability_groups_exit_0, aarch64virt_user_modeandvirt_smp(shared code; every program's filewindows are regions drawn at first touch, and an object range's fault now draws its run together). Earlier
dispatches named shared-boot members, which the harness refuses as filters, or tested earlier heads, and were
cancelled. The members this change bears on run on the shared-boot guest row (The shared boots run as guest rows, each member judged by its own exit #1271) once it lands, on main:
shm_release_reclaims(a region's frames and promises go back,memory_usedreturning, so a hole's promise leftbehind would show),
abuse_shm_length(refused at creation),shm_read_only,spawn_image_object,lent_window_refused,abuse_spawn_maps, and the inbox membersabuse_inbox,inbox_cancel_wakes,inbox_log_postandpoll_wake_pipe(rings drawn whole).memory_usedcountspromises, and nothing else reports drawn frames. That is the metal A/B's to show, below.
Metal (owed, not run)
The benches are down, so this lands on review, the host checks and the guest rows, and the speed-up is not yet
measured on metal. Owed on metal, recorded in the first-touch record, which this PR marks built (#1265 landed
first): an A/B of main before and after this on the T14 and the AMD bench, of
osbench work(
work.build_shaped.j1,.j8on the T14,.j16on the AMD bench),spawn_cost,osbench procsandosbench files. Main after must showwork.build_shaped.j1and.j<cpus>faster onboth, and no
procorfsrow slower beyond the before run's spread.Risks
pages()orpage()in interrupt context on a region made withcreatewould take the region'sand the allocator's locks there. The rule is at
pages(), and the one such caller today, an inbox's rings, is madewhole.
run already does: a touch beside a touched page draws up to 16 frames of a region that its user may never touch.
🤖 Generated with Claude Code