Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
179 changes: 179 additions & 0 deletions .github/workflows/llgo-runtime-performance.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
name: LLGo runtime performance

on:
repository_dispatch:
types: [llgo-tag-released]

permissions:
contents: read

concurrency:
group: llgo-runtime-performance
cancel-in-progress: false

jobs:
benchmark:
runs-on: ubuntu-24.04
timeout-minutes: 90
permissions:
contents: write
steps:
- uses: actions/checkout@v4

- name: Validate the LLGo release notification
env:
DISPATCH_SOURCE_REPOSITORY: ${{ github.event.client_payload.source_repository }}
DISPATCH_LLGO_REPOSITORY: ${{ github.event.client_payload.llgo_repository }}
DISPATCH_LLGO_COMMIT: ${{ github.event.client_payload.llgo_commit }}
DISPATCH_LLGO_TAG: ${{ github.event.client_payload.llgo_tag }}
run: |
set -euo pipefail
set -a
source ci/llgo-size/llgo-version.env
set +a

if [[ "$DISPATCH_SOURCE_REPOSITORY" != "xgo-dev/llgo" || \
"$DISPATCH_LLGO_REPOSITORY" != "xgo-dev/llgo" ]]; then
echo "refusing LLGo release notification from ${DISPATCH_SOURCE_REPOSITORY:-unknown}" >&2
exit 1
fi
if [[ ! "$DISPATCH_LLGO_COMMIT" =~ ^[0-9a-f]{40}$ ]]; then
echo "invalid released LLGo commit: ${DISPATCH_LLGO_COMMIT:-missing}" >&2
exit 1
fi
if ! git check-ref-format "refs/tags/$DISPATCH_LLGO_TAG"; then
echo "invalid released LLGo tag: ${DISPATCH_LLGO_TAG:-missing}" >&2
exit 1
fi

printf 'LLGO_REPOSITORY=%s\n' "$DISPATCH_LLGO_REPOSITORY" >> "$GITHUB_ENV"
printf 'LLGO_COMMIT=%s\n' "$DISPATCH_LLGO_COMMIT" >> "$GITHUB_ENV"
printf 'LLGO_TAG=%s\n' "$DISPATCH_LLGO_TAG" >> "$GITHUB_ENV"
printf 'GO_VERSION=%s\n' "$GO_VERSION" >> "$GITHUB_ENV"
printf 'LLVM_VERSION=%s\n' "$LLVM_VERSION" >> "$GITHUB_ENV"
printf 'LLGO_PERFORMANCE_REPETITIONS=5\n' >> "$GITHUB_ENV"
mkdir -p .ci
printf '%s\n' "$GO_VERSION" > .ci/go-version

- uses: actions/setup-go@v5
with:
go-version-file: .ci/go-version

- name: Install LLVM dependencies
run: |
set -euo pipefail
ubuntu_sources=/etc/apt/sources.list.d/ubuntu.sources
if [[ -f "$ubuntu_sources" ]]; then
sudo sed -i \
-e 's|mirror+file:/etc/apt/apt-mirrors.txt|https://archive.ubuntu.com/ubuntu|g' \
-e 's|http://azure.archive.ubuntu.com/ubuntu|https://archive.ubuntu.com/ubuntu|g' \
"$ubuntu_sources"
fi
apt_options=(
-o Acquire::Retries=3
-o Acquire::http::Timeout=30
-o Acquire::https::Timeout=30
-o DPkg::Lock::Timeout=60
)
sudo timeout --kill-after=30s 5m apt-get "${apt_options[@]}" update
sudo timeout --kill-after=30s 15m apt-get "${apt_options[@]}" install -y \
clang-${LLVM_VERSION} lld-${LLVM_VERSION} llvm-${LLVM_VERSION}-dev \
libuv1-dev libgc-dev libffi-dev

