diff --git a/benchmark/fixtures/coverage-many-branches.js b/benchmark/fixtures/coverage-many-branches.js new file mode 100644 index 00000000000000..9cb6360336e019 --- /dev/null +++ b/benchmark/fixtures/coverage-many-branches.js @@ -0,0 +1,115 @@ +'use strict'; + +// Exercise coverage of a class. Note, this logic is silly and exists solely +// to generate branch coverage code paths: +class CoveredClass { + constructor(x, y, opts) { + this.x = x; + this.y = y; + // Exercise coverage of nullish coalescing: + this.opts = opts ?? (Math.random() > 0.5 ? {} : undefined); + } + add() { + return this.x + this.y; + } + addSpecial() { + // Exercise coverage of optional chains: + if (this.opts?.special && this.opts?.special?.x && this.opts?.special?.y) { + return this.opts.special.x + this.opts.special.y; + } + return add(); + } + mult() { + return this.x * this.y; + } + multSpecial() { + if (this.opts?.special && this.opts?.special?.x && this.opts?.special?.y) { + return this.opts.special.x * this.opts.special.y; + } + return mult(); + } +} + +// Excercise coverage of functions: +function add(x, y) { + const mt = new CoveredClass(x, y); + return mt.add(); +} + +function addSpecial(x, y) { + let mt; + if (Math.random() > 0.5) { + mt = new CoveredClass(x, y); + } else { + mt = new CoveredClass(x, y, { + special: { + x: Math.random() * x, + y: Math.random() * y + } + }); + } + return mt.addSpecial(); +} + +function mult(x, y) { + const mt = new CoveredClass(x, y); + return mt.mult(); +} + +function multSpecial(x, y) { + let mt; + if (Math.random() > 0.5) { + mt = new CoveredClass(x, y); + } else { + mt = new CoveredClass(x, y, { + special: { + x: Math.random() * x, + y: Math.random() * y + } + }); + } + return mt.multSpecial(); +} + +for (let i = 0; i < parseInt(process.env.N); i++) { + const operations = ['add', 'addSpecial', 'mult', 'multSpecial']; + for (const operation of operations) { + // Exercise coverage of switch statements: + switch (operation) { + case 'add': + if (add(Math.random() * 10, Math.random() * 10) > 10) { + // Exercise coverage of ternary operations: + let r = addSpecial(Math.random() * 10, Math.random() * 10) > 10 ? + mult(Math.random() * 10, Math.random() * 10) : + add(Math.random() * 10, Math.random() * 10); + // Exercise && and || + if (r && Math.random() > 0.5 || Math.random() < 0.5) r++; + } + break; + case 'addSpecial': + if (addSpecial(Math.random() * 10, Math.random() * 10) > 10 && + add(Math.random() * 10, Math.random() * 10) > 10) { + let r = mult(Math.random() * 10, Math.random() * 10) > 10 ? + add(Math.random() * 10, Math.random() * 10) > 10 : + mult(Math.random() * 10, Math.random() * 10); + if (r && Math.random() > 0.5 || Math.random() < 0.5) r++; + } + break; + case 'mult': + if (mult(Math.random() * 10, Math.random() * 10) > 10) { + let r = multSpecial(Math.random() * 10, Math.random() * 10) > 10 ? + add(Math.random() * 10, Math.random() * 10) : + mult(Math.random() * 10, Math.random() * 10); + if (r && Math.random() > 0.5 || Math.random() < 0.5) r++; + } + break; + case 'multSpecial': + while (multSpecial(Math.random() * 10, Math.random() * 10) < 10) { + mult(Math.random() * 10, Math.random() * 10); + } + break; + default: + break; + } + } +} diff --git a/benchmark/process/coverage.js b/benchmark/process/coverage.js new file mode 100644 index 00000000000000..6a09d8150591c5 --- /dev/null +++ b/benchmark/process/coverage.js @@ -0,0 +1,32 @@ +// This benchmark is meant to exercise a grab bag of code paths that would +// be expected to run slower under coverage. To use this benchmark, create an +// alternate node bin that enables coverage and compare it against ./node +'use strict'; +const common = require('../common.js'); +const bench = common.createBenchmark(main, { + n: [1e5] +}); +const path = require('path'); +const { randomUUID } = require('crypto'); +const { rmSync } = require('fs'); +const { spawnSync } = require('child_process'); +const tmpdir = require('../../test/common/tmpdir'); + +const coverageDir = path.join(tmpdir.path, `./cov-${randomUUID()}`); + +function main({ n }) { + bench.start(); + const result = spawnSync(process.execPath, [ + require.resolve('../fixtures/coverage-many-branches'), + ], { + env: { + NODE_V8_COVERAGE: coverageDir, + N: n, + } + }); + rmSync(coverageDir, { recursive: true, force: true }); + if (result.status !== 0) { + throw new Error(result.stderr.toString('utf8')); + } + bench.end(n); +}