Skip to content

Commit 4c03d8c

Browse files
committed
RUST-617 add bson benchmarks
1 parent 8a7f03b commit 4c03d8c

File tree

7 files changed

+287
-15
lines changed

7 files changed

+287
-15
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ version = "0.11.5"
8383
optional = true
8484

8585
[dependencies.tokio]
86-
version = "0.2.18"
86+
version = "~0.2.18"
8787
features = ["io-util", "sync", "macros"]
8888

8989
[dependencies.tokio-rustls]

benchmarks/README.md

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22

33
This suite implements the benchmarks described in this (spec)[https://github.com/mongodb/specifications/blob/master/source/benchmarking/benchmarking.rst].
44

5-
In order to run the microbenchmarks, first run `../etc/microbenchmark-test-data.sh` to download the data.
5+
In order to run the microbenchmarks, first run `./download-data.sh`. (NOTE: the data for the deeply nested BSON encoding and decoding is
6+
currently broken, so these benchmarks will not be runnable until that's fixed).
67

78
Note: make sure you run the download script and the microbenchmarks binary from the benchmark root (the directory containing this README).
89

@@ -11,7 +12,7 @@ connection string by setting the `MONGODB_URI` environment variable). You can sp
1112
collection by setting the `DATABASE_NAME` or `COLL_NAME` environment variables respectively.
1213

1314
Additionally, you can specify custom time frames for the benchmarks by setting the `MAX_EXECUTION_TIME`, `MIN_EXECUTION_TIME`
14-
and `MAX_ITERATIONS` environment variables.
15+
and `TARGET_ITERATION_COUNT` environment variables.
1516

1617
Run `cargo run --release -- --help` to see a full list of testing options.
1718

@@ -30,6 +31,12 @@ the single-doc benchmarks. By default, all benchmarks are executed. The table be
3031
| Large doc bulk insert | 7 |
3132
| LDJSON multi-file import | 8 |
3233
| LDJSON multi-file export | 9 |
34+
| BSON flat decode | 10 |
35+
| BSON flat encode | 11 |
36+
| BSON deeply nested decode | 12 |
37+
| BSON deeply nested encode | 13 |
38+
| BSON full document decode | 14 |
39+
| BSON full document encode | 15 |
3340
| All benchmarks | all|
3441

3542
Note that in order to compare against the other drivers, an inMemory mongod instance should be used.

benchmarks/download-data.sh

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#!/bin/sh
2+
3+
fetch_data_file() {
4+
echo "Fetching $1.tgz from github..."
5+
6+
curl --retry 5 "https://raw.githubusercontent.com/mongodb/specifications/master/source/benchmarking/data/$1.tgz" --max-time 120 --remote-name --silent
7+
mkdir -p data
8+
tar xf "$1.tgz"
9+
mv "$1" data
10+
rm "$1.tgz"
11+
}
12+
13+
fetch_data_file extended_bson
14+
fetch_data_file parallel
15+
fetch_data_file single_and_multi_document

benchmarks/src/bench/bson_decode.rs

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
use std::{convert::TryInto, path::PathBuf};
2+
3+
use anyhow::{bail, Result};
4+
use mongodb::bson::{Bson, Document};
5+
use serde_json::Value;
6+
7+
use crate::{bench::Benchmark, fs::read_to_string};
8+
9+
pub struct BsonDecodeBenchmark {
10+
num_iter: usize,
11+
bytes: Vec<u8>,
12+
}
13+
14+
pub struct Options {
15+
pub num_iter: usize,
16+
pub path: PathBuf,
17+
}
18+
19+
#[async_trait::async_trait]
20+
impl Benchmark for BsonDecodeBenchmark {
21+
type Options = Options;
22+
23+
async fn setup(options: Self::Options) -> Result<Self> {
24+
let mut file = read_to_string(&options.path).await?;
25+
26+
let json: Value = serde_json::from_str(&mut file)?;
27+
let doc = match json.try_into()? {
28+
Bson::Document(doc) => doc,
29+
_ => bail!("invalid json test file"),
30+
};
31+
32+
let mut bytes: Vec<u8> = Vec::new();
33+
doc.to_writer(&mut bytes)?;
34+
35+
Ok(BsonDecodeBenchmark {
36+
num_iter: options.num_iter,
37+
bytes,
38+
})
39+
}
40+
41+
async fn do_task(&self) -> Result<()> {
42+
for _ in 0..self.num_iter {
43+
// `&[u8]` implements `Read`, and `from_reader` needs a `&mut R: Read`, so we need a
44+
// `&mut &[u8]`.
45+
let _doc = Document::from_reader(&mut &self.bytes[..])?;
46+
}
47+
48+
Ok(())
49+
}
50+
}

benchmarks/src/bench/bson_encode.rs

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
use std::{convert::TryInto, path::PathBuf};
2+
3+
use anyhow::{bail, Result};
4+
use mongodb::bson::{Bson, Document};
5+
use serde_json::Value;
6+
7+
use crate::{bench::Benchmark, fs::read_to_string};
8+
9+
pub struct BsonEncodeBenchmark {
10+
num_iter: usize,
11+
doc: Document,
12+
}
13+
14+
pub struct Options {
15+
pub num_iter: usize,
16+
pub path: PathBuf,
17+
}
18+
19+
#[async_trait::async_trait]
20+
impl Benchmark for BsonEncodeBenchmark {
21+
type Options = Options;
22+
23+
async fn setup(options: Self::Options) -> Result<Self> {
24+
let mut file = read_to_string(&options.path).await?;
25+
26+
let json: Value = serde_json::from_str(&mut file)?;
27+
let doc = match json.try_into()? {
28+
Bson::Document(doc) => doc,
29+
_ => bail!("invalid json test file"),
30+
};
31+
32+
Ok(BsonEncodeBenchmark {
33+
num_iter: options.num_iter,
34+
doc,
35+
})
36+
}
37+
38+
async fn do_task(&self) -> Result<()> {
39+
for _ in 0..self.num_iter {
40+
let mut bytes: Vec<u8> = Vec::new();
41+
self.doc.to_writer(&mut bytes)?;
42+
}
43+
44+
Ok(())
45+
}
46+
}

benchmarks/src/bench/mod.rs

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
pub mod bson_decode;
2+
pub mod bson_encode;
13
pub mod find_many;
24
pub mod find_one;
35
pub mod insert_many;
@@ -33,10 +35,10 @@ lazy_static! {
3335
.unwrap_or("60")
3436
.parse::<u64>()
3537
.expect("invalid MIN_EXECUTION_TIME");
36-
pub static ref MAX_ITERATIONS: usize = option_env!("MAX_ITERATIONS")
38+
pub static ref TARGET_ITERATION_COUNT: usize = option_env!("TARGET_ITERATION_COUNT")
3739
.unwrap_or("100")
3840
.parse::<usize>()
39-
.expect("invalid MAX_ITERATIONS");
41+
.expect("invalid TARGET_ITERATION_COUNT");
4042
}
4143

4244
#[async_trait::async_trait]
@@ -59,7 +61,9 @@ pub trait Benchmark: Sized {
5961
}
6062

6163
// execute once after benchmarking
62-
async fn teardown(&self) -> Result<()>;
64+
async fn teardown(&self) -> Result<()> {
65+
Ok(())
66+
}
6367
}
6468