- name: Build the released LLGo compiler
run: |
set -euo pipefail
git clone --filter=blob:none --no-checkout "https://github.com/${LLGO_REPOSITORY}.git" .ci/llgo
git -C .ci/llgo fetch --no-tags --depth=1 origin \
"refs/tags/$LLGO_TAG:refs/tags/$LLGO_TAG"
tag_commit=$(git -C .ci/llgo rev-parse "refs/tags/$LLGO_TAG^{commit}")
if [[ "$tag_commit" != "$LLGO_COMMIT" ]]; then
echo "LLGo tag $LLGO_TAG points to $tag_commit, not dispatched $LLGO_COMMIT" >&2
exit 1
fi
git -C .ci/llgo checkout --detach "$LLGO_COMMIT"
export GOROOT="$(go env GOROOT)"
export PATH="$GOROOT/bin:/usr/lib/llvm-${LLVM_VERSION}/bin:$PATH"
export LLGO_ROOT="$GITHUB_WORKSPACE/.ci/llgo"
(cd "$LLGO_ROOT" && go build -tags=dev -o "$LLGO_ROOT/llgo" ./cmd/llgo)

- name: Run the selected Bent comparison
env:
LLGO_BIN: ${{ github.workspace }}/.ci/llgo/llgo
LLGO_ROOT: ${{ github.workspace }}/.ci/llgo
run: |
set -euo pipefail
export GOROOT="$(go env GOROOT)"
export PATH="$GOROOT/bin:/usr/lib/llvm-${LLVM_VERSION}/bin:$PATH"
go build -o .ci/bent ./cmd/bent
GOBIN="$GITHUB_WORKSPACE/.ci/bin" \
go install golang.org/x/perf/cmd/benchstat@v0.0.0-20260813145340-fd4a688df892
mkdir -p .ci/bent-performance
(
cd .ci/bent-performance
"$GITHUB_WORKSPACE/.ci/bent" -I
"$GITHUB_WORKSPACE/.ci/bent" \
-B=benchmarks-llgo-performance.toml \
-C=configurations-llgo-performance.toml \
-N=5 -G
)
ci/llgo-performance/report.sh \
.ci/bent-performance \
.ci/bin/benchstat | tee -a "$GITHUB_STEP_SUMMARY"

- name: Upload Bent runtime results
if: always()
uses: actions/upload-artifact@v4
with:
name: llgo-runtime-performance
path: |
.ci/bent-performance/bench
.ci/bent-performance/benchstat.txt
.ci/bent-performance/benchstat.csv
.ci/bent-performance/results.json
if-no-files-found: warn

- name: Publish runtime performance history to Pages
env:
PAGES_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
set -euo pipefail
pages_dir="$GITHUB_WORKSPACE/.ci/pages"
bash ci/llgo-size/prepare-pages-branch.sh \
"$pages_dir" \
"https://x-access-token:${PAGES_TOKEN}@github.com/${GITHUB_REPOSITORY}.git"
ci/llgo-performance/publish.sh \
.ci/bent-performance \
"$pages_dir" \
ci/llgo-size/site

deploy-pages:
needs: benchmark
runs-on: ubuntu-24.04
permissions:
contents: read
pages: write
id-token: write
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
steps:
- name: Check out Pages source
uses: actions/checkout@v4
with:
ref: pages
path: pages-source
- name: Configure GitHub Pages
uses: actions/configure-pages@v5
- name: Build Pages with Jekyll
uses: actions/jekyll-build-pages@v1
with:
source: ./pages-source
destination: ./_site
- name: Upload Pages artifact
uses: actions/upload-pages-artifact@v4
with:
path: ./_site
- name: Deploy GitHub Pages
id: deployment
uses: actions/deploy-pages@v4
27 changes: 27 additions & 0 deletions ci/llgo-performance/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# LLGo runtime performance

This job compares the pinned Go and LLGo toolchains with Bent. It runs the
checked-in cases five times each, grouped by benchmark to reduce time-local
runner noise, and publishes the raw Bent output, native benchstat text/CSV, and
a structured result used by the runtime-performance Pages table. Benchstat uses
a 90% confidence interval because its default 95% interval requires at least
six samples.

It runs only after the `xgo-dev/llgo` release workflow publishes a new tag and
dispatches the exact tag and commit. Ordinary pushes and pull requests do not
start a performance run.

The selected set contains cases where LLGo or LLGo full LTO was faster in a
local `benchmarks-100.toml` survey, plus stable same-range cases that are useful
for tracking future optimization. The workflow checks sample completeness but
does not fail on a performance percentage because hosted-runner measurements
are not a reliable hard regression gate.

