Test: pin the chip-run lane's blocking wait and drop its unused API - #1743
Conversation
The lane's unbounded wait blocks on the device rather than re-polling, but nothing held that in place. The stubbed poll_run completes as soon as g_complete is set, so every wait_until in the suite returned on its first pass and a re-polling implementation would have passed all twelve cases — which is how a full-core busy-spin reached main behind a green CI. UnboundedWaitBlocksInsteadOfPolling leaves the run completable only by wait_run, so the blocking path is the sole way for the wait to finish, and asserts both that the device wait was reached and that the poll count stays at most one. A re-polling implementation would loop forever on that setup, so the poll stub completes the run itself past a bound: the regression then fails in milliseconds with "unbounded wait polled 64 times instead of blocking" rather than wedging the suite until the job timeout. Verified by reverting the blocking call — without the escape hatch the test hangs, with it the test fails fast; restored, all thirteen pass. ChipRun::wait_until_launched goes away. It has no callers and no binding — ChipRun::launched(), which the child loop does use, is a different accessor — so it was exported and untested from the start. The remaining waiter needs no launch-only variant, and leaving one shaped by guesswork would invite a caller to adopt semantics no test covers. Verified: 91/91 cpp UT (ctest -LE requires_hardware); 1277 passed / 13 skipped py UT; a2a3 onboard sweep 54 passed plus 24 passed / 2 skipped in the resource phase.
📝 WalkthroughWalkthroughThe change removes ChangesChip run waiting
Estimated code review effort: 2 (Simple) | ~10 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
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. Comment |
Review — #1743Stated goal: two code-health follow-ups on Change Breakdown
Trivial size, no split warranted. Mechanism Brief
I independently re-derived why the numbers work: Verified independently (not from PR body)
Issues FoundMust fix: none. Should fix: none. Consider:
VerdictApprove. Both changes are exactly what they claim to be, verified against the actual code rather than the PR's own account of itself; the new test is non-vacuous by the author's own mutation check (which I re-derived rather than took on faith), and the dead-API removal is clean. |
|
Thanks — approving on a re-derivation rather than on my account of it is exactly the right check, and Consider #1 was worth asking. I chased both down; neither needs a code change, but #1 turned up something worth reporting. Consider #1 — the numbers are right, but the reasoning behind the doubt was invertedThe premise was that So this branch already contains them, and The two totals being unchanged from base is expected for a different reason each:
I've added both explanations to the PR body's Validation section, since the reporting was the actual weak point.
|
Two code-health items on
ChipRunLane, both surfaced while reviewing #1650 and left open when it merged (48dc78bf).1. The blocking wait had no test holding it in place
ChipRun::wait_until(Deadline::max())blocks on the device rather than re-polling — but nothing enforced that. The stubbedpoll_runreturnsCOMPLETEas soon asg_completeis set, so everywait_untilin all twelve cases returned on its first pass, andExpiredWaitLeavesTheRunLivepasses an already-elapsed deadline so it too does one iteration.A re-polling implementation would have passed the entire suite. That is exactly how the original spin — measured at 636,336
poll_runcalls in a 200 ms run (~3.2 M/s, each one anrtSetDeviceplus a device read in production) — reached main behind a green CI.UnboundedWaitBlocksInsteadOfPollingcloses it. The run is completable only bywait_run, so the blocking path is the sole way for the wait to finish, and it asserts both halves:wait0in the event log)On the escape hatch: on that setup a re-polling implementation loops forever, and a hang is a poor CI failure — it burns the job timeout and reports nothing. So the poll stub completes the run itself past a bound (
g_poll_completes_after, set by this one test). The regression then fails in milliseconds withVerified non-vacuous by mutation: with
block_on_front()removed, the test without the hatch hangs (killed at 60 s); with the hatch it fails in 0 ms with the message above. Restored, all thirteen pass.2.
ChipRun::wait_until_launchedis deletedZero callers, zero bindings — exported and untested from birth. Confirmed with a positive control, since an absence claim from one grep spelling is worth little:
Note
ChipRun::launched()is a different accessor — it readscrossed_launch_fence, is bound as a property, and the child loop does use it. That one stays.W1b will expose a live
RunHandleand may well want a launch-only wait; deciding its shape then, against a real caller, beats keeping one shaped by guesswork that no test covers.Validation
ctest -LE requires_hardware— CI's own filter, not-L no_hardware, which omits 18 tests including this one)tests/ut/pyBoth totals are unchanged from the base
48dc78bf, which is expected and not asign of a stale measurement:
test_chip_run_lane, socteststays 91 while the binary itself goes12 → 13 (
--gtest_list_tests)..pyfiles(
git diff 48dc78bf...HEAD --name-only | grep '\.py$'→ empty). Measured1277 on the base as well, not inferred.
Not in scope
Issue #1742 (
launchedsemantics insimpler_finalize_run) is a differentlaunched— aboolin the platform-layer C API, unrelated to the lane's accessor. Same defect class, different file and layer; left alone.