Track C++ Google Benchmark microbenchmarks via ASV#2943
Track C++ Google Benchmark microbenchmarks via ASV#2943vasil-pashov wants to merge 7 commits intomasterfrom
Conversation
0bd2cee to
d1b5fb4
Compare
## What Adds C++ microbenchmark tracking alongside the existing Python ASV benchmarks. Each Google Benchmark function becomes a separate ASV class so results appear in the same dashboard with the same tooling. ### New files - `python/benchmarks/cpp_microbenchmarks.py` — ASV module that runs the C++ benchmark binary (`ARCTICDB_CPP_BENCHMARKS_BINARY`) and exposes each function as an ASV `track_*` class. Parameter variants (`BM_foo/10000/1`) become ASV params; the `unit = "ms"` attribute is set so graphs show the correct Y-axis label. Per-benchmark flag overrides are supported via `BENCHMARK_FLAGS`. - `.github/workflows/benchmark_cpp_microbenchmarks.yml` — callable workflow that builds the benchmarks binary, then runs `asv run --bench "^cpp_microbenchmarks\."`. Results are stored in a separate ArcticDB library (`cpp_microbenchmarks_asv_results`) to avoid key conflicts with Python results stored under the same 8-char commit hash. ### Changes to `analysis_workflow.yml` - New `benchmark_cpp_microbenchmarks` job runs in parallel with `benchmark_commits`, each on its own EC2 runner — no shared machine contention. - `continue-on-error: true` so C++ regressions appear as a visible failed job but do not block PRs or the Python benchmark publish step. - The publish job's `if` condition uses `always()` so a C++ failure does not prevent Python results from being published. - `run-asv-check-script` now builds the C++ benchmarks binary before running `asv_checks.py`. Without the binary `cpp_microbenchmarks.py` registers zero classes, causing `asv_checks.py` to rewrite `benchmarks.json` without C++ entries and fail the hash-change check on every PR. ## Why C++ micro-benchmark results were previously invisible. This change surfaces regressions in CI alongside the Python benchmark history without blocking existing workflows. ## Pre-existing behaviour unchanged Python ASV benchmarks (`benchmark_commits`) are unmodified. The publish job and regression detection logic for Python results are unchanged.
d1b5fb4 to
09d395c
Compare
| python -m asv compare -s -f 1.15 $(cat master_commit_hash.txt) HEAD > results.txt || exit 1 | ||
|
|
||
| # Get rid of the master results so we don't re-add them to the database. | ||
| rm python/.asv/results/**/$(cat master_commit_hash.txt)*.json || exit 1 |
There was a problem hiding this comment.
The rm command fails (exits 1) if no files match the glob — which would happen if ASV placed results in an unexpected directory or if master_commit_hash.txt is empty. Because bash globbing passes the unexpanded pattern as-is to rm when there are no matches, rm always sees a "file not found" and exits non-zero. The || exit 1 guard then immediately aborts the step.
Use rm -f to silently succeed when the file is missing:
| rm python/.asv/results/**/$(cat master_commit_hash.txt)*.json || exit 1 | |
| rm -f python/.asv/results/**/$(cat master_commit_hash.txt)*.json |
Also note that ** requires shopt -s globstar to traverse recursively in bash; without it only the immediate directory is searched. Check that the shell default in the container has globstar enabled, or switch to find:
find python/.asv/results -name "$(cat master_commit_hash.txt)*.json" -delete|
|
||
|
|
||
| # Register one ASV class per C++ benchmark function in this module's namespace. | ||
| for func_name, variants in group_benchmarks(discover_benchmark_names()).items(): |
There was a problem hiding this comment.
This module-level code runs a subprocess at import time. If the binary exists but --benchmark_list_tests exits non-zero (e.g., a crash or mislinked build), result.check_returncode() inside discover_benchmark_names() raises CalledProcessError, which propagates unhandled here and causes the entire module import to fail — with a confusing traceback rather than "no benchmarks registered".
Consider wrapping the discovery to degrade gracefully:
try:
_names = discover_benchmark_names()
except Exception as exc:
import warnings
warnings.warn(f"cpp_microbenchmarks: benchmark discovery failed: {exc}", RuntimeWarning)
_names = []
for func_name, variants in group_benchmarks(_names).items():
globals()[to_identifier(func_name)] = make_benchmark_class(func_name, variants)
ArcticDB Code Review SummaryPR: Track C++ Google Benchmark microbenchmarks via ASV (#2943) API & Compatibility
Memory & Safety
Correctness
Code Quality
Testing
Build & Dependencies
Security
PR Title & Description
Documentation
|
- Guard benchmark_commit job on EC2 runner startup success to avoid wasting the job slot when runner acquisition fails - Replace check_returncode() with returncode check in discover_benchmark_names to prevent an import-time CalledProcessError that ASV cannot handle gracefully - Extract master_commit_hash.txt into a variable and quote it in the shell comparison and rm commands to avoid word-splitting bugs - Fix typo "supress" -> "suppress" in two workflow comments
…tain permissions Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
…tain permissions Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
| apt update | ||
| apt install -y git | ||
| python -m pip install arcticdb[Testing] "protobuf<6" | ||
| python -m pip install arcticdb[Testing] asv "protobuf<6" |
There was a problem hiding this comment.
asv is already in the Testing deps?
| env: | ||
| CMAKE_BUILD_PARALLEL_LEVEL: ${{vars.CMAKE_BUILD_PARALLEL_LEVEL}} | ||
|
|
||
| - name: Build C++ benchmarks binary |
There was a problem hiding this comment.
This was already done in the other workflow file?
There was a problem hiding this comment.
There's a lot of duplication with the analysis workflow. Can't we just fold the new steps in to that one?
| shell: bash -l {0} | ||
| run: | | ||
| # Look up the most recent master commit stored in our ASV database and compare against it. | ||
| ARCTICDB_REAL_S3_BUCKET=${ASV_RESULTS_BUCKET} ./tooling_venv/bin/python build_tooling/transform_asv_results.py --mode extract-recent --arcticdb_library cpp_microbenchmarks_asv_results || exit 1 |
There was a problem hiding this comment.
Why do we need a totally separate library to store these? Are they presented properly in the UI?
| # python/benchmarks/cpp_microbenchmarks.py → python/benchmarks → python → repo root). | ||
| REPO_ROOT = Path(__file__).resolve().parents[2] | ||
|
|
||
| CPP_BENCHMARKS_BINARY = Path( |
There was a problem hiding this comment.
We should make sure we blow up with a clear error message explaining that you need to build the benchmarks binary, if this is pointing at a binary that doesn't exist. Otherwise it will be hard for people to update the ASV .json file.
|
I'm fine with the script to convert the benchmarks to ASV format, but think it should all be folded in to the existing analysis workflow rather than creating a new one. |
What
Adds C++ microbenchmark tracking alongside the existing Python ASV benchmarks.
Each Google Benchmark function becomes a separate ASV class so results appear
in the same dashboard with the same tooling.
New files
python/benchmarks/cpp_microbenchmarks.py— ASV module that runs the C++benchmark binary (
ARCTICDB_CPP_BENCHMARKS_BINARY) and exposes each functionas an ASV
track_*class. Parameter variants (BM_foo/10000/1) become ASVparams; the
unit = "ms"attribute is set so graphs show the correct Y-axislabel. Per-benchmark flag overrides are supported via
BENCHMARK_FLAGS..github/workflows/benchmark_cpp_microbenchmarks.yml— callable workflowthat builds the benchmarks binary, then runs
asv run --bench "^cpp_microbenchmarks\.".Results are stored in a separate ArcticDB library
(
cpp_microbenchmarks_asv_results) to avoid key conflicts with Python resultsstored under the same 8-char commit hash.
Changes to
analysis_workflow.ymlbenchmark_cpp_microbenchmarksjob runs in parallel withbenchmark_commits,each on its own EC2 runner — no shared machine contention.
continue-on-error: trueso C++ regressions appear as a visible failed jobbut do not block PRs or the Python benchmark publish step.
ifcondition usesalways()so a C++ failure does notprevent Python results from being published.
run-asv-check-scriptnow builds the C++ benchmarks binary before runningasv_checks.py. Without the binarycpp_microbenchmarks.pyregisters zeroclasses, causing
asv_checks.pyto rewritebenchmarks.jsonwithout C++entries and fail the hash-change check on every PR.
Why
C++ micro-benchmark results were previously invisible. This change surfaces
regressions in CI alongside the Python benchmark history without blocking
existing workflows.
Pre-existing behaviour unchanged
Python ASV benchmarks (
benchmark_commits) are unmodified. The publish job andregression detection logic for Python results are unchanged.