Skip to content

Add LLGo runtime performance job (#23) #270

Add LLGo runtime performance job (#23)

Add LLGo runtime performance job (#23) #270

name: LLGo binary size
on:
push:
branches:
- main
paths-ignore:
- ci/llgo-size/site/**
- ci/llgo-size/publish-site.sh
- ci/llgo-size/prepare-pages-branch.sh
- .github/workflows/llgo-binary-size-pages.yml
# ci/llgo-size/llgo-version.env is intentionally not ignored: changing
# the committed LLGo pin must trigger a binary-size build.
pull_request:
paths-ignore:
- ci/llgo-size/site/**
- ci/llgo-size/publish-site.sh
- ci/llgo-size/prepare-pages-branch.sh
- .github/workflows/llgo-binary-size-pages.yml
# GitHub evaluates repository-dispatch workflows from the receiving
# repository's default branch. Merge this workflow there before enabling
# the sender in xgo-dev/llgo.
repository_dispatch:
types: [llgo-main-updated]
workflow_dispatch:
inputs:
llgo_commit:
description: Optional full xgo-dev/llgo commit SHA to benchmark
required: false
type: string
permissions:
contents: read
actions: read
concurrency:
# Keep benchmark builds in their own queue. The Pages-only workflow has a
# separate queue; sharing one group would let a newer pending Pages run
# replace a pending binary-size run even with cancel-in-progress disabled.
group: llgo-binary-size-build
cancel-in-progress: false
jobs:
update-pin:
if: github.event_name == 'repository_dispatch'
permissions:
contents: write
actions: write
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
- name: Update the committed LLGo pin and start the build
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 }}
GH_TOKEN: ${{ github.token }}
run: |
set -euo pipefail
if [[ "$DISPATCH_SOURCE_REPOSITORY" != "xgo-dev/llgo" || \
"$DISPATCH_LLGO_REPOSITORY" != "xgo-dev/llgo" ]]; then
echo "refusing binary-size dispatch from ${DISPATCH_SOURCE_REPOSITORY:-unknown}" >&2
exit 1
fi
if [[ ! "$DISPATCH_LLGO_COMMIT" =~ ^[0-9a-f]{40}$ ]]; then
echo "invalid dispatched LLGo commit: ${DISPATCH_LLGO_COMMIT:-missing}" >&2
exit 1
fi
current_commit="$(awk -F= '$1 == "LLGO_COMMIT" { print $2 }' ci/llgo-size/llgo-version.env)"
if [[ "$current_commit" == "$DISPATCH_LLGO_COMMIT" ]]; then
echo "LLGo pin is already $DISPATCH_LLGO_COMMIT; no build needed"
exit 0
fi
sed -i "s/^LLGO_COMMIT=.*/LLGO_COMMIT=${DISPATCH_LLGO_COMMIT}/" \
ci/llgo-size/llgo-version.env
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git add ci/llgo-size/llgo-version.env
git commit -m "ci: pin LLGo ${DISPATCH_LLGO_COMMIT:0:12}"
git push origin HEAD:main
payload="$(jq -cn \
--arg ref main \
--arg llgo_commit "$DISPATCH_LLGO_COMMIT" \
'{ref: $ref, inputs: {llgo_commit: $llgo_commit}}')"
curl --fail-with-body --location --request POST \
--header 'Accept: application/vnd.github+json' \
--header "Authorization: Bearer ${GH_TOKEN}" \
--header 'X-GitHub-Api-Version: 2022-11-28' \
"https://api.github.com/repos/${GITHUB_REPOSITORY}/actions/workflows/llgo-binary-size.yml/dispatches" \
--data "$payload"
pr-scope:
if: github.event_name == 'pull_request'
permissions:
contents: read
runs-on: ubuntu-24.04
outputs:
full_matrix: ${{ steps.changed.outputs.full_matrix }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Detect an LLGo pin or benchmark-case change
id: changed
env:
BASE_SHA: ${{ github.event.pull_request.base.sha }}
PR_SHA: ${{ github.event.pull_request.head.sha }}
run: |
set -euo pipefail
if git diff --quiet "$BASE_SHA" "$PR_SHA" -- \
ci/llgo-size/llgo-version.env \
ci/llgo-size/bin/go \
cmd/bent \
cmd/bent/configs/benchmarks-llgo-size.toml \
cmd/bent/configs/configurations-llgo-size.toml \
cmd/bent/configs/suites.toml; then
echo 'full_matrix=false' >> "$GITHUB_OUTPUT"
echo 'The PR does not change the LLGo pin, Bent, or benchmark cases; only Go validation will run.'
else
echo 'full_matrix=true' >> "$GITHUB_OUTPUT"
echo 'The PR changes the LLGo pin, Bent, or benchmark cases; the full matrix will run without publishing.'
fi
binary-size:
if: >-
always() && github.event_name != 'repository_dispatch' &&
(github.event_name != 'pull_request' || needs.pr-scope.outputs.full_matrix == 'true')
needs: pr-scope
permissions:
contents: write
runs-on: ubuntu-24.04
timeout-minutes: 120
steps:
- uses: actions/checkout@v4
- name: Read pinned toolchain versions
env:
MANUAL_LLGO_COMMIT: ${{ inputs.llgo_commit }}
run: |
set -euo pipefail
set -a
source ci/llgo-size/llgo-version.env
set +a
if [[ -n "$MANUAL_LLGO_COMMIT" ]]; then
if [[ ! "$MANUAL_LLGO_COMMIT" =~ ^[0-9a-f]{40}$ ]]; then
echo "manual LLGo commit must be a full 40-character SHA" >&2
exit 1
fi
LLGO_REPOSITORY=xgo-dev/llgo
LLGO_COMMIT="$MANUAL_LLGO_COMMIT"
fi
printf 'LLGO_REPOSITORY=%s\n' "$LLGO_REPOSITORY" >> "$GITHUB_ENV"
printf 'LLGO_COMMIT=%s\n' "$LLGO_COMMIT" >> "$GITHUB_ENV"
printf 'GO_VERSION=%s\n' "$GO_VERSION" >> "$GITHUB_ENV"
printf 'LLVM_VERSION=%s\n' "$LLVM_VERSION" >> "$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 and CMake dependencies
run: |
set -euo pipefail
source ci/llgo-size/timing.sh
# GitHub-hosted runners prefer an Azure mirror through apt's dynamic
# mirror list. A bad mirror can leave apt-get update silent until the
# whole job times out, so use Ubuntu's HTTPS archive directly.
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
)
time_command "APT package index update" \
sudo timeout --kill-after=30s 5m apt-get "${apt_options[@]}" update
time_command "APT package installation" \
sudo timeout --kill-after=30s 15m apt-get "${apt_options[@]}" install -y \
cmake clang-${LLVM_VERSION} lld-${LLVM_VERSION} llvm-${LLVM_VERSION}-dev ninja-build \
libuv1-dev libgc-dev libffi-dev
- name: Check out pinned LLGo
run: |
set -euo pipefail
source ci/llgo-size/timing.sh
time_command "Clone pinned LLGo repository" \
git clone --progress --filter=blob:none --no-checkout "https://github.com/${LLGO_REPOSITORY}.git" .ci/llgo
time_command "Fetch pinned LLGo commit" \
git -C .ci/llgo fetch --progress --no-tags --depth=1 origin "$LLGO_COMMIT"
time_command "Check out pinned LLGo commit" \
git -C .ci/llgo checkout --detach "$LLGO_COMMIT"
- name: Build LLGo and the LTO plugin
run: |
set -euo pipefail
source ci/llgo-size/timing.sh
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"
time_command "Download LLGo Go modules" go mod download -x
time_command "Build LLGo command" go build -tags=dev -o "$LLGO_ROOT/llgo" ./cmd/llgo
)
time_command "Configure LLGo LTO plugin" \
cmake -S "$LLGO_ROOT/ltoplugin" -B "$LLGO_ROOT/ltoplugin/build" \
-DLLVM_DIR="/usr/lib/llvm-${LLVM_VERSION}/lib/cmake/llvm" \
-DCMAKE_BUILD_TYPE=Release -G Ninja
time_command "Build LLGo LTO plugin" \
cmake --build "$LLGO_ROOT/ltoplugin/build" --parallel 2 --verbose
- name: Build six binary-size configurations with Bent
env:
LLGO_BIN: ${{ github.workspace }}/.ci/llgo/llgo
LLGO_LTO_PLUGIN: ${{ github.workspace }}/.ci/llgo/ltoplugin/build/LLGOLTOPlugin.so
LLGO_ROOT: ${{ github.workspace }}/.ci/llgo
run: |
set -euo pipefail
source ci/llgo-size/timing.sh
export GOROOT="$(go env GOROOT)"
export PATH="$GOROOT/bin:/usr/lib/llvm-${LLVM_VERSION}/bin:$PATH"
echo "[toolchain] selected llvm-config:"
llvm-config --version
echo "[toolchain] selected clang++:"
clang++ --version
time_command "Build Bent command" go build -o .ci/bent ./cmd/bent
mkdir -p .ci/bent-run
export BENT_REAL_GO="$GOROOT/bin/go"
export BENT_TIMING_LOG="$GITHUB_WORKSPACE/.ci/bent-run/download-timings.log"
export PATH="$GITHUB_WORKSPACE/ci/llgo-size/bin:$PATH"
print_download_log() {
if [[ -s "$BENT_TIMING_LOG" ]]; then
echo "::group::Bent dependency download timings and output"
cat "$BENT_TIMING_LOG"
echo "::endgroup::"
else
echo "[timing] Bent did not record dependency downloads"
fi
}
trap print_download_log EXIT
(
cd .ci/bent-run
time_command "Bent initialize run directory" \
"$GITHUB_WORKSPACE/.ci/bent" -I
time_command "Bent dependency acquisition and six-configuration build" \
"$GITHUB_WORKSPACE/.ci/bent" -v -report-build-time -build-only \
-B=benchmarks-llgo-size.toml \
-C=configurations-llgo-size.toml
)
time_command "Generate binary-size report" \
bash -c 'set -o pipefail; ci/llgo-size/report.sh .ci/bent-run | tee -a "$GITHUB_STEP_SUMMARY"'
- name: Upload binary-size results
uses: actions/upload-artifact@v4
with:
name: llgo-binary-size
path: .ci/bent-run/results
if-no-files-found: error
- name: Publish binary-size history to Pages
if: github.ref == 'refs/heads/main'
env:
PAGES_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GH_TOKEN: ${{ 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-size/publish.sh \
.ci/bent-run/results \
"$pages_dir" \
ci/llgo-size/site
deploy-pages:
if: >-
always() && github.ref == 'refs/heads/main' &&
github.event_name != 'pull_request' && needs.binary-size.result == 'success'
needs: binary-size
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
pr-validation:
if: >-
always() && github.event_name == 'pull_request' &&
needs.pr-scope.result == 'success' && needs.pr-scope.outputs.full_matrix != 'true'
needs: pr-scope
permissions:
contents: read
runs-on: ubuntu-24.04
timeout-minutes: 30
steps:
- uses: actions/checkout@v4
- name: Read the PR validation Go version
run: |
set -euo pipefail
source ci/llgo-size/llgo-version.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: Run the LLGo-size benchmark cases with Go
run: |
set -euo pipefail
go build -o .ci/bent ./cmd/bent
mkdir -p .ci/bent-pr
(
cd .ci/bent-pr
"$GITHUB_WORKSPACE/.ci/bent" -I
"$GITHUB_WORKSPACE/.ci/bent" -v \
-B=benchmarks-llgo-size.toml \
-C=configurations-llgo-size.toml \
-c=Go
)