Repository navigation
sched: a wake its poster parks or exits behind runs where it was posted - #1111
Conversation
7e33a51 to
a966187
Compare
2ad4439 to
dd9bf97
Compare
A request for the waker-LLC wake-affinity A/B on the AMD (from #1121, IPC phase 2)Please have that A/B's AMD rows include Why:
The base for #1121 is #1108 |
|
Follow-up to my earlier note: #1121's AMD |
…ts buffer The pass's opening held every wake it found behind the running task, and the disposition placed each against the CPU it left. When the poster parked, every held wake saw an idle CPU and stayed, so a burst its poster parked behind queued whole on the poster's CPU. Before the hold each had gone to its own idle sibling. For RT wakes nothing could move the second, because only fair tasks are stolen: the soundserver waking two boosted clients and parking ran them in turn on one CPU. place_settled now treats a held task as behind when its band already has a queued task, an earlier held one included. The first held task of each band takes the freed CPU and the rest are forwarded as before. Two host tests, fair and RT, hold it; dropping the queued-ahead check reds both and nothing else. settle took the held vector by value, so every hold allocated and freed under the kernel's global heap lock, twice per request/reply round trip. It now drains the vector and puts the buffer back. begin asserts that the previous pass was disposed, since an undisposed pass would now lose held tasks rather than skip a pick. The issue record said the branch decided the case and stayed assigned. It is renamed for what remains: no metal row prices the hold, and the T14 rows that read 1-3% slower in the first A/B, whose head also carried affinity and the spawn tie-break, are not attributed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review r2 of #1111 at
|
SYS_MESSAGE_CALL is SYS_MESSAGE_SEND and then a blocking SYS_MESSAGE_RECV on the same connection, in one syscall. A refused send answers as a send does with nothing sent; once the request is queued the receive answers as a receive does, into the same two windows. A protocol whose peer answers each request in turn makes the next message its answer. The request carries no handles: an error could come from either half, so a caller could not know whether they had moved. The call no longer tells the scheduler that its caller parks next: #1111 dropped WakeCause::parks_next (e938fe3), and #1129's waker-LLC affinity carries the waker on every wake instead. What is left is one syscall entry and exit per round trip. Consumers: the file server's client (toyos::fs's request and reply) and osbench's ipc.reqrep rows, whose request's last frame and answer's first are one call. Connection::call takes the answer straight into the caller's buffer, as recv_into does. messages_are_whole checks that a call takes the answer its peer sends, with the answer's handle, split across both windows. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
SchedPass::begin drains the mailbox before the pass knows its disposition, so a fair wake posted on the poster's own CPU was judged behind the running task in the very pass that parks or ends that task, and was forwarded to an idle CPU: an IPI and a cold cache where a local switch a moment later was free. osbench's same-CPU pingpong rows held their placement in none of 53 T14 boots, which is what this forward predicts; a thread started and then joined meets it at the join. The opening drain now holds what it finds behind the running task, and each disposition places it against the CPU as it leaves it: after a park, a stop or an exit it runs here; before a yield or with the task kept it is forwarded as before. Only the opening drain holds, so the CPU's own later drains are unchanged. WakeCause gains `parker`, the CPU whose task posted the wake and parks next in the same call. The home CPU hands such a fair wake to that CPU inside one LLC, where the poster's park runs it and the pair's later wakes are local. No caller sets it yet: it is the placement input the whole-message IPC's combined call drives in its phase 2. The simulator's turn_taking_pair holds the first half across seeds: both threads start on cpu0 beside an idle cpu1 with balancing off, and no turn is forwarded. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
b24b37a added CpuSched::held and ::holding without entries in tripwire_field, so a shadow mismatch inside either was reported as the nearest field below it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
WakeCause::parks_next(cpu) named the CPU of a poster that parks next, and the home CPU handed such a fair wake there inside one LLC. No caller ever set it. The IPC call meant to set it is recommended for dropping, and the waker-LLC wake affinity that follows this PR carries the waker on every wake instead, so the field, the hand-off and their three tests go. Step 1 stays: a wake the opening drain finds behind a poster that parks, stops or exits still runs where it was posted. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ts buffer The pass's opening held every wake it found behind the running task, and the disposition placed each against the CPU it left. When the poster parked, every held wake saw an idle CPU and stayed, so a burst its poster parked behind queued whole on the poster's CPU. Before the hold each had gone to its own idle sibling. For RT wakes nothing could move the second, because only fair tasks are stolen: the soundserver waking two boosted clients and parking ran them in turn on one CPU. place_settled now treats a held task as behind when its band already has a queued task, an earlier held one included. The first held task of each band takes the freed CPU and the rest are forwarded as before. Two host tests, fair and RT, hold it; dropping the queued-ahead check reds both and nothing else. settle took the held vector by value, so every hold allocated and freed under the kernel's global heap lock, twice per request/reply round trip. It now drains the vector and puts the buffer back. begin asserts that the previous pass was disposed, since an undisposed pass would now lose held tasks rather than skip a pick. The issue record said the branch decided the case and stayed assigned. It is renamed for what remains: no metal row prices the hold, and the T14 rows that read 1-3% slower in the first A/B, whose head also carried affinity and the spawn tie-break, are not attributed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The A/B of #1111 alone on the T14 (base 24a538c against 042b2b2, 4+4 boots) reproduced seven disk rows 1.2-2.3% slower and left ipc unchanged. Timer rows the hold cannot reach read slower by the same amount there and in the AMD A/Bs of #1129, each with the base booting first and a different image per side, so the rows are not attributed. The record says so and asks for an order-balanced A/B. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Problem
SchedPass::begindrains the mailbox before the pass knows its disposition. A fair wake posted on the poster's own CPU was judged against the running task in the very pass that parks or ends that task, and was forwarded to an idle CPU: an IPI and a cold cache where a local switch a moment later was free. The same forward moves communicating pairs apart. In fs-rtt's r2 sweep on the AMD bench, a client that landed on the server's CPU had the server forwarded away (10→14, 14→8), and a pair split across the two CCXs pays about 1.9 µs per round trip (read_4k_at 16.1–16.4 µs in one LLC against 19.9–20.4 µs across).Behaviour
CpuSched::place_settled):beginasserts the previous pass was disposed.e938fe3e5).WakeCause::parks_nextand its hand-off had no caller. sched: a woken partner follows its waker's LLC #1129's waker-LLC wake affinity carries the waker on every wake instead.issues/a-wake-whose-waker-parks-next-is-forwarded-to-an-idle-cpu.mdbecomesissues/a-wake-held-for-its-posters-park-is-unpriced-on-metal.md(defect,open). It records what is left: no metal row prices the hold, and the T14 slowdown below is unattributed. Both citations move.Checks
Evidence:
pr-1111/r4at 24a8a3d0; earlier roundsr1,r3.cargo run -- --ci hostat the top of the stack (#1116, #1117, #1129)1178599c4cargo test -p kernel --lib,cargo test -p kernel-simfnparameter →bool)libc_children×6 on QEMU x86-64 (2 CPUs) at this head and ×6 at its base24a538c88042b2b299,24a538c88turn_taking_pairholds over 40 seeds: no turn is forwarded off its CPU.1178599c4. Step 1's two earlier controls (never hold; yield settles late) each red only their own tests.8520204a0(after clock: the TSC keeps CPUID 15H's rate or one the HPET refines; a step the RTC confirms is slewed, a second demotes it #1104, IPC phase 2: a connection carries whole messages #1121, paged objects: a file's pages are the kernel's, read by its holders without a request (memory stage 7a) #1123 and osbench: a row says where its processes ran #1126), with no conflict in this PR. Host CI at the stack's top: 109 steps, all green, exit 0 (log).Metal A/B (base
0c7e62ca7, head28a55585c= this PR's step 1 with #1116 and #1117, before review r1; 4 boots per image per side per bench, evidence)Every boot returned rc=0. A row resolves only when all 4 of one side's runs beat all 4 of the other's (p = 0.029).
issues/a-wake-held-for-its-posters-park-is-unpriced-on-metal.mdrecords them. A T14 A/B of this PR alone against its base is staged (below).fs.disk.read_4k_at: base boots ran 16.7, 16.9, 17.0 and 21.3 µs; head boots ran 21.1–22.0 µs.ipc.reqrep.8: base 6.5, 6.5, 6.7 and 8.2 µs; head 8.2–8.5 µs. The other disk rows and the other ipc reqrep rows split the same way, base fast in 3 boots of 4, head slow in all 4.pr-1111/r2).ipc.reqrep.8read 8.39–8.55 µs when split across the LLCs, 6.66–6.85 µs within one, and 6.18 µs on one CPU.fs.disk.read_4k_atread 11.57–11.71 µs split, 9.65–9.68 µs within one LLC, and 11.10 µs on the file server's SMT sibling.issues/placement-has-no-migration-cost-or-wake-affinity.md's gap, which sched: a woken partner follows its waker's LLC #1129 addresses.tty_interruptstall (libc_children, QEMU x86-64, 2 CPUs). Every run so far:24a538c88: 1 stall in 10 (4 earlier runs, then 6 this round with none);f5ae75f6b: 0 in 6;042b2b299: 0 in 6;dd9bf974d, step 1 with step 2's then-uncalled hand-off: 2 failures in 3. One was this stall and the othersignal_quit: stalled driving the child that reloads, which main has not shown.signal_quit's stall is unexplained. The issue is issues: libc_children's tty_interrupt can stall at the nested shell's line #1127.T14 A/B of this PR alone (base
24a538c88, head042b2b299, 4+4 interleaved, judgment)Every boot EXIT=0. Judged in pinned check trees at each side's revision: osbench and both I219 rows PASS on all 8.
ipc.reqrep.*unchanged (ratios 1.002–1.007).fs.disk.fstat,pread_4k,read_4k_at,write_4k_atand threedirect.*.fs.mem.read_4kresolves 5% faster.wake.periodic.idle+2.8% andtail.*+1.6%, timer wakes on idle CPUs, where nothing runs to hold behind.tail.*also reads slower on head in both AMD A/Bs of sched: a woken partner follows its waker's LLC #1129, a different change. In each of these A/Bs the base boots first and the two images differ, so they carry a head bias of 1–3% on rows nothing reaches.issues/a-wake-held-for-its-posters-park-is-unpriced-on-metal.mdrecords this (1b9e7c57d) and asks for an order-balanced A/B.Risks
🤖 Generated with Claude Code