Skip to content

Commit

Permalink
Add MVP of mocha-like benchmark tests
Browse files Browse the repository at this point in the history
Based on #1163 by @mohawk2
  • Loading branch information
IvanGoncharov committed Feb 5, 2018
1 parent b333b30 commit 8e2c7f1
Show file tree
Hide file tree
Showing 9 changed files with 398 additions and 16 deletions.
1 change: 1 addition & 0 deletions .flowconfig
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
.*/dist/.*
.*/coverage/.*
.*/resources/.*
.*/benchmark/.*

[include]

Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ node_modules
coverage
dist
npm
benchmark
1 change: 1 addition & 0 deletions .npmignore
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,4 @@ resources
src
dist
npm
benchmark
8 changes: 7 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
"prettier": "prettier --write 'src/**/*.js'",
"check": "flow check",
"check-cover": "for file in {src/*.js,src/**/*.js}; do echo $file; flow coverage $file; done",
"benchmark": "node resources/benchmark.js",
"build": "npm run build:clean && npm run build:cp && npm run build:npm && npm run build:npm-flow && npm run build:module && npm run build:module-flow && npm run build:package-json",
"build:clean": "rm -rf ./dist && mkdir ./dist",
"build:cp": "cp README.md LICENSE ./dist",
Expand All @@ -53,19 +54,24 @@
"babel-plugin-transform-flow-strip-types": "6.22.0",
"babel-plugin-transform-object-rest-spread": "6.26.0",
"babel-preset-env": "^1.5.2",
"beautify-benchmark": "0.2.4",
"benchmark": "2.1.4",
"chai": "4.1.2",
"chai-json-equal": "0.0.1",
"chai-spies-next": "0.9.3",
"chai-subset": "1.6.0",
"chalk": "2.3.0",
"coveralls": "3.0.0",
"eslint": "4.16.0",
"eslint-plugin-babel": "4.1.2",
"eslint-plugin-flowtype": "2.42.0",
"eslint-plugin-prettier": "2.5.0",
"flow-bin": "0.64.0",
"isparta": "4.0.0",
"microtime": "2.1.7",
"mocha": "5.0.0",
"prettier": "1.10.2",
"sane": "2.3.0"
"sane": "2.3.0",
"shelljs": "0.8.1"
}
}
112 changes: 112 additions & 0 deletions resources/benchmark.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
const benchmark = require('benchmark');
const beautifyBenchmark = require('beautify-benchmark');
const sh = require('shelljs');
const chalk = require('chalk');
const pathJoin = require('path').join;

const args = process.argv.slice(2);
args[0] = args[0] || 'HEAD';
args[1] = args[1] || 'local';

console.log('Benchmarking revisions: ' + args.join(', '));

const localDistDir = './benchmark/local';
sh.rm('-rf', localDistDir);
console.log(`Building local dist: ${localDistDir}`);
sh.mkdir('-p', localDistDir);
exec(`babel src --optional runtime --copy-files --out-dir ${localDistDir}`);

const revisions = {};
for (const arg of args) {
const distPath = buildRevisionDist(arg);
const distRequire = (path) => reqireFromCWD(pathJoin(distPath, path));
revisions[arg] = distRequire;
}

const suites = {};
global.suite = suite;
const testFiles = sh.ls(`${localDistDir}/**/__tests__/**/*-benchmark.js`);
for (const file of testFiles) {
reqireFromCWD(file);
}

dummyRun();
for (const [name, measures] of Object.entries(suites)) {
console.log(chalk.green(name) + '\n');
benchmark.invoke(measures, 'run');
}

function reqireFromCWD(path) {
return require(pathJoin(process.cwd(), path))
}

function dummyRun() {
(new benchmark.Suite('dummy'))
.add('dummy', () => { Math.pow(2, 256); })
.run();
}

function newMeasurement(name) {
return new benchmark.Suite(name, {
onStart(event) {
console.log(' ⏱️ ', event.currentTarget.name);
},
onCycle(event) {
beautifyBenchmark.add(event.target);
},
onComplete() {
beautifyBenchmark.log();
},
});
}

