@@ -6,9 +6,6 @@ const path = require('path');
6
6
const assert = require ( 'assert' ) ;
7
7
const cp = require ( 'child_process' ) ;
8
8
9
- const { red, green, yellow, cyan, grey } = require ( './colors' ) ;
10
- const { exec, rmdirRecursive, readdirRecursive } = require ( './utils' ) ;
11
-
12
9
const NS_PER_SEC = 1e9 ;
13
10
const LOCAL = 'local' ;
14
11
@@ -21,64 +18,76 @@ function localDir(...paths) {
21
18
return path . join ( __dirname , '..' , ...paths ) ;
22
19
}
23
20
21
+ function exec ( command , options = { } ) {
22
+ const result = cp . execSync ( command , {
23
+ encoding : 'utf-8' ,
24
+ stdio : [ 'inherit' , 'pipe' , 'inherit' ] ,
25
+ ...options ,
26
+ } ) ;
27
+ return result && result . trimEnd ( ) ;
28
+ }
29
+
24
30
// Build a benchmark-friendly environment for the given revision
25
31
// and returns path to its 'dist' directory.
26
- function prepareRevision ( revision ) {
27
- console . log ( `🍳 Preparing ${ revision } ...` ) ;
32
+ function prepareBenchmarkProjects ( revisionList ) {
33
+ const tmpDir = path . join ( os . tmpdir ( ) , 'graphql-js-benchmark' ) ;
34
+ fs . mkdirSync ( tmpDir , { recursive : true } ) ;
35
+
36
+ const setupDir = path . join ( tmpDir , 'setup' ) ;
37
+ fs . rmdirSync ( setupDir , { recursive : true } ) ;
38
+ fs . mkdirSync ( setupDir ) ;
39
+
40
+ return revisionList . map ( ( revision ) => {
41
+ console . log ( `🍳 Preparing ${ revision } ...` ) ;
42
+ const projectPath = path . join ( setupDir , revision ) ;
43
+ fs . rmdirSync ( projectPath , { recursive : true } ) ;
44
+ fs . mkdirSync ( projectPath ) ;
45
+
46
+ fs . writeFileSync (
47
+ path . join ( projectPath , 'package.json' ) ,
48
+ '{ "private": true }' ,
49
+ ) ;
50
+ exec ( 'npm --quiet install ' + prepareNPMPackage ( revision ) , {
51
+ cwd : projectPath ,
52
+ } ) ;
53
+ exec ( `cp -R ${ localDir ( 'benchmark' ) } ${ projectPath } ` ) ;
28
54
29
- if ( revision === LOCAL ) {
30
- return babelBuild ( localDir ( ) ) ;
31
- }
55
+ return { revision, projectPath } ;
56
+ } ) ;
32
57
33
- // Returns the complete git hash for a given git revision reference.
34
- const hash = exec ( `git rev-parse "${ revision } "` ) ;
58
+ function prepareNPMPackage ( revision ) {
59
+ if ( revision === LOCAL ) {
60
+ const repoDir = localDir ( ) ;
61
+ const archivePath = path . join ( tmpDir , 'graphql-local.tgz' ) ;
62
+ fs . renameSync ( buildNPMArchive ( repoDir ) , archivePath ) ;
63
+ return archivePath ;
64
+ }
35
65
36
- const dir = path . join ( os . tmpdir ( ) , 'graphql-js-benchmark' , hash ) ;
37
- rmdirRecursive ( dir ) ;
38
- fs . mkdirSync ( dir , { recursive : true } ) ;
66
+ // Returns the complete git hash for a given git revision reference.
67
+ const hash = exec ( `git rev-parse "${ revision } "` ) ;
39
68
40
- exec ( `git archive "${ hash } " | tar -xC "${ dir } "` ) ;
41
- exec ( 'npm ci' , { cwd : dir } ) ;
69
+ const archivePath = path . join ( tmpDir , `graphql-${ hash } .tgz` ) ;
70
+ if ( fs . existsSync ( archivePath ) ) {
71
+ return archivePath ;
72
+ }
42
73
43
- for ( const file of findFiles ( localDir ( 'src' ) , '*/__tests__/*' ) ) {
44
- const from = localDir ( 'src' , file ) ;
45
- const to = path . join ( dir , 'src' , file ) ;
46
- fs . copyFileSync ( from , to ) ;
74
+ const repoDir = path . join ( tmpDir , hash ) ;
75
+ fs . rmdirSync ( repoDir , { recursive : true } ) ;
76
+ fs . mkdirSync ( repoDir ) ;
77
+ exec ( `git archive "${ hash } " | tar -xC "${ repoDir } "` ) ;
78
+ exec ( 'npm --quiet ci' , { cwd : repoDir } ) ;
79
+ fs . renameSync ( buildNPMArchive ( repoDir ) , archivePath ) ;
80
+ fs . rmdirSync ( repoDir , { recursive : true } ) ;
81
+ return archivePath ;
47
82
}
48
- exec ( `cp -R "${ localDir ( ) } /src/__fixtures__/" "${ dir } /src/__fixtures__/"` ) ;
49
83
50
- return babelBuild ( dir ) ;
51
- }
84
+ function buildNPMArchive ( repoDir ) {
85
+ exec ( 'npm --quiet run build:npm' , { cwd : repoDir } ) ;
52
86
53
- function babelBuild ( dir ) {
54
- const oldCWD = process . cwd ( ) ;
55
- process . chdir ( dir ) ;
56
-
57
- rmdirRecursive ( './benchmarkDist' ) ;
58
- fs . mkdirSync ( './benchmarkDist' ) ;
59
-
60
- const babelPath = path . join ( dir , 'node_modules' , '@babel' , 'core' ) ;
61
- const babel = require ( babelPath ) ;
62
- for ( const filepath of readdirRecursive ( './src' ) ) {
63
- const srcPath = path . join ( './src' , filepath ) ;
64
- const destPath = path . join ( './benchmarkDist' , filepath ) ;
65
-
66
- fs . mkdirSync ( path . dirname ( destPath ) , { recursive : true } ) ;
67
- if ( filepath . endsWith ( '.js' ) ) {
68
- const cjs = babel . transformFileSync ( srcPath , { envName : 'cjs' } ) . code ;
69
- fs . writeFileSync ( destPath , cjs ) ;
70
- } else {
71
- fs . copyFileSync ( srcPath , destPath ) ;
72
- }
87
+ const distDir = path . join ( repoDir , 'npmDist' ) ;
88
+ const archiveName = exec ( `npm --quiet pack ${ distDir } ` , { cwd : repoDir } ) ;
89
+ return path . join ( repoDir , archiveName ) ;
73
90
}
74
-
75
- process . chdir ( oldCWD ) ;
76
- return path . join ( dir , 'benchmarkDist' ) ;
77
- }
78
-
79
- function findFiles ( cwd , pattern ) {
80
- const out = exec ( `find . -path '${ pattern } '` , { cwd } ) ;
81
- return out . split ( '\n' ) . filter ( Boolean ) ;
82
91
}
83
92
84
93
async function collectSamples ( modulePath ) {
@@ -220,17 +229,14 @@ function maxBy(array, fn) {
220
229
}
221
230
222
231
// Prepare all revisions and run benchmarks matching a pattern against them.
223
- async function prepareAndRunBenchmarks ( benchmarkPatterns , revisions ) {
224
- const environments = revisions . map ( ( revision ) => ( {
225
- revision,
226
- distPath : prepareRevision ( revision ) ,
227
- } ) ) ;
232
+ async function runBenchmarks ( benchmarks , revisions ) {
233
+ const benchmarkProjects = prepareBenchmarkProjects ( revisions ) ;
228
234
229
- for ( const benchmark of matchBenchmarks ( benchmarkPatterns ) ) {
235
+ for ( const benchmark of benchmarks ) {
230
236
const results = [ ] ;
231
- for ( let i = 0 ; i < environments . length ; ++ i ) {
232
- const environment = environments [ i ] ;
233
- const modulePath = path . join ( environment . distPath , benchmark ) ;
237
+ for ( let i = 0 ; i < benchmarkProjects . length ; ++ i ) {
238
+ const { revision , projectPath } = benchmarkProjects [ i ] ;
239
+ const modulePath = path . join ( projectPath , benchmark ) ;
234
240
235
241
if ( i === 0 ) {
236
242
const { name } = await sampleModule ( modulePath ) ;
@@ -241,13 +247,13 @@ async function prepareAndRunBenchmarks(benchmarkPatterns, revisions) {
241
247
const samples = await collectSamples ( modulePath ) ;
242
248
243
249
results . push ( {
244
- name : environment . revision ,
250
+ name : revision ,
245
251
samples,
246
252
...computeStats ( samples ) ,
247
253
} ) ;
248
254
process . stdout . write ( ' ' + cyan ( i + 1 ) + ' tests completed.\u000D' ) ;
249
255
} catch ( error ) {
250
- console . log ( ' ' + environment . revision + ': ' + red ( String ( error ) ) ) ;
256
+ console . log ( ' ' + revision + ': ' + red ( String ( error ) ) ) ;
251
257
}
252
258
}
253
259
console . log ( '\n' ) ;
@@ -257,57 +263,74 @@ async function prepareAndRunBenchmarks(benchmarkPatterns, revisions) {
257
263
}
258
264
}
259
265
260
- // Find all benchmark tests to be run.
261
- function matchBenchmarks ( patterns ) {
262
- let benchmarks = findFiles ( localDir ( 'src' ) , '*/__tests__/*-benchmark.js' ) ;
263
- if ( patterns . length > 0 ) {
264
- benchmarks = benchmarks . filter ( ( benchmark ) =>
265
- patterns . some ( ( pattern ) => path . join ( 'src' , benchmark ) . includes ( pattern ) ) ,
266
- ) ;
267
- }
268
-
269
- if ( benchmarks . length === 0 ) {
270
- console . warn ( 'No benchmarks matching: ' + patterns . map ( bold ) . join ( '' ) ) ;
271
- }
272
-
273
- return benchmarks ;
274
- }
275
-
276
266
function getArguments ( argv ) {
277
267
const revsIdx = argv . indexOf ( '--revs' ) ;
278
268
const revsArgs = revsIdx === - 1 ? [ ] : argv . slice ( revsIdx + 1 ) ;
279
- const benchmarkPatterns = revsIdx === - 1 ? argv : argv . slice ( 0 , revsIdx ) ;
269
+ const specificBenchmarks = revsIdx === - 1 ? argv : argv . slice ( 0 , revsIdx ) ;
280
270
let assumeArgs ;
281
271
let revisions ;
282
272
switch ( revsArgs . length ) {
283
273
case 0 :
284
- assumeArgs = [ ...benchmarkPatterns , '--revs' , 'local' , 'HEAD' ] ;
274
+ assumeArgs = [ ...specificBenchmarks , '--revs' , 'local' , 'HEAD' ] ;
285
275
revisions = [ LOCAL , 'HEAD' ] ;
286
276
break ;
287
277
case 1 :
288
- assumeArgs = [ ...benchmarkPatterns , '--revs' , 'local' , revsArgs [ 0 ] ] ;
278
+ assumeArgs = [ ...specificBenchmarks , '--revs' , 'local' , revsArgs [ 0 ] ] ;
289
279
revisions = [ LOCAL , revsArgs [ 0 ] ] ;
290
280
break ;
291
281
default :
292
282
revisions = revsArgs ;
293
283
break ;
294
284
}
285
+
295
286
if ( assumeArgs ) {
296
287
console . warn (
297
288
'Assuming you meant: ' + bold ( 'benchmark ' + assumeArgs . join ( ' ' ) ) ,
298
289
) ;
299
290
}
300
- return { benchmarkPatterns, revisions } ;
291
+
292
+ return { specificBenchmarks, revisions } ;
301
293
}
302
294
303
295
function bold ( str ) {
304
296
return '\u001b[1m' + str + '\u001b[0m' ;
305
297
}
306
298
299
+ function red ( str ) {
300
+ return '\u001b[31m' + str + '\u001b[0m' ;
301
+ }
302
+
303
+ function green ( str ) {
304
+ return '\u001b[32m' + str + '\u001b[0m' ;
305
+ }
306
+
307
+ function yellow ( str ) {
308
+ return '\u001b[33m' + str + '\u001b[0m' ;
309
+ }
310
+
311
+ function cyan ( str ) {
312
+ return '\u001b[36m' + str + '\u001b[0m' ;
313
+ }
314
+
315
+ function grey ( str ) {
316
+ return '\u001b[90m' + str + '\u001b[0m' ;
317
+ }
318
+
319
+ function findAllBenchmarks ( ) {
320
+ return fs
321
+ . readdirSync ( localDir ( 'benchmark' ) , { withFileTypes : true } )
322
+ . filter ( ( dirent ) => dirent . isFile ( ) )
323
+ . map ( ( dirent ) => dirent . name )
324
+ . filter ( ( name ) => name . endsWith ( '-benchmark.js' ) )
325
+ . map ( ( name ) => path . join ( 'benchmark' , name ) ) ;
326
+ }
327
+
307
328
// Get the revisions and make things happen!
308
329
if ( require . main === module ) {
309
- const { benchmarkPatterns, revisions } = getArguments ( process . argv . slice ( 2 ) ) ;
310
- prepareAndRunBenchmarks ( benchmarkPatterns , revisions ) . catch ( ( error ) => {
330
+ const { specificBenchmarks, revisions } = getArguments ( process . argv . slice ( 2 ) ) ;
331
+ const benchmarks =
332
+ specificBenchmarks . length > 0 ? specificBenchmarks : findAllBenchmarks ( ) ;
333
+ runBenchmarks ( benchmarks , revisions ) . catch ( ( error ) => {
311
334
console . error ( error ) ;
312
335
process . exit ( 1 ) ;
313
336
} ) ;
@@ -350,7 +373,7 @@ function sampleModule(modulePath) {
350
373
'--noconcurrent_sweeping' ,
351
374
'--predictable' ,
352
375
'--expose-gc' ,
353
- '-e ' ,
376
+ '--eval ' ,
354
377
sampleCode ,
355
378
] ,
356
379
{
0 commit comments