@@ -10,31 +10,33 @@ jobs:
10
10
profile :
11
11
runs-on : ubuntu-latest
12
12
steps :
13
- - uses : actions/checkout@v3
13
+ - uses : actions/checkout@v4
14
14
with :
15
15
fetch-depth : 0
16
16
17
17
- name : Install Rust
18
- uses : actions-rs/toolchain@v1
19
- with :
20
- profile : minimal
21
- toolchain : stable
18
+ uses : dtolnay/rust-toolchain@stable
22
19
23
20
- name : Install Valgrind
24
21
run : |
25
22
sudo apt update
26
23
sudo apt install -y valgrind
27
24
28
- - name : Cache dependencies
29
- uses : actions/cache@v3
25
+ - name : Cache Rust dependencies
26
+ uses : Swatinem/rust-cache@v2
27
+ with :
28
+ # Cache on Cargo.lock file
29
+ cache-on-failure : true
30
+
31
+ - name : Cache iai-callgrind binary
32
+ id : cache-iai
33
+ uses : actions/cache@v4
30
34
with :
31
- path : |
32
- ~/.cargo/registry
33
- ~/.cargo/git
34
- target
35
- key : ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
35
+ path : ~/.cargo/bin/iai-callgrind-runner
36
+ key : ${{ runner.os }}-iai-callgrind-runner-0.12.3
36
37
37
38
- name : Install iai-callgrind
39
+ if : steps.cache-iai.outputs.cache-hit != 'true'
38
40
run : |
39
41
40
42
43
45
git fetch origin master:master
44
46
git checkout master
45
47
48
+ - name : Get master commit SHA
49
+ id : master-sha
50
+ run : echo "sha=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT
51
+
52
+ - name : Cache benchmark baselines
53
+ id : cache-benchmark-baselines
54
+ uses : actions/cache@v4
55
+ with :
56
+ path : target/iai
57
+ key : ${{ runner.os }}-benchmark-baselines-master-${{ steps.master-sha.outputs.sha }}
58
+ restore-keys : |
59
+ ${{ runner.os }}-benchmark-baselines-master-
60
+
46
61
- name : Run baseline benchmarks
62
+ if : steps.cache-benchmark-baselines.outputs.cache-hit != 'true'
47
63
run : |
64
+ # Compile benchmarks
48
65
cargo bench --bench compile_demo_art_iai -- --save-baseline=master
66
+
67
+ # Runtime benchmarks
68
+ cargo bench --bench update_executor_iai -- --save-baseline=master
69
+ cargo bench --bench run_once_iai -- --save-baseline=master
70
+ cargo bench --bench run_cached_iai -- --save-baseline=master
49
71
50
72
- name : Checkout PR branch
51
73
run : |
@@ -54,13 +76,33 @@ jobs:
54
76
- name : Run PR benchmarks
55
77
id : benchmark
56
78
run : |
57
- BENCH_OUTPUT=$(cargo bench --bench compile_demo_art_iai -- --baseline=master --output-format=json | jq -sc | sed 's/\\"//g')
58
- echo "BENCHMARK_OUTPUT<<EOF" >> $GITHUB_OUTPUT
59
- echo "$BENCH_OUTPUT" >> $GITHUB_OUTPUT
79
+ # Compile benchmarks
80
+ COMPILE_OUTPUT=$(cargo bench --bench compile_demo_art_iai -- --baseline=master --output-format=json | jq -sc | sed 's/\\"//g')
81
+
82
+ # Runtime benchmarks
83
+ UPDATE_OUTPUT=$(cargo bench --bench update_executor_iai -- --baseline=master --output-format=json | jq -sc | sed 's/\\"//g')
84
+ RUN_ONCE_OUTPUT=$(cargo bench --bench run_once_iai -- --baseline=master --output-format=json | jq -sc | sed 's/\\"//g')
85
+ RUN_CACHED_OUTPUT=$(cargo bench --bench run_cached_iai -- --baseline=master --output-format=json | jq -sc | sed 's/\\"//g')
86
+
87
+ # Store outputs
88
+ echo "COMPILE_OUTPUT<<EOF" >> $GITHUB_OUTPUT
89
+ echo "$COMPILE_OUTPUT" >> $GITHUB_OUTPUT
90
+ echo "EOF" >> $GITHUB_OUTPUT
91
+
92
+ echo "UPDATE_OUTPUT<<EOF" >> $GITHUB_OUTPUT
93
+ echo "$UPDATE_OUTPUT" >> $GITHUB_OUTPUT
94
+ echo "EOF" >> $GITHUB_OUTPUT
95
+
96
+ echo "RUN_ONCE_OUTPUT<<EOF" >> $GITHUB_OUTPUT
97
+ echo "$RUN_ONCE_OUTPUT" >> $GITHUB_OUTPUT
98
+ echo "EOF" >> $GITHUB_OUTPUT
99
+
100
+ echo "RUN_CACHED_OUTPUT<<EOF" >> $GITHUB_OUTPUT
101
+ echo "$RUN_CACHED_OUTPUT" >> $GITHUB_OUTPUT
60
102
echo "EOF" >> $GITHUB_OUTPUT
61
103
62
104
- name : Make old comments collapsed by default
63
- uses : actions/github-script@v6
105
+ uses : actions/github-script@v7
64
106
with :
65
107
github-token : ${{secrets.GITHUB_TOKEN}}
66
108
script : |
@@ -85,11 +127,15 @@ jobs:
85
127
}
86
128
87
129
- name : Comment PR
88
- uses : actions/github-script@v6
130
+ uses : actions/github-script@v7
89
131
with :
90
132
github-token : ${{secrets.GITHUB_TOKEN}}
91
133
script : |
92
- const benchmarkOutput = JSON.parse(`${{ steps.benchmark.outputs.BENCHMARK_OUTPUT }}`);
134
+ const compileOutput = JSON.parse(`${{ steps.benchmark.outputs.COMPILE_OUTPUT }}`);
135
+ const updateOutput = JSON.parse(`${{ steps.benchmark.outputs.UPDATE_OUTPUT }}`);
136
+ const runOnceOutput = JSON.parse(`${{ steps.benchmark.outputs.RUN_ONCE_OUTPUT }}`);
137
+ const runCachedOutput = JSON.parse(`${{ steps.benchmark.outputs.RUN_CACHED_OUTPUT }}`);
138
+
93
139
let significantChanges = false;
94
140
let commentBody = "";
95
141
@@ -110,58 +156,97 @@ jobs:
110
156
return str.padStart(len);
111
157
}
112
158
113
- for (const benchmark of benchmarkOutput) {
114
- if (benchmark.callgrind_summary && benchmark.callgrind_summary.summaries) {
115
- const summary = benchmark.callgrind_summary.summaries[0];
116
- const irDiff = summary.events.Ir;
117
-
118
- if (irDiff.diff_pct !== null) {
119
- const changePercentage = formatPercentage(irDiff.diff_pct);
120
- const color = irDiff.diff_pct > 0 ? "red" : "lime";
121
-
122
- commentBody += "---\n\n";
123
- commentBody += `${benchmark.module_path} ${benchmark.id}:${benchmark.details}\n`;
124
- commentBody += `Instructions: \`${formatNumber(irDiff.old)}\` (master) -> \`${formatNumber(irDiff.new)}\` (HEAD) : `;
125
- commentBody += `$$\\color{${color}}${changePercentage.replace("%", "\\\\%")}$$\n\n`;
159
+ function processBenchmarkOutput(benchmarkOutput, sectionTitle, isLast = false) {
160
+ let sectionBody = "";
161
+ let hasResults = false;
162
+ let hasSignificantChanges = false;
163
+
164
+ for (const benchmark of benchmarkOutput) {
165
+ if (benchmark.callgrind_summary && benchmark.callgrind_summary.summaries) {
166
+ const summary = benchmark.callgrind_summary.summaries[0];
167
+ const irDiff = summary.events.Ir;
126
168
127
- commentBody += "<details>\n<summary>Detailed metrics</summary>\n\n```\n";
128
- commentBody += `Baselines: master| HEAD\n`;
129
-
130
- for (const [eventKind, costsDiff] of Object.entries(summary.events)) {
131
- if (costsDiff.diff_pct !== null) {
132
- const changePercentage = formatPercentage(costsDiff.diff_pct);
133
- const line = `${padRight(eventKind, 20)} ${padLeft(formatNumber(costsDiff.old), 11)}|${padLeft(formatNumber(costsDiff.new), 11)} ${padLeft(changePercentage, 15)}`;
134
- commentBody += `${line}\n`;
169
+ if (irDiff.diff_pct !== null) {
170
+ hasResults = true;
171
+ const changePercentage = formatPercentage(irDiff.diff_pct);
172
+ const color = irDiff.diff_pct > 0 ? "red" : "lime";
173
+
174
+ sectionBody += `**${benchmark.module_path} ${benchmark.id}:${benchmark.details}**\n`;
175
+ sectionBody += `Instructions: \`${formatNumber(irDiff.old)}\` (master) → \`${formatNumber(irDiff.new)}\` (HEAD) : `;
176
+ sectionBody += `$$\\color{${color}}${changePercentage.replace("%", "\\\\%")}$$\n\n`;
177
+
178
+ sectionBody += "<details>\n<summary>Detailed metrics</summary>\n\n```\n";
179
+ sectionBody += `Baselines: master| HEAD\n`;
180
+
181
+ for (const [eventKind, costsDiff] of Object.entries(summary.events)) {
182
+ if (costsDiff.diff_pct !== null) {
183
+ const changePercentage = formatPercentage(costsDiff.diff_pct);
184
+ const line = `${padRight(eventKind, 20)} ${padLeft(formatNumber(costsDiff.old), 11)}|${padLeft(formatNumber(costsDiff.new), 11)} ${padLeft(changePercentage, 15)}`;
185
+ sectionBody += `${line}\n`;
186
+ }
187
+ }
188
+
189
+ sectionBody += "```\n</details>\n\n";
190
+
191
+ if (Math.abs(irDiff.diff_pct) > 5) {
192
+ significantChanges = true;
193
+ hasSignificantChanges = true;
135
194
}
136
- }
137
-
138
- commentBody += "```\n</details>\n\n";
139
-
140
- if (Math.abs(irDiff.diff_pct) > 5) {
141
- significantChanges = true;
142
195
}
143
196
}
144
197
}
198
+
199
+ if (hasResults) {
200
+ // Wrap section in collapsible details, open only if there are significant changes
201
+ const openAttribute = hasSignificantChanges ? " open" : "";
202
+ const ruler = isLast ? "" : "\n\n---";
203
+ return `<details${openAttribute}>\n<summary><h2>${sectionTitle}</h2></summary>\n\n${sectionBody}${ruler}\n</details>`;
204
+ }
205
+ return "";
145
206
}
146
207
147
- const output = `
148
- <details open>
149
-
150
- <summary>Performance Benchmark Results</summary>
151
-
152
- ${commentBody}
153
-
154
- </details>
155
- `;
156
-
157
- if (significantChanges) {
158
- github.rest.issues.createComment({
159
- issue_number: context.issue.number,
160
- owner: context.repo.owner,
161
- repo: context.repo.repo,
162
- body: output
163
- });
208
+ // Process each benchmark category
209
+ const sections = [
210
+ { output: compileOutput, title: "🔧 Graph Compilation" },
211
+ { output: updateOutput, title: "🔄 Executor Update" },
212
+ { output: runOnceOutput, title: "🚀 Render: Cold Execution" },
213
+ { output: runCachedOutput, title: "⚡ Render: Cached Execution" }
214
+ ];
215
+
216
+ // Generate sections and determine which ones have results
217
+ const generatedSections = sections.map(({ output, title }) =>
218
+ processBenchmarkOutput(output, title, true) // temporarily mark all as last
219
+ ).filter(section => section.length > 0);
220
+
221
+ // Re-generate with correct isLast flags
222
+ let sectionIndex = 0;
223
+ const finalSections = sections.map(({ output, title }) => {
224
+ const section = processBenchmarkOutput(output, title, true); // check if it has results
225
+ if (section.length > 0) {
226
+ const isLast = sectionIndex === generatedSections.length - 1;
227
+ sectionIndex++;
228
+ return processBenchmarkOutput(output, title, isLast);
229
+ }
230
+ return "";
231
+ }).filter(section => section.length > 0);
232
+
233
+ // Combine all sections
234
+ commentBody = finalSections.join("\n\n");
235
+
236
+ if (commentBody.length > 0) {
237
+ const output = `<details open>\n<summary>Performance Benchmark Results</summary>\n\n${commentBody}\n</details>`;
238
+
239
+ if (significantChanges) {
240
+ github.rest.issues.createComment({
241
+ issue_number: context.issue.number,
242
+ owner: context.repo.owner,
243
+ repo: context.repo.repo,
244
+ body: output
245
+ });
246
+ } else {
247
+ console.log("No significant performance changes detected. Skipping comment.");
248
+ console.log(output);
249
+ }
164
250
} else {
165
- console.log("No significant performance changes detected. Skipping comment.");
166
- console.log(output);
251
+ console.log("No benchmark results to display.");
167
252
}
0 commit comments