function suite(name, fn) {
const measures = {};
for (const [revision, distRequire] of Object.entries(revisions)) {
currentRevision = revision;
global.measure = (name, fn) => {
measures[name] = measures[name] || newMeasurement(name);
measures[name].add(revision, fn);
};
try {
fn(distRequire);
} catch (e) {
console.error(e.stack);
}
}
global.measure = undefined;
suites[name] = Object.values(measures);
}

function exec(command) {
const {code, stdout, stderr} = sh.exec(command, {silent: true});
if (code !== 0) {
console.error(stdout);
console.error(stderr);
sh.exit(code);
}
return stdout.trim();
}

function buildRevisionDist(revision) {
if (revision === 'local') {
return localDistDir;
}

const hash = exec(`git log -1 --format=%h "${revision}"`);
const buildDir = './benchmark/' + hash;
const distDir = buildDir + '/dist'

if (sh.test('-d', buildDir)) {
return distDir;
}
console.log(`Building "${revision}"(${hash}) revision: ${buildDir}`);
sh.mkdir('-p', buildDir);
exec(`git archive "${hash}" | tar -xC "${buildDir}"`);

const pwd = sh.pwd();
sh.cd(buildDir);
exec('yarn && npm run build');
sh.cd(pwd);
return buildDir + '/dist';
}
45 changes: 45 additions & 0 deletions src/language/__tests__/lexer-benchmark.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

import { readFileSync } from 'fs';
import { join } from 'path';
import { getIntrospectionQuery } from '../../utilities/introspectionQuery';
/* global suite, measure */

function readFile(path) {
const fullPath = join(__dirname, path);
return readFileSync(fullPath, { encoding: 'utf8' });
}

const introspectionQuery = getIntrospectionQuery();
const kitchenSink = readFile('./kitchen-sink.graphql');
const schemaKitchenSink = readFile('./schema-kitchen-sink.graphql');

suite('Run lexer on a string', distRequire => {
const { Source } = distRequire('language/source');
const { createLexer } = distRequire('language/lexer');

function runLexer(source) {
const lexer = createLexer(source);
let token;
do {
token = lexer.advance();
} while (token.kind !== '<EOF>');
}

measure('Introspection Query', () => {
runLexer(new Source(introspectionQuery));
});

measure('Kitchen Sink', () => {
runLexer(new Source(kitchenSink));
});

measure('Schema Kitchen Sink', () => {
runLexer(new Source(schemaKitchenSink));
});
});
28 changes: 28 additions & 0 deletions src/language/__tests__/parser-benchmark.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

import { readFileSync } from 'fs';
import { join } from 'path';
import { getIntrospectionQuery } from '../../utilities/introspectionQuery';
/* global suite, measure */

function readFile(path) {
const fullPath = join(__dirname, path);
return readFileSync(fullPath, { encoding: 'utf8' });
}

const introspectionQuery = getIntrospectionQuery();
const kitchenSink = readFile('./kitchen-sink.graphql');
const schemaKitchenSink = readFile('./schema-kitchen-sink.graphql');

suite('Parse string to AST', distRequire => {
const { parse } = distRequire('language/parser');

measure('Introspection Query', () => parse(introspectionQuery));
measure('Kitchen Sink', () => parse(kitchenSink));
measure('Schema Kitchen Sink', () => parse(schemaKitchenSink));
});
25 changes: 25 additions & 0 deletions src/language/__tests__/printer-benchmark.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

import { readFileSync } from 'fs';
import { join } from 'path';
import { getIntrospectionQuery } from '../../utilities/introspectionQuery';
/* global suite, measure */

suite('Print AST', distRequire => {
const { print } = distRequire('language/printer');
const { parse } = distRequire('language/parser');

const kitchenSink = readFileSync(join(__dirname, './kitchen-sink.graphql'), {
encoding: 'utf8',
});
const kitchenSinkAST = parse(kitchenSink);
measure('Kitchen Sink', () => print(kitchenSinkAST));

const introspectionQueryAST = parse(getIntrospectionQuery());
measure('Introspection Query', () => print(introspectionQueryAST));
});
Loading

0 comments on commit 8e2c7f1

Please sign in to comment.