diff --git a/resources/benchmark.js b/resources/benchmark.js index ed6c06b3fc..d28fe9327e 100644 --- a/resources/benchmark.js +++ b/resources/benchmark.js @@ -9,19 +9,21 @@ const { Suite } = require('benchmark'); const beautifyBenchmark = require('beautify-benchmark'); const { execSync } = require('child_process'); const os = require('os'); +const fs = require('fs'); const path = require('path'); // Like build:cjs, but includes __tests__ and copies other files. const BUILD_CMD = 'babel src --optional runtime --copy-files --out-dir dist/'; const LOCAL = 'local'; -const LOCAL_DIR = path.join(__dirname, '../'); -const TEMP_DIR = os.tmpdir(); +function LOCAL_DIR(...paths) { + return path.join(__dirname, '..', ...paths); +} +function TEMP_DIR(...paths) { + return path.join(os.tmpdir(), 'graphql-js-benchmark', ...paths); +} // Returns the complete git hash for a given git revision reference. function hashForRevision(revision) { - if (revision === LOCAL) { - return revision; - } const out = execSync(`git rev-parse "${revision}"`, { encoding: 'utf8' }); const match = /[0-9a-f]{8,40}/.exec(out); if (!match) { @@ -30,55 +32,48 @@ function hashForRevision(revision) { return match[0]; } -// Returns the temporary directory which hosts the files for this git hash. -function dirForHash(hash) { - if (hash === LOCAL) { - return path.join(__dirname, '../'); - } - return path.join(TEMP_DIR, 'graphql-js-benchmark', hash); -} - -// Build a benchmarkable environment for the given revision. +// Build a benchmarkable environment for the given revision +// and returns path to its 'dist' directory. function prepareRevision(revision) { console.log(`🍳 Preparing ${revision}...`); - const hash = hashForRevision(revision); - const dir = dirForHash(hash); - if (hash === LOCAL) { - execSync(`(cd "${dir}" && yarn run ${BUILD_CMD})`); + + if (revision === LOCAL) { + execSync(`yarn run ${BUILD_CMD}`); + return LOCAL_DIR('dist'); } else { - execSync(` - if [ ! -d "${dir}" ]; then - mkdir -p "${dir}" && - git archive "${hash}" | tar -xC "${dir}" && - (cd "${dir}" && yarn install); - fi && - # Copy in local tests so the same logic applies to each revision. - for file in $(cd "${LOCAL_DIR}src"; find . -path '*/__tests__/*'); - do cp "${LOCAL_DIR}src/$file" "${dir}/src/$file"; - done && - cp -R "${LOCAL_DIR}/src/__fixtures__" "${dir}/src/__fixtures__" && - (cd "${dir}" && yarn run ${BUILD_CMD}) - `); + if (!fs.existsSync(TEMP_DIR())) { + fs.mkdirSync(TEMP_DIR()); + } + + const hash = hashForRevision(revision); + const dir = TEMP_DIR(hash); + + if (!fs.existsSync(dir)) { + fs.mkdirSync(dir); + execSync(`git archive "${hash}" | tar -xC "${dir}"`); + execSync('yarn install', { cwd: dir }); + } + for (const file of findFiles(LOCAL_DIR('src'), '*/__tests__/*')) { + const from = LOCAL_DIR('src', file); + const to = path.join(dir, 'src', file); + fs.copyFileSync(from, to); + } + execSync(`cp -R "${LOCAL_DIR()}/src/__fixtures__/" "${dir}/src/__fixtures__/"`); + execSync(`yarn run ${BUILD_CMD}`, { cwd: dir }); + + return path.join(dir, 'dist'); } } -// Find all benchmark tests to be run. -function findBenchmarks() { - const out = execSync( - `(cd ${LOCAL_DIR}src; find . -path '*/__tests__/*-benchmark.js')`, - { encoding: 'utf8' }, - ); +function findFiles(cwd, pattern) { + const out = execSync(`find . -path '${pattern}'`, { cwd, encoding: 'utf8' }); return out.split('\n').filter(Boolean); } // Run a given benchmark test with the provided revisions. -function runBenchmark(benchmark, revisions) { - const modules = revisions.map(revision => - require(path.join( - dirForHash(hashForRevision(revision)), - 'dist', - benchmark, - )), +function runBenchmark(benchmark, enviroments) { + const modules = enviroments.map(({distPath}) => + require(path.join(distPath, benchmark)), ); const suite = new Suite(modules[0].name, { onStart(event) { @@ -95,19 +90,24 @@ function runBenchmark(benchmark, revisions) { beautifyBenchmark.log(); }, }); - for (let i = 0; i < revisions.length; i++) { - suite.add(revisions[i], modules[i].measure); + for (let i = 0; i < enviroments.length; i++) { + suite.add(enviroments[i].revision, modules[i].measure); } suite.run({ async: false }); } // Prepare all revisions and run benchmarks matching a pattern against them. function prepareAndRunBenchmarks(benchmarkPatterns, revisions) { - const benchmarks = findBenchmarks().filter( - benchmark => - benchmarkPatterns.length === 0 || - benchmarkPatterns.some(pattern => benchmark.indexOf(pattern) !== -1), - ); + // Find all benchmark tests to be run. + let benchmarks = findFiles(LOCAL_DIR('src'), '*/__tests__/*-benchmark.js'); + if (benchmarkPatterns.length !== 0) { + benchmarks = benchmarks.filter( + benchmark => benchmarkPatterns.some( + pattern => path.join('src', benchmark).includes(pattern) + ), + ); + } + if (benchmarks.length === 0) { console.warn( 'No benchmarks matching: ' + @@ -115,8 +115,11 @@ function prepareAndRunBenchmarks(benchmarkPatterns, revisions) { ); return; } - revisions.forEach(revision => prepareRevision(revision)); - benchmarks.forEach(benchmark => runBenchmark(benchmark, revisions)); + + const enviroments = revisions.map( + revision => ({ revision, distPath: prepareRevision(revision)}) + ); + benchmarks.forEach(benchmark => runBenchmark(benchmark, enviroments)); } function getArguments(argv) {