benchmark: fix race condition on fs benchs

PR-URL: https://github.com/nodejs/node/pull/50035
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
This commit is contained in:
Vinicius Lourenço 2023-10-15 07:55:27 -03:00 committed by GitHub
parent 0f0dd1a493
commit 33c87ec096
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 103 additions and 71 deletions

View File

@ -14,7 +14,6 @@ const filename = path.resolve(__dirname,
`.removeme-benchmark-garbage-${process.pid}`);
const fs = require('fs');
const zlib = require('zlib');
const assert = require('assert');
const bench = common.createBenchmark(main, {
duration: [5],
@ -35,20 +34,28 @@ function main({ len, duration, concurrent, encoding }) {
const zipData = Buffer.alloc(1024, 'a');
let waitConcurrent = 0;
// Plus one because of zip
const targetConcurrency = concurrent + 1;
const startedAt = Date.now();
const endAt = startedAt + (duration * 1000);
let reads = 0;
let zips = 0;
let benchEnded = false;
bench.start();
setTimeout(() => {
function stop() {
const totalOps = reads + zips;
benchEnded = true;
bench.end(totalOps);
try {
fs.unlinkSync(filename);
} catch {
// Continue regardless of error.
}
}, duration * 1000);
}
function read() {
fs.readFile(filename, encoding, afterRead);
@ -56,11 +63,6 @@ function main({ len, duration, concurrent, encoding }) {
function afterRead(er, data) {
if (er) {
if (er.code === 'ENOENT') {
// Only OK if unlinked by the timer from main.
assert.ok(benchEnded);
return;
}
throw er;
}
@ -68,8 +70,13 @@ function main({ len, duration, concurrent, encoding }) {
throw new Error('wrong number of bytes returned');
reads++;
if (!benchEnded)
const benchEnded = Date.now() >= endAt;
if (benchEnded && (++waitConcurrent) === targetConcurrency) {
stop();
} else if (!benchEnded) {
read();
}
}
function zip() {
@ -81,12 +88,17 @@ function main({ len, duration, concurrent, encoding }) {
throw er;
zips++;
if (!benchEnded)
const benchEnded = Date.now() >= endAt;
if (benchEnded && (++waitConcurrent) === targetConcurrency) {
stop();
} else if (!benchEnded) {
zip();
}
}
// Start reads
while (concurrent-- > 0) read();
for (let i = 0; i < concurrent; i++) read();
// Start a competing zip
zip();

View File

@ -5,7 +5,6 @@
const common = require('../common.js');
const fs = require('fs');
const assert = require('assert');
const tmpdir = require('../../test/common/tmpdir');
tmpdir.refresh();
@ -36,18 +35,24 @@ function main({ len, duration, concurrent, encoding }) {
data = null;
let reads = 0;
let benchEnded = false;
let waitConcurrent = 0;
const startedAt = Date.now();
const endAt = startedAt + (duration * 1000);
bench.start();
setTimeout(() => {
benchEnded = true;
function stop() {
bench.end(reads);
try {
fs.unlinkSync(filename);
} catch {
// Continue regardless of error.
}
process.exit(0);
}, duration * 1000);
}
function read() {
fs.readFile(filename, encoding, afterRead);
@ -55,11 +60,6 @@ function main({ len, duration, concurrent, encoding }) {
function afterRead(er, data) {
if (er) {
if (er.code === 'ENOENT') {
// Only OK if unlinked by the timer from main.
assert.ok(benchEnded);
return;
}
throw er;
}
@ -67,9 +67,14 @@ function main({ len, duration, concurrent, encoding }) {
throw new Error('wrong number of bytes returned');
reads++;
if (!benchEnded)
const benchEnded = Date.now() >= endAt;
if (benchEnded && (++waitConcurrent) === concurrent) {
stop();
} else if (!benchEnded) {
read();
}
}
while (concurrent--) read();
for (let i = 0; i < concurrent; i++) read();
}

View File

@ -5,7 +5,6 @@
const common = require('../common.js');
const fs = require('fs');
const assert = require('assert');
const tmpdir = require('../../test/common/tmpdir');
tmpdir.refresh();
@ -35,19 +34,25 @@ function main({ len, duration, concurrent, encoding }) {
fs.writeFileSync(filename, data);
data = null;
let writes = 0;
let benchEnded = false;
let reads = 0;
let waitConcurrent = 0;
const startedAt = Date.now();
const endAt = startedAt + (duration * 1000);
bench.start();
setTimeout(() => {
benchEnded = true;
bench.end(writes);
function stop() {
bench.end(reads);
try {
fs.unlinkSync(filename);
} catch {
// Continue regardless of error.
}
process.exit(0);
}, duration * 1000);
}
function read() {
fs.promises.readFile(filename, encoding)
@ -57,21 +62,21 @@ function main({ len, duration, concurrent, encoding }) {
function afterRead(er, data) {
if (er) {
if (er.code === 'ENOENT') {
// Only OK if unlinked by the timer from main.
assert.ok(benchEnded);
return;
}
throw er;
}
if (data.length !== len)
throw new Error('wrong number of bytes returned');
writes++;
if (!benchEnded)
reads++;
const benchEnded = Date.now() >= endAt;
if (benchEnded && (++waitConcurrent) === concurrent) {
stop();
} else if (!benchEnded) {
read();
}
}
while (concurrent--) read();
for (let i = 0; i < concurrent; i++) read();
}

View File

@ -5,7 +5,6 @@
const common = require('../common.js');
const fs = require('fs');
const assert = require('assert');
const tmpdir = require('../../test/common/tmpdir');
tmpdir.refresh();
@ -29,30 +28,31 @@ function main({ len, duration, concurrent, encoding }) {
data = null;
let reads = 0;
let benchEnded = false;
let waitConcurrent = 0;
const startedAt = Date.now();
const endAt = startedAt + (duration * 1000);
bench.start();
setTimeout(() => {
benchEnded = true;
bench.end(reads);
try {
fs.unlinkSync(filename);
} catch {
// Continue regardless of error.
}
process.exit(0);
}, duration * 1000);
function read() {
fs.readFile(filename, encoding, afterRead);
}
function stop() {
bench.end(reads);
try {
fs.unlinkSync(filename);
} catch {
// Continue regardless of error.
}
process.exit(0);
}
function afterRead(er, data) {
if (er) {
if (er.code === 'ENOENT') {
// Only OK if unlinked by the timer from main.
assert.ok(benchEnded);
return;
}
throw er;
}
@ -60,9 +60,14 @@ function main({ len, duration, concurrent, encoding }) {
throw new Error('wrong number of bytes returned');
reads++;
if (!benchEnded)
const benchEnded = Date.now() >= endAt;
if (benchEnded && (++waitConcurrent) === concurrent) {
stop();
} else if (!benchEnded) {
read();
}
}
while (concurrent--) read();
for (let i = 0; i < concurrent; i++) read();
}

View File

@ -5,7 +5,6 @@
const common = require('../common.js');
const fs = require('fs');
const assert = require('assert');
const tmpdir = require('../../test/common/tmpdir');
tmpdir.refresh();
@ -38,11 +37,16 @@ function main({ encodingType, duration, concurrent, size }) {
}
let writes = 0;
let benchEnded = false;
let waitConcurrent = 0;
const startedAt = Date.now();
const endAt = startedAt + (duration * 1000);
bench.start();
setTimeout(() => {
benchEnded = true;
function stop() {
bench.end(writes);
for (let i = 0; i < filesWritten; i++) {
try {
fs.unlinkSync(`${filename}-${i}`);
@ -50,8 +54,9 @@ function main({ encodingType, duration, concurrent, size }) {
// Continue regardless of error.
}
}
process.exit(0);
}, duration * 1000);
}
function write() {
fs.promises.writeFile(`${filename}-${filesWritten++}`, chunk, encoding)
@ -61,18 +66,18 @@ function main({ encodingType, duration, concurrent, size }) {
function afterWrite(er) {
if (er) {
if (er.code === 'ENOENT') {
// Only OK if unlinked by the timer from main.
assert.ok(benchEnded);
return;
}
throw er;
}
writes++;
if (!benchEnded)
const benchEnded = Date.now() >= endAt;
if (benchEnded && (++waitConcurrent) === concurrent) {
stop();
} else if (!benchEnded) {
write();
}
}
while (concurrent--) write();
for (let i = 0; i < concurrent; i++) write();
}