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

refactor(NODE-4617): use promise apis in benchmarks #3399

Merged
merged 7 commits into from Sep 15, 2022
22 changes: 20 additions & 2 deletions test/benchmarks/mongoBench/benchmark.js
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.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* Sets the task type - either a synchronous or asynchronous task. The default is async.
* 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
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();
nbbeeken marked this conversation as resolved.
Show resolved Hide resolved

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
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
@@ -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
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