@@ -2,6 +2,7 @@ import { spawn } from "node:child_process";
22import { mkdirSync , mkdtempSync , rmSync , writeFileSync } from "node:fs" ;
33import os from "node:os" ;
44import path from "node:path" ;
5+ import { pathToFileURL } from "node:url" ;
56
67type CommandCase = {
78 id : string ;
@@ -394,6 +395,17 @@ function parseRepeatableFlag(flag: string): string[] {
394395}
395396
396397function parsePositiveInt ( raw : string | undefined , fallback : number ) : number {
398+ if ( ! raw ) {
399+ return fallback ;
400+ }
401+ const parsed = Number . parseInt ( raw , 10 ) ;
402+ if ( ! Number . isFinite ( parsed ) || parsed < 1 ) {
403+ return fallback ;
404+ }
405+ return parsed ;
406+ }
407+
408+ function parseNonNegativeInt ( raw : string | undefined , fallback : number ) : number {
397409 if ( ! raw ) {
398410 return fallback ;
399411 }
@@ -747,6 +759,25 @@ function printDelta(primary: SuiteResult, secondary: SuiteResult): void {
747759 }
748760}
749761
762+ export function collectFailedSamples ( result : SuiteResult ) : string [ ] {
763+ const failures : string [ ] = [ ] ;
764+ for ( const commandCase of result . cases ) {
765+ if ( commandCase . samples . length === 0 ) {
766+ failures . push ( `${ result . entry } ${ commandCase . id } : no measured samples` ) ;
767+ continue ;
768+ }
769+ for ( const [ sampleIndex , sample ] of commandCase . samples . entries ( ) ) {
770+ const label = `${ result . entry } ${ commandCase . id } sample ${ sampleIndex + 1 } ` ;
771+ if ( sample . signal !== null ) {
772+ failures . push ( `${ label } : exited via signal ${ sample . signal } ` ) ;
773+ } else if ( sample . exitCode !== 0 ) {
774+ failures . push ( `${ label } : exited with code ${ String ( sample . exitCode ) } ` ) ;
775+ }
776+ }
777+ }
778+ return failures ;
779+ }
780+
750781async function buildSuiteResult ( params : {
751782 entry : string ;
752783 options : CliOptions ;
@@ -796,7 +827,7 @@ function parseOptions(): CliOptions {
796827 entryPrimary : parseFlagValue ( "--entry-primary" ) ?? parseFlagValue ( "--entry" ) ?? DEFAULT_ENTRY ,
797828 entrySecondary : parseFlagValue ( "--entry-secondary" ) ,
798829 runs : parsePositiveInt ( parseFlagValue ( "--runs" ) , DEFAULT_RUNS ) ,
799- warmup : parsePositiveInt ( parseFlagValue ( "--warmup" ) , DEFAULT_WARMUP ) ,
830+ warmup : parseNonNegativeInt ( parseFlagValue ( "--warmup" ) , DEFAULT_WARMUP ) ,
800831 timeoutMs : parsePositiveInt ( parseFlagValue ( "--timeout-ms" ) , DEFAULT_TIMEOUT_MS ) ,
801832 json : hasFlag ( "--json" ) ,
802833 output : parseFlagValue ( "--output" ) ,
@@ -864,6 +895,10 @@ async function main(): Promise<void> {
864895 primary,
865896 secondary : secondary ?? null ,
866897 } ;
898+ const failures = [
899+ ...collectFailedSamples ( primary ) ,
900+ ...( secondary ? collectFailedSamples ( secondary ) : [ ] ) ,
901+ ] ;
867902
868903 if ( options . output ) {
869904 mkdirSync ( path . dirname ( options . output ) , { recursive : true } ) ;
@@ -872,6 +907,12 @@ async function main(): Promise<void> {
872907
873908 if ( options . json ) {
874909 console . log ( JSON . stringify ( report , null , 2 ) ) ;
910+ if ( failures . length > 0 ) {
911+ process . exitCode = 1 ;
912+ for ( const failure of failures ) {
913+ console . error ( `[startup-bench] ${ failure } ` ) ;
914+ }
915+ }
875916 return ;
876917 }
877918
@@ -894,9 +935,28 @@ async function main(): Promise<void> {
894935 printSuite ( secondary ) ;
895936 printDelta ( primary , secondary ) ;
896937 }
938+
939+ if ( failures . length > 0 ) {
940+ process . exitCode = 1 ;
941+ console . error ( "\nFailed startup benchmark samples:" ) ;
942+ for ( const failure of failures ) {
943+ console . error ( `- ${ failure } ` ) ;
944+ }
945+ }
897946 } finally {
898947 rmSync ( tmpDir , { recursive : true , force : true } ) ;
899948 }
900949}
901950
902- await main ( ) ;
951+ export const testing = {
952+ collectFailedSamples,
953+ parseNonNegativeInt,
954+ parsePositiveInt,
955+ } ;
956+
957+ if ( import . meta. url === pathToFileURL ( process . argv [ 1 ] ?? "" ) . href ) {
958+ await main ( ) . catch ( ( error : unknown ) => {
959+ console . error ( error instanceof Error ? error . stack : String ( error ) ) ;
960+ process . exit ( 1 ) ;
961+ } ) ;
962+ }
0 commit comments