Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

benchmark: add benchmark for coverage #36972

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
115 changes: 115 additions & 0 deletions 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;
}
}
}
32 changes: 32 additions & 0 deletions 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.
'use strict';

const common = require('../common.js');
const bench = common.createBenchmark(main, {
n: [1e5]
});
const path = require('path');
const { rmSync } = require('fs');
const { spawnSync } = require('child_process');
const tmpdir = require('../../test/common/tmpdir');

const coverageDir = path.join(tmpdir.path, `./cov-${Date.now()}`);

function main({ n }) {
bench.start();
const result = spawnSync(process.execPath, [
require.resolve('../fixtures/coverage-many-branches'),
], {
env: {
NODE_V8_COVERAGE: coverageDir,
N: n,
...process.env
}
});
bench.end(n);
rmSync(coverageDir, { recursive: true, force: true });
if (result.status !== 0) {
throw new Error(result.stderr.toString('utf8'));
}
}