Skip to content

Commit 8ffdeca

Browse files
committed
Add DB benchmark
Add a benchmark using `criterion` to benchmark DB performance, specifically when the DB has a large number of profiles/items/items_tags * Set `bench = false` * https://bheisler.github.io/criterion.rs/book/faq.html#cargo-bench-gives-unrecognized-option-errors-for-valid-command-line-options Signed-off-by: Robbie Blaine <[email protected]>
1 parent 3e210af commit 8ffdeca

File tree

3 files changed

+130
-0
lines changed

3 files changed

+130
-0
lines changed

Cargo.toml

+9
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ rust-version = "1.65"
1818
name = "aries_askar"
1919
path = "src/lib.rs"
2020
crate-type = ["staticlib", "rlib", "cdylib"]
21+
bench = false
2122

2223
[package.metadata.docs.rs]
2324
features = ["all_backends"]
@@ -62,3 +63,11 @@ features = ["any"]
6263
codegen-units = 1
6364
lto = true
6465
panic = "abort"
66+
67+
[dev-dependencies]
68+
criterion = { version = "0.5", features = ["html_reports"] }
69+
rand = { version = "0.8" }
70+
71+
[[bench]]
72+
name = "benchmark"
73+
harness = false

benches/README.md

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
### Aries Askar Benchmarks
2+
3+
Running `cargo bench` will run the benchmarks against an in-memory SQLite by default.
4+
5+
To run against a Postgres, you need to set the `POSTGRES_URL` environment variable like so:
6+
```sh
7+
docker run --rm -p 5432:5432 --net aries --name aries-test-postgres -e POSTGRES_PASSWORD=mysecretpassword -d postgres
8+
POSTGRES_URL=postgres://postgres:mysecretpassword@localhost:5432/test-db cargo bench
9+
```
10+
11+
To run comparison benchmarks:
12+
```sh
13+
git checkout main
14+
cargo bench -- --save-baseline main
15+
git checkout feature
16+
cargo bench -- --save-baseline feature
17+
18+
# Compare `feature` (new) to `main` (original)
19+
cargo bench -- --load-baseline feature --baseline main
20+
```

benches/benchmark.rs

+101
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
use criterion::{criterion_group, criterion_main, Criterion};
2+
use rand::{distributions::Alphanumeric, Rng};
3+
4+
use aries_askar::{
5+
future::block_on,
6+
kms::{KeyAlg, LocalKey},
7+
Store, StoreKeyMethod,
8+
};
9+
10+
const ERR_RAW_KEY: &str = "Error creating raw store key";
11+
const ERR_SESSION: &str = "Error creating store session";
12+
const ERR_OPEN: &str = "Error opening test store instance";
13+
const ERR_REQ_ROW: &str = "Row required";
14+
const ERR_CLOSE: &str = "Error closing test store instance";
15+
16+
const ROOT_SEED: [u8; 32] = [0x55; 32];
17+
18+
/// Initalize a clean DB for benchmarking
19+
fn initialize_database() -> Store {
20+
block_on(async {
21+
let db_url = match std::env::var("POSTGRES_URL") {
22+
Ok(p) if !p.is_empty() => p,
23+
_ => "sqlite://:memory:".to_string(),
24+
};
25+
let pass_key = Store::new_raw_key(Some(&ROOT_SEED)).expect(ERR_RAW_KEY);
26+
27+
Store::provision(
28+
&db_url,
29+
StoreKeyMethod::RawKey,
30+
pass_key,
31+
Some("askar-bench".to_string()),
32+
true,
33+
)
34+
.await
35+
.expect(ERR_OPEN)
36+
})
37+
}
38+
39+
/// Inject `n` number of keys and profiles into the DB
40+
fn populate_database_keys_profiles(db: &Store, n: u64) {
41+
block_on(async {
42+
let mut conn = db.session(None).await.expect(ERR_SESSION);
43+
44+
for _ in 0..n {
45+
let keypair =
46+
LocalKey::generate(KeyAlg::Ed25519, false).expect("Error creating keypair");
47+
let key_name = rand::thread_rng()
48+
.sample_iter(&Alphanumeric)
49+
.take(10)
50+
.map(char::from)
51+
.collect::<String>();
52+
let metadata = rand::thread_rng()
53+
.sample_iter(&Alphanumeric)
54+
.take(10)
55+
.map(char::from)
56+
.collect::<String>();
57+
58+
conn.insert_key(&key_name, &keypair, Some(metadata.as_str()), None, None)
59+
.await
60+
.expect("Error inserting key");
61+
62+
let found = conn
63+
.fetch_key(&key_name, false)
64+
.await
65+
.expect("Error fetching key")
66+
.expect(ERR_REQ_ROW);
67+
assert_eq!(found.algorithm(), Some(KeyAlg::Ed25519.as_str()));
68+
assert_eq!(found.name(), key_name);
69+
assert_eq!(found.metadata(), Some(metadata.as_str()));
70+
assert!(found.is_local());
71+
found.load_local_key().expect("Error loading key");
72+
73+
db.create_profile(None)
74+
.await
75+
.expect("Error creating profile");
76+
}
77+
78+
drop(conn);
79+
});
80+
}
81+
82+
fn criterion_benchmarks(c: &mut Criterion) {
83+
let db = initialize_database();
84+
populate_database_keys_profiles(&db, 10_000);
85+
86+
c.bench_function("benchmark_database", |b| {
87+
b.iter(|| {
88+
let db = db.clone();
89+
populate_database_keys_profiles(&db, 1);
90+
});
91+
});
92+
93+
block_on(async { db.close().await.expect(ERR_CLOSE) });
94+
}
95+
96+
criterion_group!(
97+
name = benchmarks;
98+
config = Criterion::default().sample_size(1_000);
99+
targets = criterion_benchmarks
100+
);
101+
criterion_main!(benchmarks);

0 commit comments

Comments
 (0)