Skip to content

Commit

Permalink
refactor(NODE-4617): use promise apis in benchmarks (#3399)
Browse files Browse the repository at this point in the history
Co-authored-by: Neal Beeken <[email protected]>
  • Loading branch information
baileympearson and nbbeeken committed Sep 15, 2022
1 parent 8758890 commit 64b3ee9
Show file tree
Hide file tree
Showing 5 changed files with 97 additions and 111 deletions.
22 changes: 20 additions & 2 deletions test/benchmarks/mongoBench/benchmark.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ class Benchmark {
// Meta information
this._taskSize = null;
this._description = null;
this._taskType = 'async';
}

/**
Expand Down Expand Up @@ -96,6 +97,23 @@ class Benchmark {
return this;
}

/**
* Sets the task type - either a synchronous or asynchronous task. The default is async.
*
* @param {'async' | 'sync'} type - the type of task
*/
taskType(type) {
if (['async', 'sync'].includes(type)) {
this._taskType = type;
} else {
throw new Error(
`Invalid value for benchmark field _taskType: expected either 'async' or 'sync', but received ${type}`
);
}

return this;
}

/**
* Set the Description
*
Expand All @@ -122,11 +140,11 @@ class Benchmark {
* @throws Error
*/
validate() {
['_task', '_taskSize'].forEach(key => {
for (const key of ['_task', '_taskSize', '_taskType']) {
if (!this[key]) {
throw new Error(`Benchmark is missing required field ${key}`);
}
});
}
}

toObj() {
Expand Down
37 changes: 12 additions & 25 deletions test/benchmarks/mongoBench/runner.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,33 +9,18 @@ function percentileIndex(percentile, total) {
return Math.max(Math.floor((total * percentile) / 100 - 1), 0);
}

function timeDoneTask(task, ctx) {
return new Promise((resolve, reject) => {
let called = false;
const start = performance.now();
task.call(ctx, err => {
const end = performance.now(start);
if (called) return;
if (err) return reject(err);
return resolve((end - start) / 1000);
});
});
}
function timeSyncTask(task, ctx) {
const start = performance.now();
task.call(ctx);
const end = performance.now();

async function timeTask(task, ctx) {
// Some tasks are async, so they take callbacks.
if (task.length) {
return timeDoneTask(task, ctx);
}
return (end - start) / 1000;
}

async function timeAsyncTask(task, ctx) {
const start = performance.now();
const ret = task.call(ctx);
let end = performance.now();

if (ret && ret.then) {
await ret;
end = performance.now();
}
await task.call(ctx);
const end = performance.now();

return (end - start) / 1000;
}
Expand Down Expand Up @@ -180,9 +165,11 @@ class Runner {
let time = performance.now() - start;
let count = 1;

const taskTimer = benchmark._taskType === 'sync' ? timeSyncTask : timeAsyncTask;

while (time < maxExecutionTime && (time < minExecutionTime || count < minExecutionCount)) {
await benchmark.beforeTask.call(ctx);
const executionTime = await timeTask(benchmark.task, ctx);
const executionTime = await taskTimer(benchmark.task, ctx);
rawData.push(executionTime);
count++;
time = performance.now();
Expand Down
12 changes: 6 additions & 6 deletions test/benchmarks/mongoBench/suites/bsonBench.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,22 +27,22 @@ function makeBsonBench({ suite, BSON }) {
}
return suite
.benchmark('flatBsonEncoding', benchmark =>
benchmark.taskSize(75.31).setup(makeBSONLoader('flat_bson')).task(encodeBSON)
benchmark.taskSize(75.31).taskType('sync').setup(makeBSONLoader('flat_bson')).task(encodeBSON)
)
.benchmark('flatBsonDecoding', benchmark =>
benchmark.taskSize(75.31).setup(makeBSONLoader('flat_bson')).task(decodeBSON)
benchmark.taskSize(75.31).taskType('sync').setup(makeBSONLoader('flat_bson')).task(decodeBSON)
)
.benchmark('deepBsonEncoding', benchmark =>
benchmark.taskSize(19.64).setup(makeBSONLoader('deep_bson')).task(encodeBSON)
benchmark.taskSize(19.64).taskType('sync').setup(makeBSONLoader('deep_bson')).task(encodeBSON)
)
.benchmark('deepBsonDecoding', benchmark =>
benchmark.taskSize(19.64).setup(makeBSONLoader('deep_bson')).task(decodeBSON)
benchmark.taskSize(19.64).taskType('sync').setup(makeBSONLoader('deep_bson')).task(decodeBSON)
)
.benchmark('fullBsonEncoding', benchmark =>
benchmark.taskSize(57.34).setup(makeBSONLoader('full_bson')).task(encodeBSON)
benchmark.taskSize(57.34).taskType('sync').setup(makeBSONLoader('full_bson')).task(encodeBSON)
)
.benchmark('fullBsonDecoding', benchmark =>
benchmark.taskSize(57.34).setup(makeBSONLoader('full_bson')).task(decodeBSON)
benchmark.taskSize(57.34).taskType('sync').setup(makeBSONLoader('full_bson')).task(decodeBSON)
);
}

Expand Down
68 changes: 33 additions & 35 deletions test/benchmarks/mongoBench/suites/multiBench.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
const { Readable } = require('stream');
const { pipeline } = require('stream/promises');
const {
loadSpecFile,
makeLoadJSON,
Expand All @@ -12,30 +14,24 @@ const {
createCollection,
dropCollection,
dropBucket,
initBucket
initBucket,
writeSingleByteFileToBucket
} = require('../../driverBench/common');

function loadGridFs() {
this.bin = loadSpecFile(['single_and_multi_document', 'gridfs_large.bin']);
}

function findManyAndEmptyCursor(done) {
return this.collection.find({}).forEach(() => {}, done);
}

function docBulkInsert(done) {
return this.collection.insertMany(this.docs, { ordered: true }, done);
}

function gridFsInitUploadStream() {
this.stream = this.bucket.openUploadStream('gridfstest');
this.uploadStream = this.bucket.openUploadStream('gridfstest');
}

function writeSingleByteToUploadStream() {
return new Promise((resolve, reject) => {
this.stream.write('\0', null, err => (err ? reject(err) : resolve()));
});
async function gridFsUpload() {
const uploadData = Readable.from(this.bin);
const uploadStream = this.uploadStream;
await pipeline(uploadData, uploadStream);
}

function makeMultiBench(suite) {
return suite
.benchmark('findManyAndEmptyCursor', benchmark =>
Expand All @@ -48,7 +44,12 @@ function makeMultiBench(suite) {
.setup(dropDb)
.setup(initCollection)
.setup(makeLoadTweets(false))
.task(findManyAndEmptyCursor)
.task(async function () {
// eslint-disable-next-line no-unused-vars
for await (const _ of this.collection.find({})) {
// do nothing
}
})
.teardown(dropDb)
.teardown(disconnectClient)
)
Expand All @@ -67,7 +68,9 @@ function makeMultiBench(suite) {
.beforeTask(dropCollection)
.beforeTask(createCollection)
.beforeTask(initCollection)
.task(docBulkInsert)
.task(async function () {
await this.collection.insertMany(this.docs, { ordered: true });
})
.teardown(dropDb)
.teardown(disconnectClient)
)
Expand All @@ -86,7 +89,9 @@ function makeMultiBench(suite) {
.beforeTask(dropCollection)
.beforeTask(createCollection)
.beforeTask(initCollection)
.task(docBulkInsert)
.task(async function () {
await this.collection.insertMany(this.docs, { ordered: true });
})
.teardown(dropDb)
.teardown(disconnectClient)
)
Expand All @@ -103,10 +108,8 @@ function makeMultiBench(suite) {
.beforeTask(dropBucket)
.beforeTask(initBucket)
.beforeTask(gridFsInitUploadStream)
.beforeTask(writeSingleByteToUploadStream)
.task(function (done) {
this.stream.on('error', done).end(this.bin, null, () => done());
})
.beforeTask(writeSingleByteFileToBucket)
.task(gridFsUpload)
.teardown(dropDb)
.teardown(disconnectClient)
)
Expand All @@ -123,21 +126,16 @@ function makeMultiBench(suite) {
.setup(dropBucket)
.setup(initBucket)
.setup(gridFsInitUploadStream)
.setup(function () {
return new Promise((resolve, reject) => {
this.stream.end(this.bin, null, err => {
if (err) {
return reject(err);
}

this.id = this.stream.id;
this.stream = undefined;
resolve();
});
});
.setup(async function () {
await gridFsUpload.call(this);
this.id = this.uploadStream.id;
this.uploadData = undefined;
})
.task(function (done) {
this.bucket.openDownloadStream(this.id).resume().on('end', done);
.task(async function () {
// eslint-disable-next-line no-unused-vars
for await (const _ of this.bucket.openDownloadStream(this.id)) {
// do nothing
}
})
.teardown(dropDb)
.teardown(disconnectClient)
Expand Down
69 changes: 26 additions & 43 deletions test/benchmarks/mongoBench/suites/singleBench.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,45 +11,6 @@ const {
makeLoadTweets
} = require('../../driverBench/common');

function makeTestInsertOne(numberOfOps) {
return function (done) {
const loop = _id => {
if (_id > numberOfOps) {
return done();
}

const doc = Object.assign({}, this.doc);

this.collection.insertOne(doc, err => (err ? done(err) : loop(_id + 1)));
};

loop(1);
};
}

function findOneById(done) {
const loop = _id => {
if (_id > 10000) {
return done();
}

return this.collection.findOne({ _id }, err => (err ? done(err) : loop(_id + 1)));
};

return loop(1);
}

function runCommand(done) {
const loop = _id => {
if (_id > 10000) {
return done();
}
return this.db.command({ hello: true }, err => (err ? done(err) : loop(_id + 1)));
};

return loop(1);
}

function makeSingleBench(suite) {
suite
.benchmark('runCommand', benchmark =>
Expand All @@ -58,7 +19,11 @@ function makeSingleBench(suite) {
.setup(makeClient)
.setup(connectClient)
.setup(initDb)
.task(runCommand)
.task(async function () {
for (let i = 0; i < 10000; ++i) {
await this.db.command({ hello: true });
}
})
.teardown(disconnectClient)
)
.benchmark('findOne', benchmark =>
Expand All @@ -71,7 +36,11 @@ function makeSingleBench(suite) {
.setup(dropDb)
.setup(initCollection)
.setup(makeLoadTweets(true))
.task(findOneById)
.task(async function () {
for (let _id = 0; _id < 10000; ++_id) {
await this.collection.findOne({ _id });
}
})
.teardown(dropDb)
.teardown(disconnectClient)
)
Expand All @@ -89,7 +58,14 @@ function makeSingleBench(suite) {
.beforeTask(dropCollection)
.beforeTask(createCollection)
.beforeTask(initCollection)
.task(makeTestInsertOne(10000))
.beforeTask(function () {
this.docs = Array.from({ length: 10000 }, () => Object.assign({}, this.doc));
})
.task(async function () {
for (const doc of this.docs) {
await this.collection.insertOne(doc);
}
})
.teardown(dropDb)
.teardown(disconnectClient)
)
Expand All @@ -107,7 +83,14 @@ function makeSingleBench(suite) {
.beforeTask(dropCollection)
.beforeTask(createCollection)
.beforeTask(initCollection)
.task(makeTestInsertOne(10))
.beforeTask(function () {
this.docs = Array.from({ length: 10 }, () => Object.assign({}, this.doc));
})
.task(async function () {
for (const doc of this.docs) {
await this.collection.insertOne(doc);
}
})
.teardown(dropDb)
.teardown(disconnectClient)
);
Expand Down

0 comments on commit 64b3ee9

Please sign in to comment.