ci: collect and compare benchmark results - #141
Conversation
Greptile SummaryThe PR adds automated benchmark collection, baseline persistence, and pull-request comparison reporting.
Confidence Score: 5/5The PR appears safe to merge. No blocking failure remains.
|
| Filename | Overview |
|---|---|
| .github/workflows/bench.yml | Adds parallel benchmark jobs, complete-run-gated baseline writes, and pull-request comparison artifact generation; the previously reported write-job action references are now pinned. |
| scripts/bench_results.py | Updates Criterion identifier extraction and supports Gungraun’s tagged integer metric representation. |
| scripts/run-benches.sh | Centralizes Rust wall-clock and instruction-count benchmark command sequences. |
| justfile | Delegates local Rust benchmark recipes to the shared benchmark runner. |
| bench/test_bench_results.py | Updates Criterion fixtures and adds coverage for tagged Gungraun integer metrics. |
Flowchart
%%{init: {'theme': 'neutral'}}%%
flowchart TD
Trigger[Push to main or pull request] --> Micro[Rust micro benchmarks]
Trigger --> Wall[Rust wall benchmarks]
Trigger --> Node[Node FFI benchmarks]
Micro --> Gate{Event and result status}
Wall --> Gate
Node --> Gate
Gate -->|Main push and all complete| Baseline[Update bench-data baseline]
Gate -->|Pull request| Compare[Merge slices and compare with baseline]
Compare --> Artifact[Upload comparison artifact]
Reviews (2): Last reviewed commit: "refactor: share benchmark command lists" | Re-trigger Greptile
There was a problem hiding this comment.
All reported issues were addressed across 3 files (changes from recent commits).
Tip: Review your code locally with the cubic CLI to iterate faster.
Re-trigger cubic
|
Addressed @cubic-dev-ai’s duplication finding in d550803. The benchmark command lists now live in |
There was a problem hiding this comment.
1 issue found across 5 files (changes from recent commits).
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="scripts/bench_results.py">
<violation number="1" location="scripts/bench_results.py:118">
P1: estimate.with_name('benchmark.json') points into the new/ directory (<id>/new/benchmark.json), but Criterion stores benchmark.json as a sibling of new/ and base/ (<id>/benchmark.json). load_json will fail on every estimate, so collect_criterion always raises BenchError and the rust-wall measurement job always fails. Use estimate.parent.parent / 'benchmark.json'.</violation>
</file>
Tip: Review your code locally with the cubic CLI to iterate faster.
Re-trigger cubic
| name = load_json(estimate.with_name("benchmark.json")).get("full_id") | ||
| if not isinstance(name, str) or not name: | ||
| raise BenchError(f"missing full_id in {estimate.with_name('benchmark.json')}") |
There was a problem hiding this comment.
P1: estimate.with_name('benchmark.json') points into the new/ directory (/new/benchmark.json), but Criterion stores benchmark.json as a sibling of new/ and base/ (/benchmark.json). load_json will fail on every estimate, so collect_criterion always raises BenchError and the rust-wall measurement job always fails. Use estimate.parent.parent / 'benchmark.json'.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At scripts/bench_results.py, line 118:
<comment>estimate.with_name('benchmark.json') points into the new/ directory (<id>/new/benchmark.json), but Criterion stores benchmark.json as a sibling of new/ and base/ (<id>/benchmark.json). load_json will fail on every estimate, so collect_criterion always raises BenchError and the rust-wall measurement job always fails. Use estimate.parent.parent / 'benchmark.json'.</comment>
<file context>
@@ -115,8 +115,9 @@ def collect_criterion(root: Path, output: Path, git_sha: str, since: Path) -> No
continue
- relative = estimate.relative_to(root)
- name = "/".join(relative.parts[:-2])
+ name = load_json(estimate.with_name("benchmark.json")).get("full_id")
+ if not isinstance(name, str) or not name:
+ raise BenchError(f"missing full_id in {estimate.with_name('benchmark.json')}")
</file context>
| name = load_json(estimate.with_name("benchmark.json")).get("full_id") | |
| if not isinstance(name, str) or not name: | |
| raise BenchError(f"missing full_id in {estimate.with_name('benchmark.json')}") | |
| benchmark = load_json(estimate.parent.parent / "benchmark.json") | |
| name = benchmark.get("full_id") | |
| if not isinstance(name, str) or not name: | |
| raise BenchError(f"missing full_id in {estimate.parent.parent / 'benchmark.json'}") |
|
@cubic-dev-ai’s latest |
|
@greptileai rereview |
Closes #138
Adds the Bench workflow with three parallel measurement jobs, strict main-only baseline writes to
bench-data, and fork-safe PR comparison artifacts. Failed measurement tiers contribute an empty slice so successful tiers still reach comparison, while any incomplete main run leaves the baseline untouched.The workflow bootstraps
bench-dataon its first fully successful main run.Checks run locally:
python3 -m unittest discover -s bench -p "test_*.py"pnpm test:workflowsactionlint .github/workflows/bench.ymlgit diff --checkSummary by cubic
Adds a Bench CI workflow that closes #138 by running benchmarks on main and PRs, storing baseline results in
bench-data, and uploading a comparison artifact for each PR. The Gungraun collector parses tagged integerIrmetrics, the Criterion collector reads benchmark identifiers frombenchmark.json, and the baseline job pins its actions to immutable SHAs.scripts/run-benches.sh, shared by the workflow and the localjustrecipes.Written for commit d550803. Summary will update on new commits.