6569
pub(crate) async fn parse_json_file_to_documents(file: File) -> Result<Vec<Document>> {
@@ -81,7 +85,7 @@ pub(crate) async fn parse_json_file_to_documents(file: File) -> Result<Vec<Docum
8185

8286
fn finished(duration: Duration, iter: usize) -> bool {
8387
let elapsed = duration.as_secs();
84-
elapsed >= *MAX_EXECUTION_TIME || (iter >= *MAX_ITERATIONS && elapsed > *MIN_EXECUTION_TIME)
88+
elapsed >= *MAX_EXECUTION_TIME || (iter >= *TARGET_ITERATION_COUNT && elapsed > *MIN_EXECUTION_TIME)
8589
}
8690

8791
pub async fn run_benchmark<B: Benchmark + Send + Sync>(
@@ -91,7 +95,7 @@ pub async fn run_benchmark<B: Benchmark + Send + Sync>(
9195

9296
let mut test_durations = Vec::new();
9397

94-
let progress_bar = ProgressBar::new(*MAX_ITERATIONS as u64);
98+
let progress_bar = ProgressBar::new(*TARGET_ITERATION_COUNT as u64);
9599
progress_bar.set_style(
96100
ProgressStyle::default_bar()
97101
.template(

0 commit comments

Comments
 (0)