mirror of
https://github.com/max-sixty/worktrunk.git
synced 2026-09-14 20:00:38 +08:00
00ab0ffa26
Benchmark fixtures still encoded the benchmark that first needed each repository state, which left overlapping recipes and variants after the earlier harness consolidation. This change reduces the fixture catalog to two provenance-based bases: `Generated` builds an ordinary Git repository locally, while `Imported` copies the pinned `rust-lang/rust` corpus. Worktree, branch, and remote-ref populations remain parameters on `Generated`; prune candidates and backdrop are overlays that work with either base. The generated base deliberately combines heterogeneous worktree states, history-spread branches, and optional remote refs so ordinary list, completion, picker, first-output, alias, remove, and prune benchmarks can share it. Imported history-spread branches and clean base-tip worktrees carry their own commits, preserving the base populations without making them incidental prune candidates when overlays advance the default branch. The benchmark matrix now keeps single-factor contrasts: list scaling uses the 1- and 8-worktree endpoints; alias dispatch has a startup floor, two population endpoints, and one warm/cold variable-resolution pair; completion keeps one full-surface case; remove and prune vary cache or hook state only where the command exercises it. Historical recipes, redundant cache rows, and intermediate scaling points are removed. Manual setup paths live under `target/`, and the benchmark guide documents the resulting fixture and cache model. Tests: `cargo run -- hook pre-merge --yes` after merging current `main` (4,571 tests); targeted Criterion test-mode runs; `cargo test -p wt-perf`; benchmark check, clippy, formatting, and diff checks. > _This was written by Codex on behalf of max-sixty_
166 lines
5.9 KiB
YAML
166 lines
5.9 KiB
YAML
name: benchmarks
|
|
# Full criterion suite plus the time-series gist append. Runs ~80 min and
|
|
# checks performance, not correctness, so it stands apart from the PR/merge
|
|
# flow and from nightly's correctness checks: a slow or failing bench never
|
|
# gates a merge. The daily cron is the perf-history feed (it appends to the
|
|
# gist); workflow_dispatch covers on-demand runs against a chosen branch.
|
|
#
|
|
# Not run on PRs or pushes, so the daily run is the only signal that the bench
|
|
# harness still builds — create-issue-on-benchmark-failure surfaces a break.
|
|
#
|
|
# Runner version pinned; see ci.yaml header comment for rationale.
|
|
|
|
on:
|
|
schedule:
|
|
# 3:47 UTC daily. Off-peak, offset from nightly's 5:37 so the two long
|
|
# runs don't contend, and off :00 to be a good citizen w.r.t. GitHub's
|
|
# cron scheduler.
|
|
- cron: '47 3 * * *'
|
|
workflow_dispatch:
|
|
|
|
concurrency:
|
|
group: ${{ github.workflow }}-${{ github.ref }}
|
|
cancel-in-progress: false
|
|
|
|
env:
|
|
# Match ci.yaml/nightly.yaml: Swatinem/rust-cache hashes CARGO*/RUST* into
|
|
# the cache key, so the shared `test` cache only restores when these agree
|
|
# (see .github/CLAUDE.md).
|
|
CARGO_TERM_COLOR: always
|
|
CARGO_INCREMENTAL: 0
|
|
RUSTFLAGS: -C debuginfo=0
|
|
|
|
jobs:
|
|
benchmarks:
|
|
runs-on: ubuntu-24.04
|
|
steps:
|
|
- name: 📂 Checkout code
|
|
uses: actions/checkout@v7
|
|
|
|
- name: 💰 Cache
|
|
uses: Swatinem/rust-cache@v2
|
|
with:
|
|
# Restore the shared `test` cache (registry + deps), never save —
|
|
# `cargo bench` is release-profile so it rebuilds its own artifacts,
|
|
# but the dependency download/extract is still worth restoring.
|
|
prefix-key: v1-rust
|
|
shared-key: shared
|
|
cache-bin: "false"
|
|
save-if: false
|
|
|
|
- name: Install shells and jq
|
|
run: sudo apt-get update && sudo apt-get install -y zsh fish jq
|
|
|
|
- name: Install nushell
|
|
uses: hustcer/setup-nu@v3
|
|
with:
|
|
version: '0.114.1'
|
|
|
|
- name: 💰 Imported fixture cache
|
|
uses: actions/cache@v6
|
|
with:
|
|
# The fixture file pins the corpus revision. Including its hash keeps
|
|
# a prior corpus out of the cache after either constant changes.
|
|
path: target/wt-perf/bench-repos
|
|
key: bench-repos-imported-${{ runner.os }}-${{ hashFiles('benches/imported-fixture') }}
|
|
|
|
- name: 📊 Run benchmarks
|
|
run: cargo bench
|
|
|
|
- name: 📦 Upload benchmark results
|
|
uses: actions/upload-artifact@v7
|
|
with:
|
|
name: benchmark-results-${{ github.run_id }}
|
|
path: target/criterion
|
|
|
|
# Time-series benchmark store, owned by worktrunk-bot:
|
|
# https://gist.github.com/worktrunk-bot/19bb23cb9658722abfe69479d0a4f9bf
|
|
#
|
|
# Cron-only: workflow_dispatch runs aren't appended (would pollute the
|
|
# time series). Skipped on forks: the environment's secrets aren't exposed
|
|
# there.
|
|
#
|
|
# Its own job so the token stays off `benchmarks`. The copy this job reads
|
|
# is in the `tend` environment, whose policy admits `main` alone, so a job
|
|
# naming it is refused on every other ref — which would take
|
|
# workflow_dispatch against a chosen branch with it. A job GitHub skips
|
|
# never requests its environment, so the cron gate above keeps the gate off
|
|
# the dispatch path.
|
|
append-gist:
|
|
needs: benchmarks
|
|
if: github.repository_owner == 'max-sixty' && github.event_name == 'schedule'
|
|
runs-on: ubuntu-24.04
|
|
environment:
|
|
name: tend
|
|
# A secret scope, not a deploy target — see .github/CLAUDE.md.
|
|
deployment: false
|
|
permissions:
|
|
contents: read
|
|
steps:
|
|
- name: 📦 Download benchmark results
|
|
uses: actions/download-artifact@v8
|
|
with:
|
|
name: benchmark-results-${{ github.run_id }}
|
|
path: target/criterion
|
|
|
|
- name: 💾 Append results to gist
|
|
env:
|
|
GITHUB_TOKEN: ${{ secrets.TEND_BOT_TOKEN }}
|
|
GIST_ID: 19bb23cb9658722abfe69479d0a4f9bf
|
|
run: |
|
|
set -euo pipefail
|
|
timestamp="$(date -u +'%Y-%m-%dT%H:%M:%SZ')"
|
|
find target/criterion -path '*/new/estimates.json' -print0 \
|
|
| sort -z \
|
|
| xargs -0 -r jq -c --arg ts "$timestamp" --arg sha "$GITHUB_SHA" '
|
|
{
|
|
ts: $ts,
|
|
sha: $sha,
|
|
bench: (
|
|
input_filename
|
|
| sub("^target/criterion/"; "")
|
|
| sub("/new/estimates\\.json$"; "")
|
|
),
|
|
mean_ns: .mean.point_estimate,
|
|
stddev_ns: .std_dev.point_estimate
|
|
}
|
|
' > new-rows.jsonl
|
|
test -s new-rows.jsonl
|
|
git clone "https://x-access-token:${GITHUB_TOKEN}@gist.github.com/${GIST_ID}.git" /tmp/gist
|
|
cat new-rows.jsonl >> /tmp/gist/results.jsonl
|
|
git -C /tmp/gist \
|
|
-c user.name=worktrunk-bot \
|
|
-c user.email=worktrunk-bot@users.noreply.github.com \
|
|
commit -am "benchmarks: ${GITHUB_SHA::7}"
|
|
git -C /tmp/gist push
|
|
|
|
create-issue-on-benchmark-failure:
|
|
needs:
|
|
- benchmarks
|
|
- append-gist
|
|
if: always() && contains(needs.*.result, 'failure') && github.repository_owner == 'max-sixty' && github.event_name == 'schedule'
|
|
runs-on: ubuntu-24.04
|
|
environment:
|
|
name: tend
|
|
# A secret scope, not a deploy target — see .github/CLAUDE.md.
|
|
deployment: false
|
|
permissions:
|
|
contents: read
|
|
issues: write
|
|
steps:
|
|
- name: 📂 Checkout code
|
|
uses: actions/checkout@v7
|
|
|
|
- uses: JasonEtco/create-an-issue@v2
|
|
env:
|
|
# Use TEND_BOT_TOKEN for a consistent bot identity (per
|
|
# .github/CLAUDE.md) and so any future issue-triage automation can
|
|
# cascade off issue creation — events from the default GITHUB_TOKEN
|
|
# don't trigger other workflows.
|
|
GITHUB_TOKEN: ${{ secrets.TEND_BOT_TOKEN }}
|
|
LINK: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
|
|
with:
|
|
filename: .github/benchmark-failure.md
|
|
update_existing: true
|
|
search_existing: open
|