@@ -38,20 +38,45 @@ namespace Harness.Parallel.Host {
38
38
return undefined ;
39
39
}
40
40
41
- function hashName ( runner : TestRunnerKind , test : string ) {
41
+ function hashName ( runner : TestRunnerKind | "unittest" , test : string ) {
42
42
return `tsrunner-${ runner } ://${ test } ` ;
43
43
}
44
44
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 ;
45
48
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 ) {
46
75
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..." ) ;
48
78
const discoverStart = + ( new Date ( ) ) ;
49
79
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 ;
55
80
for ( const runner of runners ) {
56
81
const files = runner . enumerateTestFiles ( ) ;
57
82
for ( const file of files ) {
@@ -87,8 +112,7 @@ namespace Harness.Parallel.Host {
87
112
}
88
113
tasks . sort ( ( a , b ) => a . size - b . size ) ;
89
114
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 ;
92
116
const packfraction = 0.9 ;
93
117
const chunkSize = 1000 ; // ~1KB or 1s for sending batches near the end of a test
94
118
const batchSize = ( totalCost / workerCount ) * packfraction ; // Keep spare tests for unittest thread in reserve
@@ -113,7 +137,7 @@ namespace Harness.Parallel.Host {
113
137
let closedWorkers = 0 ;
114
138
for ( let i = 0 ; i < workerCount ; i ++ ) {
115
139
// 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 } ;
117
141
const configPath = ts . combinePaths ( taskConfigsFolder , `task-config${ i } .json` ) ;
118
142
Harness . IO . writeFile ( configPath , JSON . stringify ( config ) ) ;
119
143
const child = fork ( __filename , [ `--config="${ configPath } "` ] ) ;
@@ -187,7 +211,7 @@ namespace Harness.Parallel.Host {
187
211
// It's only really worth doing an initial batching if there are a ton of files to go through
188
212
if ( totalFiles > 1000 ) {
189
213
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 ) ;
191
215
const doneBatching = new Array ( batchCount ) ;
192
216
let scheduledTotal = 0 ;
193
217
batcher: while ( true ) {
@@ -230,7 +254,7 @@ namespace Harness.Parallel.Host {
230
254
if ( payload ) {
231
255
worker . send ( { type : "batch" , payload } ) ;
232
256
}
233
- else { // Unittest thread - send off just one test
257
+ else { // Out of batches, send off just one test
234
258
const payload = tasks . pop ( ) ;
235
259
ts . Debug . assert ( ! ! payload ) ; // The reserve kept above should ensure there is always an initial task available, even in suboptimal scenarios
236
260
worker . send ( { type : "test" , payload } ) ;
0 commit comments