Skip to content

Commit ddd7196

Browse files
committed
fix and trim
1 parent 86474cf commit ddd7196

1 file changed

Lines changed: 25 additions & 38 deletions

File tree

.github/workflows/codspeed.yml

Lines changed: 25 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,6 @@
1-
# Instruction-count (Callgrind) perf-regression gate against a COMMITTED baseline. No CodSpeed account/token/runner:
2-
# compare_baseline.py parses raw callgrind dumps and diffs each benchmark against benchmarks/baseline.json. Counts
3-
# are near-deterministic with PYTHONHASHSEED pinned (~0.1% noise), so the 5% gate threshold sits far above it.
4-
# Details + rationale: benchmarks/README.md and benchmarks/PLAN.md.
5-
#
6-
# Triggers: nightly schedule + manual workflow_dispatch (no pull_request/push). A dispatch on a feature branch
7-
# compares that branch's counts vs the baseline.json committed on it, answering "did my branch regress vs main".
8-
#
9-
# Modes (workflow_dispatch input `regen`):
10-
# regen=false (default) -> COMPARE + report. Report-only for now (never fails); flip to --enforce once trusted.
11-
# regen=true -> write a fresh baseline.json + upload as an artifact to commit deliberately. Bump
12-
# requirements-bench.txt FIRST (separate commit) if the pins should change.
13-
#
14-
# The concurrency module is excluded from the sweep (Callgrind serializes threads, so its signal is meaningless).
15-
# Memory mode (a second sweep for produce peak-RSS) is deferred (see PLAN.md).
1+
# Instruction-count (Callgrind) perf gate vs a committed benchmarks/baseline.json; no CodSpeed account needed
2+
# (compare_baseline.py parses the raw callgrind dumps). Rationale in benchmarks/README.md and benchmarks/PLAN.md.
3+
# workflow_dispatch input `regen`: false compares (report only), true writes baseline.json and uploads it.
164

175
name: Benchmarks
186

@@ -33,24 +21,23 @@ concurrency:
3321
jobs:
3422
benchmarks:
3523
runs-on: ubuntu-latest
36-
timeout-minutes: 90 # ~25 min sweep at BENCH_SCALE=10 (12-core Linux) + ~10 min cold build; margin for CI
24+
timeout-minutes: 90 # ~25 min sweep (BENCH_SCALE=10) + ~10 min cold build, plus margin
3725
permissions:
3826
contents: read
3927
env:
40-
PYTHONHASHSEED: "0" # stable instruction counts for dict/struct paths
41-
CODSPEED_ENV: "1" # activates pytest-codspeed's instrument hooks
42-
# shrink the O(rows) benches so the sweep fits under timeout-minutes. Local runs leave this unset -> full N.
43-
# Recorded in baseline.json meta.bench_scale; a baseline only compares to a run at the SAME scale.
28+
PYTHONHASHSEED: "0" # deterministic instruction counts
29+
CODSPEED_ENV: "1" # enable pytest-codspeed callgrind hooks
30+
# shrink O(rows) benches to fit the timeout; a baseline only compares to a run at the SAME scale (meta.bench_scale)
4431
BENCH_SCALE: "10"
4532
steps:
4633
- uses: actions/checkout@v4
4734
with:
48-
submodules: recursive # the DuckDB engine submodule is needed to build
49-
fetch-depth: 0 # setuptools_scm needs history for version detection
35+
submodules: recursive
36+
fetch-depth: 0 # setuptools_scm needs history
5037

5138
- name: Resolve DuckDB submodule SHA
5239
id: duckdb_sha
53-
# used for the sccache key AND passed to compare_baseline.py for the engine-bump guard
40+
# sccache key + compare_baseline.py engine-bump guard
5441
run: echo "sha=$(git rev-parse HEAD:external/duckdb)" >> "$GITHUB_OUTPUT"
5542

