diff --git a/README.md b/README.md index 899682f..53cafe1 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,33 @@ packages operations. - [x] winston - [x] underscore -## Running +## Install + +```console +npm i -g nodejs-package-benchmark +``` + +## Comparison + +To compare binaries, you can use the `bench-it` script. + +### Syntax: `bench-it $BINARY ["baseline"]` + +This script allows you to compare the performance of binaries. If it's your first run, you need to generate the `baseline` data using: + +```console +$ bench-it ./node baseline +``` + +To compare subsequent runs, simply omit the "baseline" option: + +```console +$ bench-it ./node +``` + +> **Note:** It's recommended to have `colordiff` installed for a clearer comparison of differences. + +## Single run To a pretty terminal output, run `index.js` diff --git a/bench-it.js b/bench-it.js new file mode 100755 index 0000000..4d1a74b --- /dev/null +++ b/bench-it.js @@ -0,0 +1,52 @@ +#!/usr/bin/env node + +const { execSync } = require('child_process'); +const fs = require('fs'); + +const NODEJS_PACKAGE_BENCHMARK_PATH = __dirname; + +if (process.argv.length < 3) { + console.log("You must pass the binary as argument. Example: bench-it ./node"); + process.exit(1); +} + +const BINARY = process.argv[2]; + +if (process.argv[3] === "baseline") { + const baseline = execSync('git rev-parse HEAD').toString().trim(); + const result = execSync(`${BINARY} ${NODEJS_PACKAGE_BENCHMARK_PATH}/index.js`, { + env: { TTY: true }, + }).toString(); + fs.writeFileSync('baseline.out', `${baseline}\n${result}`); + console.log("Baseline generated."); + process.exit(0); +} + +if (!fs.existsSync('./baseline.out')) { + console.log(`The baseline.out does not exist. Generate it with: $ bench-it ${BINARY} baseline.`); + process.exit(1); +} + +let diffCmd = "colordiff"; +try { + execSync("command -v colordiff"); +} catch (error) { + console.log("⚠️ 'colordiff' was not found. Using 'diff' as fallback."); + diffCmd = "diff"; +} + +const currentResult = execSync(`${BINARY} ${NODEJS_PACKAGE_BENCHMARK_PATH}/index.js`, { + env: { TTY: true }, +}).toString(); +fs.writeFileSync('current.out', currentResult); + +try { + const stdout = execSync(`${diffCmd} -y baseline.out current.out`, { + cwd: process.cwd() + }) + console.log(stdout.toString()) +} catch (e) { + // `diff` returns a non-0 exit code + console.log(e.message) + console.log(e.stdout.toString()) +} diff --git a/console-output.js b/console-output.js index 7649964..025a4f6 100644 --- a/console-output.js +++ b/console-output.js @@ -5,14 +5,20 @@ module.exports = { console.log(str); }, printResults (results) { - const halfScreen = process.stdout.columns / 2; + const halfScreen = process.stdout.columns ? + process.stdout.columns / 2 : 44; // arbitrary number console.log('-'.repeat(halfScreen)); for (const result of results) { console.log(`${result.name}`); // TODO(rafaelgss): support non-operation method for (const operation of result.operations) { const opName = ` ${operation.name}:`; - const spaces = ' '.repeat(halfScreen - opName.length); + let spaces = ''; + if (opName.length > halfScreen) { + spaces = opName.length + 2; + } else { + spaces = ' '.repeat(halfScreen - opName.length); + } console.log(opName + `${spaces}${opsSecFormatter.format(operation.opsSec)} (${operation.samples} samples)`); } diff --git a/index.js b/index.js index 5ce3637..75d08cc 100644 --- a/index.js +++ b/index.js @@ -1,3 +1,5 @@ +#!/usr/bin/env node + const fs = require('node:fs/promises'); const path = require('node:path'); const Piscina = require('piscina'); diff --git a/package.json b/package.json index 5262196..0ece2d6 100644 --- a/package.json +++ b/package.json @@ -1,4 +1,29 @@ { + "name": "nodejs-package-benchmark", + "description": "This package allows you to benchmark different runtimes using popular packages operations.", + "version": "1.0.0-beta.1", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/NodeSource/nodejs-package-benchmark.git" + }, + "keywords": [ + "benchmark", + "nodejs", + "core" + ], + "author": "RafaelGSS ", + "license": "MIT", + "bugs": { + "url": "https://github.com/NodeSource/nodejs-package-benchmark/issues" + }, + "homepage": "https://github.com/NodeSource/nodejs-package-benchmark#readme", + "bin": { + "bench-it": "./bench-it.js" + }, "dependencies": { "@babel/standalone": "7.24.0", "dotenv": "16.4.5", @@ -9,9 +34,7 @@ "piscina": "4.4.0", "prettier": "3.2.5", "underscore": "1.13.6", - "winston": "3.12.0" - }, - "devDependencies": { + "winston": "3.12.0", "autocannon": "7.15.0", "benchmark": "2.1.4" } diff --git a/src/prettier-benchmark.js b/src/prettier-benchmark.js index a022d28..e5f711a 100644 --- a/src/prettier-benchmark.js +++ b/src/prettier-benchmark.js @@ -11,36 +11,36 @@ module.exports = { type: 'operation', operations: [ { - name: 'format (semi=true)', + name: 'format', fn: () => { let v = undefined; for (const p of payloads) { - v= prettier.format(p, { semi: true, parser: 'babel' }); + v= prettier.format(p, { parser: 'babel' }); } return v; }, }, { - name: 'format (singleQuote=true semi=true tabs=true)', + name: 'format (singleQuote=true useTabs=true)', fn: () => { let v = undefined; for (const p of payloads) { v = prettier.format( p, - { singleQuote: true, semi: true, tabs: true, parser: 'babel' }, + { singleQuote: true, useTabs: true, parser: 'babel' }, ); } return v; }, }, { - name: 'format (singleQuote=false semi=false tabs=false)', + name: 'format (semi=false)', fn: () => { let v = undefined; for (const p of payloads) { v = prettier.format( p, - { singleQuote: false, semi: false, tabs: false, parser: 'babel' } + { semi: false, parser: 'babel' } ); } return v;