1010 * node vnext/Scripts/perf/compare-results.js [options]
1111 *
1212 * Options:
13- * --results <path> Path to CI results JSON (default: .perf-results/results.json)
13+ * --results <path> Path to CI results JSON (repeatable, default: .perf-results/results.json)
1414 * --baselines <dir> Path to base branch perf snapshots directory
1515 * --output <path> Path to write markdown report (default: .perf-results/report.md)
1616 * --fail-on-regression Exit 1 if regressions found (default: true in CI)
@@ -25,17 +25,29 @@ const path = require('path');
2525
2626function parseArgs ( ) {
2727 const args = process . argv . slice ( 2 ) ;
28+
29+ // Auto-discover results files: JS perf + native perf
30+ const defaultResults = [
31+ '.perf-results/results.json' ,
32+ '.native-perf-results/results.json' ,
33+ ] . filter ( p => fs . existsSync ( p ) ) ;
34+
2835 const opts = {
29- results : '.perf-results/results.json' ,
36+ results : defaultResults ,
3037 baselines : null , // auto-detect from test file paths
3138 output : '.perf-results/report.md' ,
3239 failOnRegression : ! ! process . env . CI ,
3340 } ;
3441
42+ let explicitResults = false ;
3543 for ( let i = 0 ; i < args . length ; i ++ ) {
3644 switch ( args [ i ] ) {
3745 case '--results' :
38- opts . results = args [ ++ i ] ;
46+ if ( ! explicitResults ) {
47+ opts . results = [ ] ;
48+ explicitResults = true ;
49+ }
50+ opts . results . push ( args [ ++ i ] ) ;
3951 break ;
4052 case '--baselines' :
4153 opts . baselines = args [ ++ i ] ;
@@ -257,17 +269,27 @@ function generateMarkdown(suiteComparisons, ciResults) {
257269function main ( ) {
258270 const opts = parseArgs ( ) ;
259271
260- // 1. Load CI results JSON
261- if ( ! fs . existsSync ( opts . results ) ) {
262- console . error ( `❌ Results file not found: ${ opts . results } ` ) ;
272+ // 1. Load CI results JSON (supports multiple --results paths)
273+ const ciResults = { suites : [ ] , branch : '' , commitSha : '' , timestamp : '' , summary : { totalSuites : 0 , totalTests : 0 , passed : 0 , failed : 0 , durationMs : 0 } } ;
274+ const resultsPaths = opts . results . filter ( p => fs . existsSync ( p ) ) ;
275+ if ( resultsPaths . length === 0 ) {
276+ console . error ( `❌ No results files found: ${ opts . results . join ( ', ' ) } ` ) ;
263277 console . error ( 'Run perf tests with CI=true first: CI=true yarn perf:ci' ) ;
264278 process . exit ( 1 ) ;
265279 }
266-
267- const ciResults = JSON . parse ( fs . readFileSync ( opts . results , 'utf-8' ) ) ;
268- console . log (
269- `📊 Loaded ${ ciResults . suites . length } suite(s) from ${ opts . results } ` ,
270- ) ;
280+ for ( const resultsPath of resultsPaths ) {
281+ const partial = JSON . parse ( fs . readFileSync ( resultsPath , 'utf-8' ) ) ;
282+ ciResults . suites . push ( ...( partial . suites || [ ] ) ) ;
283+ ciResults . branch = ciResults . branch || partial . branch ;
284+ ciResults . commitSha = ciResults . commitSha || partial . commitSha ;
285+ ciResults . timestamp = ciResults . timestamp || partial . timestamp ;
286+ ciResults . summary . totalSuites += partial . summary ?. totalSuites || 0 ;
287+ ciResults . summary . totalTests += partial . summary ?. totalTests || 0 ;
288+ ciResults . summary . passed += partial . summary ?. passed || 0 ;
289+ ciResults . summary . failed += partial . summary ?. failed || 0 ;
290+ ciResults . summary . durationMs += partial . summary ?. durationMs || 0 ;
291+ console . log ( `📊 Loaded ${ partial . suites . length } suite(s) from ${ resultsPath } ` ) ;
292+ }
271293
272294 // 2. Compare each suite against its committed baseline
273295 const suiteComparisons = [ ] ;
0 commit comments