@@ -21,6 +21,32 @@ function updateProgress(current, total, label = '', width) {
2121 process . stdout . write ( `${ label } [${ bar } ] ${ current } /${ total } ` ) ;
2222}
2323
24+ /**
25+ * Create a name filter function from CLI argument
26+ * - Supports substring match (default)
27+ * - Supports /regex/flags syntax
28+ * @param {string|undefined } arg
29+ * @returns {(name: string) => boolean }
30+ */
31+ function createNameFilter ( arg ) {
32+ if ( ! arg ) {
33+ return ( ) => true ;
34+ }
35+ if ( arg . startsWith ( '/' ) && arg . lastIndexOf ( '/' ) > 0 ) {
36+ const lastSlash = arg . lastIndexOf ( '/' ) ;
37+ const pattern = arg . slice ( 1 , lastSlash ) ;
38+ const flags = arg . slice ( lastSlash + 1 ) ;
39+ try {
40+ const re = new RegExp ( pattern , flags ) ;
41+ return ( name ) => re . test ( name ) ;
42+ } catch ( e ) {
43+ console . error ( 'Invalid regular expression for --filter:' , e . message ) ;
44+ process . exit ( 1 ) ;
45+ }
46+ }
47+ return ( name ) => name . includes ( arg ) ;
48+ }
49+
2450/**
2551 * Calculate coefficient of variation (relative standard deviation)
2652 * @param {Array<number> } values - Array of measurement values
@@ -238,24 +264,28 @@ function saveJsonResults(filePath, data) {
238264 * @param {Object } results - Results object to store benchmark data
239265 * @returns {Promise<void> }
240266 */
241- async function singleRun ( results ) {
267+ async function singleRun ( results , nameFilter ) {
242268 const options = await defaultNodeSetup ( { } )
269+ const benchmarkRunner = ( name , body ) => {
270+ if ( nameFilter && ! nameFilter ( name ) ) {
271+ return ;
272+ }
273+ const startTime = performance . now ( ) ;
274+ body ( ) ;
275+ const endTime = performance . now ( ) ;
276+ const duration = endTime - startTime ;
277+ if ( ! results [ name ] ) {
278+ results [ name ] = [ ]
279+ }
280+ results [ name ] . push ( duration )
281+ }
243282 const { exports } = await instantiate ( {
244283 ...options ,
245- imports : {
284+ getImports : ( ) => ( {
246285 benchmarkHelperNoop : ( ) => { } ,
247286 benchmarkHelperNoopWithNumber : ( n ) => { } ,
248- benchmarkRunner : ( name , body ) => {
249- const startTime = performance . now ( ) ;
250- body ( ) ;
251- const endTime = performance . now ( ) ;
252- const duration = endTime - startTime ;
253- if ( ! results [ name ] ) {
254- results [ name ] = [ ]
255- }
256- results [ name ] . push ( duration )
257- }
258- }
287+ benchmarkRunner : benchmarkRunner
288+ } )
259289 } ) ;
260290 exports . run ( ) ;
261291}
@@ -266,7 +296,7 @@ async function singleRun(results) {
266296 * @param {Object } options - Adaptive sampling options
267297 * @returns {Promise<void> }
268298 */
269- async function runUntilStable ( results , options , width ) {
299+ async function runUntilStable ( results , options , width , nameFilter , filterArg ) {
270300 const {
271301 minRuns = 5 ,
272302 maxRuns = 50 ,
@@ -285,9 +315,14 @@ async function runUntilStable(results, options, width) {
285315 // Update progress with estimated completion
286316 updateProgress ( runs , maxRuns , "Benchmark Progress:" , width ) ;
287317
288- await singleRun ( results ) ;
318+ await singleRun ( results , nameFilter ) ;
289319 runs ++ ;
290320
321+ if ( runs === 1 && Object . keys ( results ) . length === 0 ) {
322+ console . error ( `\nNo benchmarks matched filter: ${ filterArg } ` ) ;
323+ process . exit ( 1 ) ;
324+ }
325+
291326 // Check if we've reached minimum runs
292327 if ( runs < minRuns ) continue ;
293328
@@ -349,6 +384,7 @@ Options:
349384 --min-runs=NUMBER Minimum runs for adaptive sampling (default: 5)
350385 --max-runs=NUMBER Maximum runs for adaptive sampling (default: 50)
351386 --target-cv=NUMBER Target coefficient of variation % (default: 5)
387+ --filter=PATTERN Filter benchmarks by name (substring or /regex/flags)
352388 --help Show this help message
353389` ) ;
354390}
@@ -363,7 +399,8 @@ async function main() {
363399 adaptive : { type : 'boolean' , default : false } ,
364400 'min-runs' : { type : 'string' , default : '5' } ,
365401 'max-runs' : { type : 'string' , default : '50' } ,
366- 'target-cv' : { type : 'string' , default : '5' }
402+ 'target-cv' : { type : 'string' , default : '5' } ,
403+ filter : { type : 'string' }
367404 }
368405 } ) ;
369406
@@ -374,6 +411,8 @@ async function main() {
374411
375412 const results = { } ;
376413 const width = 30 ;
414+ const filterArg = args . values . filter ;
415+ const nameFilter = createNameFilter ( filterArg ) ;
377416
378417 if ( args . values . adaptive ) {
379418 // Adaptive sampling mode
@@ -388,7 +427,7 @@ async function main() {
388427 console . log ( `Results will be saved to: ${ args . values . output } ` ) ;
389428 }
390429
391- await runUntilStable ( results , options , width ) ;
430+ await runUntilStable ( results , options , width , nameFilter , filterArg ) ;
392431 } else {
393432 // Fixed number of runs mode
394433 const runs = parseInt ( args . values . runs , 10 ) ;
@@ -410,7 +449,12 @@ async function main() {
410449 console . log ( "\nOverall Progress:" ) ;
411450 for ( let i = 0 ; i < runs ; i ++ ) {
412451 updateProgress ( i , runs , "Benchmark Runs:" , width ) ;
413- await singleRun ( results ) ;
452+ await singleRun ( results , nameFilter ) ;
453+ if ( i === 0 && Object . keys ( results ) . length === 0 ) {
454+ process . stdout . write ( "\n" ) ;
455+ console . error ( `No benchmarks matched filter: ${ filterArg } ` ) ;
456+ process . exit ( 1 ) ;
457+ }
414458 }
415459 updateProgress ( runs , runs , "Benchmark Runs:" , width ) ;
416460 console . log ( "\n" ) ;
0 commit comments