fix(beat): the LinReg speed beat was measuring the host, not the algorithms - #2345
Merged
Conversation
…rithms
The nightly failed on BEAT-SKLEARN-LINREG-SPEED. It is not a regression - the
beat's stated rationale is false and its workload is too small to measure.
WHAT THE FILE CLAIMED, in its own doc comment:
A relative comparison cancels machine-speed variance, so a slow runner
slows both sides proportionally and the ratio holds.
WHAT THE NIGHTLY MEASURED, two runs an hour apart on the same host:
apr=2.289ms sklearn=9.770ms ratio=0.234 PASS
apr=5.798ms sklearn=5.556ms ratio=1.044 FAIL (ceiling 0.90)
The sides did not move proportionally - they moved in OPPOSITE directions.
sklearn nearly halved while apr more than doubled. The assumption the gate
rests on is falsified by the gate's own output.
MECHANISM. At 10_000x20 apr's fit+predict is ~1.2ms. One scheduler preemption
(~1ms) is an ~80% perturbation; sklearn's ~4.5ms absorbs the same event. The
ratio therefore tracks whoever got unlucky with the scheduler.
FIX: 200_000x50 (~50x the work), RUNS 5 -> 9. apr ~117ms, sklearn ~217ms, so
millisecond jitter is ~1% instead of ~80%. Measured on lambda-vector
(Threadripper 7960X, 48 threads):
size idle cpu-load mem-load CI
10_000x20 0.255-0.339 0.128-0.189 0.253-0.362 0.234 .. 1.044
200_000x50 0.494-0.582 0.593-0.636 - -
Final config, 5 consecutive runs: 0.543 0.552 0.519 0.519 0.565
-> 8.9% spread, vs 33% at the old size, 42% headroom to the 0.90 ceiling.
CORROBORATION I did not expect. The contract's recorded baseline_floor is
0.5600, annotated "measured apr/sklearn ~0.56 (apr 1.78x faster, commit
34d61a6)". The new configuration measures 0.519-0.565 (~1.85x). The 10_000x20
configuration measures ~0.26. So 0.56 was always the LARGE-workload number and
the test had drifted to a size its own contract was not written for. Contract
updated to say n_samples=200000 and to record the corroboration.
TWO THINGS STATED HONESTLY RATHER THAN GLOSSED:
1. The headline win SHRINKS with size: ~3.6x at 10_000x20, ~1.7-1.85x at
200_000x50. Both are true of different regimes. The smaller number is the
one that can be measured reliably, and a gate that measures reliably is
worth more than a gate that flatters. baseline_floor 0.56 and ceiling 0.90
are unchanged - this restores the regime they describe.
2. I could NOT reproduce the CI failure mode locally. Under CPU-spin load the
small workload got BETTER (0.128-0.189: sklearn slowed, apr did not); under
memory-bandwidth load it was unchanged (0.253-0.362, apr steady at ~1.18ms).
apr never exceeded 1.94ms locally versus 5.798ms on CI. This box (48
threads) cannot emulate 17 runners on 32 threads. The justification is
therefore the stability comparison above, not a reproduction of the
mechanism - and the fix is sound either way, because a measurement whose
noise floor rivals its signal cannot gate anything.
Hypotheses tested and REJECTED before landing this, so they are not retried:
min-of-N instead of median (median and min agree to 0.08% under sustained load
- min only helps with spiky noise); RAYON_NUM_THREADS pinning (no effect, the
path is already effectively single-threaded); missing warmup (both sides
already warm up).
pv validate: 0 errors, 0 warnings. cargo fmt clean.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The nightly failed on
BEAT-SKLEARN-LINREG-SPEED. It is not a regression — the beat's stated rationale is false, and its workload is too small to measure.What the file claimed, in its own doc comment
What the nightly measured — two runs, one hour apart, same host
The sides did not move proportionally — they moved in opposite directions. sklearn nearly halved while apr more than doubled. The assumption the gate rests on is falsified by the gate's own output.
Mechanism: at 10 000×20, apr's fit+predict is ~1.2 ms. One scheduler preemption (~1 ms) is an ~80% perturbation; sklearn's ~4.5 ms absorbs the same event. The ratio tracks whoever got unlucky with the scheduler.
Fix: 200 000×50 (~50× the work),
RUNS5 → 9apr ~117 ms, sklearn ~217 ms — millisecond jitter is ~1% instead of ~80%.
Final config, 5 consecutive runs:
0.543 0.552 0.519 0.519 0.565— 8.9% spread vs 33% at the old size, 42% headroom to the 0.90 ceiling.Corroboration I didn't expect
The contract's
baseline_flooris 0.5600, annotated "measured apr/sklearn ~0.56 (apr 1.78× faster, commit 34d61a6)".So 0.56 was always the large-workload number, and the test had drifted to a size its own contract wasn't written for. This restores the regime the contract describes;
baseline_floorandbeat_thresholdare unchanged.Two things stated rather than glossed
1. The headline win shrinks with size — ~3.6× at 10 000×20, ~1.7–1.85× at 200 000×50. Both are true of different regimes. The smaller number is the one that can be measured reliably, and a gate that measures reliably is worth more than a gate that flatters.
2. I could not reproduce the CI failure locally. Under CPU-spin load the small workload got better (0.128–0.189: sklearn slowed, apr didn't); under memory-bandwidth load it was unchanged (0.253–0.362, apr steady at ~1.18 ms). apr never exceeded 1.94 ms locally versus 5.798 ms on CI — this box (48 threads) can't emulate 17 runners on 32 threads. The justification is the stability comparison above, not a reproduction of the mechanism. The fix is sound either way: a measurement whose noise floor rivals its signal cannot gate anything.
Hypotheses tested and rejected before landing
Recorded so they aren't retried:
RAYON_NUM_THREADSpinning — no effect; the path is already effectively single-threaded.pv validate: 0 errors, 0 warnings.cargo fmtclean.🤖 Generated with Claude Code