Skip to content

fix(parser): object-literal async shorthand methods now track async-f… #72

fix(parser): object-literal async shorthand methods now track async-f…

fix(parser): object-literal async shorthand methods now track async-f… #72

Workflow file for this run

name: Perf Timeline
# Records one immutable benchmark snapshot per commit on the dedicated, unprotected
# `perf-data` branch (NOT main — keeps main clean and dodges branch protection).
# The "Are we fast yet?" page (pages.yml) reads these at deploy time. Each snapshot
# is anchor-normalized, so the trend is meaningful across varying CI runners.
on:
push:
branches: [main]
paths-ignore:
- 'docs/perf/index.html'
- 'docs/perf/timeline/**'
# Manual backfill: dispatch once per historical commit to fill the timeline.
# Snapshot identity is derived from the checked-out HEAD (sha + commit time),
# so the rest of the job is commit-agnostic.
workflow_dispatch:
inputs:
ref:
description: 'Commit SHA/ref to snapshot (backfill)'
required: true
default: 'main'
test262:
description: 'Also run the ~4-min Test262 macro benchmark'
type: boolean
default: false
permissions:
contents: write
concurrency:
group: perf-timeline-main
# Serialize snapshot runs — they push to the perf-data branch, which can't take
# concurrent writers. Forward-only (one snapshot per push) means no backfill
# bursts to queue, so cancel-in-progress: false is enough.
cancel-in-progress: false
jobs:
snapshot:
if: github.actor != 'github-actions[bot]'
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Check out target ref
env:
TARGET_REF: ${{ github.event.inputs.ref || github.sha }}
run: |
# A short SHA is read by actions/checkout as a branch name and fails;
# fetch-depth:0 pulled everything, so resolve any committish locally.
git checkout --force "$TARGET_REF"
# Corpus for the opt-in Test262 macro series (see "Add Test262 macro" below).
# Gated on the same condition so non-opted-in commits skip the restore.
- name: Cache Test262 corpus
if: contains(github.event.head_commit.message, '[perf-test262]') || github.event.inputs.test262 == 'true'
uses: actions/cache@v4
with:
path: test262
key: test262-${{ hashFiles('.test262-rev') }}
restore-keys: test262-
- uses: actions/setup-go@v5
with:
go-version-file: go.mod
- name: Capture snapshot
id: snap
run: |
set -euo pipefail
short_sha="$(git rev-parse --short=12 HEAD)"
commit_epoch="$(git show -s --format=%ct HEAD)"
stamp="$(date -u -d "@${commit_epoch}" +%Y%m%dT%H%M%SZ)"
name="${stamp}-${short_sha}.json"
out="${RUNNER_TEMP}/${name}"
go run ./cmd/bench-ratchet \
-count 3 -benchtime 1s -timeout 20m \
-baseline "${out}" \
snapshot
echo "name=${name}" >> "$GITHUB_OUTPUT"
echo "out=${out}" >> "$GITHUB_OUTPUT"
# Opt-in: fold the Test262 macro-benchmark into the snapshot as a
# `test262.total` series. Runs only on commits whose message carries
# `[perf-test262]`, or a manual dispatch with the `test262` input checked,
# since the macro adds ~4 min. Non-fatal: a macro hiccup must never drop
# the micro snapshot above.
- name: Add Test262 macro to snapshot
if: contains(github.event.head_commit.message, '[perf-test262]') || github.event.inputs.test262 == 'true'
continue-on-error: true
env:
PER_TEST_TIMEOUT: 1.2s
run: |
set -euo pipefail
out="${{ steps.snap.outputs.out }}"
./setup-test262.sh
./scripts/macro-test262.sh "${RUNNER_TEMP}/t262.jsonl" "${RUNNER_TEMP}/t262.stats.json"
# JSONL: one record per line, so filter per-line — no -s slurp needed.
total_ns="$(jq 'select(.name=="total") | .ns_per_op' "${RUNNER_TEMP}/t262.jsonl")"
passed="$(jq 'select(.name=="total") | .iterations' "${RUNNER_TEMP}/t262.jsonl")"
set_hash="$(jq -r 'select(.name=="total") | .set_hash // ""' "${RUNNER_TEMP}/t262.jsonl")"
anchor_ns="$(jq -r '.anchor.ns_per_op' "$out")"
# Skip the fold if nothing passed — mean over an empty set is undefined
# (and the series would carry no signal anyway).
if [ "${passed:-0}" -gt 0 ]; then
# Metric is the MEAN per-test ns (summed_ns / passing_count), not the sum:
# the sum conflates per-test speed with how many tests pass, so a
# conformance win (more passing tests add their durations) reads as a perf
# regression. The mean removes that count-inflation. set_hash fingerprints
# the exact contributing set (from bench-test262, #24), so the consumer can
# still see a residual composition shift the mean can't cancel. Anchor-
# normalized like every other series; the page plots each self-relative, so
# the absolute ratio doesn't affect chart scale.
jq --argjson ns "$total_ns" --argjson a "$anchor_ns" --argjson p "$passed" --arg h "$set_hash" '
($ns / $p) as $mean
| .benchmarks["test262.total"] = ({
ns_per_op: $mean, allocs_per_op: 0, bytes_per_op: 0,
ratio_to_anchor: ($mean / $a),
samples: [{ iterations: $p, ns_per_op: $mean, ratio_to_anchor: ($mean / $a) }]
} + (if $h == "" then {} else { set_hash: $h } end))' "$out" > "${out}.tmp"
mv "${out}.tmp" "$out"
echo "test262.total: mean $(jq -r '.benchmarks["test262.total"].ns_per_op' "$out") ns/test" \
"over ${passed} passing tests (set ${set_hash:-none}," \
"ratio $(jq -r '.benchmarks["test262.total"].ratio_to_anchor' "$out"))"
fi
- name: Render run summary
run: |
src="${{ steps.snap.outputs.out }}"
{
echo "## Snapshot ${{ steps.snap.outputs.name }}"
echo
echo "anchor \`$(jq -r '.anchor.ns_per_op' "$src")\` ns/op · machine \`$(jq -r '.machine.cpu_model' "$src")\` · go \`$(jq -r '.machine.go_version' "$src")\`"
echo
echo "| Benchmark | Anchor× | Wall (ns/op) | Allocs/op |"
echo "|---|---:|---:|---:|"
jq -r '.benchmarks | to_entries | sort_by(-.value.ratio_to_anchor)[]
| "| \(.key | sub("github.com/nooga/paserati/";"")) | \((.value.ratio_to_anchor*1000|round)/1000) | \(.value.ns_per_op|round) | \(.value.allocs_per_op) |"' "$src"
} >> "$GITHUB_STEP_SUMMARY"
- name: Publish to perf-data branch
run: |
set -euo pipefail
name="${{ steps.snap.outputs.name }}"
src="${{ steps.snap.outputs.out }}"
remote="https://x-access-token:${{ github.token }}@github.com/${{ github.repository }}.git"
wt="${RUNNER_TEMP}/perf-data"
if git ls-remote --exit-code --heads "$remote" perf-data >/dev/null 2>&1; then
git clone --depth 1 --branch perf-data "$remote" "$wt"
else
# First run: orphan branch with no history/files.
git clone --depth 1 "$remote" "$wt"
git -C "$wt" checkout --orphan perf-data
git -C "$wt" rm -rf . >/dev/null 2>&1 || true
fi
mkdir -p "$wt/timeline"
cp "$src" "$wt/timeline/$name"
git -C "$wt" config user.name "github-actions[bot]"
git -C "$wt" config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git -C "$wt" add timeline
if git -C "$wt" diff --cached --quiet; then
echo "snapshot already present — nothing to publish"
exit 0
fi
git -C "$wt" commit -m "perf: snapshot ${name}"
git -C "$wt" push "$remote" HEAD:perf-data