You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

184 lines
3.6 KiB
JavaScript

#!/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 NEWER_PEGJS_BIN = "bin/peg.js";
let NEWER_BENCHMARK_BIN = "test/benchmark/run";
const ef = {
get pegjs() {
return fs.existsSync( NEWER_PEGJS_BIN ) ? NEWER_PEGJS_BIN : "bin/pegjs";
},
get benchmark() {
return fs.existsSync( NEWER_BENCHMARK_BIN ) ? NEWER_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 " + ef.benchmark )
// 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 ${ ef.pegjs } ${ 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() }.
` );