fix(bench): give query-benchmark.ts's diffImpact metric a warmup too - #2591
fix(bench): give query-benchmark.ts's diffImpact metric a warmup too#2591carlos-alm wants to merge 2 commits into
Conversation
WARMUP_RUNS in scripts/query-benchmark.ts was applied only inside benchDepths, which serves fnDeps and fnImpact. benchDiffImpact called timeMedian directly with no warmup, making diffImpact latency the one query metric measured cold -- the same defect class #2584 just fixed for benchmark.ts's Full build metric, and that #2436 traced part of the pre-publish gate's non-determinism to. The warmup those earlier calls already paid does not carry over: diffImpactData is a distinct query path with its own prepared statements and its own DB pages, and it shells out to git to read the staged diff. Measured on this repo, 3 runs per variant, native engine: before 10.9 / 10.8 / 11.2 ms after 9.9 / 9.8 / 9.9 ms Both a ~10% drop and a much tighter spread. WASM is unchanged (9.4/9.2/9.6 -> 9.4/9.4/9.7), as expected -- the cold-start cost this removes is the native NAPI/rusqlite one. Refs #2590 Impact: 1 functions changed, 1 affected
Greptile SummaryAdds three untimed
Confidence Score: 4/5The PR appears safe to merge, with only a non-blocking documentation correction needed for the prepared-statement warmup claim. The added calls operate against a stable staged diff through readonly database connections and retain existing cleanup behavior; the only accepted concern is that the explanatory comment overstates which state persists into timed calls. Files Needing Attention: scripts/query-benchmark.ts Important Files Changed
Reviews (1): Last reviewed commit: "Merge origin/main into fix/query-bench-d..." | Re-trigger Greptile |
| // fnDeps/fnImpact. diffImpactData is a distinct query path from those -- | ||
| // its own prepared statements, its own DB pages, and a `git` subprocess to | ||
| // read the staged diff -- so the warmup those calls already paid does not | ||
| // carry over. Without this, diffImpact was the only query metric measured |
There was a problem hiding this comment.
Prepared-statement warmup claim is inaccurate
The new explanation says these calls warm diffImpact's prepared statements, but every invocation opens and closes a separate database connection and the statement cache is connection-scoped. Only process-wide initialization and OS page-cache state persist, so this wording can mislead future benchmark investigations about which cold-start costs remain in measured runs.
Codegraph Impact Analysis1 functions changed → 1 callers affected across 1 files
|
|
CI result for this branch, for the record — the full pipeline is green, including the pre-publish benchmark gate (18m50s). Measured on that run: native Worth stating plainly rather than claiming a win: 16.0ms is still +58% over the recorded 10.1 baseline, and it passes only because the 5.9ms delta stays under the ~10ms So: the warmup removes a real methodological defect and is worth landing on its own merits, but it does not on this evidence resolve the gate's fragility. The binding problem is the one still tracked in #2590 — the baseline is stale relative to where this metric actually runs on CI, so the check is riding on the absolute-delta floor rather than on real headroom, and any run landing at ≥20.1ms fails regardless of this fix. |
Summary
WARMUP_RUNSinscripts/query-benchmark.tswas applied only insidebenchDepths, which servesfnDepsandfnImpact.benchDiffImpactcalledtimeMediandirectly with no warmup loop, makingdiffImpact latencythe only query metric measured cold.This is the same defect class #2584 just fixed for
benchmark.ts's Full build metric, and that #2436 traced part of the pre-publish gate's non-determinism to — the one metric that measured without this warmup.diffImpactwas the remaining instance.The warmup the earlier
benchDepthscalls already paid does not carry over:diffImpactDatais a distinct query path with its own prepared statements and its own DB pages, and it shells out togitto read the staged diff.Why this surfaced now
Discovered while diagnosing why the pre-publish benchmark gate kept failing #2586, whose diff (one
enum_declarationmap arm per engine) provably cannot affect any benchmark — the benchmarked corpus contains zeroexport enumdeclarations. Three consecutive runs of that unchanged head each failed on a different metric, with each previously-failing metric returning to baseline:Native
diffImpact latencyacross the four most recent PR runs — 12.4, 16.5, 16.9, then 12.3 / 21.8 / 26.5 — against a recorded 3.17.0 baseline of 10.1. Recent passing runs at 16.5–16.9 were already +63–67% over the 25% threshold and survived only because the ~10msMIN_ABSOLUTE_DELTAfloor filtered their 6.8ms delta. Full analysis in #2590.Test plan
Ran
scripts/query-benchmark.tsagainst this repo, 3 runs per variant, alternating baseline/fixed to control for machine drift:Both a ~10% drop and a visibly tighter spread on native. WASM is unchanged, which is the expected signature — the cold-start cost this removes is the native NAPI/rusqlite one, exactly as the
WARMUP_RUNSdocstring describes.Output JSON stays well-formed and
affectedFunctions/affectedFilesstill populate (the warmup loop deliberately does not assignlastResult, so the reported result still comes from a timed run).npm run lintclean.Honest scope note
This fixes a real methodological defect and measurably tightens the metric, but to be straight about what it does not prove: a ~1ms improvement measured on a quiet local machine is not evidence that CI will stop spiking to 21–26ms. The gate's remaining exposure — a stale 10.1 baseline that the metric no longer sits near, and the fact that
affectedFunctions: 0on every historical entry means this benchmark measures near-pure fixed overhead — is tracked in #2590 and deliberately left out of this PR to keep it to one concern.Note that adding
diffImpact latencytoNOISY_METRICSwould not have helped: a failure needs both the percentage and the ~10ms absolute-delta floor to trip, and 21.8ms clears a 50% threshold on a 10.1 baseline just as it clears 25%.Refs #2590