Skip to content

fix(beat): the LinReg speed beat was measuring the host, not the algorithms - #2345

Merged
noahgift merged 1 commit into
mainfrom
fix/linreg-beat-noise-floor
Jul 30, 2026
Merged

fix(beat): the LinReg speed beat was measuring the host, not the algorithms#2345
noahgift merged 1 commit into
mainfrom
fix/linreg-beat-noise-floor

Conversation

@noahgift

Copy link
Copy Markdown
Contributor

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, one hour apart, 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 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), RUNS 5 → 9

apr ~117 ms, sklearn ~217 ms — millisecond jitter is ~1% instead of ~80%.

size idle cpu-load mem-load CI
10 000×20 0.255–0.339 0.128–0.189 0.253–0.362 0.234 … 1.044
200 000×50 0.494–0.582 0.593–0.636

Final config, 5 consecutive runs: 0.543 0.552 0.519 0.519 0.5658.9% spread vs 33% at the old size, 42% headroom to the 0.90 ceiling.

Corroboration I didn't expect

The contract's baseline_floor is 0.5600, annotated "measured apr/sklearn ~0.56 (apr 1.78× faster, commit 34d61a6)".

  • new configuration: 0.519–0.565 (~1.85×)
  • 10 000×20 configuration: ~0.26

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_floor and beat_threshold are 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:

  • 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.

🤖 Generated with Claude Code

…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>
@noahgift
noahgift enabled auto-merge July 30, 2026 09:12
@noahgift
noahgift added this pull request to the merge queue Jul 30, 2026
Merged via the queue into main with commit 2722b94 Jul 30, 2026
14 checks passed
@noahgift
noahgift deleted the fix/linreg-beat-noise-floor branch July 30, 2026 10:00
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