@@ -38,20 +38,45 @@ namespace Harness.Parallel.Host {
3838 return undefined ;
3939 }
4040
41- function hashName ( runner : TestRunnerKind , test : string ) {
41+ function hashName ( runner : TestRunnerKind | "unittest" , test : string ) {
4242 return `tsrunner-${ runner } ://${ test } ` ;
4343 }
4444
45+ let tasks : { runner : TestRunnerKind | "unittest" , file : string , size : number } [ ] = [ ] ;
46+ const newTasks : { runner : TestRunnerKind | "unittest" , file : string , size : number } [ ] = [ ] ;
47+ let unknownValue : string | undefined ;
4548 export function start ( ) {
49+ const perfData = readSavedPerfData ( configOption ) ;
50+ let totalCost = 0 ;
51+ if ( runUnitTests ) {
52+ ( global as any ) . describe = ( suiteName : string ) => {
53+ // Note, sub-suites are not indexed (we assume such granularity is not required)
54+ let size = 0 ;
55+ if ( perfData ) {
56+ size = perfData [ hashName ( "unittest" , suiteName ) ] ;
57+ if ( size === undefined ) {
58+ newTasks . push ( { runner : "unittest" , file : suiteName , size : 0 } ) ;
59+ unknownValue = suiteName ;
60+ return ;
61+ }
62+ }
63+ tasks . push ( { runner : "unittest" , file : suiteName , size } ) ;
64+ totalCost += size ;
65+ } ;
66+ }
67+ else {
68+ ( global as any ) . describe = ts . noop ;
69+ }
70+
71+ setTimeout ( ( ) => startDelayed ( perfData , totalCost ) , 0 ) ; // Do real startup on next tick, so all unit tests have been collected
72+ }
73+
74+ function startDelayed ( perfData : { [ testHash : string ] : number } , totalCost : number ) {
4675 initializeProgressBarsDependencies ( ) ;
47- console . log ( "Discovering tests..." ) ;
76+ console . log ( `Discovered ${ tasks . length } unittest suites` + ( newTasks . length ? ` and ${ newTasks . length } new suites.` : "." ) ) ;
77+ console . log ( "Discovering runner-based tests..." ) ;
4878 const discoverStart = + ( new Date ( ) ) ;
4979 const { statSync } : { statSync ( path : string ) : { size : number } ; } = require ( "fs" ) ;
50- let tasks : { runner : TestRunnerKind , file : string , size : number } [ ] = [ ] ;
51- const newTasks : { runner : TestRunnerKind , file : string , size : number } [ ] = [ ] ;
52- const perfData = readSavedPerfData ( configOption ) ;
53- let totalCost = 0 ;
54- let unknownValue : string | undefined ;
5580 for ( const runner of runners ) {
5681 const files = runner . enumerateTestFiles ( ) ;
5782 for ( const file of files ) {
@@ -87,8 +112,7 @@ namespace Harness.Parallel.Host {
87112 }
88113 tasks . sort ( ( a , b ) => a . size - b . size ) ;
89114 tasks = tasks . concat ( newTasks ) ;
90- // 1 fewer batches than threads to account for unittests running on the final thread
91- const batchCount = runners . length === 1 ? workerCount : workerCount - 1 ;
115+ const batchCount = workerCount ;
92116 const packfraction = 0.9 ;
93117 const chunkSize = 1000 ; // ~1KB or 1s for sending batches near the end of a test
94118 const batchSize = ( totalCost / workerCount ) * packfraction ; // Keep spare tests for unittest thread in reserve
@@ -113,7 +137,7 @@ namespace Harness.Parallel.Host {
113137 let closedWorkers = 0 ;
114138 for ( let i = 0 ; i < workerCount ; i ++ ) {
115139 // TODO: Just send the config over the IPC channel or in the command line arguments
116- const config : TestConfig = { light : Harness . lightMode , listenForWork : true , runUnitTests : runners . length === 1 ? false : i === workerCount - 1 } ;
140+ const config : TestConfig = { light : Harness . lightMode , listenForWork : true , runUnitTests : runners . length !== 1 } ;
117141 const configPath = ts . combinePaths ( taskConfigsFolder , `task-config${ i } .json` ) ;
118142 Harness . IO . writeFile ( configPath , JSON . stringify ( config ) ) ;
119143 const child = fork ( __filename , [ `--config="${ configPath } "` ] ) ;
@@ -187,7 +211,7 @@ namespace Harness.Parallel.Host {
187211 // It's only really worth doing an initial batching if there are a ton of files to go through
188212 if ( totalFiles > 1000 ) {
189213 console . log ( "Batching initial test lists..." ) ;
190- const batches : { runner : TestRunnerKind , file : string , size : number } [ ] [ ] = new Array ( batchCount ) ;
214+ const batches : { runner : TestRunnerKind | "unittest" , file : string , size : number } [ ] [ ] = new Array ( batchCount ) ;
191215 const doneBatching = new Array ( batchCount ) ;
192216 let scheduledTotal = 0 ;
193217 batcher: while ( true ) {
@@ -230,7 +254,7 @@ namespace Harness.Parallel.Host {
230254 if ( payload ) {
231255 worker . send ( { type : "batch" , payload } ) ;
232256 }
233- else { // Unittest thread - send off just one test
257+ else { // Out of batches, send off just one test
234258 const payload = tasks . pop ( ) ;
235259 ts . Debug . assert ( ! ! payload ) ; // The reserve kept above should ensure there is always an initial task available, even in suboptimal scenarios
236260 worker . send ( { type : "test" , payload } ) ;
0 commit comments