@@ -124,6 +124,65 @@ jobs:
124124 });
125125 }
126126
127+ - name : Analyze profiling changes
128+ id : analyze
129+ uses : actions/github-script@v7
130+ with :
131+ script : |
132+ const fs = require('fs');
133+
134+ function isSignificantChange(diffPct, absoluteChange, benchmarkType) {
135+ const meetsPercentageThreshold = Math.abs(diffPct) > 5;
136+ const meetsAbsoluteThreshold = absoluteChange > 200000;
137+ const isCachedExecution = benchmarkType === 'run_cached' ||
138+ benchmarkType.includes('Cached Execution');
139+
140+ return isCachedExecution
141+ ? (meetsPercentageThreshold && meetsAbsoluteThreshold)
142+ : meetsPercentageThreshold;
143+ }
144+
145+ const allOutputs = [
146+ JSON.parse(fs.readFileSync('/tmp/compile_output.json', 'utf8')),
147+ JSON.parse(fs.readFileSync('/tmp/update_output.json', 'utf8')),
148+ JSON.parse(fs.readFileSync('/tmp/run_once_output.json', 'utf8')),
149+ JSON.parse(fs.readFileSync('/tmp/run_cached_output.json', 'utf8'))
150+ ];
151+ const outputNames = ['compile', 'update', 'run_once', 'run_cached'];
152+ const sectionTitles = ['Compilation', 'Update', 'Run Once', 'Cached Execution'];
153+
154+ let hasSignificantChanges = false;
155+ let regressionDetails = [];
156+
157+ for (let i = 0; i < allOutputs.length; i++) {
158+ const benchmarkOutput = allOutputs[i];
159+ const outputName = outputNames[i];
160+ const sectionTitle = sectionTitles[i];
161+
162+ for (const benchmark of benchmarkOutput) {
163+ if (benchmark.profiles?.[0]?.summaries?.parts?.[0]?.metrics_summary?.Callgrind?.Ir?.diffs?.diff_pct) {
164+ const diffPct = parseFloat(benchmark.profiles[0].summaries.parts[0].metrics_summary.Callgrind.Ir.diffs.diff_pct);
165+ const oldValue = benchmark.profiles[0].summaries.parts[0].metrics_summary.Callgrind.Ir.metrics.Both[1].Int;
166+ const newValue = benchmark.profiles[0].summaries.parts[0].metrics_summary.Callgrind.Ir.metrics.Both[0].Int;
167+ const absoluteChange = Math.abs(newValue - oldValue);
168+
169+ if (isSignificantChange(diffPct, absoluteChange, outputName)) {
170+ hasSignificantChanges = true;
171+ regressionDetails.push({
172+ module_path: benchmark.module_path,
173+ id: benchmark.id,
174+ diffPct,
175+ absoluteChange,
176+ sectionTitle
177+ });
178+ }
179+ }
180+ }
181+ }
182+
183+ core.setOutput('has-significant-changes', hasSignificantChanges);
184+ core.setOutput('regression-details', JSON.stringify(regressionDetails));
185+
127186 - name : Comment PR
128187 if : github.event.pull_request.head.repo.full_name == github.repository
129188 uses : actions/github-script@v7
@@ -137,7 +196,7 @@ jobs:
137196 const runOnceOutput = JSON.parse(fs.readFileSync('/tmp/run_once_output.json', 'utf8'));
138197 const runCachedOutput = JSON.parse(fs.readFileSync('/tmp/run_cached_output.json', 'utf8'));
139198
140- let significantChanges = false ;
199+ const hasSignificantChanges = '${{ steps.analyze.outputs.has-significant-changes }}' === 'true' ;
141200 let commentBody = "";
142201
143202 function formatNumber(num) {
@@ -161,6 +220,17 @@ jobs:
161220 let sectionBody = "";
162221 let hasResults = false;
163222 let hasSignificantChanges = false;
223+
224+ function isSignificantChange(diffPct, absoluteChange, benchmarkType) {
225+ const meetsPercentageThreshold = Math.abs(diffPct) > 5;
226+ const meetsAbsoluteThreshold = absoluteChange > 200000;
227+ const isCachedExecution = benchmarkType === 'run_cached' ||
228+ benchmarkType.includes('Cached Execution');
229+
230+ return isCachedExecution
231+ ? (meetsPercentageThreshold && meetsAbsoluteThreshold)
232+ : meetsPercentageThreshold;
233+ }
164234
165235 for (const benchmark of benchmarkOutput) {
166236 if (benchmark.profiles && benchmark.profiles.length > 0) {
@@ -197,8 +267,8 @@ jobs:
197267 }
198268
199269 sectionBody += "```\n</details>\n\n";
200-
201- if (Math.abs(irDiff.diff_pct) > 5 ) {
270+
271+ if (isSignificantChange(irDiff.diff_pct, Math.abs(irDiff.new - irDiff.old), sectionTitle) ) {
202272 significantChanges = true;
203273 hasSignificantChanges = true;
204274 }
@@ -248,7 +318,7 @@ jobs:
248318 if (commentBody.length > 0) {
249319 const output = `<details open>\n<summary>Performance Benchmark Results</summary>\n\n${commentBody}\n</details>`;
250320
251- if (significantChanges ) {
321+ if (hasSignificantChanges ) {
252322 github.rest.issues.createComment({
253323 issue_number: context.issue.number,
254324 owner: context.repo.owner,
@@ -264,26 +334,11 @@ jobs:
264334 }
265335
266336 - name : Fail on significant regressions
337+ if : steps.analyze.outputs.has-significant-changes == 'true'
267338 uses : actions/github-script@v7
268339 with :
269340 script : |
270- const fs = require('fs');
341+ const regressionDetails = JSON.parse('${{ steps.analyze.outputs.regression-details }}');
342+ const firstRegression = regressionDetails[0];
271343
272- const allOutputs = [
273- JSON.parse(fs.readFileSync('/tmp/compile_output.json', 'utf8')),
274- JSON.parse(fs.readFileSync('/tmp/update_output.json', 'utf8')),
275- JSON.parse(fs.readFileSync('/tmp/run_once_output.json', 'utf8')),
276- JSON.parse(fs.readFileSync('/tmp/run_cached_output.json', 'utf8'))
277- ];
278-
279- for (const benchmarkOutput of allOutputs) {
280- for (const benchmark of benchmarkOutput) {
281- if (benchmark.profiles?.[0]?.summaries?.parts?.[0]?.metrics_summary?.Callgrind?.Ir?.diffs?.diff_pct) {
282- const diffPct = parseFloat(benchmark.profiles[0].summaries.parts[0].metrics_summary.Callgrind.Ir.diffs.diff_pct);
283- if (diffPct > 5) {
284- core.setFailed(`Significant performance regression detected: ${benchmark.module_path} ${benchmark.id} increased by ${diffPct.toFixed(2)}%`);
285- return;
286- }
287- }
288- }
289- }
344+ core.setFailed(`Significant performance regression detected: ${firstRegression.module_path} ${firstRegression.id} increased by ${firstRegression.absoluteChange.toLocaleString()} instructions (${firstRegression.diffPct.toFixed(2)}%)`);
0 commit comments