Configuration¶
Inputs¶
All inputs are configured in the workflow YAML under with:.
Required Inputs¶
github-tokenGitHub token for API access. Default:
${{ github.token }}. The token needspull-requests: writeandissues: writepermissions.
Conditional Inputs¶
results-pathPath to the directory containing downloaded ASV results. Required unless
comparison-text-fileis provided.
SHA Resolution¶
The action needs to know which commits to compare. There are several ways to provide this depending on the comparison mode:
For compare Mode (Default)¶
Option 1: Metadata File (Recommended)¶
metadata-filePath to a text file containing SHA mappings. Supports these keys:
main_sha=a1b2c3d4e5f67890abcdef1234567890abcdef12
pr_sha=e5f6g7h890abcdef1234567890abcdef12345678
Both main_sha= and base_sha= are accepted for the base commit. This is the
approach used by eOn and metatensor – the benchmark workflow writes this file
and includes it in the artifact.
Option 2: Explicit SHAs¶
base-shaBase commit SHA (the commit to compare against)
pr-shaPR head commit SHA
Explicit inputs override metadata file values if both are provided.
Option 3: Direct File Paths¶
base-fileDirect path to base result JSON file
pr-fileDirect path to PR result JSON file
Use this when files are not named by SHA prefix, or when you know the exact paths (e.g., from a matrix workflow).
For compare-many Mode¶
Option 1: Direct File Paths (Recommended)¶
baseline-fileDirect path to the baseline result JSON file
contender-filesComma-separated direct paths to contender result JSON files. Order must match
contender-labels.
Use this for cross-environment comparisons where the same commit is benchmarked in different environments (both result files share the same SHA prefix).
Option 2: SHA-Based Lookup¶
baseline-shaThe baseline commit SHA. Used to find the baseline result file by SHA prefix.
contender-shasComma-separated contender commit SHAs. Used to find contender result files by SHA prefix.
Use this when each contender ran a different commit.
Comparison Mode¶
comparison-modeEither
compare(default, two-way) orcompare-many(multi-way baseline vs multiple contenders).
YAML-Based Pipeline Inputs¶
These inputs let the action run benchmarks before comparing. Each entry can include environment activation via two fields:
run-prefix– A wrapper command prepended with a space. Use this for tools like pixi, conda, or nix that wrap the command.setup– A shell command prepended with&&. Use this for sourcing scripts, exporting variables, or activating virtualenvs.
Both can be combined. The {sha} placeholder is replaced in all three
fields. The constructed shell command is:
bash -c '<setup with {sha}> && <run-prefix with {sha}> <benchmark-command with {sha}>'
Each part is optional – omit what you don’t need. If an entry has no sha,
benchmarking is skipped for that entry (useful when results already exist).
Contender benchmarks run in parallel via Promise.all. If your builds
modify shared state (same build directory), use setup to isolate them.
Init command¶
Use init-command to run a one-time setup before any benchmarks:
init-command: pixi run bash -c "pip install asv && asv machine --yes"
This runs once, before any baseline or contender benchmarks.
Build pattern (C++, Fortran, Rust)¶
Use setup with {sha} to checkout and build per-commit:
baseline: |
label: main
sha: abc123def
setup: >-
git checkout -f {sha} && git clean -fd &&
meson setup bbdir --prefix=$CONDA_PREFIX --buildtype release --wipe 2>/dev/null ||
meson setup bbdir --prefix=$CONDA_PREFIX --buildtype release &&
meson install -C bbdir
run-prefix: pixi run
The {sha} placeholder is replaced in setup, run-prefix, and
benchmark-command. This enables one action step to handle checkout,
build, and benchmark for each entry.
Wrapper pattern (pixi, conda, nix)¶
Use run-prefix. The tool wraps the entire benchmark command:
baseline: |
label: main
sha: abc123def
run-prefix: pixi run -e bench
This runs: pixi run -e bench asv run --record-samples abc123def^!
Source pattern (virtualenv, shell scripts)¶
Use setup. The script runs first, then the benchmark command:
baseline: |
label: main
sha: abc123def
setup: source ./envs/bench.sh
This runs: source ./envs/bench.sh && asv run --record-samples abc123def^!
Combined (e.g. env vars + wrapper)¶
contenders: |
- label: pr-debug
sha: def456abc
setup: export CFLAGS="-O0 -g"
run-prefix: pixi run -e bench-debug
This runs: export CFLAGS”-O0 -g” && pixi run -e bench-debug asv run –record-samples def456abc^!=
Field Reference¶
baselineYAML string defining the baseline entry. Fields:
label(string) – Display label for the baseline column.sha(string) – Commit SHA for benchmarking and result lookup.file(string) – Direct path to a result JSON file (bypasses SHA lookup).run-prefix(string) – Wrapper command prepended to benchmark command (e.g.pixi run -e bench,conda run -n bench,nix develop -c).setup(string) – Shell command sourced before the benchmark command (e.g.source ./envs/bench.sh,export CC=gcc-12).env(string) – Environment name shown in PR comment details.description(string) – Human-readable description shown in PR comment.
When
baselineis provided, it overridesbaseline-sha,baseline-file, andbaseline-label.contendersYAML list of contender objects. Each object accepts the same fields as
baseline(label, sha, file, run-prefix, setup, env, description). Works in bothcomparemode (first contender used as the “after” side) andcompare-manymode (all contenders compared against baseline). When provided, this overridescontender-shas,contender-files, andcontender-labels.init-commandShell command run once before any benchmarks. Use for one-time setup like
asv machine --yesor stashing benchmark suites.preserve-pathsComma-separated paths to preserve across git checkouts. When an entry has a
shafield, the action runsgit checkout -f {sha} && git clean -fdautomatically. These paths are stashed to/tmpbefore checkout and restored after. Example:
preserve-paths: benchmarks/, asv.conf.json
This eliminates the need for manual cp / stash boilerplate in setup.
Without preserve-paths, the action does not run git checkout at all –
the setup field must handle it.
benchmark-commandShell command template for running benchmarks. Default:
asv run --record-samples {sha}^!. The placeholder{sha}is replaced in this field,setup, andrun-prefix. Each entry’srun-prefixis prepended andsetupis sourced before this command. Entries without ashafield skip benchmarking.Example with a custom command:
benchmark-command: 'asv run --quick {sha}^!'
Full Pipeline with C++ Build (Single Job)¶
Use preserve-paths to automatically stash/restore files across git
checkouts. The setup field handles only the build – no checkout or copy
boilerplate needed.
- uses: prefix-dev/setup-pixi@v0.8.10
with:
activate-environment: true
- uses: HaoZeke/asv-perch@v1
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
results-path: .asv/results/
init-command: pixi run bash -c "pip install asv && asv machine --yes"
preserve-paths: benchmarks/, asv.conf.json
benchmark-command: >-
asv run -E "existing:$(which python)"
--set-commit-hash {sha} --record-samples --quick
baseline: |
label: main
sha: ${{ github.event.pull_request.base.sha }}
setup: >-
pixi run bash -c "meson setup bbdir
--prefix=$CONDA_PREFIX --libdir=lib
--buildtype release --wipe 2>/dev/null
|| meson setup bbdir --prefix=$CONDA_PREFIX
--libdir=lib --buildtype release" &&
pixi run meson install -C bbdir
run-prefix: pixi run
contenders: |
- label: pr
sha: ${{ github.event.pull_request.head.sha }}
setup: >-
pixi run bash -c "meson setup bbdir
--prefix=$CONDA_PREFIX --libdir=lib
--buildtype release --wipe 2>/dev/null
|| meson setup bbdir --prefix=$CONDA_PREFIX
--libdir=lib --buildtype release" &&
pixi run meson install -C bbdir
run-prefix: pixi run
label-before: main
label-after: pr
runner-info: ubuntu-22.04
Full Pipeline with C++ Build (Matrix – Parallel)¶
For parallel execution, use a matrix strategy with a combine job. Each SHA gets its own runner. The commenter downloads combined results.
jobs:
benchmark:
strategy:
fail-fast: false
matrix:
include:
- label: main
sha: ${{ github.event.pull_request.base.sha }}
- label: pr
sha: ${{ github.event.pull_request.head.sha }}
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Checkout target
run: |
mkdir -p /tmp/_bench_preserve
cp -r benchmarks/ /tmp/_bench_preserve/
cp asv.conf.json /tmp/_bench_preserve/
git checkout -f ${{ matrix.sha }}
git clean -fd
cp -r /tmp/_bench_preserve/benchmarks/ benchmarks/
cp /tmp/_bench_preserve/asv.conf.json asv.conf.json
- uses: prefix-dev/setup-pixi@v0.8.10
with:
activate-environment: true
- name: Build and benchmark
run: |
pixi run bash -c "meson setup bbdir \
--prefix=$CONDA_PREFIX --libdir=lib \
--buildtype release --wipe 2>/dev/null \
|| meson setup bbdir --prefix=$CONDA_PREFIX \
--libdir=lib --buildtype release"
pixi run meson install -C bbdir
pixi run bash -c "pip install asv && asv machine --yes"
pixi run asv run -E "existing:$(which python)" \
--set-commit-hash ${{ matrix.sha }} \
--record-samples --quick
- uses: actions/upload-artifact@v4
with:
name: bench-${{ matrix.label }}
path: .asv/results/
combine:
needs: benchmark
runs-on: ubuntu-latest
steps:
- uses: astral-sh/setup-uv@v5
- uses: actions/download-artifact@v4
with:
name: bench-main
path: results/
- uses: actions/download-artifact@v4
with:
name: bench-pr
path: results/
- name: Compare and write metadata
run: |
BASE_FILE=$(find results -name "${{ github.event.pull_request.base.sha | truncate 8 }}*.json" | head -1)
PR_FILE=$(find results -name "${{ github.event.pull_request.head.sha | truncate 8 }}*.json" | head -1)
uvx --from "git+https://github.com/airspeed-velocity/asv_spyglass.git" \
asv-spyglass compare "$BASE_FILE" "$PR_FILE" \
--label-before main --label-after pr > results/comparison.txt
echo "main_sha=${{ github.event.pull_request.base.sha }}" > results/metadata.txt
echo "pr_sha=${{ github.event.pull_request.head.sha }}" >> results/metadata.txt
- uses: actions/upload-artifact@v4
with:
name: benchmark-results
path: results/
The commenter workflow then downloads benchmark-results and posts the
comment. See the Getting Started tutorial.
Pre-computed Output¶
comparison-text-filePath to a pre-computed comparison output file. When provided, the action skips running asv-spyglass entirely and parses this file directly. Both
results-pathand SHA inputs become optional.
You can also place a file named comparison.txt inside results-path for the
same effect (checked before running asv-spyglass in compare mode).
Comparison Options¶
asv-spyglass-refGit ref (branch or tag) for
asv-spyglassinstallation. Default:main. The action installs asv-spyglass viauvx --from "git+https://github.com/airspeed-velocity/asv_spyglass.git@<ref>".label-before/label-afterLabels for the before/after columns in the comparison. Default:
main/pr. Passed toasv-spyglass compare --label-before / --label-after. Only used incomparemode.baseline-labelLabel for the baseline column in
compare-manymode. Passed toasv-spyglass compare-many --label(baseline first).contender-labelsComma-separated labels for each contender, matching the order of
contender-shas. Each label is passed as an additional--labelargument toasv-spyglass compare-many.asv-spyglass-argsExtra CLI flags passed through to asv-spyglass (e.g.,
--split --only-changed --factor 1.05). Space-separated. See Custom ASV Flags for details.
Regression Detection¶
regression-thresholdRatio above which a benchmark counts as a critical regression. Default:
10. For example, if a benchmark’s ratio is 15.0 (15x slower), and the threshold is 10, it is flagged as critical.auto-draft-on-regressionWhen set to
'true'and a critical regression is detected, the action converts the PR to draft status via the GitHub GraphQL API. Default:'false'. This prevents accidental merges of severely regressed code.
Outputs¶
Output |
Type |
Description |
|---|---|---|
|
string |
Raw asv-spyglass comparison output |
|
string |
|
|
string |
GitHub comment ID (empty if no PR found) |
|
string |
PR number (empty if no PR found) |
Use these in subsequent steps:
- name: Post benchmark comment
id: bench
uses: HaoZeke/asv-perch@v1
with:
# ...
- name: Fail on regression
if: steps.bench.outputs.regression-detected == 'true'
run: exit 1
Full Examples¶
Two-Way Comparison¶
- name: Post benchmark comment
uses: HaoZeke/asv-perch@v1
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
results-path: results/
metadata-file: results/metadata.txt
regression-threshold: '10'
auto-draft-on-regression: 'true'
label-before: main
label-after: pr
runner-info: ubuntu-22.04
dashboard-url: https://my-project.github.io/benchmarks/
asv-spyglass-ref: main
Multi-Way Comparison¶
- name: Post benchmark comment
uses: HaoZeke/asv-perch@v1
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
results-path: results/
comparison-mode: compare-many
baseline-sha: ${{ env.BASELINE_SHA }}
contender-shas: '${{ env.OPT_SHA }}, ${{ env.DEBUG_SHA }}'
baseline-label: default
contender-labels: 'optimized, debug'
runner-info: ubuntu-latest
Full Pipeline with pixi (run-prefix)¶
- uses: prefix-dev/setup-pixi@v0.8.0
- name: Benchmark and compare
uses: HaoZeke/asv-perch@v1
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
results-path: .asv/results/
comparison-mode: compare-many
baseline: |
label: main
sha: ${{ env.BASE_SHA }}
run-prefix: pixi run -e bench
contenders: |
- label: pr
sha: ${{ env.PR_SHA }}
run-prefix: pixi run -e bench
- label: pr-debug
sha: ${{ env.PR_SHA }}
run-prefix: pixi run -e bench-debug
description: Debug build with sanitizers
runner-info: ubuntu-latest
Full Pipeline with virtualenv (setup)¶
- name: Benchmark and compare
uses: HaoZeke/asv-perch@v1
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
results-path: .asv/results/
comparison-mode: compare-many
baseline: |
label: main
sha: ${{ env.BASE_SHA }}
setup: source ./envs/bench.sh
contenders: |
- label: pr
sha: ${{ env.PR_SHA }}
setup: source ./envs/bench.sh
runner-info: ubuntu-latest
Pre-computed Output¶
- name: Post benchmark comment
uses: HaoZeke/asv-perch@v1
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
comparison-text-file: comparison.txt
base-sha: ${{ env.BASE_SHA }}
pr-sha: ${{ env.PR_SHA }}
Comment Formatting¶
comment-markerHTML comment used to identify the benchmark comment for idempotent updates. Default:
<!-- asv-benchmark-result -->. Change this only if you have multiple benchmark actions posting to the same PR.runner-infoText shown in the “Details” section indicating which runner produced the results. Default:
ubuntu-latest.dashboard-urlURL to an ASV dashboard. If provided, a “View full results” link is added to the details section.