Skip to content

Commit 64b3ee9

Browse files
refactor(NODE-4617): use promise apis in benchmarks (#3399)
Co-authored-by: Neal Beeken <[email protected]>
1 parent 8758890 commit 64b3ee9

File tree

5 files changed

+97
-111
lines changed

5 files changed

+97
-111
lines changed

test/benchmarks/mongoBench/benchmark.js

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ class Benchmark {
1414
// Meta information
1515
this._taskSize = null;
1616
this._description = null;
17+
this._taskType = 'async';
1718
}
1819

1920
/**
@@ -96,6 +97,23 @@ class Benchmark {
9697
return this;
9798
}
9899

100+
/**
101+
* Sets the task type - either a synchronous or asynchronous task. The default is async.
102+
*
103+
* @param {'async' | 'sync'} type - the type of task
104+
*/
105+
taskType(type) {
106+
if (['async', 'sync'].includes(type)) {
107+
this._taskType = type;
108+
} else {
109+
throw new Error(
110+
`Invalid value for benchmark field _taskType: expected either 'async' or 'sync', but received ${type}`
111+
);
112+
}
113+
114+
return this;
115+
}
116+
99117
/**
100118
* Set the Description
101119
*
@@ -122,11 +140,11 @@ class Benchmark {
122140
* @throws Error
123141
*/
124142
validate() {
125-
['_task', '_taskSize'].forEach(key => {
143+
for (const key of ['_task', '_taskSize', '_taskType']) {
126144
if (!this[key]) {
127145
throw new Error(`Benchmark is missing required field ${key}`);
128146
}
129-
});
147+
}
130148
}
131149

132150
toObj() {

test/benchmarks/mongoBench/runner.js

Lines changed: 12 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -9,33 +9,18 @@ function percentileIndex(percentile, total) {
99
return Math.max(Math.floor((total * percentile) / 100 - 1), 0);
1010
}
1111

12-
function timeDoneTask(task, ctx) {
13-
return new Promise((resolve, reject) => {
14-
let called = false;
15-
const start = performance.now();
16-
task.call(ctx, err => {
17-
const end = performance.now(start);
18-
if (called) return;
19-
if (err) return reject(err);
20-
return resolve((end - start) / 1000);
21-
});
22-
});
23-
}
12+
function timeSyncTask(task, ctx) {
13+
const start = performance.now();
14+
task.call(ctx);
15+
const end = performance.now();
2416

25-
async function timeTask(task, ctx) {
26-
// Some tasks are async, so they take callbacks.
27-
if (task.length) {
28-
return timeDoneTask(task, ctx);
29-
}
17+
return (end - start) / 1000;
18+
}
3019

20+
async function timeAsyncTask(task, ctx) {
3121
const start = performance.now();
32-
const ret = task.call(ctx);
33-
let end = performance.now();
34-
35-
if (ret && ret.then) {
36-
await ret;
37-
end = performance.now();
38-
}
22+
await task.call(ctx);
23+
const end = performance.now();
3924

4025
return (end - start) / 1000;
4126
}
@@ -180,9 +165,11 @@ class Runner {
180165
let time = performance.now() - start;
181166
let count = 1;
182167

168+
const taskTimer = benchmark._taskType === 'sync' ? timeSyncTask : timeAsyncTask;
169+
183170
while (time < maxExecutionTime && (time < minExecutionTime || count < minExecutionCount)) {
184171
await benchmark.beforeTask.call(ctx);
185-
const executionTime = await timeTask(benchmark.task, ctx);
172+
const executionTime = await taskTimer(benchmark.task, ctx);
186173
rawData.push(executionTime);
187174
count++;
188175
time = performance.now();

test/benchmarks/mongoBench/suites/bsonBench.js

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,22 +27,22 @@ function makeBsonBench({ suite, BSON }) {
2727
}
2828
return suite
2929
.benchmark('flatBsonEncoding', benchmark =>
30-
benchmark.taskSize(75.31).setup(makeBSONLoader('flat_bson')).task(encodeBSON)
30+
benchmark.taskSize(75.31).taskType('sync').setup(makeBSONLoader('flat_bson')).task(encodeBSON)
3131
)
3232
.benchmark('flatBsonDecoding', benchmark =>
33-
benchmark.taskSize(75.31).setup(makeBSONLoader('flat_bson')).task(decodeBSON)
33+
benchmark.taskSize(75.31).taskType('sync').setup(makeBSONLoader('flat_bson')).task(decodeBSON)
3434
)
3535
.benchmark('deepBsonEncoding', benchmark =>
36-
benchmark.taskSize(19.64).setup(makeBSONLoader('deep_bson')).task(encodeBSON)
36+
benchmark.taskSize(19.64).taskType('sync').setup(makeBSONLoader('deep_bson')).task(encodeBSON)
3737
)
3838
.benchmark('deepBsonDecoding', benchmark =>
39-
benchmark.taskSize(19.64).setup(makeBSONLoader('deep_bson')).task(decodeBSON)
39+
benchmark.taskSize(19.64).taskType('sync').setup(makeBSONLoader('deep_bson')).task(decodeBSON)
4040
)
4141
.benchmark('fullBsonEncoding', benchmark =>
42-
benchmark.taskSize(57.34).setup(makeBSONLoader('full_bson')).task(encodeBSON)
42+
benchmark.taskSize(57.34).taskType('sync').setup(makeBSONLoader('full_bson')).task(encodeBSON)
4343
)
4444
.benchmark('fullBsonDecoding', benchmark =>
45-
benchmark.taskSize(57.34).setup(makeBSONLoader('full_bson')).task(decodeBSON)
45+
benchmark.taskSize(57.34).taskType('sync').setup(makeBSONLoader('full_bson')).task(decodeBSON)
4646
);
4747
}
4848

test/benchmarks/mongoBench/suites/multiBench.js

Lines changed: 33 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
const { Readable } = require('stream');
2+
const { pipeline } = require('stream/promises');
13
const {
24
loadSpecFile,
35
makeLoadJSON,
@@ -12,30 +14,24 @@ const {
1214
createCollection,
1315
dropCollection,
1416
dropBucket,
15-
initBucket
17+
initBucket,
18+
writeSingleByteFileToBucket
1619
} = require('../../driverBench/common');
1720

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

22-
function findManyAndEmptyCursor(done) {
23-
return this.collection.find({}).forEach(() => {}, done);
24-
}
25-
26-
function docBulkInsert(done) {
27-
return this.collection.insertMany(this.docs, { ordered: true }, done);
28-
}
29-
3025
function gridFsInitUploadStream() {
31-
this.stream = this.bucket.openUploadStream('gridfstest');
26+
this.uploadStream = this.bucket.openUploadStream('gridfstest');
3227
}
3328

34-
function writeSingleByteToUploadStream() {
35-
return new Promise((resolve, reject) => {
36-
this.stream.write('\0', null, err => (err ? reject(err) : resolve()));
37-
});
29+
async function gridFsUpload() {
30+
const uploadData = Readable.from(this.bin);
31+
const uploadStream = this.uploadStream;
32+
await pipeline(uploadData, uploadStream);
3833
}
34+
3935
function makeMultiBench(suite) {
4036
return suite
4137
.benchmark('findManyAndEmptyCursor', benchmark =>
@@ -48,7 +44,12 @@ function makeMultiBench(suite) {
4844
.setup(dropDb)
4945
.setup(initCollection)
5046
.setup(makeLoadTweets(false))
51-
.task(findManyAndEmptyCursor)
47+
.task(async function () {
48+
// eslint-disable-next-line no-unused-vars
49+
for await (const _ of this.collection.find({})) {
50+
// do nothing
51+
}
52+
})
5253
.teardown(dropDb)
5354
.teardown(disconnectClient)
5455
)
@@ -67,7 +68,9 @@ function makeMultiBench(suite) {
6768
.beforeTask(dropCollection)
6869
.beforeTask(createCollection)
6970
.beforeTask(initCollection)
70-
.task(docBulkInsert)
71+
.task(async function () {
72+
await this.collection.insertMany(this.docs, { ordered: true });
73+
})
7174
.teardown(dropDb)
7275
.teardown(disconnectClient)
7376
)
@@ -86,7 +89,9 @@ function makeMultiBench(suite) {
8689
.beforeTask(dropCollection)
8790
.beforeTask(createCollection)
8891
.beforeTask(initCollection)
89-
.task(docBulkInsert)
92+
.task(async function () {
93+
await this.collection.insertMany(this.docs, { ordered: true });
94+
})
9095
.teardown(dropDb)
9196
.teardown(disconnectClient)
9297
)
@@ -103,10 +108,8 @@ function makeMultiBench(suite) {
103108
.beforeTask(dropBucket)
104109
.beforeTask(initBucket)
105110
.beforeTask(gridFsInitUploadStream)
106-
.beforeTask(writeSingleByteToUploadStream)
107-
.task(function (done) {
108-
this.stream.on('error', done).end(this.bin, null, () => done());
109-
})
111+
.beforeTask(writeSingleByteFileToBucket)
112+
.task(gridFsUpload)
110113
.teardown(dropDb)
111114
.teardown(disconnectClient)
112115
)
@@ -123,21 +126,16 @@ function makeMultiBench(suite) {
123126
.setup(dropBucket)
124127
.setup(initBucket)
125128
.setup(gridFsInitUploadStream)
126-
.setup(function () {
127-
return new Promise((resolve, reject) => {
128-
this.stream.end(this.bin, null, err => {
129-
if (err) {
130-
return reject(err);
131-
}
132-
133-
this.id = this.stream.id;
134-
this.stream = undefined;
135-
resolve();
136-
});
137-
});
129+
.setup(async function () {
130+
await gridFsUpload.call(this);
131+
this.id = this.uploadStream.id;
132+
this.uploadData = undefined;
138133
})
139-
.task(function (done) {
140-
this.bucket.openDownloadStream(this.id).resume().on('end', done);
134+
.task(async function () {
135+
// eslint-disable-next-line no-unused-vars
136+
for await (const _ of this.bucket.openDownloadStream(this.id)) {
137+
// do nothing
138+
}
141139
})
142140
.teardown(dropDb)
143141
.teardown(disconnectClient)

test/benchmarks/mongoBench/suites/singleBench.js

Lines changed: 26 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -11,45 +11,6 @@ const {
1111
makeLoadTweets
1212
} = require('../../driverBench/common');
1313

14-
function makeTestInsertOne(numberOfOps) {
15-
return function (done) {
16-
const loop = _id => {
17-
if (_id > numberOfOps) {
18-
return done();
19-
}
20-
21-
const doc = Object.assign({}, this.doc);
22-
23-
this.collection.insertOne(doc, err => (err ? done(err) : loop(_id + 1)));
24-
};
25-
26-
loop(1);
27-
};
28-
}
29-
30-
function findOneById(done) {
31-
const loop = _id => {
32-
if (_id > 10000) {
33-
return done();
34-
}
35-
36-
return this.collection.findOne({ _id }, err => (err ? done(err) : loop(_id + 1)));
37-
};
38-
39-
return loop(1);
40-
}
41-
42-
function runCommand(done) {
43-
const loop = _id => {
44-
if (_id > 10000) {
45-
return done();
46-
}
47-
return this.db.command({ hello: true }, err => (err ? done(err) : loop(_id + 1)));
48-
};
49-
50-
return loop(1);
51-
}
52-
5314
function makeSingleBench(suite) {
5415
suite
5516
.benchmark('runCommand', benchmark =>
@@ -58,7 +19,11 @@ function makeSingleBench(suite) {
5819
.setup(makeClient)
5920
.setup(connectClient)
6021
.setup(initDb)
61-
.task(runCommand)
22+
.task(async function () {
23+
for (let i = 0; i < 10000; ++i) {
24+
await this.db.command({ hello: true });
25+
}
26+
})
6227
.teardown(disconnectClient)
6328
)
6429
.benchmark('findOne', benchmark =>
@@ -71,7 +36,11 @@ function makeSingleBench(suite) {
7136
.setup(dropDb)
7237
.setup(initCollection)
7338
.setup(makeLoadTweets(true))
74-
.task(findOneById)
39+
.task(async function () {
40+
for (let _id = 0; _id < 10000; ++_id) {
41+
await this.collection.findOne({ _id });
42+
}
43+
})
7544
.teardown(dropDb)
7645
.teardown(disconnectClient)
7746
)
@@ -89,7 +58,14 @@ function makeSingleBench(suite) {
8958
.beforeTask(dropCollection)
9059
.beforeTask(createCollection)
9160
.beforeTask(initCollection)
92-
.task(makeTestInsertOne(10000))
61+
.beforeTask(function () {
62+
this.docs = Array.from({ length: 10000 }, () => Object.assign({}, this.doc));
63+
})
64+
.task(async function () {
65+
for (const doc of this.docs) {
66+
await this.collection.insertOne(doc);
67+
}
68+
})
9369
.teardown(dropDb)
9470
.teardown(disconnectClient)
9571
)
@@ -107,7 +83,14 @@ function makeSingleBench(suite) {
10783
.beforeTask(dropCollection)
10884
.beforeTask(createCollection)
10985
.beforeTask(initCollection)
110-
.task(makeTestInsertOne(10))
86+
.beforeTask(function () {
87+
this.docs = Array.from({ length: 10 }, () => Object.assign({}, this.doc));
88+
})
89+
.task(async function () {
90+
for (const doc of this.docs) {
91+
await this.collection.insertOne(doc);
92+
}
93+
})
11194
.teardown(dropDb)
11295
.teardown(disconnectClient)
11396
);

0 commit comments

Comments
 (0)