name: Bench Readme
on:
workflow_dispatch:
pull_request:
paths:
- "README.md"
- "benches/**"
- "src/**"
- "Cargo.toml"
- "Cargo.lock"
- "scripts/update_readme_bench.sh"
- "scripts/readme_bench_tables.py"
- ".github/workflows/bench-readme.yml"
permissions:
contents: read
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
vs-bitvec-readme:
name: compare bench + README check
if: github.event_name == 'pull_request'
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
with:
toolchain: 1.86.0
- name: Cache cargo artifacts
uses: Swatinem/rust-cache@v2
- name: Run compare benchmarks
run: cargo bench --bench compare
- name: Check README benchmark tables
id: readme_check
run: |
set +e
scripts/update_readme_bench.sh --check-structure
status=$?
echo "status=$status" >> "$GITHUB_OUTPUT"
if [[ "${status}" -eq 1 ]]; then
echo "structural_mismatch=1" >> "$GITHUB_OUTPUT"
else
echo "structural_mismatch=0" >> "$GITHUB_OUTPUT"
fi
exit 0
- name: Render benchmark comment
id: bench_comment
if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.fork == false
run: |
set -euo pipefail
args=(--comment)
if [[ "${{ steps.readme_check.outputs.structural_mismatch }}" == "1" ]]; then
args+=(--readme-stale)
fi
python3 scripts/readme_bench_tables.py "${args[@]}" > "${RUNNER_TEMP}/bench-comment.md"
- name: Comment benchmark report on PR
if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.fork == false
uses: actions/github-script@v7
env:
COMMENT_PATH: ${{ runner.temp }}/bench-comment.md
with:
script: |
const fs = require("fs");
const marker = "<!-- bench-readme-check -->";
const body = fs.readFileSync(process.env.COMMENT_PATH, "utf8");
const { owner, repo } = context.repo;
const issue_number = context.payload.pull_request.number;
const comments = await github.paginate(
github.rest.issues.listComments,
{ owner, repo, issue_number, per_page: 100 }
);
const existing = comments.find(
(comment) =>
comment.user?.type === "Bot" &&
typeof comment.body === "string" &&
comment.body.includes(marker)
);
if (existing) {
await github.rest.issues.updateComment({
owner,
repo,
comment_id: existing.id,
body,
});
} else {
await github.rest.issues.createComment({
owner,
repo,
issue_number,
body,
});
}
vs-bitflags-smoke:
name: vs_bitflags benchmark smoke
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
with:
toolchain: 1.86.0
- name: Cache cargo artifacts
uses: Swatinem/rust-cache@v2
- name: Run vs_bitflags benchmarks
run: cargo bench --bench vs_bitflags -- --sample-size 20 --warm-up-time 0.1 --measurement-time 0.2
update-readme:
name: regenerate README benchmarks
if: github.event_name == 'workflow_dispatch'
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
steps:
- name: Checkout
uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 with:
persist-credentials: false
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@6bed0761d98439e5a578e2877258200ad565ba87 with:
toolchain: 1.86.0
- name: Cache cargo artifacts
uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6
- name: Run compare benchmarks
run: cargo bench --bench compare
- name: Regenerate README benchmark tables
id: readme
run: |
set -euo pipefail
scripts/update_readme_bench.sh
scripts/update_readme_bench.sh --check
if git diff --quiet -- README.md; then
echo "changed=false" >> "${GITHUB_OUTPUT}"
echo "::notice title=README unchanged::README.md benchmark tables are unchanged."
else
echo "changed=true" >> "${GITHUB_OUTPUT}"
fi
- name: Commit README and open or update pull request
if: steps.readme.outputs.changed == 'true'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GIT_AUTHOR_NAME: github-actions[bot]
GIT_AUTHOR_EMAIL: 41898282+github-actions[bot]@users.noreply.github.com
GIT_COMMITTER_NAME: github-actions[bot]
GIT_COMMITTER_EMAIL: 41898282+github-actions[bot]@users.noreply.github.com
run: |
set -euo pipefail
if [[ "${GITHUB_REF_NAME}" == "bench-readme-update" ]]; then
echo "::error::Dispatch from the branch that should receive the README, not bench-readme-update."
exit 1
fi
git add -- README.md
git commit -m "Update README benchmark tables from CI" -m "Source commit: ${GITHUB_SHA}"
gh auth setup-git
git push --force origin "HEAD:bench-readme-update"
os_name="$(awk -F= '/^PRETTY_NAME=/{ gsub(/"/, "", $2); print $2; exit }' /etc/os-release)"
cpu_name="$(lscpu | awk -F: '/^[Mm]odel name:/ { sub(/^[ \t]+/, "", $2); print $2; exit }')"
rustc_version="$(rustc --version)"
body_file="${RUNNER_TEMP}/bench-readme-pr.md"
{
echo "Benchmark numbers regenerated on a GitHub-hosted runner."
echo
echo "- OS: ${os_name}"
echo "- CPU: ${cpu_name}"
echo "- rustc: ${rustc_version}"
printf -- '- Commit: `%s`\n' "${GITHUB_SHA}"
echo
echo "These numbers come from a GitHub-hosted runner."
} > "${body_file}"
title="Update README benchmark tables"
existing="$(gh pr list --repo "${GITHUB_REPOSITORY}" --head bench-readme-update --state open --json number --jq '.[0].number // empty')"
if [[ -n "${existing}" ]]; then
gh pr edit "${existing}" --repo "${GITHUB_REPOSITORY}" --base "${GITHUB_REF_NAME}" --title "${title}" --body-file "${body_file}"
else
gh pr create --repo "${GITHUB_REPOSITORY}" --base "${GITHUB_REF_NAME}" --head bench-readme-update --title "${title}" --body-file "${body_file}"
fi