name: perf
on:
pull_request:
push:
branches: [main]
workflow_dispatch:
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
permissions:
contents: read
env:
CARGO_TERM_COLOR: always
jobs:
measure:
name: measure
runs-on: [self-hosted, bbtree-perf]
timeout-minutes: 30
defaults:
run:
shell: nix develop .#bench --command bash -euo pipefail {0}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
persist-credentials: false
- name: Choose the base
env:
PULL_REQUEST_BASE: ${{ github.event.pull_request.base.sha }}
PUSHED_OVER: ${{ github.event.before }}
run: |
case "$GITHUB_EVENT_NAME" in
pull_request) base=$PULL_REQUEST_BASE ;;
# All zeros when the push made the branch: no base.
push) [[ $PUSHED_OVER =~ ^0+$ ]] && base="" || base=$PUSHED_OVER ;;
*) base=$(git rev-parse --verify --quiet HEAD^ || true) ;;
esac
echo "BASE=$base" >> "$GITHUB_ENV"
- name: Build the bench
working-directory: bench
run: cargo build --release --bin bbtree-bench
- name: Measure this commit
run: bench/target/release/bbtree-bench ci --perf --out "$RUNNER_TEMP/head"
- name: Measure the base
if: env.BASE != ''
run: |
mkdir -p "$RUNNER_TEMP/base"
kept="$RUNNER_NAME/$BASE.csv"
if git fetch --quiet --depth=1 origin bench-data &&
git show "FETCH_HEAD:$kept" > "$RUNNER_TEMP/base/kept-timing.csv" 2>/dev/null; then
echo "BASE_SOURCE=main's run" >> "$GITHUB_ENV"
else
rm -f "$RUNNER_TEMP/base/kept-timing.csv"
# This machine keeps its checkout between jobs but empties
# RUNNER_TEMP, so a past job's worktree is registered and gone.
git worktree prune
git worktree add --detach "$RUNNER_TEMP/base-source" "$BASE"
cd "$RUNNER_TEMP/base-source/bench"
if cargo build --release --bin bbtree-bench &&
target/release/bbtree-bench ci --perf --out "$RUNNER_TEMP/base"; then
echo "BASE_SOURCE=measured here" >> "$GITHUB_ENV"
else
echo "::warning::The base couldn't be measured; the report shows this commit alone"
rm -rf "$RUNNER_TEMP/base"
fi
fi
- name: Write the report
env:
PULL_REQUEST_HEAD: ${{ github.event.pull_request.head.sha }}
run: |
head_csv=$(echo "$RUNNER_TEMP"/head/*-timing.csv)
base_csv=$(echo "$RUNNER_TEMP"/base/*-timing.csv 2>/dev/null || true)
compare=(--head "$head_csv")
if [ -f "$base_csv" ]; then
compare+=(--base "$base_csv")
base_line="base \`${BASE:0:12}\` (${BASE_SOURCE})"
else
base_line="no base"
fi
if [ -n "$PULL_REQUEST_HEAD" ]; then
head_line="head \`${PULL_REQUEST_HEAD:0:12}\` merged into its base"
else
head_line="head \`${GITHUB_SHA:0:12}\`"
fi
cpu=$(sed -n 's/^model name\s*: //p' /proc/cpuinfo | head -1)
out="$RUNNER_TEMP/perf-report"
mkdir -p "$out/results/$RUNNER_NAME"
{
echo "### Performance: bbtree against std's BTreeMap"
echo
echo "The bench's \`ci\` suite, $head_line, $base_line, on $RUNNER_NAME ($cpu)."
echo "A report only: nothing here fails the pull request."
echo
bench/target/release/bbtree-bench compare "${compare[@]}"
} > "$out/report.md"
cp "$head_csv" "$out/results/$RUNNER_NAME/$GITHUB_SHA.csv"
cp "${head_csv%.csv}.md" "$out/results/$RUNNER_NAME/$GITHUB_SHA.md"
cat "$out/report.md" >> "$GITHUB_STEP_SUMMARY"
- uses: actions/upload-artifact@v4
with:
name: perf-report
path: ${{ runner.temp }}/perf-report
retention-days: 30
comment:
name: comment
needs: measure
if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository
runs-on: ubuntu-latest
permissions:
pull-requests: write
steps:
- uses: actions/download-artifact@v4
with:
name: perf-report
- name: Comment on the pull request
env:
GH_TOKEN: ${{ github.token }}
PULL_REQUEST: ${{ github.event.pull_request.number }}
run: |
gh pr comment "$PULL_REQUEST" --repo "$GITHUB_REPOSITORY" \
--body-file report.md --edit-last --create-if-none
record:
name: record
needs: measure
if: github.event_name != 'pull_request' && github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
permissions:
contents: write
concurrency:
group: bench-data
cancel-in-progress: false
steps:
- uses: actions/checkout@v4
- uses: actions/download-artifact@v4
with:
name: perf-report
path: ${{ runner.temp }}/perf-report
- name: Commit the results to bench-data
run: |
if git fetch --depth=1 origin bench-data; then
git switch --detach FETCH_HEAD
else
git switch --orphan bench-data
fi
cp -r "$RUNNER_TEMP/perf-report/results/." .
git add --all
# A re-run of a commit replaces its results.
if git diff --cached --quiet; then
echo "bench-data already has these results"
exit 0
fi
git -c user.name="github-actions[bot]" \
-c user.email="41898282+github-actions[bot]@users.noreply.github.com" \
commit --quiet --message "Results of $GITHUB_SHA"
git push origin HEAD:refs/heads/bench-data