What
build-test-cpu went red on an unrelated PR with one failure out of 404:
303/404 Test #303: test_cpu_threadpool ...***Failed 0.36 sec
tests/vt/test_cpu_threadpool.cpp:536: MESSAGE: empty-op dispatch: 2 threads 0.48 us, 5 threads 48.752 us, ratio 101.567
tests/vt/test_cpu_threadpool.cpp:539: ERROR: CHECK( ratio < 100.0 ) is NOT correct!
values: CHECK( 101.567 < 100 )
[doctest] test cases: 9 | 8 passed | 1 failed | 1 skipped
[doctest] assertions: 19602 | 19601 passed | 1 failed |
Evidence: https://github.com/mudler/vllm.cpp/actions/runs/31698569035/job/94441971697
Why the guard is fragile
TEST CASE: oversubscribed dispatch does not cost a scheduler timeslice
(tests/vt/test_cpu_threadpool.cpp:499, added by 2028c8c74 for #391) asserts a
ratio of two wall-clock medians, over_us / fits_us, against a fixed 100.
The numerator and denominator are both machine-shape dependent, and the
denominator is the problem: it is the dispatch cost at a thread count that
fits the box. On a 2-core runner that was 0.48 us, small enough that
ordinary scheduler noise in the numerator moves the ratio by tens.
The two observations, same commit, same code:
| Box |
fits |
over |
ratio |
| 2-core CI runner |
2 threads, 0.48 us |
5 threads, 48.752 us |
101.567 (RED) |
| 20-core dev box |
10 threads, 7.213 us |
21 threads, 19.467 us |
2.699 (GREEN, 37x margin) |
A guard that reads 2.7 on one machine and 101.6 on another is not measuring what
it names. It fires at 1.6% over the line on the small box while a genuine
regression on the large box would need a 37x blowup to trip it. That is the
shape this repo has recorded before: a tolerance that bounds nothing at one end
and everything at the other.
Not a flake to be re-run away
It is intermittent -- build-test-cpu is green on the scheduled main lane,
including the newest baseline 7572b0f4e2fb -- but the cause is structural, not
random: it depends on the runner's core count and on how small fits_us lands.
Re-running moves the dice, it does not fix the guard.
Suggested direction (needs its own spec, per AGENTS.md)
The intent is "the waiter yields its core instead of spinning through a
scheduler timeslice". That is a claim about an ABSOLUTE cost -- a timeslice is
milliseconds -- not about a ratio. Bounding over_us against a timeslice-scaled
absolute, or skipping when fits_us is below a floor where the ratio stops
being meaningful, would both keep the finding and lose the machine dependence.
Explicitly not proposed: raising 100 to some larger number. That is widening
a scope to turn a red gate green, which the protocol forbids and which would
make the large-box end even more permissive than it already is.
Found while landing #606, whose diff is argument parsing only and cannot reach
the threadpool. Filed rather than fixed in flow: this changes a gate's semantics,
so it needs a spec and red-before evidence of its own.
What
build-test-cpuwent red on an unrelated PR with one failure out of 404:Evidence: https://github.com/mudler/vllm.cpp/actions/runs/31698569035/job/94441971697
Why the guard is fragile
TEST CASE: oversubscribed dispatch does not cost a scheduler timeslice(
tests/vt/test_cpu_threadpool.cpp:499, added by2028c8c74for #391) asserts aratio of two wall-clock medians,
over_us / fits_us, against a fixed 100.The numerator and denominator are both machine-shape dependent, and the
denominator is the problem: it is the dispatch cost at a thread count that
fits the box. On a 2-core runner that was 0.48 us, small enough that
ordinary scheduler noise in the numerator moves the ratio by tens.
The two observations, same commit, same code:
A guard that reads 2.7 on one machine and 101.6 on another is not measuring what
it names. It fires at 1.6% over the line on the small box while a genuine
regression on the large box would need a 37x blowup to trip it. That is the
shape this repo has recorded before: a tolerance that bounds nothing at one end
and everything at the other.
Not a flake to be re-run away
It is intermittent --
build-test-cpuis green on the scheduledmainlane,including the newest baseline
7572b0f4e2fb-- but the cause is structural, notrandom: it depends on the runner's core count and on how small
fits_uslands.Re-running moves the dice, it does not fix the guard.
Suggested direction (needs its own spec, per AGENTS.md)
The intent is "the waiter yields its core instead of spinning through a
scheduler timeslice". That is a claim about an ABSOLUTE cost -- a timeslice is
milliseconds -- not about a ratio. Bounding
over_usagainst a timeslice-scaledabsolute, or skipping when
fits_usis below a floor where the ratio stopsbeing meaningful, would both keep the finding and lose the machine dependence.
Explicitly not proposed: raising 100 to some larger number. That is widening
a scope to turn a red gate green, which the protocol forbids and which would
make the large-box end even more permissive than it already is.
Found while landing #606, whose diff is argument parsing only and cannot reach
the threadpool. Filed rather than fixed in flow: this changes a gate's semantics,
so it needs a spec and red-before evidence of its own.