Each successful release run is stored under `data/performance/runs/<tag>/` on
the `pages` branch. The lightweight `performance.html` view follows benchstat's
layout: Go is the baseline, with LLGo and LLGo full-LTO values, confidence
ranges, deltas, and p-values shown side by side. The existing `index.html`
continues to show only binary size and build time.

The suite versions come from `cmd/bent/configs/suites.toml`. Keep those versions
pinned for comparable history; update them deliberately in a reviewed change.
102 changes: 102 additions & 0 deletions ci/llgo-performance/publish.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
#!/usr/bin/env bash
set -euo pipefail

run_dir=$1
pages_dir=$2
site_dir=$3
if [[ -z "$run_dir" || -z "$pages_dir" || -z "$site_dir" ]]; then
echo "usage: publish.sh RUN_DIR PAGES_DIR SITE_DIR" >&2
exit 2
fi

result_json="$run_dir/results.json"
for file in "$result_json" "$run_dir/benchstat.txt" "$run_dir/benchstat.csv"; do
if [[ ! -s "$file" ]]; then
echo "missing performance result: $file" >&2
exit 1
fi
done

run_key=$(python3 - "$result_json" <<'PY'
import json
import re
import sys

with open(sys.argv[1], encoding="utf-8") as source:
run = json.load(source)["run"]
key = str(run.get("llgoTag") or run.get("llgoCommit") or run.get("id") or "manual")
if not re.fullmatch(r"[A-Za-z0-9._-]+", key):
raise SystemExit("invalid performance run key: " + repr(key))
print(key)
PY
)

performance_dir="$pages_dir/data/performance"
published_run_dir="$performance_dir/runs/$run_key"
mkdir -p "$published_run_dir"
cp "$result_json" "$published_run_dir/results.json"
cp "$run_dir/benchstat.txt" "$published_run_dir/benchstat.txt"
cp "$run_dir/benchstat.csv" "$published_run_dir/benchstat.csv"
if [[ -d "$published_run_dir/raw" ]]; then
rm -r "$published_run_dir/raw"
fi
mkdir -p "$published_run_dir/raw"
if compgen -G "$run_dir/bench/*.stdout" >/dev/null; then
cp "$run_dir/bench/"*.stdout "$published_run_dir/raw/"
fi

python3 - "$performance_dir" <<'PY'
import glob
import json
import os
import sys
from datetime import datetime, timezone

data_dir = sys.argv[1]
runs = []
for path in glob.glob(os.path.join(data_dir, "runs", "*", "results.json")):
with open(path, encoding="utf-8") as source:
document = json.load(source)
run = document.get("run", {})
key = os.path.basename(os.path.dirname(path))
runs.append({
"key": key,
"id": run.get("id", ""),
"attempt": run.get("attempt"),
"createdAt": run.get("createdAt", ""),
"sourceCommit": run.get("sourceCommit", ""),
"llgoRepository": run.get("llgoRepository", ""),
"llgoCommit": run.get("llgoCommit", ""),
"llgoTag": run.get("llgoTag", ""),
"goVersion": run.get("goVersion", ""),
"llvmVersion": run.get("llvmVersion", ""),
"workflowUrl": run.get("workflowUrl", ""),
"path": "performance/runs/" + key + "/results.json",
})
runs.sort(key=lambda item: item["createdAt"], reverse=True)

index = {
"schemaVersion": 1,
"generatedAt": datetime.now(timezone.utc).isoformat().replace("+00:00", "Z"),
"runs": runs,
}
os.makedirs(data_dir, exist_ok=True)
with open(os.path.join(data_dir, "index.json"), "w", encoding="utf-8") as destination:
json.dump(index, destination, indent=2)
destination.write("\n")
PY

for file in index.html app.js performance.html performance.js style.css _config.yml; do
cp "$site_dir/$file" "$pages_dir/$file"
done
rm -f "$pages_dir/.nojekyll"

git -C "$pages_dir" config user.name "github-actions[bot]"
git -C "$pages_dir" config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git -C "$pages_dir" add -A
if git -C "$pages_dir" diff --cached --quiet; then
echo "Performance history is already up to date"
else
git -C "$pages_dir" commit -m "ci: publish LLGo performance run $run_key"
git -C "$pages_dir" push origin HEAD:pages
fi
Loading