Skip to content

fix(kio): identify a batch's waker by data pointer; keep Miri tests under SLOW - #7895

Merged
kixelated merged 7 commits into
mainfrom
quest/m0/nightly/miri
Nov 5, 2026
Merged

kixelated merged 7 commits into
mainfrom
quest/m0/nightly/miri

Conversation

@kixelated

@kixelated kixelated commented Nov 4, 2026 •

Copy link
Copy Markdown
Collaborator

Works on quest/m0/nightly/miri.md, the Nightly passes on main child for the Miri job.

Summary

The first scheduled Nightly with rust-src (run 41852517544, 2026-11-04, after moq-dev/moq#7812) failed Tests (rs miri) in its strict pass:

  • kio task::tests::a_self_waking_task_spends_the_budget_and_stops: 4 owner wakes, expected 1.
  • kio task::tests::a_nested_batch_holds_wakes_for_the_outer_batch: 1 owner wake at budget 2, expected 0.

Root cause. Waiter::batch holds a set's wake of its own task by comparing waker identities, which were (data, vtable) pointers. std's Arc-backed waker builds its RawWakerVTable as a promoted constant in two functions (raw_waker and clone_waker); natively LLVM merges them, but the address is not unique, and Miri deliberately varies it. So the stored clone of the parent waker never matched the batch's original, every wake went straight through, and the executor would poll again for nothing. Reproduced locally on nightly-2026-11-03 with just rs miri -E 'test(/^task::tests::a_(nested_batch|self_waking)/)'.

Fix. Identify a waker by its data pointer only (rs/kio/src/task.rs). A foreign waker that happens to share a batch's data pointer only has its wake held until that batch returns and is then delivered, so the looser match can delay a wake, never lose one.

Slow tests. The same run's slowest test, model::frame::tests::a_delivery_attaching_mid_write_publishes_one_payload, took 372 s, past nextest's 300 s SLOW mark (rs/AGENTS.md: a SLOW test is a bug). Measured locally under Miri:

Test Change Before After
a_delivery_attaching_mid_write_publishes_one_payload fill the 1 MiB payload by repeating one 251-byte period instead of a per-byte map (the fill alone took 119 s) 213 s 104 s
clock::sim::tests::a_large_task_set_counts_each_child_alone (212 s on ARM) 4097 children, one past the sim's Ready limit (now coop::READY_LIMIT), instead of 10,000 280 s 56 s
model::group::test::a_group_has_no_frame_cap (epoch pass) #[cfg_attr(miri, ignore)]: ~30 ms per write under Miri, linear (2500 writes 70 s), so 10,000 run past SLOW; batched writes only cut that 1.7x >300 s ignored

Recorded timings (run 41852517544, ubuntu-24.04-arm): job 19 min 22 s; tests start 6 min in; strict pass 228 tests in 800 s (13.3 min) against the 60-minute job; slowest test 372 s against the 900 s per-test cap. The epoch pass never ran, since sh/rs/miri.sh exits after a failed pass. All 17 model::frame:: tests ran and passed, including both single-delivery tests from moq-dev/moq#7508, so the strict selection needs no change.

Locally (loaded 24-core desktop, all changes): strict 228/228 in 333 s, epoch 96/96 in 317 s.

The quest is rewritten to what remains: the next scheduled Nightly after this lands must pass both passes on ARM and record the epoch timings.

Public API: none (coop::READY_LIMIT is pub(crate)). Wire: none.

Choices made without asking

  • a_group_has_no_frame_cap is ignored under Miri rather than shrunk. The quest Plan said a smaller Miri workload "must still exceed the former 8192-frame cap"; 8193 writes still run about 230 s locally, past SLOW on ARM. Its point (no frame cap) is functional and still runs natively in the merge gate with 10,000 frames; kio's log:: tests already cover segment chaining under Miri, and empty_frame_batches_shed_by_their_slots is ignored under Miri for the same reason.
  • Data-pointer identity over a test-only change (a static-vtable test waker). The vtable comparison is best effort even natively; fixing the tests alone would leave the batch depending on it.

Validation

  • just rs miri (both passes) on nightly-2026-11-03 with miri, rust-src: 228 + 96 passed.
  • The two failing tests fail before the fix and pass after it (-E 'package(kio) & test(/^task::/)': 19/19).
  • just ci origin/main: passed (check rs, test rs: 11397 tests passed).

Review

Codex gpt-6.1-sol, medium effort, via quest review --base origin/main (round 1), reviewed head 267a7a353d52b4ae0d8b75515fae87b86b50d2d0: no findings.

Suggested follow-ups

None.

🤖 Generated with Claude Code

(Written by Claude Opus 5.5)

kixelated and others added 7 commits November 3, 2026 21:01
Quest-Claim: ac4f1ff84a56bbbe
Co-Authored-By: GPT-6.1 Sol <noreply@openai.com>
Co-Authored-By: GPT-6.1 Sol <noreply@openai.com>
Quest-Claim: 86bede8a02f900ff
…/nightly/miri

# Conflicts:
#	quest/m0/nightly/miri.md
A RawWakerVTable is a promoted constant with no unique address, so a clone
of an Arc-backed waker can carry a different vtable pointer than the
original. Miri varies it on purpose, so Waiter::batch never matched its own
task's set wakes and Nightly's Miri pass failed two kio task tests.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The scheduled Miri run took 372 s on a_delivery_attaching_mid_write_publishes_one_payload,
half of it filling the payload byte by byte; repeat one period instead.
a_large_task_set_counts_each_child_alone needs only one child past the
sim's 4096 Ready limit, so name the limit and use it. a_group_has_no_frame_cap
spends ~30 ms per write under Miri, so 10,000 runs past SLOW; it still runs
natively in the merge gate.

Rewrite the quest to the remaining wait: a scheduled run with both passes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@kixelated kixelated changed the title Nightly's Miri job stays inside its time budget fix(kio): identify a batch's waker by data pointer; keep Miri tests under SLOW Nov 4, 2026
@kixelated
kixelated marked this pull request as ready for review November 4, 2026 20:51
@coderabbitai

coderabbitai Bot commented Nov 4, 2026

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Next included review available in 36 seconds.

Check out review usage here.

View limit details

Limit details: You’ve used all 4 included reviews currently available.

Learn how review limits work.

Review configuration:

Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 9487bfff-a5df-41cc-9844-6696f550645d
Commits

Reviewing files that changed from the base of the PR and between f37d964 and 267a7a3.

Files selected for processing: 7
  • quest/m0/nightly/README.md
  • quest/m0/nightly/miri.md
  • rs/kio/src/clock/sim.rs
  • rs/kio/src/coop.rs
  • rs/kio/src/task.rs
  • rs/moq-net/src/model/frame.rs
  • rs/moq-net/src/model/group.rs
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

Share

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ No new issues found.

Reviewed changes

Reviewed both PR commits against main: the batch waker identity fix plus the Miri test/quest adjustments.

  • Batch waker identity — Polling now identifies a batch by Waker::data() alone, so a cloned Arc-backed waker (whose vtable address Miri varies) still matches its own task's held wakes. A shared data pointer can only delay a foreign wake until the batch returns, never lose it.
  • Sim Ready limit — the 4096 literal becomes pub(crate) const READY_LIMIT, and a_large_task_set_counts_each_child_alone pushes READY_LIMIT + 1 children, preserving the per-child-scope regression check at a fraction of Miri's cost.
  • Miri workload — the frame payload is filled by repeating one 251-byte period (byte-identical), and a_group_has_no_frame_cap is ignored under Miri because ~30 ms per write puts 10,000 past SLOW; it still runs natively.
  • Quest docs — record the 2026-11-04 strict-pass timings and leave the epoch ARM timing as the remaining wait.

Pullfrog  | View workflow run | Using deepseek-v4.1-flash-1017 (free via Pullfrog for OSS) | 𝕏

@kixelated kixelated left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Automated review by review (OpenAI)

Reviewed commit: 267a7a3

No actionable findings. Data-pointer matching can defer a foreign waker, but each held entry retains its own Shared state and releases its registered parent at batch exit; it does not merge pending state or lose that wake. The reduced simulation workload still exceeds READY_LIMIT, and the repeated frame payload preserves the previous byte sequence. The native 10,000-frame no-cap test remains enabled.

Overall direction: the focused fix addresses unstable waker-vtable identity, and the quest correctly leaves the next scheduled ARM run outstanding.

Verification limits: GitHub-only review of all seven changed files and relevant callers, including an independent pass. I did not run Miri, tests or timing measurements. Reported local timings are author evidence; pinned Quest context was read rather than executed.

(Written by review (OpenAI))

@kixelated
kixelated added this pull request to the merge queue Nov 5, 2026
Merged via the queue into main with commit e113c06 Nov 5, 2026
14 checks passed
@kixelated
kixelated deleted the quest/m0/nightly/miri branch November 5, 2026 05: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