@@ -6,9 +6,6 @@ const path = require('path');
66const assert = require ( 'assert' ) ;
77const cp = require ( 'child_process' ) ;
88
9- const { red, green, yellow, cyan, grey } = require ( './colors' ) ;
10- const { exec, rmdirRecursive, readdirRecursive } = require ( './utils' ) ;
11-
129const NS_PER_SEC = 1e9 ;
1310const LOCAL = 'local' ;
1411
@@ -21,64 +18,76 @@ function localDir(...paths) {
2118 return path . join ( __dirname , '..' , ...paths ) ;
2219}
2320
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+
2430// Build a benchmark-friendly environment for the given revision
2531// 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 } ` ) ;
2854
29- if ( revision === LOCAL ) {
30- return babelBuild ( localDir ( ) ) ;
31- }
55+ return { revision, projectPath } ;
56+ } ) ;
3257
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+ }
3565
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 } "` ) ;
3968
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+ }
4273
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 ;
4782 }
48- exec ( `cp -R "${ localDir ( ) } /src/__fixtures__/" "${ dir } /src/__fixtures__/"` ) ;
4983
50- return babelBuild ( dir ) ;
51- }
84+ function buildNPMArchive ( repoDir ) {
85+ exec ( 'npm --quiet run build:npm' , { cwd : repoDir } ) ;
5286
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 ) ;
7390 }
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 ) ;
8291}
8392
8493async function collectSamples ( modulePath ) {
@@ -220,17 +229,14 @@ function maxBy(array, fn) {
220229}
221230
222231// 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 ) ;
228234
229- for ( const benchmark of matchBenchmarks ( benchmarkPatterns ) ) {
235+ for ( const benchmark of benchmarks ) {
230236 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 ) ;
234240
235241 if ( i === 0 ) {
236242 const { name } = await sampleModule ( modulePath ) ;
@@ -241,13 +247,13 @@ async function prepareAndRunBenchmarks(benchmarkPatterns, revisions) {
241247 const samples = await collectSamples ( modulePath ) ;
242248
243249 results . push ( {
244- name : environment . revision ,
250+ name : revision ,
245251 samples,
246252 ...computeStats ( samples ) ,
247253 } ) ;
248254 process . stdout . write ( ' ' + cyan ( i + 1 ) + ' tests completed.\u000D' ) ;
249255 } catch ( error ) {
250- console . log ( ' ' + environment . revision + ': ' + red ( String ( error ) ) ) ;
256+ console . log ( ' ' + revision + ': ' + red ( String ( error ) ) ) ;
251257 }
252258 }
253259 console . log ( '\n' ) ;
@@ -257,57 +263,74 @@ async function prepareAndRunBenchmarks(benchmarkPatterns, revisions) {
257263 }
258264}
259265
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-
276266function getArguments ( argv ) {
277267 const revsIdx = argv . indexOf ( '--revs' ) ;
278268 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 ) ;
280270 let assumeArgs ;
281271 let revisions ;
282272 switch ( revsArgs . length ) {
283273 case 0 :
284- assumeArgs = [ ...benchmarkPatterns , '--revs' , 'local' , 'HEAD' ] ;
274+ assumeArgs = [ ...specificBenchmarks , '--revs' , 'local' , 'HEAD' ] ;
285275 revisions = [ LOCAL , 'HEAD' ] ;
286276 break ;
287277 case 1 :
288- assumeArgs = [ ...benchmarkPatterns , '--revs' , 'local' , revsArgs [ 0 ] ] ;
278+ assumeArgs = [ ...specificBenchmarks , '--revs' , 'local' , revsArgs [ 0 ] ] ;
289279 revisions = [ LOCAL , revsArgs [ 0 ] ] ;
290280 break ;
291281 default :
292282 revisions = revsArgs ;
293283 break ;
294284 }
285+
295286 if ( assumeArgs ) {
296287 console . warn (
297288 'Assuming you meant: ' + bold ( 'benchmark ' + assumeArgs . join ( ' ' ) ) ,
298289 ) ;
299290 }
300- return { benchmarkPatterns, revisions } ;
291+
292+ return { specificBenchmarks, revisions } ;
301293}
302294
303295function bold ( str ) {
304296 return '\u001b[1m' + str + '\u001b[0m' ;
305297}
306298
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+
307328// Get the revisions and make things happen!
308329if ( 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 ) => {
311334 console . error ( error ) ;
312335 process . exit ( 1 ) ;
313336 } ) ;
@@ -350,7 +373,7 @@ function sampleModule(modulePath) {
350373 '--noconcurrent_sweeping' ,
351374 '--predictable' ,
352375 '--expose-gc' ,
353- '-e ' ,
376+ '--eval ' ,
354377 sampleCode ,
355378 ] ,
356379 {
0 commit comments