Skip to content

Commit

Permalink
test: refactor test-readline-async-iterators into a benchmark
Browse files Browse the repository at this point in the history
PR-URL: #49237
Fixes: #49224
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
  • Loading branch information
shubham9411 authored and ruyadorno committed Sep 28, 2023
1 parent b8a4fef commit 3db9b40
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 112 deletions.
38 changes: 36 additions & 2 deletions benchmark/readline/readline-iterable.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ const { Readable } = require('stream');

const bench = common.createBenchmark(main, {
n: [1e1, 1e2, 1e3, 1e4, 1e5, 1e6],
type: ['old', 'new'],
});

const loremIpsum = `Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed
Expand All @@ -21,6 +22,37 @@ Condimentum mattis pellentesque id nibh tortor id aliquet lectus proin.
Diam in arcu cursus euismod quis viverra nibh.
Rest of line`;

function oldWay() {
const readable = new Readable({
objectMode: true,
read: () => {
this.resume();
},
destroy: (err, cb) => {
this.off('line', lineListener);
this.off('close', closeListener);
this.close();
cb(err);
},
});
const lineListener = (input) => {
if (!readable.push(input)) {
// TODO(rexagod): drain to resume flow
this.pause();
}
};
const closeListener = () => {
readable.push(null);
};
const errorListener = (err) => {
readable.destroy(err);
};
this.on('error', errorListener);
this.on('line', lineListener);
this.on('close', closeListener);
return readable[Symbol.asyncIterator]();
}

function getLoremIpsumStream(repetitions) {
const readable = Readable({
objectMode: true,
Expand All @@ -32,16 +64,18 @@ function getLoremIpsumStream(repetitions) {
return readable;
}

async function main({ n }) {
async function main({ n, type }) {
bench.start();
let lineCount = 0;

const iterable = readline.createInterface({
input: getLoremIpsumStream(n),
});

const readlineIterable = type === 'old' ? oldWay.call(iterable) : iterable;

// eslint-disable-next-line no-unused-vars
for await (const _ of iterable) {
for await (const _ of readlineIterable) {
lineCount++;
}
bench.end(lineCount);
Expand Down
110 changes: 0 additions & 110 deletions test/parallel/test-readline-async-iterators.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,115 +73,6 @@ async function testMutual() {
}
}

async function testPerformance() {
const loremIpsum = `Lorem ipsum dolor sit amet, consectetur adipiscing elit,
sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Dui accumsan sit amet nulla facilisi morbi tempus iaculis urna.
Eget dolor morbi non arcu risus quis varius quam quisque.
Lacus viverra vitae congue eu consequat ac felis donec.
Amet porttitor eget dolor morbi non arcu.
Velit ut tortor pretium viverra suspendisse.
Mauris nunc congue nisi vitae suscipit tellus.
Amet nisl suscipit adipiscing bibendum est ultricies integer.
Sit amet dictum sit amet justo donec enim diam.
Condimentum mattis pellentesque id nibh tortor id aliquet lectus proin.
Diam in arcu cursus euismod quis viverra nibh.
`;

const REPETITIONS = 10000;
const SAMPLE = 100;
const THRESHOLD = 81;

function getLoremIpsumStream() {
const readable = Readable({
objectMode: true,
});
let i = 0;
readable._read = () => readable.push(
i++ >= REPETITIONS ? null : loremIpsum
);
return readable;
}

function oldWay() {
const readable = new Readable({
objectMode: true,
read: () => {
this.resume();
},
destroy: (err, cb) => {
this.off('line', lineListener);
this.off('close', closeListener);
this.close();
cb(err);
},
});
const lineListener = (input) => {
if (!readable.push(input)) {
// TODO(rexagod): drain to resume flow
this.pause();
}
};
const closeListener = () => {
readable.push(null);
};
const errorListener = (err) => {
readable.destroy(err);
};
this.on('error', errorListener);
this.on('line', lineListener);
this.on('close', closeListener);
return readable[Symbol.asyncIterator]();
}

function getAvg(mean, x, n) {
return (mean * n + x) / (n + 1);
}

let totalTimeOldWay = 0;
let totalTimeNewWay = 0;
let totalCharsOldWay = 0;
let totalCharsNewWay = 0;
const linesOldWay = [];
const linesNewWay = [];

for (let time = 0; time < SAMPLE; time++) {
const rlOldWay = readline.createInterface({
input: getLoremIpsumStream(),
});
let currenttotalTimeOldWay = Date.now();
for await (const line of oldWay.call(rlOldWay)) {
totalCharsOldWay += line.length;
if (time === 0) {
linesOldWay.push(line);
}
}
currenttotalTimeOldWay = Date.now() - currenttotalTimeOldWay;
totalTimeOldWay = getAvg(totalTimeOldWay, currenttotalTimeOldWay, SAMPLE);

const rlNewWay = readline.createInterface({
input: getLoremIpsumStream(),
});
let currentTotalTimeNewWay = Date.now();
for await (const line of rlNewWay) {
totalCharsNewWay += line.length;
if (time === 0) {
linesNewWay.push(line);
}
}
currentTotalTimeNewWay = Date.now() - currentTotalTimeNewWay;
totalTimeNewWay = getAvg(totalTimeNewWay, currentTotalTimeNewWay, SAMPLE);
}

assert.strictEqual(totalCharsOldWay, totalCharsNewWay);
assert.strictEqual(linesOldWay.length, linesNewWay.length);
linesOldWay.forEach((line, index) =>
assert.strictEqual(line, linesNewWay[index])
);
const percentage = totalTimeNewWay * 100 / totalTimeOldWay;
assert.ok(percentage <= THRESHOLD, `Failed: ${totalTimeNewWay} isn't lesser than ${THRESHOLD}% of ${totalTimeOldWay}. Actual percentage: ${percentage.toFixed(2)}%`);
}

async function testSlowStreamForLeaks() {
const message = 'a\nb\nc\n';
const DELAY = 1;
Expand Down Expand Up @@ -225,6 +116,5 @@ async function testSlowStreamForLeaks() {

testSimple()
.then(testMutual)
.then(testPerformance)
.then(testSlowStreamForLeaks)
.then(common.mustCall());

0 comments on commit 3db9b40

Please sign in to comment.