Repository navigation
feat(codspeed): run the warmup with the simulated cache kept warm - #199
not-matthias wants to merge 1 commit into
Conversation
Under Valgrind, every benchmark was measured from a flushed simulated cache: the harness ran its unmeasured iterations with instrumentation off, then issued CALLGRIND_START_INSTRUMENTATION right before the measured one, which flushes the cache simulator. Each measured iteration therefore paid an artificial cold-cache phase whose size depends on how the benchmark's memory happens to be laid out, which is one of the suspected sources of run-to-run variance in simulation mode. Reorder the client requests so the cache stays warm: - START_INSTRUMENTATION is sent once, before the first warmup iteration - ZERO_STATS alone separates the warmup from the measured iteration; it resets the cost centers that end up in the `totals:` line of the dump without touching the cache state - STOP_INSTRUMENTATION + DUMP_STATS_AT after the measured iteration are unchanged The warmup is bounded by iterations and time: at least WARMUP_MIN_ITERATIONS (1), at most WARMUP_MAX_ITERATIONS (5), and no new iteration starts after WARMUP_MAX_DURATION (1 s of simulator time). The bencher, criterion and divan compat layers all drive it through the same `CodSpeed::warmup_iteration` loop, which also gives divan its first warmup (it had none) and makes `iter_manual_unstable` warm up like `iter`. Each `Measured:`/`Checked:` line now reports the warmup iteration count so analyses can stratify on it. The `summary:` line of a dump is derived from a per-thread baseline that ZERO_STATS only keeps consistent while instrumentation is off, so it now wraps to a negative value; the parser ignores that line and reads `totals:`, which is correct under both orders.
[Medium impact] The changes affect benchmark measurements across the Rust compatibility workflows. The logging requirement must be satisfied before merging; no behavioral blocker was found.
|
| "{}: {}{} (warmup: {} iterations)", | ||
| action_str, | ||
| self.current_benchmark.to_string_lossy(), | ||
| group_str | ||
| group_str, | ||
| self.warmup_iterations, |
There was a problem hiding this comment.
Warmup output bypasses tracing
The expanded benchmark message uses println!, but the repository requires Rust messages to use tracing macros instead of println! or eprintln!. Move this message to info! to satisfy the requirement before merging.
Rule Used: Never use println!/eprintln! in Rust; use tracing macros (info!/debug!/warn!/error!). (source)
Prompt To Fix With AI
This is a comment left during a code review.
Path: crates/codspeed/src/codspeed.rs
Line: 200-204
Comment:
**Warmup output bypasses tracing**
The expanded benchmark message uses `println!`, but the repository requires Rust messages to use tracing macros instead of `println!` or `eprintln!`. Move this message to `info!` to satisfy the requirement before merging.
**Rule Used:** Never use `println!`/`eprintln!` in Rust; use tracing macros (`info!`/`debug!`/`warn!`/`error!`). ([source](https://app.greptile.com/codspeed/-/custom-context?memory=f04f734b-e556-482b-98b9-64c7ce663663))
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
Performance comparison unavailableThe base and head of this comparison were measured with different runner settings, so their benchmark values are not directly comparable. What changed between base and head:
Re-run the base with the same settings to get a valid performance comparison. Comparing |
TLDR: Under Valgrind every measured iteration started from a flushed simulated cache, because
CALLGRIND_START_INSTRUMENTATIONwas sent right before it (and it flushes the cache simulator). The harness now switches instrumentation on once before the warmup and only issuesZERO_STATSbefore the measured iteration, so the measurement sees the cache state the warmup built up (simulation/memory modes only; walltime is untouched).CodSpeed::warmup_iteration()drives the warmup for bencher, criterion and divan compat: ≥WARMUP_MIN_ITERATIONS(1), ≤WARMUP_MAX_ITERATIONS(5), no new iteration afterWARMUP_MAX_DURATION(1 s of simulator time).iter_manual_unstablenow warms up likeiter.Measured:/Checked:lines append(warmup: N iterations)so analyses can stratify on the count.strided_walkDLmr 32769 → 0;sort_cloneI1mr/ILmr 11 → 0, DLmr 32770 → 0, D1mw/DLmw 1 → 0. Ir unchanged (+4 for the loop condition).Review notes
summary:line now wraps negative: callgrind derives it from a per-thread baseline thatZERO_STATSonly keeps consistent while instrumentation is off.callgrind-parserskipssummary:and readstotals:, which is correct under both orders.Part of COD-3915