5643
- name: Install uv
@@ -78,29 +65,29 @@ jobs:
7865
CMAKE_C_COMPILER_LAUNCHER: sccache
7966
CMAKE_CXX_COMPILER_LAUNCHER: sccache
8067
run: |
81-
# step 1: build deps only (needed for --no-build-isolation), no project
8268
uv sync --only-group build --no-install-project -p 3.13
83-
# step 2: the frozen bench pins (exact ==), so the only cross-run delta is the binding. MUST precede the
84-
# build: numpy>=2.0 is a [build-system].requires (numpy C API headers), which --no-build-isolation does
85-
# not auto-install and which is not in the `build` group, so CMake's find_package(... NumPy) fails first.
69+
# pins BEFORE the build: numpy>=2.0 is a build-system.requires (C API headers), absent under
70+
# --no-build-isolation and not in the `build` group, so find_package(NumPy) fails otherwise.
8671
uv pip install -r benchmarks/requirements-bench.txt
87-
# step 3: build+install the project (release), no default `dev` group (torch/tensorflow/pyspark). uv pip
88-
# install is additive; uv sync here would prune numpy back out before the build and re-break the config.
72+
# uv pip is additive; uv sync would prune numpy back out before the build. release, no dev group.
8973
uv pip install --no-build-isolation --no-deps --reinstall -C cmake.build-type=Release .
9074
9175
- name: Collect gate node-ids
92-
# the gate/informational marker split; regen uses it to classify each benchmark
93-
run: uv run --no-sync pytest benchmarks/ -m gate --collect-only -q -o addopts= -p no:cacheprovider \
94-
| grep '::' > gate_list.txt || true
76+
# regen uses these to classify each benchmark. Block scalar so `\` is a real shell continuation; a plain
77+
# scalar folds it to a literal `\ `, mangling pytest args into an empty (all-informational) gate list.
78+
run: |
79+
uv run --no-sync pytest benchmarks/ -m gate --collect-only -q -o addopts= -p no:cacheprovider \
80+
| grep '::' > gate_list.txt || true
81+
# an empty gate list yields a 0-gate baseline that never catches a regression
82+
test -s gate_list.txt || { echo "ERROR: gate_list.txt empty"; exit 1; }
83+
echo "collected $(wc -l < gate_list.txt) gate node-ids"
9584
9685
- name: Run benchmarks under Callgrind (per-benchmark instruction counts)
97-
# ONE sweep over gate+informational EXCEPT the concurrency module (thread-serialized, expensive). Each
98-
# benchmark emits a callgrind dump keyed by its uri.
86+
# one sweep; concurrency module excluded (Callgrind serializes threads).
9987
run: |
10088
mkdir -p profiles
101-
# Invoke the venv python DIRECTLY under valgrind, not `uv run`: uv run forks pytest as a child, and
102-
# valgrind without --trace-children only instruments uv, so the child runs un-instrumented (native
103-
# speed) and pytest-codspeed's callgrind_dump_stats_at calls no-op -> zero dumps.
89+
# run the venv python directly, NOT `uv run`: valgrind without --trace-children only instruments uv,
90+
# leaving pytest un-instrumented (native speed, zero dumps).
10491
CODSPEED_PROFILE_FOLDER="$PWD/profiles" valgrind --tool=callgrind --instr-atstart=no \
10592
--callgrind-out-file="$PWD/profiles/cg.%p.%n" \
10693
"$VIRTUAL_ENV/bin/python" -m pytest benchmarks/ \
@@ -109,7 +96,7 @@ jobs:
10996
11097
- name: Compare against committed baseline (report-only)
11198
if: ${{ !inputs.regen }}
112-
# report-only: prints the delta table, never fails the job. Add --enforce once trusted.
99+
# report only, never fails; add --enforce once trusted
113100
run: |
114101
uv run --no-sync python benchmarks/compare_baseline.py compare \
115102
--profiles profiles --baseline benchmarks/baseline.json \

0 commit comments

Comments
 (0)