-
Notifications
You must be signed in to change notification settings - Fork 27
121 lines (113 loc) · 5.55 KB
/
code-size.yml
File metadata and controls
121 lines (113 loc) · 5.55 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
name: Code size
on:
pull_request:
types: [opened, synchronize, reopened]
# Only run when something that can change generated code size moves.
paths:
- 'compiler/**'
- 'runtime/**'
- 'embossc'
- 'testdata/benchmark.emb'
- 'testdata/many_conditionals.emb'
- 'scripts/size_bench.py'
- 'scripts/size_comment.py'
- '.github/workflows/code-size.yml'
# Read the PR's commits; post/update one sticky size comment.
permissions:
contents: read
pull-requests: write
# Supersede an in-flight size run when the PR is pushed again.
concurrency:
group: code-size-${{ github.event.pull_request.number }}
cancel-in-progress: true
jobs:
size-report:
name: Generated code size
runs-on: ubuntu-latest
steps:
- name: Check out PR head (full history for merge-base + revision checkouts)
uses: actions/checkout@v6
with:
ref: ${{ github.event.pull_request.head.sha }}
fetch-depth: 0
# embossc formats generated headers with clang-format (the clang-format
# PyPI package, pinned in requirements.txt), so the codegen run needs the
# Emboss Python deps. setup-python avoids the runner's externally-managed
# system Python (PEP 668).
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.x'
cache: 'pip'
cache-dependency-path: requirements.txt
- name: Install Emboss Python deps (clang-format for codegen)
run: pip install -r requirements.txt
- name: Install host clang and the ARM (STM32 / Cortex-M4) gcc toolchain
run: sudo apt-get update && sudo apt-get install -y clang gcc-arm-none-eabi
# embedded code-size targets compile against the MicroBlaze gcc toolchain
# hard-coded under /opt/microblaze/...; cache the Bootlin tarball in a
# runner-writable path (caching /opt fights root perms on restore), then
# extract it into place. clang has no MicroBlaze back end, so MicroBlaze is
# gcc-only.
- name: Cache MicroBlaze (Bootlin) toolchain tarball
uses: actions/cache@v4
with:
path: ~/mb-toolchain/mb.tar.xz
key: bootlin-microblazebe--glibc--stable-2025.08-1
- name: Provision MicroBlaze toolchain
run: |
set -euo pipefail
url="https://toolchains.bootlin.com/downloads/releases/toolchains/microblazebe/tarballs/microblazebe--glibc--stable-2025.08-1.tar.xz"
if [ ! -f "$HOME/mb-toolchain/mb.tar.xz" ]; then
mkdir -p "$HOME/mb-toolchain"
curl -fsSL "$url" -o "$HOME/mb-toolchain/mb.tar.xz"
fi
sudo mkdir -p /opt/microblaze
sudo tar -C /opt/microblaze -xJf "$HOME/mb-toolchain/mb.tar.xz"
test -x /opt/microblaze/microblazebe--glibc--stable-2025.08-1/bin/microblaze-buildroot-linux-gnu-g++
- name: Measure generated code size (merge-base vs PR head)
env:
BASE_SHA: ${{ github.event.pull_request.base.sha }}
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
run: |
set -euo pipefail
# Baseline against the merge-base, NOT the base-branch tip, so codegen
# that landed on the base after this PR branched is not misattributed.
# size_bench.py holds the benchmark schema fixed (pulled forward from
# head), so only the generator/runtime under test differs.
base="$(git merge-base "$BASE_SHA" "$HEAD_SHA")"
echo "Comparing merge-base $base -> head $HEAD_SHA"
python3 scripts/size_bench.py --revisions "$base" "$HEAD_SHA" --out-dir "$RUNNER_TEMP/size"
# Fail loudly rather than post an empty table if the head build produced
# no data (missing toolchain/dep or a codegen break).
python3 -c 'import json,sys; d=json.load(open(sys.argv[1])); h=d["revisions"][-1]["results"]; sys.exit(0 if any(cfg.get("benchmark") for t in h.values() for c in t.values() for cfg in c.values()) else 1)' "$RUNNER_TEMP/size/size_bench.json" \
|| { echo "::error::size_bench produced no head benchmark data (toolchain/codegen failure); see output above."; exit 1; }
python3 scripts/size_comment.py "$RUNNER_TEMP/size/size_bench.json" > "$RUNNER_TEMP/size/comment.md"
- name: Post / update size comment
# Fork PRs get a read-only GITHUB_TOKEN; same-repo PRs (the chain branches)
# can comment. (Fork-safe upgrade: a separate workflow_run job.)
if: ${{ github.event.pull_request.head.repo.full_name == github.repository }}
uses: actions/github-script@v7
env:
COMMENT_PATH: ${{ runner.temp }}/size/comment.md
with:
script: |
const fs = require('fs');
const marker = '<!-- emboss-size-bench -->';
let body;
try {
body = fs.readFileSync(process.env.COMMENT_PATH, 'utf8');
} catch (e) {
return; // measure step failed; its red check is the signal.
}
const { owner, repo } = context.repo;
const issue_number = context.issue.number;
const comments = await github.paginate(github.rest.issues.listComments, {
owner, repo, issue_number, per_page: 100,
});
const existing = comments.find(c => c.body && c.body.includes(marker));
if (existing) {
await github.rest.issues.updateComment({ owner, repo, comment_id: existing.id, body });
} else {
await github.rest.issues.createComment({ owner, repo, issue_number, body });
}