|
|
|
#!/usr/bin/env node
|
|
|
|
|
|
|
|
//
|
|
|
|
// Measures impact of a Git commit (or multiple commits) on generated parsers
|
|
|
|
// speed and size. Makes sense to use only on PEG.js git repository checkout.
|
|
|
|
//
|
|
|
|
|
|
|
|
/* eslint prefer-const: 0 */
|
|
|
|
|
|
|
|
"use strict";
|
|
|
|
|
|
|
|
const child_process = require( "child_process" );
|
|
|
|
const fs = require( "fs" );
|
|
|
|
const os = require( "os" );
|
|
|
|
const path = require( "path" );
|
|
|
|
const dedent = require( "dedent" );
|
|
|
|
const glob = require( "glob" );
|
|
|
|
|
|
|
|
// Current Working Directory
|
|
|
|
|
|
|
|
const cwd = path.join( __dirname, ".." );
|
|
|
|
if ( process.cwd() !== cwd ) process.chdir( cwd );
|
|
|
|
|
|
|
|
// Execution Files
|
|
|
|
|
|
|
|
let PEGJS_BIN = "bin/peg.js";
|
|
|
|
let BENCHMARK_BIN = "test/benchmark/run";
|
|
|
|
|
|
|
|
if ( ! fs.existsSync( PEGJS_BIN ) ) {
|
|
|
|
|
|
|
|
PEGJS_BIN = "bin/pegjs";
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( ! fs.existsSync( BENCHMARK_BIN ) ) {
|
|
|
|
|
|
|
|
BENCHMARK_BIN = "benchmark/run";
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// Utils
|
|
|
|
|
|
|
|
function echo( message ) {
|
|
|
|
|
|
|
|
process.stdout.write( message );
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
function exec( command ) {
|
|
|
|
|
|
|
|
return child_process.execSync( command, { encoding: "utf8" } );
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
function prepare( commit ) {
|
|
|
|
|
|
|
|
exec( `git checkout --quiet "${ commit }"` );
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
function runBenchmark() {
|
|
|
|
|
|
|
|
return parseFloat(
|
|
|
|
exec( "node " + BENCHMARK_BIN )
|
|
|
|
|
|
|
|
// Split by table seprator, reverse and return the total bytes per second
|
|
|
|
.split( "│" )
|
|
|
|
.reverse()[ 1 ]
|
|
|
|
|
|
|
|
// Trim the whitespaces and remove ` kB/s` from the end
|
|
|
|
.trim()
|
|
|
|
.slice( 0, -5 )
|
|
|
|
);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
function measureSpeed() {
|
|
|
|
|
|
|
|
return ( runBenchmark() + runBenchmark() + runBenchmark() + runBenchmark() + runBenchmark() / 5 ).toFixed( 2 );
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
function measureSize() {
|
|
|
|
|
|
|
|
let size = 0;
|
|
|
|
|
|
|
|
glob.sync( "examples/*.pegjs" )
|
|
|
|
.forEach( example => {
|
|
|
|
|
|
|
|
exec( `node ${ PEGJS_BIN } ${ example }` );
|
|
|
|
example = example.slice( 0, -5 ) + "js";
|
|
|
|
size += fs.statSync( example ).size;
|
|
|
|
fs.unlinkSync( example );
|
|
|
|
|
|
|
|
} );
|
|
|
|
|
|
|
|
return size;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
function difference( $1, $2 ) {
|
|
|
|
|
|
|
|
return ( ( $2 / $1 - 1 ) * 100 ).toFixed( 4 );
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// Prepare
|
|
|
|
|
|
|
|
const argv = process.argv.slice( 2 );
|
|
|
|
let commit_before, commit_after;
|
|
|
|
|
|
|
|
if ( argv.length === 1 ) {
|
|
|
|
|
|
|
|
commit_before = argv[ 0 ] + "~1";
|
|
|
|
commit_after = argv[ 0 ];
|
|
|
|
|
|
|
|
} else if ( argv.length === 2 ) {
|
|
|
|
|
|
|
|
commit_before = argv[ 0 ];
|
|
|
|
commit_after = argv[ 1 ];
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
console.log( dedent`
|
|
|
|
|
|
|
|
Usage:
|
|
|
|
|
|
|
|
test/impact <commit>
|
|
|
|
test/impact <commit_before> <commit_after>
|
|
|
|
|
|
|
|
Measures impact of a Git commit (or multiple commits) on generated parser's
|
|
|
|
speed and size. Makes sense to use only on PEG.js Git repository checkout.
|
|
|
|
|
|
|
|
` );
|
|
|
|
process.exit( 1 );
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// Measure
|
|
|
|
|
|
|
|
const branch = exec( "git rev-parse --abbrev-ref HEAD" );
|
|
|
|
let speed1, size1, speed2, size2;
|
|
|
|
|
|
|
|
echo( `Measuring commit ${ commit_before }...` );
|
|
|
|
prepare( commit_before );
|
|
|
|
speed1 = measureSpeed();
|
|
|
|
size1 = measureSize();
|
|
|
|
echo( " OK" + os.EOL );
|
|
|
|
|
|
|
|
echo( `Measuring commit ${ commit_after }...` );
|
|
|
|
prepare( commit_after );
|
|
|
|
speed2 = measureSpeed();
|
|
|
|
size2 = measureSize();
|
|
|
|
echo( " OK" + os.EOL );
|
|
|
|
|
|
|
|
// Finish
|
|
|
|
|
|
|
|
prepare( branch );
|
|
|
|
|
|
|
|
console.log( dedent`
|
|
|
|
|
|
|
|
test/impact ${ commit_before } ${ commit_after }
|
|
|
|
|
|
|
|
Speed impact
|
|
|
|
------------
|
|
|
|
Before: ${ speed1 } kB/s
|
|
|
|
After: ${ speed2 } kB/s
|
|
|
|
Difference: ${ difference( parseFloat( speed1 ), parseFloat( speed2 ) ) }%
|
|
|
|
|
|
|
|
Size impact
|
|
|
|
-----------
|
|
|
|
Before: ${ size1 } b
|
|
|
|
After: ${ size2 } b
|
|
|
|
Difference: ${ difference( size1, size2 ) }%
|
|
|
|
|
|
|
|
- Measured by /test/impact with Node.js ${ process.version }
|
|
|
|
- Your system: ${ os.type() } ${ os.release() } ${ os.arch() }.
|
|
|
|
|
|
|
|
` );
|