From 7a94952e144ace471f733afe039741663ee4f981 Mon Sep 17 00:00:00 2001 From: "hinto.janai" Date: Mon, 21 Oct 2024 17:01:11 -0400 Subject: [PATCH 1/5] copy #98 --- benches/criterion/cuprate-database/Cargo.toml | 24 + benches/criterion/cuprate-database/README.md | 48 ++ .../criterion/cuprate-database/benches/db.rs | 583 +++++++++++++++++ .../benches/db_multi_thread.rs | 584 ++++++++++++++++++ .../criterion/cuprate-database/benches/env.rs | 161 +++++ .../benches/env_multi_thread.rs | 162 +++++ .../cuprate-database/benches/main.rs | 91 +++ .../cuprate-database/benches/service.rs | 25 + .../cuprate-database/benches/storable.rs | 81 +++ .../criterion/cuprate-database/src/helper.rs | 30 + benches/criterion/cuprate-database/src/lib.rs | 83 +++ 11 files changed, 1872 insertions(+) create mode 100644 benches/criterion/cuprate-database/Cargo.toml create mode 100644 benches/criterion/cuprate-database/README.md create mode 100644 benches/criterion/cuprate-database/benches/db.rs create mode 100644 benches/criterion/cuprate-database/benches/db_multi_thread.rs create mode 100644 benches/criterion/cuprate-database/benches/env.rs create mode 100644 benches/criterion/cuprate-database/benches/env_multi_thread.rs create mode 100644 benches/criterion/cuprate-database/benches/main.rs create mode 100644 benches/criterion/cuprate-database/benches/service.rs create mode 100644 benches/criterion/cuprate-database/benches/storable.rs create mode 100644 benches/criterion/cuprate-database/src/helper.rs create mode 100644 benches/criterion/cuprate-database/src/lib.rs diff --git a/benches/criterion/cuprate-database/Cargo.toml b/benches/criterion/cuprate-database/Cargo.toml new file mode 100644 index 0000000..c37d265 --- /dev/null +++ b/benches/criterion/cuprate-database/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "cuprate-database-benchmark" +version = "0.0.0" +edition = "2021" +description = "Benchmarking for Cuprate's database abstraction" +license = "MIT" +authors = ["hinto-janai"] +repository = "https://github.com/Cuprate/cuprate/tree/main/database/benchmark" +keywords = ["cuprate", "database", "benchmark"] + +[features] +default = [] + +[dependencies] +criterion = { workspace = true } +cuprate-database = { path = "../", features = ["default"] } +cuprate-helper = { path = "../../helper", features = ["fs", "thread"] } +# cuprate-types = { path = "../../types", features = ["service"] } +function_name = { version = "0.3.0" } +tempfile = { version = "3.10.0" } + +[[bench]] +name = "main" +harness = false \ No newline at end of file diff --git a/benches/criterion/cuprate-database/README.md b/benches/criterion/cuprate-database/README.md new file mode 100644 index 0000000..6e8314f --- /dev/null +++ b/benches/criterion/cuprate-database/README.md @@ -0,0 +1,48 @@ +# `cuprate-database-benchmark` +This is a benchmarking suite that allows testing/benchmarking `cuprate-database` with [`criterion`](https://bheisler.github.io/criterion.rs/book/criterion_rs.html). + +For more information on `cargo bench` and `criterion`: +- https://doc.rust-lang.org/cargo/commands/cargo-bench.html +- https://bheisler.github.io/criterion.rs/book/criterion_rs.html + + +1. [Usage](#Usage) +1. [File Structure](#file-structure) + - [`src/`](#src) + - [`benches/`](#benches) + +# Usage +Ensure the system is as quiet as possible (no background tasks) before starting and during the benchmarks. + +To start all benchmarks, run: +```bash +cargo bench --package cuprate-database-benchmarks +``` + +# File Structure +A quick reference of the structure of the folders & files in `cuprate-database`. + +Note that `lib.rs/mod.rs` files are purely for re-exporting/visibility/lints, and contain no code. Each sub-directory has a corresponding `mod.rs`. + +## `src/` +The top-level `src/` files. + +The actual `cuprate-database-benchmark` library crate is just used as a helper for the benchmarks within `benches/`. + +| File | Purpose | +|---------------------|---------| +| `helper.rs` | Helper functions + +## `benches/` +The actual benchmarks. + +Each file represents some logical benchmark grouping. + +| File | Purpose | +|-----------------------|---------| +| `db.rs` | `trait Database{Ro,Rw,Iter}` benchmarks +| `db_multi_thread.rs` | Same as `db.rs` but multi-threaded +| `env.rs` | `trait {Env, EnvInner, TxR{o,w}, Tables[Mut]}` benchmarks +| `env_multi_thread.rs` | Same as `env.rs` but multi-threaded +| `service.rs` | `cuprate_database::service` benchmarks +| `storable.rs` | `trait Storable` benchmarks \ No newline at end of file diff --git a/benches/criterion/cuprate-database/benches/db.rs b/benches/criterion/cuprate-database/benches/db.rs new file mode 100644 index 0000000..686d60a --- /dev/null +++ b/benches/criterion/cuprate-database/benches/db.rs @@ -0,0 +1,583 @@ +//! `trait Database{Ro,Rw,Iter}` benchmarks. + +use std::time::Instant; + +//---------------------------------------------------------------------------------------------------- Import +use criterion::{black_box, criterion_group, criterion_main, Criterion}; + +use function_name::named; + +use cuprate_database::{ + tables::Outputs, + types::{Output, PreRctOutputId}, + DatabaseIter, DatabaseRo, DatabaseRw, Env, EnvInner, TxRw, +}; + +use cuprate_database_benchmark::tmp_env; + +//---------------------------------------------------------------------------------------------------- Criterion +criterion_group! { + benches, + ro_get, + ro_len, + ro_first, + ro_last, + ro_is_empty, + ro_contains, + rw_get, + rw_len, + rw_first, + rw_last, + rw_is_empty, + rw_contains, + put, + delete, + pop_first, + pop_last, + get_range, + iter, + keys, + values, +} +criterion_main!(benches); + +//---------------------------------------------------------------------------------------------------- Constants +/// The (1st) key. +const KEY: PreRctOutputId = PreRctOutputId { + amount: 1, + amount_index: 123, +}; + +/// The expected value. +const VALUE: Output = Output { + key: [35; 32], + height: 45_761_798, + output_flags: 0, + tx_idx: 2_353_487, +}; + +//---------------------------------------------------------------------------------------------------- DatabaseRo +// Read-only table operations. +// This uses `TxRw + TablesMut` briefly to insert values, then +// uses `TxRo + Tables` for the actual operation. +// +// See further below for using `TxRw + TablesMut` on the same operations. + +/// [`DatabaseRo::get`] +#[named] +fn ro_get(c: &mut Criterion) { + let (env, _tempdir) = tmp_env(); + let env_inner = env.env_inner(); + let tx_rw = env_inner.tx_rw().unwrap(); + let mut table = env_inner.open_db_rw::(&tx_rw).unwrap(); + + table.put(&KEY, &VALUE).unwrap(); + drop(table); + tx_rw.commit().unwrap(); + + let tx_ro = env_inner.tx_ro().unwrap(); + let table = env_inner.open_db_ro::(&tx_ro).unwrap(); + + c.bench_function(function_name!(), |b| { + b.iter(|| { + let _value: Output = table.get(black_box(&KEY)).unwrap(); + }); + }); +} + +/// [`DatabaseRo::len`] +#[named] +fn ro_len(c: &mut Criterion) { + let (env, _tempdir) = tmp_env(); + let env_inner = env.env_inner(); + let tx_rw = env_inner.tx_rw().unwrap(); + let mut table = env_inner.open_db_rw::(&tx_rw).unwrap(); + + table.put(&KEY, &VALUE).unwrap(); + drop(table); + tx_rw.commit().unwrap(); + + let tx_ro = env_inner.tx_ro().unwrap(); + let table = env_inner.open_db_ro::(&tx_ro).unwrap(); + + c.bench_function(function_name!(), |b| { + b.iter(|| { + black_box(table.len()).unwrap(); + }); + }); +} + +/// [`DatabaseRo::first`] +#[named] +fn ro_first(c: &mut Criterion) { + let (env, _tempdir) = tmp_env(); + let env_inner = env.env_inner(); + let tx_rw = env_inner.tx_rw().unwrap(); + let mut table = env_inner.open_db_rw::(&tx_rw).unwrap(); + + table.put(&KEY, &VALUE).unwrap(); + drop(table); + tx_rw.commit().unwrap(); + + let tx_ro = env_inner.tx_ro().unwrap(); + let table = env_inner.open_db_ro::(&tx_ro).unwrap(); + + c.bench_function(function_name!(), |b| { + b.iter(|| { + let (_, _): (PreRctOutputId, Output) = black_box(table.first()).unwrap(); + }); + }); +} + +/// [`DatabaseRo::last`] +#[named] +fn ro_last(c: &mut Criterion) { + let (env, _tempdir) = tmp_env(); + let env_inner = env.env_inner(); + let tx_rw = env_inner.tx_rw().unwrap(); + let mut table = env_inner.open_db_rw::(&tx_rw).unwrap(); + + table.put(&KEY, &VALUE).unwrap(); + drop(table); + tx_rw.commit().unwrap(); + + let tx_ro = env_inner.tx_ro().unwrap(); + let table = env_inner.open_db_ro::(&tx_ro).unwrap(); + + c.bench_function(function_name!(), |b| { + b.iter(|| { + let (_, _): (PreRctOutputId, Output) = black_box(table.last()).unwrap(); + }); + }); +} + +/// [`DatabaseRo::is_empty`] +#[named] +fn ro_is_empty(c: &mut Criterion) { + let (env, _tempdir) = tmp_env(); + let env_inner = env.env_inner(); + let tx_rw = env_inner.tx_rw().unwrap(); + let mut table = env_inner.open_db_rw::(&tx_rw).unwrap(); + + table.put(&KEY, &VALUE).unwrap(); + drop(table); + tx_rw.commit().unwrap(); + + let tx_ro = env_inner.tx_ro().unwrap(); + let table = env_inner.open_db_ro::(&tx_ro).unwrap(); + + c.bench_function(function_name!(), |b| { + b.iter(|| { + black_box(table.is_empty()).unwrap(); + }); + }); +} + +/// [`DatabaseRo::contains`] +#[named] +fn ro_contains(c: &mut Criterion) { + let (env, _tempdir) = tmp_env(); + let env_inner = env.env_inner(); + let tx_rw = env_inner.tx_rw().unwrap(); + let mut table = env_inner.open_db_rw::(&tx_rw).unwrap(); + + table.put(&KEY, &VALUE).unwrap(); + drop(table); + tx_rw.commit().unwrap(); + + let tx_ro = env_inner.tx_ro().unwrap(); + let table = env_inner.open_db_ro::(&tx_ro).unwrap(); + + c.bench_function(function_name!(), |b| { + b.iter(|| { + table.contains(black_box(&KEY)).unwrap(); + }); + }); +} + +//---------------------------------------------------------------------------------------------------- DatabaseRo (using TxRw) +// These are the same benchmarks as above, but it uses a +// `TxRw` and a `TablesMut` instead to ensure our read/write tables +// using read operations perform the same as normal read-only tables. + +/// [`DatabaseRo::get`] +#[named] +fn rw_get(c: &mut Criterion) { + let (env, _tempdir) = tmp_env(); + let env_inner = env.env_inner(); + let tx_rw = env_inner.tx_rw().unwrap(); + let mut table = env_inner.open_db_rw::(&tx_rw).unwrap(); + + table.put(&KEY, &VALUE).unwrap(); + drop(table); + tx_rw.commit().unwrap(); + + let tx_rw = env_inner.tx_rw().unwrap(); + let table = env_inner.open_db_rw::(&tx_rw).unwrap(); + + c.bench_function(function_name!(), |b| { + b.iter(|| { + let _value: Output = table.get(black_box(&KEY)).unwrap(); + }); + }); +} + +/// [`DatabaseRo::len`] +#[named] +fn rw_len(c: &mut Criterion) { + let (env, _tempdir) = tmp_env(); + let env_inner = env.env_inner(); + let tx_rw = env_inner.tx_rw().unwrap(); + let mut table = env_inner.open_db_rw::(&tx_rw).unwrap(); + + table.put(&KEY, &VALUE).unwrap(); + drop(table); + tx_rw.commit().unwrap(); + + let tx_rw = env_inner.tx_rw().unwrap(); + let table = env_inner.open_db_rw::(&tx_rw).unwrap(); + + c.bench_function(function_name!(), |b| { + b.iter(|| { + black_box(table.len()).unwrap(); + }); + }); +} + +/// [`DatabaseRo::first`] +#[named] +fn rw_first(c: &mut Criterion) { + let (env, _tempdir) = tmp_env(); + let env_inner = env.env_inner(); + let tx_rw = env_inner.tx_rw().unwrap(); + let mut table = env_inner.open_db_rw::(&tx_rw).unwrap(); + + table.put(&KEY, &VALUE).unwrap(); + drop(table); + tx_rw.commit().unwrap(); + + let tx_rw = env_inner.tx_rw().unwrap(); + let table = env_inner.open_db_rw::(&tx_rw).unwrap(); + + c.bench_function(function_name!(), |b| { + b.iter(|| { + let (_, _): (PreRctOutputId, Output) = black_box(table.first()).unwrap(); + }); + }); +} + +/// [`DatabaseRo::last`] +#[named] +fn rw_last(c: &mut Criterion) { + let (env, _tempdir) = tmp_env(); + let env_inner = env.env_inner(); + let tx_rw = env_inner.tx_rw().unwrap(); + let mut table = env_inner.open_db_rw::(&tx_rw).unwrap(); + + table.put(&KEY, &VALUE).unwrap(); + drop(table); + tx_rw.commit().unwrap(); + + let tx_rw = env_inner.tx_rw().unwrap(); + let table = env_inner.open_db_rw::(&tx_rw).unwrap(); + + c.bench_function(function_name!(), |b| { + b.iter(|| { + let (_, _): (PreRctOutputId, Output) = black_box(table.last()).unwrap(); + }); + }); +} + +/// [`DatabaseRo::is_empty`] +#[named] +fn rw_is_empty(c: &mut Criterion) { + let (env, _tempdir) = tmp_env(); + let env_inner = env.env_inner(); + let tx_rw = env_inner.tx_rw().unwrap(); + let mut table = env_inner.open_db_rw::(&tx_rw).unwrap(); + + table.put(&KEY, &VALUE).unwrap(); + drop(table); + tx_rw.commit().unwrap(); + + let tx_rw = env_inner.tx_rw().unwrap(); + let table = env_inner.open_db_rw::(&tx_rw).unwrap(); + + c.bench_function(function_name!(), |b| { + b.iter(|| { + black_box(table.is_empty()).unwrap(); + }); + }); +} + +/// [`DatabaseRo::contains`] +#[named] +fn rw_contains(c: &mut Criterion) { + let (env, _tempdir) = tmp_env(); + let env_inner = env.env_inner(); + let tx_rw = env_inner.tx_rw().unwrap(); + let mut table = env_inner.open_db_rw::(&tx_rw).unwrap(); + + table.put(&KEY, &VALUE).unwrap(); + drop(table); + tx_rw.commit().unwrap(); + + let tx_rw = env_inner.tx_rw().unwrap(); + let table = env_inner.open_db_rw::(&tx_rw).unwrap(); + + c.bench_function(function_name!(), |b| { + b.iter(|| { + table.contains(black_box(&KEY)).unwrap(); + }); + }); +} + +//---------------------------------------------------------------------------------------------------- DatabaseRw +/// [`DatabaseRw::put`] +#[named] +fn put(c: &mut Criterion) { + let (env, _tempdir) = tmp_env(); + let env_inner = env.env_inner(); + let tx_rw = env_inner.tx_rw().unwrap(); + let mut table = env_inner.open_db_rw::(&tx_rw).unwrap(); + + let mut key = KEY; + + c.bench_function(function_name!(), |b| { + b.iter(|| { + table.put(black_box(&key), black_box(&VALUE)).unwrap(); + key.amount += 1; + }); + }); +} + +/// [`DatabaseRw::delete`] +#[named] +fn delete(c: &mut Criterion) { + let (env, _tempdir) = tmp_env(); + let env_inner = env.env_inner(); + let tx_rw = env_inner.tx_rw().unwrap(); + let mut table = env_inner.open_db_rw::(&tx_rw).unwrap(); + + let mut key = KEY; + + c.bench_function(function_name!(), |b| { + b.iter_custom(|iters| { + for _ in 0..iters { + table.put(&key, &VALUE).unwrap(); + key.amount += 1; + } + + key = KEY; + + let start = Instant::now(); + for _ in 0..iters { + table.delete(&key).unwrap(); + key.amount += 1; + } + start.elapsed() + }); + }); +} + +/// [`DatabaseRw::pop_first`] +#[named] +fn pop_first(c: &mut Criterion) { + let (env, _tempdir) = tmp_env(); + let env_inner = env.env_inner(); + let tx_rw = env_inner.tx_rw().unwrap(); + let mut table = env_inner.open_db_rw::(&tx_rw).unwrap(); + + let mut key = KEY; + + c.bench_function(function_name!(), |b| { + b.iter_custom(|iters| { + for _ in 0..iters { + table.put(&key, &VALUE).unwrap(); + key.amount += 1; + } + + key = KEY; + + let start = Instant::now(); + for _ in 0..iters { + table.pop_first().unwrap(); + key.amount += 1; + } + start.elapsed() + }); + }); +} + +/// [`DatabaseRw::pop_last`] +#[named] +fn pop_last(c: &mut Criterion) { + let (env, _tempdir) = tmp_env(); + let env_inner = env.env_inner(); + let tx_rw = env_inner.tx_rw().unwrap(); + let mut table = env_inner.open_db_rw::(&tx_rw).unwrap(); + + let mut key = KEY; + + c.bench_function(function_name!(), |b| { + b.iter_custom(|iters| { + for _ in 0..iters { + table.put(&key, &VALUE).unwrap(); + key.amount += 1; + } + + key = KEY; + + let start = Instant::now(); + for _ in 0..iters { + table.pop_last().unwrap(); + key.amount += 1; + } + start.elapsed() + }); + }); +} + +// TODO: waiting on PR 102 +// /// [`DatabaseRw::take`] +// #[named] +// fn take(c: &mut Criterion) { +// let (env, _tempdir) = tmp_env(); +// let env_inner = env.env_inner(); +// let tx_rw = env_inner.tx_rw().unwrap(); +// let mut table = env_inner.open_db_rw::(&tx_rw).unwrap(); + +// let mut key = KEY; +// for _ in 0..100 { +// table.put(&key, &VALUE).unwrap(); +// key.amount += 1; +// } + +// c.bench_function(function_name!(), |b| { +// b.iter(|| { +// table.put(&KEY, &VALUE).unwrap(); +// let value: Output = black_box(table.take(&black_box(KEY)).unwrap()); +// }); +// }); +// } + +//---------------------------------------------------------------------------------------------------- DatabaseIter +/// [`DatabaseRo::get_range`] +#[named] +fn get_range(c: &mut Criterion) { + let (env, _tempdir) = tmp_env(); + let env_inner = env.env_inner(); + let tx_rw = env_inner.tx_rw().unwrap(); + let mut table = env_inner.open_db_rw::(&tx_rw).unwrap(); + + let mut key = KEY; + for _ in 0..100 { + table.put(&key, &VALUE).unwrap(); + key.amount += 1; + } + + drop(table); + TxRw::commit(tx_rw).unwrap(); + + let tx_ro = env_inner.tx_ro().unwrap(); + let table = env_inner.open_db_ro::(&tx_ro).unwrap(); + + c.bench_function(function_name!(), |b| { + b.iter(|| { + let range = table.get_range(black_box(..)).unwrap(); + for result in range { + let _value: Output = black_box(result.unwrap()); + } + }); + }); +} + +/// [`DatabaseRo::iter`] +#[named] +fn iter(c: &mut Criterion) { + let (env, _tempdir) = tmp_env(); + let env_inner = env.env_inner(); + let tx_rw = env_inner.tx_rw().unwrap(); + let mut table = env_inner.open_db_rw::(&tx_rw).unwrap(); + + let mut key = KEY; + for _ in 0..100 { + table.put(&key, &VALUE).unwrap(); + key.amount += 1; + } + + drop(table); + TxRw::commit(tx_rw).unwrap(); + + let tx_ro = env_inner.tx_ro().unwrap(); + let table = env_inner.open_db_ro::(&tx_ro).unwrap(); + + c.bench_function(function_name!(), |b| { + b.iter(|| { + let iter = black_box(table.iter()).unwrap(); + for result in iter { + let _: (PreRctOutputId, Output) = black_box(result.unwrap()); + } + }); + }); +} + +/// [`DatabaseRo::keys`] +#[named] +fn keys(c: &mut Criterion) { + let (env, _tempdir) = tmp_env(); + let env_inner = env.env_inner(); + let tx_rw = env_inner.tx_rw().unwrap(); + let mut table = env_inner.open_db_rw::(&tx_rw).unwrap(); + + let mut key = KEY; + for _ in 0..100 { + table.put(&key, &VALUE).unwrap(); + key.amount += 1; + } + + drop(table); + TxRw::commit(tx_rw).unwrap(); + + let tx_ro = env_inner.tx_ro().unwrap(); + let table = env_inner.open_db_ro::(&tx_ro).unwrap(); + + c.bench_function(function_name!(), |b| { + b.iter(|| { + let keys = black_box(table.keys()).unwrap(); + for result in keys { + let _: PreRctOutputId = black_box(result.unwrap()); + } + }); + }); +} + +/// [`DatabaseRo::values`] +#[named] +fn values(c: &mut Criterion) { + let (env, _tempdir) = tmp_env(); + let env_inner = env.env_inner(); + let tx_rw = env_inner.tx_rw().unwrap(); + let mut table = env_inner.open_db_rw::(&tx_rw).unwrap(); + + let mut key = KEY; + for _ in 0..100 { + table.put(&key, &VALUE).unwrap(); + key.amount += 1; + } + + drop(table); + TxRw::commit(tx_rw).unwrap(); + + let tx_ro = env_inner.tx_ro().unwrap(); + let table = env_inner.open_db_ro::(&tx_ro).unwrap(); + + c.bench_function(function_name!(), |b| { + b.iter(|| { + let values = black_box(table.values()).unwrap(); + for result in values { + let _: Output = black_box(result.unwrap()); + } + }); + }); +} diff --git a/benches/criterion/cuprate-database/benches/db_multi_thread.rs b/benches/criterion/cuprate-database/benches/db_multi_thread.rs new file mode 100644 index 0000000..8089929 --- /dev/null +++ b/benches/criterion/cuprate-database/benches/db_multi_thread.rs @@ -0,0 +1,584 @@ +//! Same as `db.rs` but multi-threaded. +//! TODO: create multi-threaded benchmarks + +use std::time::Instant; + +//---------------------------------------------------------------------------------------------------- Import +use criterion::{black_box, criterion_group, criterion_main, Criterion}; + +use function_name::named; + +use cuprate_database::{ + tables::Outputs, + types::{Output, PreRctOutputId}, + DatabaseIter, DatabaseRo, DatabaseRw, Env, EnvInner, TxRw, +}; + +use cuprate_database_benchmark::tmp_env_all_threads; + +//---------------------------------------------------------------------------------------------------- Criterion +criterion_group! { + benches, + ro_get, + ro_len, + ro_first, + ro_last, + ro_is_empty, + ro_contains, + rw_get, + rw_len, + rw_first, + rw_last, + rw_is_empty, + rw_contains, + put, + delete, + pop_first, + pop_last, + get_range, + iter, + keys, + values, +} +criterion_main!(benches); + +//---------------------------------------------------------------------------------------------------- Constants +/// The (1st) key. +const KEY: PreRctOutputId = PreRctOutputId { + amount: 1, + amount_index: 123, +}; + +/// The expected value. +const VALUE: Output = Output { + key: [35; 32], + height: 45_761_798, + output_flags: 0, + tx_idx: 2_353_487, +}; + +//---------------------------------------------------------------------------------------------------- DatabaseRo +// Read-only table operations. +// This uses `TxRw + TablesMut` briefly to insert values, then +// uses `TxRo + Tables` for the actual operation. +// +// See further below for using `TxRw + TablesMut` on the same operations. + +/// [`DatabaseRo::get`] +#[named] +fn ro_get(c: &mut Criterion) { + let (env, _tempdir) = tmp_env_all_threads(); + let env_inner = env.env_inner(); + let tx_rw = env_inner.tx_rw().unwrap(); + let mut table = env_inner.open_db_rw::(&tx_rw).unwrap(); + + table.put(&KEY, &VALUE).unwrap(); + drop(table); + tx_rw.commit().unwrap(); + + let tx_ro = env_inner.tx_ro().unwrap(); + let table = env_inner.open_db_ro::(&tx_ro).unwrap(); + + c.bench_function(function_name!(), |b| { + b.iter(|| { + let _value: Output = table.get(black_box(&KEY)).unwrap(); + }); + }); +} + +/// [`DatabaseRo::len`] +#[named] +fn ro_len(c: &mut Criterion) { + let (env, _tempdir) = tmp_env_all_threads(); + let env_inner = env.env_inner(); + let tx_rw = env_inner.tx_rw().unwrap(); + let mut table = env_inner.open_db_rw::(&tx_rw).unwrap(); + + table.put(&KEY, &VALUE).unwrap(); + drop(table); + tx_rw.commit().unwrap(); + + let tx_ro = env_inner.tx_ro().unwrap(); + let table = env_inner.open_db_ro::(&tx_ro).unwrap(); + + c.bench_function(function_name!(), |b| { + b.iter(|| { + black_box(table.len()).unwrap(); + }); + }); +} + +/// [`DatabaseRo::first`] +#[named] +fn ro_first(c: &mut Criterion) { + let (env, _tempdir) = tmp_env_all_threads(); + let env_inner = env.env_inner(); + let tx_rw = env_inner.tx_rw().unwrap(); + let mut table = env_inner.open_db_rw::(&tx_rw).unwrap(); + + table.put(&KEY, &VALUE).unwrap(); + drop(table); + tx_rw.commit().unwrap(); + + let tx_ro = env_inner.tx_ro().unwrap(); + let table = env_inner.open_db_ro::(&tx_ro).unwrap(); + + c.bench_function(function_name!(), |b| { + b.iter(|| { + let (_, _): (PreRctOutputId, Output) = black_box(table.first()).unwrap(); + }); + }); +} + +/// [`DatabaseRo::last`] +#[named] +fn ro_last(c: &mut Criterion) { + let (env, _tempdir) = tmp_env_all_threads(); + let env_inner = env.env_inner(); + let tx_rw = env_inner.tx_rw().unwrap(); + let mut table = env_inner.open_db_rw::(&tx_rw).unwrap(); + + table.put(&KEY, &VALUE).unwrap(); + drop(table); + tx_rw.commit().unwrap(); + + let tx_ro = env_inner.tx_ro().unwrap(); + let table = env_inner.open_db_ro::(&tx_ro).unwrap(); + + c.bench_function(function_name!(), |b| { + b.iter(|| { + let (_, _): (PreRctOutputId, Output) = black_box(table.last()).unwrap(); + }); + }); +} + +/// [`DatabaseRo::is_empty`] +#[named] +fn ro_is_empty(c: &mut Criterion) { + let (env, _tempdir) = tmp_env_all_threads(); + let env_inner = env.env_inner(); + let tx_rw = env_inner.tx_rw().unwrap(); + let mut table = env_inner.open_db_rw::(&tx_rw).unwrap(); + + table.put(&KEY, &VALUE).unwrap(); + drop(table); + tx_rw.commit().unwrap(); + + let tx_ro = env_inner.tx_ro().unwrap(); + let table = env_inner.open_db_ro::(&tx_ro).unwrap(); + + c.bench_function(function_name!(), |b| { + b.iter(|| { + black_box(table.is_empty()).unwrap(); + }); + }); +} + +/// [`DatabaseRo::contains`] +#[named] +fn ro_contains(c: &mut Criterion) { + let (env, _tempdir) = tmp_env_all_threads(); + let env_inner = env.env_inner(); + let tx_rw = env_inner.tx_rw().unwrap(); + let mut table = env_inner.open_db_rw::(&tx_rw).unwrap(); + + table.put(&KEY, &VALUE).unwrap(); + drop(table); + tx_rw.commit().unwrap(); + + let tx_ro = env_inner.tx_ro().unwrap(); + let table = env_inner.open_db_ro::(&tx_ro).unwrap(); + + c.bench_function(function_name!(), |b| { + b.iter(|| { + table.contains(black_box(&KEY)).unwrap(); + }); + }); +} + +//---------------------------------------------------------------------------------------------------- DatabaseRo (using TxRw) +// These are the same benchmarks as above, but it uses a +// `TxRw` and a `TablesMut` instead to ensure our read/write tables +// using read operations perform the same as normal read-only tables. + +/// [`DatabaseRo::get`] +#[named] +fn rw_get(c: &mut Criterion) { + let (env, _tempdir) = tmp_env_all_threads(); + let env_inner = env.env_inner(); + let tx_rw = env_inner.tx_rw().unwrap(); + let mut table = env_inner.open_db_rw::(&tx_rw).unwrap(); + + table.put(&KEY, &VALUE).unwrap(); + drop(table); + tx_rw.commit().unwrap(); + + let tx_rw = env_inner.tx_rw().unwrap(); + let table = env_inner.open_db_rw::(&tx_rw).unwrap(); + + c.bench_function(function_name!(), |b| { + b.iter(|| { + let _value: Output = table.get(black_box(&KEY)).unwrap(); + }); + }); +} + +/// [`DatabaseRo::len`] +#[named] +fn rw_len(c: &mut Criterion) { + let (env, _tempdir) = tmp_env_all_threads(); + let env_inner = env.env_inner(); + let tx_rw = env_inner.tx_rw().unwrap(); + let mut table = env_inner.open_db_rw::(&tx_rw).unwrap(); + + table.put(&KEY, &VALUE).unwrap(); + drop(table); + tx_rw.commit().unwrap(); + + let tx_rw = env_inner.tx_rw().unwrap(); + let table = env_inner.open_db_rw::(&tx_rw).unwrap(); + + c.bench_function(function_name!(), |b| { + b.iter(|| { + black_box(table.len()).unwrap(); + }); + }); +} + +/// [`DatabaseRo::first`] +#[named] +fn rw_first(c: &mut Criterion) { + let (env, _tempdir) = tmp_env_all_threads(); + let env_inner = env.env_inner(); + let tx_rw = env_inner.tx_rw().unwrap(); + let mut table = env_inner.open_db_rw::(&tx_rw).unwrap(); + + table.put(&KEY, &VALUE).unwrap(); + drop(table); + tx_rw.commit().unwrap(); + + let tx_rw = env_inner.tx_rw().unwrap(); + let table = env_inner.open_db_rw::(&tx_rw).unwrap(); + + c.bench_function(function_name!(), |b| { + b.iter(|| { + let (_, _): (PreRctOutputId, Output) = black_box(table.first()).unwrap(); + }); + }); +} + +/// [`DatabaseRo::last`] +#[named] +fn rw_last(c: &mut Criterion) { + let (env, _tempdir) = tmp_env_all_threads(); + let env_inner = env.env_inner(); + let tx_rw = env_inner.tx_rw().unwrap(); + let mut table = env_inner.open_db_rw::(&tx_rw).unwrap(); + + table.put(&KEY, &VALUE).unwrap(); + drop(table); + tx_rw.commit().unwrap(); + + let tx_rw = env_inner.tx_rw().unwrap(); + let table = env_inner.open_db_rw::(&tx_rw).unwrap(); + + c.bench_function(function_name!(), |b| { + b.iter(|| { + let (_, _): (PreRctOutputId, Output) = black_box(table.last()).unwrap(); + }); + }); +} + +/// [`DatabaseRo::is_empty`] +#[named] +fn rw_is_empty(c: &mut Criterion) { + let (env, _tempdir) = tmp_env_all_threads(); + let env_inner = env.env_inner(); + let tx_rw = env_inner.tx_rw().unwrap(); + let mut table = env_inner.open_db_rw::(&tx_rw).unwrap(); + + table.put(&KEY, &VALUE).unwrap(); + drop(table); + tx_rw.commit().unwrap(); + + let tx_rw = env_inner.tx_rw().unwrap(); + let table = env_inner.open_db_rw::(&tx_rw).unwrap(); + + c.bench_function(function_name!(), |b| { + b.iter(|| { + black_box(table.is_empty()).unwrap(); + }); + }); +} + +/// [`DatabaseRo::contains`] +#[named] +fn rw_contains(c: &mut Criterion) { + let (env, _tempdir) = tmp_env_all_threads(); + let env_inner = env.env_inner(); + let tx_rw = env_inner.tx_rw().unwrap(); + let mut table = env_inner.open_db_rw::(&tx_rw).unwrap(); + + table.put(&KEY, &VALUE).unwrap(); + drop(table); + tx_rw.commit().unwrap(); + + let tx_rw = env_inner.tx_rw().unwrap(); + let table = env_inner.open_db_rw::(&tx_rw).unwrap(); + + c.bench_function(function_name!(), |b| { + b.iter(|| { + table.contains(black_box(&KEY)).unwrap(); + }); + }); +} + +//---------------------------------------------------------------------------------------------------- DatabaseRw +/// [`DatabaseRw::put`] +#[named] +fn put(c: &mut Criterion) { + let (env, _tempdir) = tmp_env_all_threads(); + let env_inner = env.env_inner(); + let tx_rw = env_inner.tx_rw().unwrap(); + let mut table = env_inner.open_db_rw::(&tx_rw).unwrap(); + + let mut key = KEY; + + c.bench_function(function_name!(), |b| { + b.iter(|| { + table.put(black_box(&key), black_box(&VALUE)).unwrap(); + key.amount += 1; + }); + }); +} + +/// [`DatabaseRw::delete`] +#[named] +fn delete(c: &mut Criterion) { + let (env, _tempdir) = tmp_env_all_threads(); + let env_inner = env.env_inner(); + let tx_rw = env_inner.tx_rw().unwrap(); + let mut table = env_inner.open_db_rw::(&tx_rw).unwrap(); + + let mut key = KEY; + + c.bench_function(function_name!(), |b| { + b.iter_custom(|iters| { + for _ in 0..iters { + table.put(&key, &VALUE).unwrap(); + key.amount += 1; + } + + key = KEY; + + let start = Instant::now(); + for _ in 0..iters { + table.delete(&key).unwrap(); + key.amount += 1; + } + start.elapsed() + }); + }); +} + +/// [`DatabaseRw::pop_first`] +#[named] +fn pop_first(c: &mut Criterion) { + let (env, _tempdir) = tmp_env_all_threads(); + let env_inner = env.env_inner(); + let tx_rw = env_inner.tx_rw().unwrap(); + let mut table = env_inner.open_db_rw::(&tx_rw).unwrap(); + + let mut key = KEY; + + c.bench_function(function_name!(), |b| { + b.iter_custom(|iters| { + for _ in 0..iters { + table.put(&key, &VALUE).unwrap(); + key.amount += 1; + } + + key = KEY; + + let start = Instant::now(); + for _ in 0..iters { + table.pop_first().unwrap(); + key.amount += 1; + } + start.elapsed() + }); + }); +} + +/// [`DatabaseRw::pop_last`] +#[named] +fn pop_last(c: &mut Criterion) { + let (env, _tempdir) = tmp_env_all_threads(); + let env_inner = env.env_inner(); + let tx_rw = env_inner.tx_rw().unwrap(); + let mut table = env_inner.open_db_rw::(&tx_rw).unwrap(); + + let mut key = KEY; + + c.bench_function(function_name!(), |b| { + b.iter_custom(|iters| { + for _ in 0..iters { + table.put(&key, &VALUE).unwrap(); + key.amount += 1; + } + + key = KEY; + + let start = Instant::now(); + for _ in 0..iters { + table.pop_last().unwrap(); + key.amount += 1; + } + start.elapsed() + }); + }); +} + +// TODO: waiting on PR 102 +// /// [`DatabaseRw::take`] +// #[named] +// fn take(c: &mut Criterion) { +// let (env, _tempdir) = tmp_env_all_threads(); +// let env_inner = env.env_inner(); +// let tx_rw = env_inner.tx_rw().unwrap(); +// let mut table = env_inner.open_db_rw::(&tx_rw).unwrap(); + +// let mut key = KEY; +// for _ in 0..100 { +// table.put(&key, &VALUE).unwrap(); +// key.amount += 1; +// } + +// c.bench_function(function_name!(), |b| { +// b.iter(|| { +// table.put(&KEY, &VALUE).unwrap(); +// let value: Output = black_box(table.take(&black_box(KEY)).unwrap()); +// }); +// }); +// } + +//---------------------------------------------------------------------------------------------------- DatabaseIter +/// [`DatabaseRo::get_range`] +#[named] +fn get_range(c: &mut Criterion) { + let (env, _tempdir) = tmp_env_all_threads(); + let env_inner = env.env_inner(); + let tx_rw = env_inner.tx_rw().unwrap(); + let mut table = env_inner.open_db_rw::(&tx_rw).unwrap(); + + let mut key = KEY; + for _ in 0..100 { + table.put(&key, &VALUE).unwrap(); + key.amount += 1; + } + + drop(table); + TxRw::commit(tx_rw).unwrap(); + + let tx_ro = env_inner.tx_ro().unwrap(); + let table = env_inner.open_db_ro::(&tx_ro).unwrap(); + + c.bench_function(function_name!(), |b| { + b.iter(|| { + let range = table.get_range(black_box(..)).unwrap(); + for result in range { + let _value: Output = black_box(result.unwrap()); + } + }); + }); +} + +/// [`DatabaseRo::iter`] +#[named] +fn iter(c: &mut Criterion) { + let (env, _tempdir) = tmp_env_all_threads(); + let env_inner = env.env_inner(); + let tx_rw = env_inner.tx_rw().unwrap(); + let mut table = env_inner.open_db_rw::(&tx_rw).unwrap(); + + let mut key = KEY; + for _ in 0..100 { + table.put(&key, &VALUE).unwrap(); + key.amount += 1; + } + + drop(table); + TxRw::commit(tx_rw).unwrap(); + + let tx_ro = env_inner.tx_ro().unwrap(); + let table = env_inner.open_db_ro::(&tx_ro).unwrap(); + + c.bench_function(function_name!(), |b| { + b.iter(|| { + let iter = black_box(table.iter()).unwrap(); + for result in iter { + let _: (PreRctOutputId, Output) = black_box(result.unwrap()); + } + }); + }); +} + +/// [`DatabaseRo::keys`] +#[named] +fn keys(c: &mut Criterion) { + let (env, _tempdir) = tmp_env_all_threads(); + let env_inner = env.env_inner(); + let tx_rw = env_inner.tx_rw().unwrap(); + let mut table = env_inner.open_db_rw::(&tx_rw).unwrap(); + + let mut key = KEY; + for _ in 0..100 { + table.put(&key, &VALUE).unwrap(); + key.amount += 1; + } + + drop(table); + TxRw::commit(tx_rw).unwrap(); + + let tx_ro = env_inner.tx_ro().unwrap(); + let table = env_inner.open_db_ro::(&tx_ro).unwrap(); + + c.bench_function(function_name!(), |b| { + b.iter(|| { + let keys = black_box(table.keys()).unwrap(); + for result in keys { + let _: PreRctOutputId = black_box(result.unwrap()); + } + }); + }); +} + +/// [`DatabaseRo::values`] +#[named] +fn values(c: &mut Criterion) { + let (env, _tempdir) = tmp_env_all_threads(); + let env_inner = env.env_inner(); + let tx_rw = env_inner.tx_rw().unwrap(); + let mut table = env_inner.open_db_rw::(&tx_rw).unwrap(); + + let mut key = KEY; + for _ in 0..100 { + table.put(&key, &VALUE).unwrap(); + key.amount += 1; + } + + drop(table); + TxRw::commit(tx_rw).unwrap(); + + let tx_ro = env_inner.tx_ro().unwrap(); + let table = env_inner.open_db_ro::(&tx_ro).unwrap(); + + c.bench_function(function_name!(), |b| { + b.iter(|| { + let values = black_box(table.values()).unwrap(); + for result in values { + let _: Output = black_box(result.unwrap()); + } + }); + }); +} diff --git a/benches/criterion/cuprate-database/benches/env.rs b/benches/criterion/cuprate-database/benches/env.rs new file mode 100644 index 0000000..4c0f6d4 --- /dev/null +++ b/benches/criterion/cuprate-database/benches/env.rs @@ -0,0 +1,161 @@ +//! `trait {Env, EnvInner, TxR{o,w}, Tables[Mut]}` benchmarks. + +//---------------------------------------------------------------------------------------------------- Import +use criterion::{black_box, criterion_group, criterion_main, Criterion}; + +use function_name::named; + +use cuprate_database::{ + config::Config, + resize::{page_size, ResizeAlgorithm}, + tables::Outputs, + ConcreteEnv, Env, EnvInner, TxRo, TxRw, +}; + +use cuprate_database_benchmark::tmp_env; + +//---------------------------------------------------------------------------------------------------- Criterion +criterion_group! { + benches, + open, + env_inner, + tx_ro, + tx_rw, + open_tables, + open_tables_mut, + resize, + current_map_size, + disk_size_bytes, +} +criterion_main!(benches); + +//---------------------------------------------------------------------------------------------------- Env benchmarks +/// [`Env::open`]. +#[named] +fn open(c: &mut Criterion) { + let tempdir = tempfile::tempdir().unwrap(); + let config = Config::low_power(Some(tempdir.path().into())); + + c.bench_function(function_name!(), |b| { + b.iter_with_large_drop(|| { + ConcreteEnv::open(config.clone()).unwrap(); + }); + }); +} + +/// [`Env::env_inner`]. +#[named] +fn env_inner(c: &mut Criterion) { + let (env, _tempdir) = tmp_env(); + + c.bench_function(function_name!(), |b| { + b.iter(|| { + black_box(env.env_inner()); + }); + }); +} + +/// Create and commit read-only transactions. +#[named] +fn tx_ro(c: &mut Criterion) { + let (env, _tempdir) = tmp_env(); + let env_inner = env.env_inner(); + + c.bench_function(function_name!(), |b| { + b.iter(|| { + let tx_ro = black_box(env_inner.tx_ro()).unwrap(); + TxRo::commit(black_box(tx_ro)).unwrap(); + }); + }); +} + +/// Create and commit read/write transactions. +#[named] +fn tx_rw(c: &mut Criterion) { + let (env, _tempdir) = tmp_env(); + let env_inner = env.env_inner(); + + c.bench_function(function_name!(), |b| { + b.iter(|| { + let tx_rw = black_box(env_inner.tx_rw()).unwrap(); + TxRw::commit(black_box(tx_rw)).unwrap(); + }); + }); +} + +/// Open all database tables in read-only mode. +#[named] +fn open_tables(c: &mut Criterion) { + let (env, _tempdir) = tmp_env(); + let env_inner = env.env_inner(); + let tx_ro = env_inner.tx_ro().unwrap(); + + c.bench_function(function_name!(), |b| { + b.iter(|| { + black_box(env_inner.open_db_ro::(&tx_ro)).unwrap(); + // env_inner.open_tables(&tx_ro).unwrap(); + // TODO: waiting on PR 102 + }); + }); +} + +/// Open all database tables in read/write mode. +#[named] +fn open_tables_mut(c: &mut Criterion) { + let (env, _tempdir) = tmp_env(); + let env_inner = env.env_inner(); + let tx_rw = env_inner.tx_rw().unwrap(); + + c.bench_function(function_name!(), |b| { + b.iter(|| { + black_box(env_inner.open_db_rw::(&tx_rw)).unwrap(); + // env_inner.open_tables_mut(&mut tx_rw).unwrap(); + // TODO: waiting on PR 102 + }); + }); +} + +/// `Env` memory map resizes. +#[named] +fn resize(c: &mut Criterion) { + let (env, _tempdir) = tmp_env(); + + // Resize by the OS page size. + let page_size = page_size(); + + c.bench_function(function_name!(), |b| { + b.iter(|| { + // This test is only valid for `Env`'s that need to resize manually. + if ConcreteEnv::MANUAL_RESIZE { + env.resize_map(black_box(Some(ResizeAlgorithm::FixedBytes(page_size)))); + } + }); + }); +} + +/// Access current memory map size of the database. +#[named] +fn current_map_size(c: &mut Criterion) { + let (env, _tempdir) = tmp_env(); + + c.bench_function(function_name!(), |b| { + b.iter(|| { + // This test is only valid for `Env`'s that need to resize manually. + if ConcreteEnv::MANUAL_RESIZE { + black_box(env.current_map_size()); + } + }); + }); +} + +/// Access on-disk size of the database. +#[named] +fn disk_size_bytes(c: &mut Criterion) { + let (env, _tempdir) = tmp_env(); + + c.bench_function(function_name!(), |b| { + b.iter(|| { + black_box(env.disk_size_bytes()).unwrap(); + }); + }); +} diff --git a/benches/criterion/cuprate-database/benches/env_multi_thread.rs b/benches/criterion/cuprate-database/benches/env_multi_thread.rs new file mode 100644 index 0000000..ec796c8 --- /dev/null +++ b/benches/criterion/cuprate-database/benches/env_multi_thread.rs @@ -0,0 +1,162 @@ +//! Same as `env.rs` but multi-threaded. +//! TODO: create multi-threaded benchmarks + +//---------------------------------------------------------------------------------------------------- Import +use criterion::{black_box, criterion_group, criterion_main, Criterion}; + +use function_name::named; + +use cuprate_database::{ + config::Config, + resize::{page_size, ResizeAlgorithm}, + tables::Outputs, + ConcreteEnv, Env, EnvInner, TxRo, TxRw, +}; + +use cuprate_database_benchmark::tmp_env_all_threads; + +//---------------------------------------------------------------------------------------------------- Criterion +criterion_group! { + benches, + open, + env_inner, + tx_ro, + tx_rw, + open_tables, + open_tables_mut, + resize, + current_map_size, + disk_size_bytes, +} +criterion_main!(benches); + +//---------------------------------------------------------------------------------------------------- Env benchmarks +/// [`Env::open`]. +#[named] +fn open(c: &mut Criterion) { + let tempdir = tempfile::tempdir().unwrap(); + let config = Config::low_power(Some(tempdir.path().into())); + + c.bench_function(function_name!(), |b| { + b.iter_with_large_drop(|| { + ConcreteEnv::open(config.clone()).unwrap(); + }); + }); +} + +/// [`Env::env_inner`]. +#[named] +fn env_inner(c: &mut Criterion) { + let (env, _tempdir) = tmp_env_all_threads(); + + c.bench_function(function_name!(), |b| { + b.iter(|| { + black_box(env.env_inner()); + }); + }); +} + +/// Create and commit read-only transactions. +#[named] +fn tx_ro(c: &mut Criterion) { + let (env, _tempdir) = tmp_env_all_threads(); + let env_inner = env.env_inner(); + + c.bench_function(function_name!(), |b| { + b.iter(|| { + let tx_ro = black_box(env_inner.tx_ro()).unwrap(); + TxRo::commit(black_box(tx_ro)).unwrap(); + }); + }); +} + +/// Create and commit read/write transactions. +#[named] +fn tx_rw(c: &mut Criterion) { + let (env, _tempdir) = tmp_env_all_threads(); + let env_inner = env.env_inner(); + + c.bench_function(function_name!(), |b| { + b.iter(|| { + let tx_rw = black_box(env_inner.tx_rw()).unwrap(); + TxRw::commit(black_box(tx_rw)).unwrap(); + }); + }); +} + +/// Open all database tables in read-only mode. +#[named] +fn open_tables(c: &mut Criterion) { + let (env, _tempdir) = tmp_env_all_threads(); + let env_inner = env.env_inner(); + let tx_ro = env_inner.tx_ro().unwrap(); + + c.bench_function(function_name!(), |b| { + b.iter(|| { + black_box(env_inner.open_db_ro::(&tx_ro)).unwrap(); + // env_inner.open_tables(&tx_ro).unwrap(); + // TODO: waiting on PR 102 + }); + }); +} + +/// Open all database tables in read/write mode. +#[named] +fn open_tables_mut(c: &mut Criterion) { + let (env, _tempdir) = tmp_env_all_threads(); + let env_inner = env.env_inner(); + let tx_rw = env_inner.tx_rw().unwrap(); + + c.bench_function(function_name!(), |b| { + b.iter(|| { + black_box(env_inner.open_db_rw::(&tx_rw)).unwrap(); + // env_inner.open_tables_mut(&mut tx_rw).unwrap(); + // TODO: waiting on PR 102 + }); + }); +} + +/// `Env` memory map resizes. +#[named] +fn resize(c: &mut Criterion) { + let (env, _tempdir) = tmp_env_all_threads(); + + // Resize by the OS page size. + let page_size = page_size(); + + c.bench_function(function_name!(), |b| { + b.iter(|| { + // This test is only valid for `Env`'s that need to resize manually. + if ConcreteEnv::MANUAL_RESIZE { + env.resize_map(black_box(Some(ResizeAlgorithm::FixedBytes(page_size)))); + } + }); + }); +} + +/// Access current memory map size of the database. +#[named] +fn current_map_size(c: &mut Criterion) { + let (env, _tempdir) = tmp_env_all_threads(); + + c.bench_function(function_name!(), |b| { + b.iter(|| { + // This test is only valid for `Env`'s that need to resize manually. + if ConcreteEnv::MANUAL_RESIZE { + black_box(env.current_map_size()); + } + }); + }); +} + +/// Access on-disk size of the database. +#[named] +fn disk_size_bytes(c: &mut Criterion) { + let (env, _tempdir) = tmp_env_all_threads(); + + c.bench_function(function_name!(), |b| { + b.iter(|| { + black_box(env.disk_size_bytes()).unwrap(); + }); + }); +} diff --git a/benches/criterion/cuprate-database/benches/main.rs b/benches/criterion/cuprate-database/benches/main.rs new file mode 100644 index 0000000..74865f2 --- /dev/null +++ b/benches/criterion/cuprate-database/benches/main.rs @@ -0,0 +1,91 @@ +//! TODO + +//---------------------------------------------------------------------------------------------------- Lints +// Forbid lints. +// Our code, and code generated (e.g macros) cannot overrule these. +#![forbid( + // `unsafe` is allowed but it _must_ be + // commented with `SAFETY: reason`. + clippy::undocumented_unsafe_blocks, + + // Never. + unused_unsafe, + redundant_semicolons, + unused_allocation, + coherence_leak_check, + while_true, + clippy::missing_docs_in_private_items, + + // Maybe can be put into `#[deny]`. + unconditional_recursion, + for_loops_over_fallibles, + unused_braces, + unused_doc_comments, + unused_labels, + keyword_idents, + non_ascii_idents, + variant_size_differences, + single_use_lifetimes, + + // Probably can be put into `#[deny]`. + future_incompatible, + let_underscore, + break_with_label_and_loop, + duplicate_macro_attributes, + exported_private_dependencies, + large_assignments, + overlapping_range_endpoints, + semicolon_in_expressions_from_macros, + noop_method_call, + unreachable_pub, +)] +// Deny lints. +// Some of these are `#[allow]`'ed on a per-case basis. +#![deny( + clippy::all, + clippy::correctness, + clippy::suspicious, + clippy::style, + clippy::complexity, + clippy::perf, + clippy::pedantic, + clippy::nursery, + clippy::cargo, + unused_mut, + missing_docs, + deprecated, + unused_comparisons, + nonstandard_style +)] +#![allow(unreachable_code, unused_variables, dead_code, unused_imports)] // TODO: remove +#![allow( + // FIXME: this lint affects crates outside of + // `database/` for some reason, allow for now. + clippy::cargo_common_metadata, + + // FIXME: adding `#[must_use]` onto everything + // might just be more annoying than useful... + // although it is sometimes nice. + clippy::must_use_candidate, + + // TODO: should be removed after all `todo!()`'s are gone. + clippy::diverging_sub_expression, + + clippy::module_name_repetitions, + clippy::module_inception, + clippy::redundant_pub_crate, + clippy::option_if_let_else, + clippy::significant_drop_tightening, +)] +// Allow some lints when running in debug mode. +#![cfg_attr(debug_assertions, allow(clippy::todo, clippy::multiple_crate_versions))] + +mod db; +mod env; +mod storable; + +criterion::criterion_main! { + db::benches, + env::benches, + storable::benches, +} diff --git a/benches/criterion/cuprate-database/benches/service.rs b/benches/criterion/cuprate-database/benches/service.rs new file mode 100644 index 0000000..9c4a74f --- /dev/null +++ b/benches/criterion/cuprate-database/benches/service.rs @@ -0,0 +1,25 @@ +//! `cuprate_database::service` benchmarks. + +//---------------------------------------------------------------------------------------------------- Import +use criterion::{black_box, criterion_group, criterion_main, Criterion}; + +use function_name::named; + +use cuprate_database::{ + config::Config, + resize::{page_size, ResizeAlgorithm}, + tables::Outputs, + ConcreteEnv, Env, EnvInner, TxRo, TxRw, +}; + +use cuprate_database_benchmark::tmp_env_all_threads; + +//---------------------------------------------------------------------------------------------------- Criterion +criterion_group! { + benches, +} +criterion_main!(benches); + +//---------------------------------------------------------------------------------------------------- Benchmarks + +// TODO diff --git a/benches/criterion/cuprate-database/benches/storable.rs b/benches/criterion/cuprate-database/benches/storable.rs new file mode 100644 index 0000000..b427e26 --- /dev/null +++ b/benches/criterion/cuprate-database/benches/storable.rs @@ -0,0 +1,81 @@ +//! `trait Storable` benchmarks. + +//---------------------------------------------------------------------------------------------------- Import +use criterion::{black_box, criterion_group, criterion_main, Criterion}; + +use function_name::named; + +use cuprate_database::{ + types::{Output, PreRctOutputId}, + Storable, +}; + +//---------------------------------------------------------------------------------------------------- Criterion +criterion_group! { + benches, + pre_rct_output_id_as_bytes, + pre_rct_output_id_from_bytes, + output_as_bytes, + output_from_bytes +} +criterion_main!(benches); + +//---------------------------------------------------------------------------------------------------- Constants +/// 16 bytes. +const PRE_RCT_OUTPUT_ID: PreRctOutputId = PreRctOutputId { + amount: 1, + amount_index: 123, +}; + +/// 48 bytes. +const OUTPUT: Output = Output { + key: [35; 32], + height: 45_761_798, + output_flags: 0, + tx_idx: 2_353_487, +}; + +//---------------------------------------------------------------------------------------------------- Storable benchmarks +/// [`PreRctOutputId`] cast as bytes. +#[named] +fn pre_rct_output_id_as_bytes(c: &mut Criterion) { + c.bench_function(function_name!(), |b| { + b.iter(|| { + black_box(Storable::as_bytes(black_box(&PRE_RCT_OUTPUT_ID))); + }); + }); +} + +/// [`PreRctOutputId`] cast from bytes. +#[named] +fn pre_rct_output_id_from_bytes(c: &mut Criterion) { + let bytes = Storable::as_bytes(&PRE_RCT_OUTPUT_ID); + + c.bench_function(function_name!(), |b| { + b.iter(|| { + let _: PreRctOutputId = black_box(Storable::from_bytes(black_box(bytes))); + }); + }); +} + +/// [`Output`] cast as bytes. +#[named] +fn output_as_bytes(c: &mut Criterion) { + c.bench_function(function_name!(), |b| { + b.iter(|| { + black_box(Storable::as_bytes(black_box(&OUTPUT))); + }); + }); +} + +/// [`Output`] cast from bytes. +#[named] +fn output_from_bytes(c: &mut Criterion) { + let bytes = Storable::as_bytes(&OUTPUT); + + c.bench_function(function_name!(), |b| { + b.iter(|| { + let _: Output = black_box(Storable::from_bytes(black_box(bytes))); + }); + }); +} diff --git a/benches/criterion/cuprate-database/src/helper.rs b/benches/criterion/cuprate-database/src/helper.rs new file mode 100644 index 0000000..ecf2fd1 --- /dev/null +++ b/benches/criterion/cuprate-database/src/helper.rs @@ -0,0 +1,30 @@ +//! TODO + +// TODO: set-up env based on config + +//---------------------------------------------------------------------------------------------------- Import +use cuprate_database::{config::Config, ConcreteEnv, Env}; + +//---------------------------------------------------------------------------------------------------- Tests +/// Create an `Env` in a temporarily directory. +/// The directory is automatically removed after the `TempDir` is dropped. +/// +/// TODO: changing this to `-> impl Env` causes lifetime errors... +#[allow(clippy::missing_panics_doc)] +pub fn tmp_env() -> (ConcreteEnv, tempfile::TempDir) { + let tempdir = tempfile::tempdir().unwrap(); + let config = Config::low_power(Some(tempdir.path().into())); + let env = ConcreteEnv::open(config).unwrap(); + + (env, tempdir) +} + +/// Same as [`tmp_env`] but uses all system threads. +#[allow(clippy::missing_panics_doc)] +pub fn tmp_env_all_threads() -> (ConcreteEnv, tempfile::TempDir) { + let tempdir = tempfile::tempdir().unwrap(); + let config = Config::fast(Some(tempdir.path().into())); + let env = ConcreteEnv::open(config).unwrap(); + + (env, tempdir) +} diff --git a/benches/criterion/cuprate-database/src/lib.rs b/benches/criterion/cuprate-database/src/lib.rs new file mode 100644 index 0000000..569aacb --- /dev/null +++ b/benches/criterion/cuprate-database/src/lib.rs @@ -0,0 +1,83 @@ +//! TODO + +//---------------------------------------------------------------------------------------------------- Lints +// Forbid lints. +// Our code, and code generated (e.g macros) cannot overrule these. +#![forbid( + // `unsafe` is allowed but it _must_ be + // commented with `SAFETY: reason`. + clippy::undocumented_unsafe_blocks, + + // Never. + unused_unsafe, + redundant_semicolons, + unused_allocation, + coherence_leak_check, + while_true, + clippy::missing_docs_in_private_items, + + // Maybe can be put into `#[deny]`. + unconditional_recursion, + for_loops_over_fallibles, + unused_braces, + unused_doc_comments, + unused_labels, + keyword_idents, + non_ascii_idents, + variant_size_differences, + single_use_lifetimes, + + // Probably can be put into `#[deny]`. + future_incompatible, + let_underscore, + break_with_label_and_loop, + duplicate_macro_attributes, + exported_private_dependencies, + large_assignments, + overlapping_range_endpoints, + semicolon_in_expressions_from_macros, + noop_method_call, + unreachable_pub, +)] +// Deny lints. +// Some of these are `#[allow]`'ed on a per-case basis. +#![deny( + clippy::all, + clippy::correctness, + clippy::suspicious, + clippy::style, + clippy::complexity, + clippy::perf, + clippy::pedantic, + clippy::nursery, + clippy::cargo, + unused_mut, + missing_docs, + deprecated, + unused_comparisons, + nonstandard_style +)] +#![allow(unreachable_code, unused_variables, dead_code, unused_imports)] // TODO: remove +#![allow( + // FIXME: this lint affects crates outside of + // `database/` for some reason, allow for now. + clippy::cargo_common_metadata, + + // FIXME: adding `#[must_use]` onto everything + // might just be more annoying than useful... + // although it is sometimes nice. + clippy::must_use_candidate, + + // TODO: should be removed after all `todo!()`'s are gone. + clippy::diverging_sub_expression, + + clippy::module_name_repetitions, + clippy::module_inception, + clippy::redundant_pub_crate, + clippy::option_if_let_else, +)] +// Allow some lints when running in debug mode. +#![cfg_attr(debug_assertions, allow(clippy::todo, clippy::multiple_crate_versions))] + +mod helper; +pub use helper::{tmp_env, tmp_env_all_threads}; From da3417f71f5a9f23cc36039ae6acc089cc6acc7f Mon Sep 17 00:00:00 2001 From: "hinto.janai" Date: Mon, 21 Oct 2024 20:11:59 -0400 Subject: [PATCH 2/5] changes --- Cargo.lock | 12 + Cargo.toml | 1 + benches/benchmark/bin/src/main.rs | 10 +- benches/criterion/cuprate-database/Cargo.toml | 28 +- .../criterion/cuprate-database/benches/db.rs | 710 ++++++++++-------- .../benches/db_multi_thread.rs | 584 -------------- .../criterion/cuprate-database/benches/env.rs | 94 +-- .../benches/env_multi_thread.rs | 162 ---- .../cuprate-database/benches/main.rs | 80 +- .../cuprate-database/benches/service.rs | 25 - .../cuprate-database/benches/storable.rs | 36 +- .../cuprate-database/src/constants.rs | 17 + .../criterion/cuprate-database/src/helper.rs | 30 - benches/criterion/cuprate-database/src/lib.rs | 84 +-- .../criterion/cuprate-database/src/tmp_env.rs | 87 +++ 15 files changed, 608 insertions(+), 1352 deletions(-) delete mode 100644 benches/criterion/cuprate-database/benches/db_multi_thread.rs delete mode 100644 benches/criterion/cuprate-database/benches/env_multi_thread.rs delete mode 100644 benches/criterion/cuprate-database/benches/service.rs create mode 100644 benches/criterion/cuprate-database/src/constants.rs delete mode 100644 benches/criterion/cuprate-database/src/helper.rs create mode 100644 benches/criterion/cuprate-database/src/tmp_env.rs diff --git a/Cargo.lock b/Cargo.lock index 655d127..20cb0ed 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -739,6 +739,18 @@ dependencies = [ name = "cuprate-constants" version = "0.1.0" +[[package]] +name = "cuprate-criterion-database" +version = "0.0.0" +dependencies = [ + "criterion", + "cuprate-blockchain", + "cuprate-database", + "cuprate-helper", + "function_name", + "tempfile", +] + [[package]] name = "cuprate-criterion-example" version = "0.0.0" diff --git a/Cargo.toml b/Cargo.toml index d756b08..f09794f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,6 +9,7 @@ members = [ "benches/benchmark/example", "benches/criterion/example", "benches/criterion/cuprate-json-rpc", + "benches/criterion/cuprate-database", # Consensus "consensus", "consensus/fast-sync", diff --git a/benches/benchmark/bin/src/main.rs b/benches/benchmark/bin/src/main.rs index 2e62720..02c480a 100644 --- a/benches/benchmark/bin/src/main.rs +++ b/benches/benchmark/bin/src/main.rs @@ -20,6 +20,13 @@ use cfg_if::cfg_if; /// 1. Copy + paste a `cfg_if` block /// 2. Change it to your benchmark's feature flag /// 3. Change it to your benchmark's type +#[allow( + clippy::allow_attributes, + unused_variables, + unused_mut, + unreachable_code, + reason = "clippy does not account for all cfg()s" +)] fn main() { log::init_logger(); @@ -27,7 +34,8 @@ fn main() { cfg_if! { if #[cfg(not(any(feature = "example")))] { - compile_error!("No feature specified. Use `--features $BENCHMARK_FEATURE` when building."); + println!("No feature specified. Use `--features $BENCHMARK_FEATURE` when building."); + return; } } diff --git a/benches/criterion/cuprate-database/Cargo.toml b/benches/criterion/cuprate-database/Cargo.toml index c37d265..5629771 100644 --- a/benches/criterion/cuprate-database/Cargo.toml +++ b/benches/criterion/cuprate-database/Cargo.toml @@ -1,24 +1,30 @@ [package] -name = "cuprate-database-benchmark" +name = "cuprate-criterion-database" version = "0.0.0" edition = "2021" -description = "Benchmarking for Cuprate's database abstraction" +description = "Criterion benchmarking for cuprate-database" license = "MIT" authors = ["hinto-janai"] -repository = "https://github.com/Cuprate/cuprate/tree/main/database/benchmark" +repository = "https://github.com/Cuprate/cuprate/tree/main/benches/criterion/cuprate-database" keywords = ["cuprate", "database", "benchmark"] [features] -default = [] +default = ["heed"] +heed = ["cuprate-database/heed", "cuprate-blockchain/heed"] +redb = ["cuprate-database/redb", "cuprate-blockchain/redb"] [dependencies] -criterion = { workspace = true } -cuprate-database = { path = "../", features = ["default"] } -cuprate-helper = { path = "../../helper", features = ["fs", "thread"] } -# cuprate-types = { path = "../../types", features = ["service"] } -function_name = { version = "0.3.0" } -tempfile = { version = "3.10.0" } +criterion = { workspace = true } +cuprate-database = { path = "../../../storage/database" } +cuprate-blockchain = { path = "../../../storage/blockchain" } +cuprate-helper = { path = "../../../helper", features = ["fs", "thread"] } + +function_name = { workspace = true } +tempfile = { workspace = true} [[bench]] name = "main" -harness = false \ No newline at end of file +harness = false + +[lints] +workspace = true \ No newline at end of file diff --git a/benches/criterion/cuprate-database/benches/db.rs b/benches/criterion/cuprate-database/benches/db.rs index 686d60a..78a6b58 100644 --- a/benches/criterion/cuprate-database/benches/db.rs +++ b/benches/criterion/cuprate-database/benches/db.rs @@ -1,343 +1,559 @@ -//! `trait Database{Ro,Rw,Iter}` benchmarks. +//! Database operations. +//! +//! This module tests the functions from: +//! - [`cuprate_database::DatabaseRo`] +//! - [`cuprate_database::DatabaseRw`] +//! - [`cuprate_database::DatabaseIter`] +//! +//! There are 2 flavors of (read-only) benchmarks: +//! - Single threaded that uses [`TmpEnv::new`] +//! - Multi threaded that uses [`TmpEnv::new_all_threads`] +//! +//! They benchmark the same thing, just with different +//! amount of threads. This is done as 1 "inner" function +//! that contains the logic and 2 others to setup the [`TmpEnv`] +//! with different amounts of threads, e.g.: +//! - [`ro_get`] (inner benchmark logic) +//! - [`ro_get_single_thread`] (just calls `ro_get` with 1 thread) +//! - [`ro_get_multi_thread`] (just calls `ro_get` with all threads) +//! +//! Writes are single-threaded, so they only use [`TmpEnv::new`]. + +#![expect(clippy::significant_drop_tightening, clippy::needless_pass_by_value)] + +// TODO +use cuprate_helper as _; +use tempfile as _; use std::time::Instant; -//---------------------------------------------------------------------------------------------------- Import use criterion::{black_box, criterion_group, criterion_main, Criterion}; - use function_name::named; -use cuprate_database::{ +use cuprate_blockchain::{ tables::Outputs, types::{Output, PreRctOutputId}, - DatabaseIter, DatabaseRo, DatabaseRw, Env, EnvInner, TxRw, }; +use cuprate_database::{DatabaseIter, DatabaseRo, DatabaseRw, Env, EnvInner}; -use cuprate_database_benchmark::tmp_env; +use cuprate_criterion_database::{TmpEnv, KEY, VALUE}; -//---------------------------------------------------------------------------------------------------- Criterion criterion_group! { benches, - ro_get, - ro_len, - ro_first, - ro_last, - ro_is_empty, - ro_contains, - rw_get, - rw_len, - rw_first, - rw_last, - rw_is_empty, - rw_contains, + + // `DatabaseRo` + ro_get_single_thread, + ro_get_multi_thread, + ro_len_single_thread, + ro_len_multi_thread, + ro_first_single_thread, + ro_first_multi_thread, + ro_last_single_thread, + ro_last_multi_thread, + ro_is_empty_single_thread, + ro_is_empty_multi_thread, + ro_contains_single_thread, + ro_contains_multi_thread, + + // `DatabaseRo` with a `TxRw` + rw_get_single_thread, + rw_get_multi_thread, + rw_len_single_thread, + rw_len_multi_thread, + rw_first_single_thread, + rw_first_multi_thread, + rw_last_single_thread, + rw_last_multi_thread, + rw_is_empty_single_thread, + rw_is_empty_multi_thread, + rw_contains_single_thread, + rw_contains_multi_thread, + + // `DatabaseIter` + get_range_single_thread, + get_range_multi_thread, + iter_single_thread, + iter_multi_thread, + keys_single_thread, + keys_multi_thread, + values_single_thread, + values_multi_thread, + + // `DatabaseRw` put, delete, pop_first, pop_last, - get_range, - iter, - keys, - values, + take, } + criterion_main!(benches); -//---------------------------------------------------------------------------------------------------- Constants -/// The (1st) key. -const KEY: PreRctOutputId = PreRctOutputId { - amount: 1, - amount_index: 123, -}; - -/// The expected value. -const VALUE: Output = Output { - key: [35; 32], - height: 45_761_798, - output_flags: 0, - tx_idx: 2_353_487, -}; - -//---------------------------------------------------------------------------------------------------- DatabaseRo +//---------------------------------------------------------------------------------------------------- DatabaseRo::get // Read-only table operations. // This uses `TxRw + TablesMut` briefly to insert values, then // uses `TxRo + Tables` for the actual operation. // // See further below for using `TxRw + TablesMut` on the same operations. -/// [`DatabaseRo::get`] -#[named] -fn ro_get(c: &mut Criterion) { - let (env, _tempdir) = tmp_env(); - let env_inner = env.env_inner(); - let tx_rw = env_inner.tx_rw().unwrap(); - let mut table = env_inner.open_db_rw::(&tx_rw).unwrap(); - - table.put(&KEY, &VALUE).unwrap(); - drop(table); - tx_rw.commit().unwrap(); - +fn ro_get(env: TmpEnv, name: &'static str, c: &mut Criterion) { + let env_inner = env.env.env_inner(); let tx_ro = env_inner.tx_ro().unwrap(); let table = env_inner.open_db_ro::(&tx_ro).unwrap(); - c.bench_function(function_name!(), |b| { + c.bench_function(name, |b| { b.iter(|| { let _value: Output = table.get(black_box(&KEY)).unwrap(); }); }); } -/// [`DatabaseRo::len`] +/// [`DatabaseRo::get`] (single-thread). #[named] -fn ro_len(c: &mut Criterion) { - let (env, _tempdir) = tmp_env(); - let env_inner = env.env_inner(); - let tx_rw = env_inner.tx_rw().unwrap(); - let mut table = env_inner.open_db_rw::(&tx_rw).unwrap(); +fn ro_get_single_thread(c: &mut Criterion) { + let env = TmpEnv::new().with_key_value(); + ro_get(env, function_name!(), c); +} - table.put(&KEY, &VALUE).unwrap(); - drop(table); - tx_rw.commit().unwrap(); +/// [`DatabaseRo::get`] (multi-thread). +#[named] +fn ro_get_multi_thread(c: &mut Criterion) { + let env = TmpEnv::new_all_threads().with_key_value(); + ro_get(env, function_name!(), c); +} +//---------------------------------------------------------------------------------------------------- DatabaseRo::len +fn ro_len(env: TmpEnv, name: &'static str, c: &mut Criterion) { + let env_inner = env.env.env_inner(); let tx_ro = env_inner.tx_ro().unwrap(); let table = env_inner.open_db_ro::(&tx_ro).unwrap(); - c.bench_function(function_name!(), |b| { + c.bench_function(name, |b| { b.iter(|| { black_box(table.len()).unwrap(); }); }); } -/// [`DatabaseRo::first`] +/// [`DatabaseRo::len`] (single-thread). #[named] -fn ro_first(c: &mut Criterion) { - let (env, _tempdir) = tmp_env(); - let env_inner = env.env_inner(); - let tx_rw = env_inner.tx_rw().unwrap(); - let mut table = env_inner.open_db_rw::(&tx_rw).unwrap(); +fn ro_len_single_thread(c: &mut Criterion) { + let env = TmpEnv::new().with_key_value(); + ro_len(env, function_name!(), c); +} - table.put(&KEY, &VALUE).unwrap(); - drop(table); - tx_rw.commit().unwrap(); +/// [`DatabaseRo::len`] (multi-thread). +#[named] +fn ro_len_multi_thread(c: &mut Criterion) { + let env = TmpEnv::new_all_threads().with_key_value(); + ro_len(env, function_name!(), c); +} +//---------------------------------------------------------------------------------------------------- DatabaseRo::first +fn ro_first(env: TmpEnv, name: &'static str, c: &mut Criterion) { + let env_inner = env.env.env_inner(); let tx_ro = env_inner.tx_ro().unwrap(); let table = env_inner.open_db_ro::(&tx_ro).unwrap(); - c.bench_function(function_name!(), |b| { + c.bench_function(name, |b| { b.iter(|| { let (_, _): (PreRctOutputId, Output) = black_box(table.first()).unwrap(); }); }); } -/// [`DatabaseRo::last`] +/// [`DatabaseRo::first`] (single-thread). #[named] -fn ro_last(c: &mut Criterion) { - let (env, _tempdir) = tmp_env(); - let env_inner = env.env_inner(); - let tx_rw = env_inner.tx_rw().unwrap(); - let mut table = env_inner.open_db_rw::(&tx_rw).unwrap(); +fn ro_first_single_thread(c: &mut Criterion) { + let env = TmpEnv::new().with_key_value(); + ro_first(env, function_name!(), c); +} - table.put(&KEY, &VALUE).unwrap(); - drop(table); - tx_rw.commit().unwrap(); +/// [`DatabaseRo::first`] (multi-thread). +#[named] +fn ro_first_multi_thread(c: &mut Criterion) { + let env = TmpEnv::new_all_threads().with_key_value(); + ro_first(env, function_name!(), c); +} +//---------------------------------------------------------------------------------------------------- DatabaseRo::last +/// [`DatabaseRo::last`] +fn ro_last(env: TmpEnv, name: &'static str, c: &mut Criterion) { + let env_inner = env.env.env_inner(); let tx_ro = env_inner.tx_ro().unwrap(); let table = env_inner.open_db_ro::(&tx_ro).unwrap(); - c.bench_function(function_name!(), |b| { + c.bench_function(name, |b| { b.iter(|| { let (_, _): (PreRctOutputId, Output) = black_box(table.last()).unwrap(); }); }); } -/// [`DatabaseRo::is_empty`] +/// [`DatabaseRo::last`] (single-thread). #[named] -fn ro_is_empty(c: &mut Criterion) { - let (env, _tempdir) = tmp_env(); - let env_inner = env.env_inner(); - let tx_rw = env_inner.tx_rw().unwrap(); - let mut table = env_inner.open_db_rw::(&tx_rw).unwrap(); +fn ro_last_single_thread(c: &mut Criterion) { + let env = TmpEnv::new().with_key_value(); + ro_last(env, function_name!(), c); +} - table.put(&KEY, &VALUE).unwrap(); - drop(table); - tx_rw.commit().unwrap(); +/// [`DatabaseRo::last`] (multi-thread). +#[named] +fn ro_last_multi_thread(c: &mut Criterion) { + let env = TmpEnv::new_all_threads().with_key_value(); + ro_last(env, function_name!(), c); +} +//---------------------------------------------------------------------------------------------------- DatabaseRo::is_empty +/// [`DatabaseRo::is_empty`] +fn ro_is_empty(env: TmpEnv, name: &'static str, c: &mut Criterion) { + let env_inner = env.env.env_inner(); let tx_ro = env_inner.tx_ro().unwrap(); let table = env_inner.open_db_ro::(&tx_ro).unwrap(); - c.bench_function(function_name!(), |b| { + c.bench_function(name, |b| { b.iter(|| { black_box(table.is_empty()).unwrap(); }); }); } -/// [`DatabaseRo::contains`] +/// [`DatabaseRo::is_empty`] (single-thread). #[named] -fn ro_contains(c: &mut Criterion) { - let (env, _tempdir) = tmp_env(); - let env_inner = env.env_inner(); - let tx_rw = env_inner.tx_rw().unwrap(); - let mut table = env_inner.open_db_rw::(&tx_rw).unwrap(); +fn ro_is_empty_single_thread(c: &mut Criterion) { + let env = TmpEnv::new().with_key_value(); + ro_is_empty(env, function_name!(), c); +} - table.put(&KEY, &VALUE).unwrap(); - drop(table); - tx_rw.commit().unwrap(); +/// [`DatabaseRo::is_empty`] (multi-thread). +#[named] +fn ro_is_empty_multi_thread(c: &mut Criterion) { + let env = TmpEnv::new_all_threads().with_key_value(); + ro_is_empty(env, function_name!(), c); +} +//---------------------------------------------------------------------------------------------------- DatabaseRo::contains +/// [`DatabaseRo::contains`] +fn ro_contains(env: TmpEnv, name: &'static str, c: &mut Criterion) { + let env_inner = env.env.env_inner(); let tx_ro = env_inner.tx_ro().unwrap(); let table = env_inner.open_db_ro::(&tx_ro).unwrap(); - c.bench_function(function_name!(), |b| { + c.bench_function(name, |b| { b.iter(|| { table.contains(black_box(&KEY)).unwrap(); }); }); } -//---------------------------------------------------------------------------------------------------- DatabaseRo (using TxRw) +/// [`DatabaseRo::contains`] (single-thread). +#[named] +fn ro_contains_single_thread(c: &mut Criterion) { + let env = TmpEnv::new().with_key_value(); + ro_contains(env, function_name!(), c); +} + +/// [`DatabaseRo::contains`] (multi-thread). +#[named] +fn ro_contains_multi_thread(c: &mut Criterion) { + let env = TmpEnv::new_all_threads().with_key_value(); + ro_contains(env, function_name!(), c); +} + +//---------------------------------------------------------------------------------------------------- DatabaseRw::get // These are the same benchmarks as above, but it uses a // `TxRw` and a `TablesMut` instead to ensure our read/write tables // using read operations perform the same as normal read-only tables. -/// [`DatabaseRo::get`] -#[named] -fn rw_get(c: &mut Criterion) { - let (env, _tempdir) = tmp_env(); - let env_inner = env.env_inner(); - let tx_rw = env_inner.tx_rw().unwrap(); - let mut table = env_inner.open_db_rw::(&tx_rw).unwrap(); - - table.put(&KEY, &VALUE).unwrap(); - drop(table); - tx_rw.commit().unwrap(); - +fn rw_get(env: TmpEnv, name: &'static str, c: &mut Criterion) { + let env_inner = env.env.env_inner(); let tx_rw = env_inner.tx_rw().unwrap(); let table = env_inner.open_db_rw::(&tx_rw).unwrap(); - c.bench_function(function_name!(), |b| { + c.bench_function(name, |b| { b.iter(|| { let _value: Output = table.get(black_box(&KEY)).unwrap(); }); }); } -/// [`DatabaseRo::len`] +/// [`DatabaseRw::get`] (single-thread). #[named] -fn rw_len(c: &mut Criterion) { - let (env, _tempdir) = tmp_env(); - let env_inner = env.env_inner(); - let tx_rw = env_inner.tx_rw().unwrap(); - let mut table = env_inner.open_db_rw::(&tx_rw).unwrap(); +fn rw_get_single_thread(c: &mut Criterion) { + let env = TmpEnv::new().with_key_value(); + rw_get(env, function_name!(), c); +} - table.put(&KEY, &VALUE).unwrap(); - drop(table); - tx_rw.commit().unwrap(); +/// [`DatabaseRw::get`] (multi-thread). +#[named] +fn rw_get_multi_thread(c: &mut Criterion) { + let env = TmpEnv::new_all_threads().with_key_value(); + rw_get(env, function_name!(), c); +} +//---------------------------------------------------------------------------------------------------- DatabaseRw::len +fn rw_len(env: TmpEnv, name: &'static str, c: &mut Criterion) { + let env_inner = env.env.env_inner(); let tx_rw = env_inner.tx_rw().unwrap(); let table = env_inner.open_db_rw::(&tx_rw).unwrap(); - c.bench_function(function_name!(), |b| { + c.bench_function(name, |b| { b.iter(|| { black_box(table.len()).unwrap(); }); }); } -/// [`DatabaseRo::first`] +/// [`DatabaseRw::len`] (single-thread). #[named] -fn rw_first(c: &mut Criterion) { - let (env, _tempdir) = tmp_env(); - let env_inner = env.env_inner(); - let tx_rw = env_inner.tx_rw().unwrap(); - let mut table = env_inner.open_db_rw::(&tx_rw).unwrap(); +fn rw_len_single_thread(c: &mut Criterion) { + let env = TmpEnv::new().with_key_value(); + rw_len(env, function_name!(), c); +} - table.put(&KEY, &VALUE).unwrap(); - drop(table); - tx_rw.commit().unwrap(); +/// [`DatabaseRw::len`] (multi-thread). +#[named] +fn rw_len_multi_thread(c: &mut Criterion) { + let env = TmpEnv::new_all_threads().with_key_value(); + rw_len(env, function_name!(), c); +} +//---------------------------------------------------------------------------------------------------- DatabaseRw::first +fn rw_first(env: TmpEnv, name: &'static str, c: &mut Criterion) { + let env_inner = env.env.env_inner(); let tx_rw = env_inner.tx_rw().unwrap(); let table = env_inner.open_db_rw::(&tx_rw).unwrap(); - c.bench_function(function_name!(), |b| { + c.bench_function(name, |b| { b.iter(|| { let (_, _): (PreRctOutputId, Output) = black_box(table.first()).unwrap(); }); }); } -/// [`DatabaseRo::last`] +/// [`DatabaseRw::first`] (single-thread). #[named] -fn rw_last(c: &mut Criterion) { - let (env, _tempdir) = tmp_env(); - let env_inner = env.env_inner(); - let tx_rw = env_inner.tx_rw().unwrap(); - let mut table = env_inner.open_db_rw::(&tx_rw).unwrap(); +fn rw_first_single_thread(c: &mut Criterion) { + let env = TmpEnv::new().with_key_value(); + rw_first(env, function_name!(), c); +} - table.put(&KEY, &VALUE).unwrap(); - drop(table); - tx_rw.commit().unwrap(); +/// [`DatabaseRw::first`] (multi-thread). +#[named] +fn rw_first_multi_thread(c: &mut Criterion) { + let env = TmpEnv::new_all_threads().with_key_value(); + rw_first(env, function_name!(), c); +} +//---------------------------------------------------------------------------------------------------- DatabaseRw::last +fn rw_last(env: TmpEnv, name: &'static str, c: &mut Criterion) { + let env_inner = env.env.env_inner(); let tx_rw = env_inner.tx_rw().unwrap(); let table = env_inner.open_db_rw::(&tx_rw).unwrap(); - c.bench_function(function_name!(), |b| { + c.bench_function(name, |b| { b.iter(|| { let (_, _): (PreRctOutputId, Output) = black_box(table.last()).unwrap(); }); }); } -/// [`DatabaseRo::is_empty`] +/// [`DatabaseRw::last`] (single-thread). #[named] -fn rw_is_empty(c: &mut Criterion) { - let (env, _tempdir) = tmp_env(); - let env_inner = env.env_inner(); - let tx_rw = env_inner.tx_rw().unwrap(); - let mut table = env_inner.open_db_rw::(&tx_rw).unwrap(); +fn rw_last_single_thread(c: &mut Criterion) { + let env = TmpEnv::new().with_key_value(); + rw_last(env, function_name!(), c); +} - table.put(&KEY, &VALUE).unwrap(); - drop(table); - tx_rw.commit().unwrap(); +/// [`DatabaseRw::last`] (multi-thread). +#[named] +fn rw_last_multi_thread(c: &mut Criterion) { + let env = TmpEnv::new_all_threads().with_key_value(); + rw_last(env, function_name!(), c); +} +//---------------------------------------------------------------------------------------------------- DatabaseRw::is_empty +fn rw_is_empty(env: TmpEnv, name: &'static str, c: &mut Criterion) { + let env_inner = env.env.env_inner(); let tx_rw = env_inner.tx_rw().unwrap(); let table = env_inner.open_db_rw::(&tx_rw).unwrap(); - c.bench_function(function_name!(), |b| { + c.bench_function(name, |b| { b.iter(|| { black_box(table.is_empty()).unwrap(); }); }); } -/// [`DatabaseRo::contains`] +/// [`DatabaseRw::is_empty`] (single-thread). #[named] -fn rw_contains(c: &mut Criterion) { - let (env, _tempdir) = tmp_env(); - let env_inner = env.env_inner(); - let tx_rw = env_inner.tx_rw().unwrap(); - let mut table = env_inner.open_db_rw::(&tx_rw).unwrap(); +fn rw_is_empty_single_thread(c: &mut Criterion) { + let env = TmpEnv::new().with_key_value(); + rw_is_empty(env, function_name!(), c); +} - table.put(&KEY, &VALUE).unwrap(); - drop(table); - tx_rw.commit().unwrap(); +/// [`DatabaseRw::is_empty`] (multi-thread). +#[named] +fn rw_is_empty_multi_thread(c: &mut Criterion) { + let env = TmpEnv::new_all_threads().with_key_value(); + rw_is_empty(env, function_name!(), c); +} +//---------------------------------------------------------------------------------------------------- DatabaseRw::contains +fn rw_contains(env: TmpEnv, name: &'static str, c: &mut Criterion) { + let env_inner = env.env.env_inner(); let tx_rw = env_inner.tx_rw().unwrap(); let table = env_inner.open_db_rw::(&tx_rw).unwrap(); - c.bench_function(function_name!(), |b| { + c.bench_function(name, |b| { b.iter(|| { table.contains(black_box(&KEY)).unwrap(); }); }); } -//---------------------------------------------------------------------------------------------------- DatabaseRw +/// [`DatabaseRw::contains`] (single-thread). +#[named] +fn rw_contains_single_thread(c: &mut Criterion) { + let env = TmpEnv::new().with_key_value(); + rw_contains(env, function_name!(), c); +} + +/// [`DatabaseRw::contains`] (multi-thread). +#[named] +fn rw_contains_multi_thread(c: &mut Criterion) { + let env = TmpEnv::new_all_threads().with_key_value(); + rw_contains(env, function_name!(), c); +} + +//---------------------------------------------------------------------------------------------------- DatabaseIter::get_range +fn get_range(env: TmpEnv, name: &'static str, c: &mut Criterion) { + let env_inner = env.env.env_inner(); + let tx_ro = env_inner.tx_ro().unwrap(); + let table = env_inner.open_db_ro::(&tx_ro).unwrap(); + + c.bench_function(name, |b| { + b.iter(|| { + let range = table.get_range(black_box(..)).unwrap(); + for result in range { + let _: Output = black_box(result.unwrap()); + } + }); + }); +} + +/// [`DatabaseIter::get_range`] (single-thread). +#[named] +fn get_range_single_thread(c: &mut Criterion) { + let env = TmpEnv::new().with_key_value_100(); + get_range(env, function_name!(), c); +} + +/// [`DatabaseIter::get_range`] (multi-thread). +#[named] +fn get_range_multi_thread(c: &mut Criterion) { + let env = TmpEnv::new_all_threads().with_key_value_100(); + get_range(env, function_name!(), c); +} + +//---------------------------------------------------------------------------------------------------- DatabaseIter::iter +fn iter(env: TmpEnv, name: &'static str, c: &mut Criterion) { + let env_inner = env.env.env_inner(); + let tx_ro = env_inner.tx_ro().unwrap(); + let table = env_inner.open_db_ro::(&tx_ro).unwrap(); + + c.bench_function(name, |b| { + b.iter(|| { + let iter = black_box(table.iter()).unwrap(); + for result in iter { + let _: (PreRctOutputId, Output) = black_box(result.unwrap()); + } + }); + }); +} + +/// [`DatabaseIter::iter`] (single-thread). +#[named] +fn iter_single_thread(c: &mut Criterion) { + let env = TmpEnv::new().with_key_value_100(); + iter(env, function_name!(), c); +} + +/// [`DatabaseIter::iter`] (multi-thread). +#[named] +fn iter_multi_thread(c: &mut Criterion) { + let env = TmpEnv::new_all_threads().with_key_value_100(); + iter(env, function_name!(), c); +} + +//---------------------------------------------------------------------------------------------------- DatabaseIter::keys +/// [`DatabaseRo::keys`] +fn keys(env: TmpEnv, name: &'static str, c: &mut Criterion) { + let env_inner = env.env.env_inner(); + let tx_ro = env_inner.tx_ro().unwrap(); + let table = env_inner.open_db_ro::(&tx_ro).unwrap(); + + c.bench_function(name, |b| { + b.iter(|| { + let keys = black_box(table.keys()).unwrap(); + for result in keys { + let _: PreRctOutputId = black_box(result.unwrap()); + } + }); + }); +} + +/// [`DatabaseIter::keys`] (single-thread). +#[named] +fn keys_single_thread(c: &mut Criterion) { + let env = TmpEnv::new().with_key_value_100(); + keys(env, function_name!(), c); +} + +/// [`DatabaseIter::iter`] (multi-thread). +#[named] +fn keys_multi_thread(c: &mut Criterion) { + let env = TmpEnv::new_all_threads().with_key_value_100(); + keys(env, function_name!(), c); +} + +//---------------------------------------------------------------------------------------------------- DatabaseIter::values +/// [`DatabaseRo::values`] +fn values(env: TmpEnv, name: &'static str, c: &mut Criterion) { + let env_inner = env.env.env_inner(); + let tx_ro = env_inner.tx_ro().unwrap(); + let table = env_inner.open_db_ro::(&tx_ro).unwrap(); + + c.bench_function(name, |b| { + b.iter(|| { + let values = black_box(table.values()).unwrap(); + for result in values { + let _: Output = black_box(result.unwrap()); + } + }); + }); +} + +/// [`DatabaseIter::values`] (single-thread). +#[named] +fn values_single_thread(c: &mut Criterion) { + let env = TmpEnv::new().with_key_value_100(); + values(env, function_name!(), c); +} + +/// [`DatabaseIter::iter`] (multi-thread). +#[named] +fn values_multi_thread(c: &mut Criterion) { + let env = TmpEnv::new_all_threads().with_key_value_100(); + values(env, function_name!(), c); +} + +//---------------------------------------------------------------------------------------------------- DatabaseRw::put /// [`DatabaseRw::put`] #[named] fn put(c: &mut Criterion) { - let (env, _tempdir) = tmp_env(); - let env_inner = env.env_inner(); + let env = TmpEnv::new(); + let env_inner = env.env.env_inner(); let tx_rw = env_inner.tx_rw().unwrap(); let mut table = env_inner.open_db_rw::(&tx_rw).unwrap(); @@ -351,11 +567,12 @@ fn put(c: &mut Criterion) { }); } +//---------------------------------------------------------------------------------------------------- DatabaseRw::delete /// [`DatabaseRw::delete`] #[named] fn delete(c: &mut Criterion) { - let (env, _tempdir) = tmp_env(); - let env_inner = env.env_inner(); + let env = TmpEnv::new(); + let env_inner = env.env.env_inner(); let tx_rw = env_inner.tx_rw().unwrap(); let mut table = env_inner.open_db_rw::(&tx_rw).unwrap(); @@ -380,11 +597,12 @@ fn delete(c: &mut Criterion) { }); } +//---------------------------------------------------------------------------------------------------- DatabaseRw::pop_first /// [`DatabaseRw::pop_first`] #[named] fn pop_first(c: &mut Criterion) { - let (env, _tempdir) = tmp_env(); - let env_inner = env.env_inner(); + let env = TmpEnv::new(); + let env_inner = env.env.env_inner(); let tx_rw = env_inner.tx_rw().unwrap(); let mut table = env_inner.open_db_rw::(&tx_rw).unwrap(); @@ -409,11 +627,12 @@ fn pop_first(c: &mut Criterion) { }); } +//---------------------------------------------------------------------------------------------------- DatabaseRw::pop_last /// [`DatabaseRw::pop_last`] #[named] fn pop_last(c: &mut Criterion) { - let (env, _tempdir) = tmp_env(); - let env_inner = env.env_inner(); + let env = TmpEnv::new(); + let env_inner = env.env.env_inner(); let tx_rw = env_inner.tx_rw().unwrap(); let mut table = env_inner.open_db_rw::(&tx_rw).unwrap(); @@ -438,146 +657,19 @@ fn pop_last(c: &mut Criterion) { }); } -// TODO: waiting on PR 102 -// /// [`DatabaseRw::take`] -// #[named] -// fn take(c: &mut Criterion) { -// let (env, _tempdir) = tmp_env(); -// let env_inner = env.env_inner(); -// let tx_rw = env_inner.tx_rw().unwrap(); -// let mut table = env_inner.open_db_rw::(&tx_rw).unwrap(); - -// let mut key = KEY; -// for _ in 0..100 { -// table.put(&key, &VALUE).unwrap(); -// key.amount += 1; -// } - -// c.bench_function(function_name!(), |b| { -// b.iter(|| { -// table.put(&KEY, &VALUE).unwrap(); -// let value: Output = black_box(table.take(&black_box(KEY)).unwrap()); -// }); -// }); -// } - -//---------------------------------------------------------------------------------------------------- DatabaseIter -/// [`DatabaseRo::get_range`] +//---------------------------------------------------------------------------------------------------- DatabaseRw::take +/// [`DatabaseRw::take`] #[named] -fn get_range(c: &mut Criterion) { - let (env, _tempdir) = tmp_env(); - let env_inner = env.env_inner(); +fn take(c: &mut Criterion) { + let env = TmpEnv::new_all_threads(); + let env_inner = env.env.env_inner(); let tx_rw = env_inner.tx_rw().unwrap(); let mut table = env_inner.open_db_rw::(&tx_rw).unwrap(); - let mut key = KEY; - for _ in 0..100 { - table.put(&key, &VALUE).unwrap(); - key.amount += 1; - } - - drop(table); - TxRw::commit(tx_rw).unwrap(); - - let tx_ro = env_inner.tx_ro().unwrap(); - let table = env_inner.open_db_ro::(&tx_ro).unwrap(); - c.bench_function(function_name!(), |b| { b.iter(|| { - let range = table.get_range(black_box(..)).unwrap(); - for result in range { - let _value: Output = black_box(result.unwrap()); - } - }); - }); -} - -/// [`DatabaseRo::iter`] -#[named] -fn iter(c: &mut Criterion) { - let (env, _tempdir) = tmp_env(); - let env_inner = env.env_inner(); - let tx_rw = env_inner.tx_rw().unwrap(); - let mut table = env_inner.open_db_rw::(&tx_rw).unwrap(); - - let mut key = KEY; - for _ in 0..100 { - table.put(&key, &VALUE).unwrap(); - key.amount += 1; - } - - drop(table); - TxRw::commit(tx_rw).unwrap(); - - let tx_ro = env_inner.tx_ro().unwrap(); - let table = env_inner.open_db_ro::(&tx_ro).unwrap(); - - c.bench_function(function_name!(), |b| { - b.iter(|| { - let iter = black_box(table.iter()).unwrap(); - for result in iter { - let _: (PreRctOutputId, Output) = black_box(result.unwrap()); - } - }); - }); -} - -/// [`DatabaseRo::keys`] -#[named] -fn keys(c: &mut Criterion) { - let (env, _tempdir) = tmp_env(); - let env_inner = env.env_inner(); - let tx_rw = env_inner.tx_rw().unwrap(); - let mut table = env_inner.open_db_rw::(&tx_rw).unwrap(); - - let mut key = KEY; - for _ in 0..100 { - table.put(&key, &VALUE).unwrap(); - key.amount += 1; - } - - drop(table); - TxRw::commit(tx_rw).unwrap(); - - let tx_ro = env_inner.tx_ro().unwrap(); - let table = env_inner.open_db_ro::(&tx_ro).unwrap(); - - c.bench_function(function_name!(), |b| { - b.iter(|| { - let keys = black_box(table.keys()).unwrap(); - for result in keys { - let _: PreRctOutputId = black_box(result.unwrap()); - } - }); - }); -} - -/// [`DatabaseRo::values`] -#[named] -fn values(c: &mut Criterion) { - let (env, _tempdir) = tmp_env(); - let env_inner = env.env_inner(); - let tx_rw = env_inner.tx_rw().unwrap(); - let mut table = env_inner.open_db_rw::(&tx_rw).unwrap(); - - let mut key = KEY; - for _ in 0..100 { - table.put(&key, &VALUE).unwrap(); - key.amount += 1; - } - - drop(table); - TxRw::commit(tx_rw).unwrap(); - - let tx_ro = env_inner.tx_ro().unwrap(); - let table = env_inner.open_db_ro::(&tx_ro).unwrap(); - - c.bench_function(function_name!(), |b| { - b.iter(|| { - let values = black_box(table.values()).unwrap(); - for result in values { - let _: Output = black_box(result.unwrap()); - } + table.put(&KEY, &VALUE).unwrap(); + let _: Output = black_box(table.take(&black_box(KEY)).unwrap()); }); }); } diff --git a/benches/criterion/cuprate-database/benches/db_multi_thread.rs b/benches/criterion/cuprate-database/benches/db_multi_thread.rs deleted file mode 100644 index 8089929..0000000 --- a/benches/criterion/cuprate-database/benches/db_multi_thread.rs +++ /dev/null @@ -1,584 +0,0 @@ -//! Same as `db.rs` but multi-threaded. -//! TODO: create multi-threaded benchmarks - -use std::time::Instant; - -//---------------------------------------------------------------------------------------------------- Import -use criterion::{black_box, criterion_group, criterion_main, Criterion}; - -use function_name::named; - -use cuprate_database::{ - tables::Outputs, - types::{Output, PreRctOutputId}, - DatabaseIter, DatabaseRo, DatabaseRw, Env, EnvInner, TxRw, -}; - -use cuprate_database_benchmark::tmp_env_all_threads; - -//---------------------------------------------------------------------------------------------------- Criterion -criterion_group! { - benches, - ro_get, - ro_len, - ro_first, - ro_last, - ro_is_empty, - ro_contains, - rw_get, - rw_len, - rw_first, - rw_last, - rw_is_empty, - rw_contains, - put, - delete, - pop_first, - pop_last, - get_range, - iter, - keys, - values, -} -criterion_main!(benches); - -//---------------------------------------------------------------------------------------------------- Constants -/// The (1st) key. -const KEY: PreRctOutputId = PreRctOutputId { - amount: 1, - amount_index: 123, -}; - -/// The expected value. -const VALUE: Output = Output { - key: [35; 32], - height: 45_761_798, - output_flags: 0, - tx_idx: 2_353_487, -}; - -//---------------------------------------------------------------------------------------------------- DatabaseRo -// Read-only table operations. -// This uses `TxRw + TablesMut` briefly to insert values, then -// uses `TxRo + Tables` for the actual operation. -// -// See further below for using `TxRw + TablesMut` on the same operations. - -/// [`DatabaseRo::get`] -#[named] -fn ro_get(c: &mut Criterion) { - let (env, _tempdir) = tmp_env_all_threads(); - let env_inner = env.env_inner(); - let tx_rw = env_inner.tx_rw().unwrap(); - let mut table = env_inner.open_db_rw::(&tx_rw).unwrap(); - - table.put(&KEY, &VALUE).unwrap(); - drop(table); - tx_rw.commit().unwrap(); - - let tx_ro = env_inner.tx_ro().unwrap(); - let table = env_inner.open_db_ro::(&tx_ro).unwrap(); - - c.bench_function(function_name!(), |b| { - b.iter(|| { - let _value: Output = table.get(black_box(&KEY)).unwrap(); - }); - }); -} - -/// [`DatabaseRo::len`] -#[named] -fn ro_len(c: &mut Criterion) { - let (env, _tempdir) = tmp_env_all_threads(); - let env_inner = env.env_inner(); - let tx_rw = env_inner.tx_rw().unwrap(); - let mut table = env_inner.open_db_rw::(&tx_rw).unwrap(); - - table.put(&KEY, &VALUE).unwrap(); - drop(table); - tx_rw.commit().unwrap(); - - let tx_ro = env_inner.tx_ro().unwrap(); - let table = env_inner.open_db_ro::(&tx_ro).unwrap(); - - c.bench_function(function_name!(), |b| { - b.iter(|| { - black_box(table.len()).unwrap(); - }); - }); -} - -/// [`DatabaseRo::first`] -#[named] -fn ro_first(c: &mut Criterion) { - let (env, _tempdir) = tmp_env_all_threads(); - let env_inner = env.env_inner(); - let tx_rw = env_inner.tx_rw().unwrap(); - let mut table = env_inner.open_db_rw::(&tx_rw).unwrap(); - - table.put(&KEY, &VALUE).unwrap(); - drop(table); - tx_rw.commit().unwrap(); - - let tx_ro = env_inner.tx_ro().unwrap(); - let table = env_inner.open_db_ro::(&tx_ro).unwrap(); - - c.bench_function(function_name!(), |b| { - b.iter(|| { - let (_, _): (PreRctOutputId, Output) = black_box(table.first()).unwrap(); - }); - }); -} - -/// [`DatabaseRo::last`] -#[named] -fn ro_last(c: &mut Criterion) { - let (env, _tempdir) = tmp_env_all_threads(); - let env_inner = env.env_inner(); - let tx_rw = env_inner.tx_rw().unwrap(); - let mut table = env_inner.open_db_rw::(&tx_rw).unwrap(); - - table.put(&KEY, &VALUE).unwrap(); - drop(table); - tx_rw.commit().unwrap(); - - let tx_ro = env_inner.tx_ro().unwrap(); - let table = env_inner.open_db_ro::(&tx_ro).unwrap(); - - c.bench_function(function_name!(), |b| { - b.iter(|| { - let (_, _): (PreRctOutputId, Output) = black_box(table.last()).unwrap(); - }); - }); -} - -/// [`DatabaseRo::is_empty`] -#[named] -fn ro_is_empty(c: &mut Criterion) { - let (env, _tempdir) = tmp_env_all_threads(); - let env_inner = env.env_inner(); - let tx_rw = env_inner.tx_rw().unwrap(); - let mut table = env_inner.open_db_rw::(&tx_rw).unwrap(); - - table.put(&KEY, &VALUE).unwrap(); - drop(table); - tx_rw.commit().unwrap(); - - let tx_ro = env_inner.tx_ro().unwrap(); - let table = env_inner.open_db_ro::(&tx_ro).unwrap(); - - c.bench_function(function_name!(), |b| { - b.iter(|| { - black_box(table.is_empty()).unwrap(); - }); - }); -} - -/// [`DatabaseRo::contains`] -#[named] -fn ro_contains(c: &mut Criterion) { - let (env, _tempdir) = tmp_env_all_threads(); - let env_inner = env.env_inner(); - let tx_rw = env_inner.tx_rw().unwrap(); - let mut table = env_inner.open_db_rw::(&tx_rw).unwrap(); - - table.put(&KEY, &VALUE).unwrap(); - drop(table); - tx_rw.commit().unwrap(); - - let tx_ro = env_inner.tx_ro().unwrap(); - let table = env_inner.open_db_ro::(&tx_ro).unwrap(); - - c.bench_function(function_name!(), |b| { - b.iter(|| { - table.contains(black_box(&KEY)).unwrap(); - }); - }); -} - -//---------------------------------------------------------------------------------------------------- DatabaseRo (using TxRw) -// These are the same benchmarks as above, but it uses a -// `TxRw` and a `TablesMut` instead to ensure our read/write tables -// using read operations perform the same as normal read-only tables. - -/// [`DatabaseRo::get`] -#[named] -fn rw_get(c: &mut Criterion) { - let (env, _tempdir) = tmp_env_all_threads(); - let env_inner = env.env_inner(); - let tx_rw = env_inner.tx_rw().unwrap(); - let mut table = env_inner.open_db_rw::(&tx_rw).unwrap(); - - table.put(&KEY, &VALUE).unwrap(); - drop(table); - tx_rw.commit().unwrap(); - - let tx_rw = env_inner.tx_rw().unwrap(); - let table = env_inner.open_db_rw::(&tx_rw).unwrap(); - - c.bench_function(function_name!(), |b| { - b.iter(|| { - let _value: Output = table.get(black_box(&KEY)).unwrap(); - }); - }); -} - -/// [`DatabaseRo::len`] -#[named] -fn rw_len(c: &mut Criterion) { - let (env, _tempdir) = tmp_env_all_threads(); - let env_inner = env.env_inner(); - let tx_rw = env_inner.tx_rw().unwrap(); - let mut table = env_inner.open_db_rw::(&tx_rw).unwrap(); - - table.put(&KEY, &VALUE).unwrap(); - drop(table); - tx_rw.commit().unwrap(); - - let tx_rw = env_inner.tx_rw().unwrap(); - let table = env_inner.open_db_rw::(&tx_rw).unwrap(); - - c.bench_function(function_name!(), |b| { - b.iter(|| { - black_box(table.len()).unwrap(); - }); - }); -} - -/// [`DatabaseRo::first`] -#[named] -fn rw_first(c: &mut Criterion) { - let (env, _tempdir) = tmp_env_all_threads(); - let env_inner = env.env_inner(); - let tx_rw = env_inner.tx_rw().unwrap(); - let mut table = env_inner.open_db_rw::(&tx_rw).unwrap(); - - table.put(&KEY, &VALUE).unwrap(); - drop(table); - tx_rw.commit().unwrap(); - - let tx_rw = env_inner.tx_rw().unwrap(); - let table = env_inner.open_db_rw::(&tx_rw).unwrap(); - - c.bench_function(function_name!(), |b| { - b.iter(|| { - let (_, _): (PreRctOutputId, Output) = black_box(table.first()).unwrap(); - }); - }); -} - -/// [`DatabaseRo::last`] -#[named] -fn rw_last(c: &mut Criterion) { - let (env, _tempdir) = tmp_env_all_threads(); - let env_inner = env.env_inner(); - let tx_rw = env_inner.tx_rw().unwrap(); - let mut table = env_inner.open_db_rw::(&tx_rw).unwrap(); - - table.put(&KEY, &VALUE).unwrap(); - drop(table); - tx_rw.commit().unwrap(); - - let tx_rw = env_inner.tx_rw().unwrap(); - let table = env_inner.open_db_rw::(&tx_rw).unwrap(); - - c.bench_function(function_name!(), |b| { - b.iter(|| { - let (_, _): (PreRctOutputId, Output) = black_box(table.last()).unwrap(); - }); - }); -} - -/// [`DatabaseRo::is_empty`] -#[named] -fn rw_is_empty(c: &mut Criterion) { - let (env, _tempdir) = tmp_env_all_threads(); - let env_inner = env.env_inner(); - let tx_rw = env_inner.tx_rw().unwrap(); - let mut table = env_inner.open_db_rw::(&tx_rw).unwrap(); - - table.put(&KEY, &VALUE).unwrap(); - drop(table); - tx_rw.commit().unwrap(); - - let tx_rw = env_inner.tx_rw().unwrap(); - let table = env_inner.open_db_rw::(&tx_rw).unwrap(); - - c.bench_function(function_name!(), |b| { - b.iter(|| { - black_box(table.is_empty()).unwrap(); - }); - }); -} - -/// [`DatabaseRo::contains`] -#[named] -fn rw_contains(c: &mut Criterion) { - let (env, _tempdir) = tmp_env_all_threads(); - let env_inner = env.env_inner(); - let tx_rw = env_inner.tx_rw().unwrap(); - let mut table = env_inner.open_db_rw::(&tx_rw).unwrap(); - - table.put(&KEY, &VALUE).unwrap(); - drop(table); - tx_rw.commit().unwrap(); - - let tx_rw = env_inner.tx_rw().unwrap(); - let table = env_inner.open_db_rw::(&tx_rw).unwrap(); - - c.bench_function(function_name!(), |b| { - b.iter(|| { - table.contains(black_box(&KEY)).unwrap(); - }); - }); -} - -//---------------------------------------------------------------------------------------------------- DatabaseRw -/// [`DatabaseRw::put`] -#[named] -fn put(c: &mut Criterion) { - let (env, _tempdir) = tmp_env_all_threads(); - let env_inner = env.env_inner(); - let tx_rw = env_inner.tx_rw().unwrap(); - let mut table = env_inner.open_db_rw::(&tx_rw).unwrap(); - - let mut key = KEY; - - c.bench_function(function_name!(), |b| { - b.iter(|| { - table.put(black_box(&key), black_box(&VALUE)).unwrap(); - key.amount += 1; - }); - }); -} - -/// [`DatabaseRw::delete`] -#[named] -fn delete(c: &mut Criterion) { - let (env, _tempdir) = tmp_env_all_threads(); - let env_inner = env.env_inner(); - let tx_rw = env_inner.tx_rw().unwrap(); - let mut table = env_inner.open_db_rw::(&tx_rw).unwrap(); - - let mut key = KEY; - - c.bench_function(function_name!(), |b| { - b.iter_custom(|iters| { - for _ in 0..iters { - table.put(&key, &VALUE).unwrap(); - key.amount += 1; - } - - key = KEY; - - let start = Instant::now(); - for _ in 0..iters { - table.delete(&key).unwrap(); - key.amount += 1; - } - start.elapsed() - }); - }); -} - -/// [`DatabaseRw::pop_first`] -#[named] -fn pop_first(c: &mut Criterion) { - let (env, _tempdir) = tmp_env_all_threads(); - let env_inner = env.env_inner(); - let tx_rw = env_inner.tx_rw().unwrap(); - let mut table = env_inner.open_db_rw::(&tx_rw).unwrap(); - - let mut key = KEY; - - c.bench_function(function_name!(), |b| { - b.iter_custom(|iters| { - for _ in 0..iters { - table.put(&key, &VALUE).unwrap(); - key.amount += 1; - } - - key = KEY; - - let start = Instant::now(); - for _ in 0..iters { - table.pop_first().unwrap(); - key.amount += 1; - } - start.elapsed() - }); - }); -} - -/// [`DatabaseRw::pop_last`] -#[named] -fn pop_last(c: &mut Criterion) { - let (env, _tempdir) = tmp_env_all_threads(); - let env_inner = env.env_inner(); - let tx_rw = env_inner.tx_rw().unwrap(); - let mut table = env_inner.open_db_rw::(&tx_rw).unwrap(); - - let mut key = KEY; - - c.bench_function(function_name!(), |b| { - b.iter_custom(|iters| { - for _ in 0..iters { - table.put(&key, &VALUE).unwrap(); - key.amount += 1; - } - - key = KEY; - - let start = Instant::now(); - for _ in 0..iters { - table.pop_last().unwrap(); - key.amount += 1; - } - start.elapsed() - }); - }); -} - -// TODO: waiting on PR 102 -// /// [`DatabaseRw::take`] -// #[named] -// fn take(c: &mut Criterion) { -// let (env, _tempdir) = tmp_env_all_threads(); -// let env_inner = env.env_inner(); -// let tx_rw = env_inner.tx_rw().unwrap(); -// let mut table = env_inner.open_db_rw::(&tx_rw).unwrap(); - -// let mut key = KEY; -// for _ in 0..100 { -// table.put(&key, &VALUE).unwrap(); -// key.amount += 1; -// } - -// c.bench_function(function_name!(), |b| { -// b.iter(|| { -// table.put(&KEY, &VALUE).unwrap(); -// let value: Output = black_box(table.take(&black_box(KEY)).unwrap()); -// }); -// }); -// } - -//---------------------------------------------------------------------------------------------------- DatabaseIter -/// [`DatabaseRo::get_range`] -#[named] -fn get_range(c: &mut Criterion) { - let (env, _tempdir) = tmp_env_all_threads(); - let env_inner = env.env_inner(); - let tx_rw = env_inner.tx_rw().unwrap(); - let mut table = env_inner.open_db_rw::(&tx_rw).unwrap(); - - let mut key = KEY; - for _ in 0..100 { - table.put(&key, &VALUE).unwrap(); - key.amount += 1; - } - - drop(table); - TxRw::commit(tx_rw).unwrap(); - - let tx_ro = env_inner.tx_ro().unwrap(); - let table = env_inner.open_db_ro::(&tx_ro).unwrap(); - - c.bench_function(function_name!(), |b| { - b.iter(|| { - let range = table.get_range(black_box(..)).unwrap(); - for result in range { - let _value: Output = black_box(result.unwrap()); - } - }); - }); -} - -/// [`DatabaseRo::iter`] -#[named] -fn iter(c: &mut Criterion) { - let (env, _tempdir) = tmp_env_all_threads(); - let env_inner = env.env_inner(); - let tx_rw = env_inner.tx_rw().unwrap(); - let mut table = env_inner.open_db_rw::(&tx_rw).unwrap(); - - let mut key = KEY; - for _ in 0..100 { - table.put(&key, &VALUE).unwrap(); - key.amount += 1; - } - - drop(table); - TxRw::commit(tx_rw).unwrap(); - - let tx_ro = env_inner.tx_ro().unwrap(); - let table = env_inner.open_db_ro::(&tx_ro).unwrap(); - - c.bench_function(function_name!(), |b| { - b.iter(|| { - let iter = black_box(table.iter()).unwrap(); - for result in iter { - let _: (PreRctOutputId, Output) = black_box(result.unwrap()); - } - }); - }); -} - -/// [`DatabaseRo::keys`] -#[named] -fn keys(c: &mut Criterion) { - let (env, _tempdir) = tmp_env_all_threads(); - let env_inner = env.env_inner(); - let tx_rw = env_inner.tx_rw().unwrap(); - let mut table = env_inner.open_db_rw::(&tx_rw).unwrap(); - - let mut key = KEY; - for _ in 0..100 { - table.put(&key, &VALUE).unwrap(); - key.amount += 1; - } - - drop(table); - TxRw::commit(tx_rw).unwrap(); - - let tx_ro = env_inner.tx_ro().unwrap(); - let table = env_inner.open_db_ro::(&tx_ro).unwrap(); - - c.bench_function(function_name!(), |b| { - b.iter(|| { - let keys = black_box(table.keys()).unwrap(); - for result in keys { - let _: PreRctOutputId = black_box(result.unwrap()); - } - }); - }); -} - -/// [`DatabaseRo::values`] -#[named] -fn values(c: &mut Criterion) { - let (env, _tempdir) = tmp_env_all_threads(); - let env_inner = env.env_inner(); - let tx_rw = env_inner.tx_rw().unwrap(); - let mut table = env_inner.open_db_rw::(&tx_rw).unwrap(); - - let mut key = KEY; - for _ in 0..100 { - table.put(&key, &VALUE).unwrap(); - key.amount += 1; - } - - drop(table); - TxRw::commit(tx_rw).unwrap(); - - let tx_ro = env_inner.tx_ro().unwrap(); - let table = env_inner.open_db_ro::(&tx_ro).unwrap(); - - c.bench_function(function_name!(), |b| { - b.iter(|| { - let values = black_box(table.values()).unwrap(); - for result in values { - let _: Output = black_box(result.unwrap()); - } - }); - }); -} diff --git a/benches/criterion/cuprate-database/benches/env.rs b/benches/criterion/cuprate-database/benches/env.rs index 4c0f6d4..cc7ffae 100644 --- a/benches/criterion/cuprate-database/benches/env.rs +++ b/benches/criterion/cuprate-database/benches/env.rs @@ -1,40 +1,45 @@ -//! `trait {Env, EnvInner, TxR{o,w}, Tables[Mut]}` benchmarks. +//! Same as `env.rs` but multi-threaded. +//! TODO: create multi-threaded benchmarks + +#![expect(clippy::significant_drop_tightening)] + +// TODO +use cuprate_helper as _; +use tempfile as _; -//---------------------------------------------------------------------------------------------------- Import use criterion::{black_box, criterion_group, criterion_main, Criterion}; - use function_name::named; +use cuprate_blockchain::tables::{OpenTables, Outputs}; use cuprate_database::{ - config::Config, - resize::{page_size, ResizeAlgorithm}, - tables::Outputs, + config::ConfigBuilder, + resize::{ResizeAlgorithm, PAGE_SIZE}, ConcreteEnv, Env, EnvInner, TxRo, TxRw, }; -use cuprate_database_benchmark::tmp_env; +use cuprate_criterion_database::TmpEnv; -//---------------------------------------------------------------------------------------------------- Criterion criterion_group! { benches, open, env_inner, tx_ro, tx_rw, - open_tables, - open_tables_mut, + open_db_ro, + open_db_rw, resize, current_map_size, disk_size_bytes, } criterion_main!(benches); -//---------------------------------------------------------------------------------------------------- Env benchmarks /// [`Env::open`]. #[named] fn open(c: &mut Criterion) { let tempdir = tempfile::tempdir().unwrap(); - let config = Config::low_power(Some(tempdir.path().into())); + let config = ConfigBuilder::new(tempdir.path().to_path_buf().into()) + .low_power() + .build(); c.bench_function(function_name!(), |b| { b.iter_with_large_drop(|| { @@ -46,20 +51,20 @@ fn open(c: &mut Criterion) { /// [`Env::env_inner`]. #[named] fn env_inner(c: &mut Criterion) { - let (env, _tempdir) = tmp_env(); + let env = TmpEnv::new(); c.bench_function(function_name!(), |b| { b.iter(|| { - black_box(env.env_inner()); + drop(black_box(env.env.env_inner())); }); }); } -/// Create and commit read-only transactions. +/// [`EnvInner::tx_ro`]. #[named] fn tx_ro(c: &mut Criterion) { - let (env, _tempdir) = tmp_env(); - let env_inner = env.env_inner(); + let env = TmpEnv::new(); + let env_inner = env.env.env_inner(); c.bench_function(function_name!(), |b| { b.iter(|| { @@ -69,11 +74,11 @@ fn tx_ro(c: &mut Criterion) { }); } -/// Create and commit read/write transactions. +/// [`EnvInner::tx_rw`]. #[named] fn tx_rw(c: &mut Criterion) { - let (env, _tempdir) = tmp_env(); - let env_inner = env.env_inner(); + let env = TmpEnv::new(); + let env_inner = env.env.env_inner(); c.bench_function(function_name!(), |b| { b.iter(|| { @@ -83,79 +88,78 @@ fn tx_rw(c: &mut Criterion) { }); } -/// Open all database tables in read-only mode. +/// [`EnvInner::open_db_ro`]. #[named] -fn open_tables(c: &mut Criterion) { - let (env, _tempdir) = tmp_env(); - let env_inner = env.env_inner(); +fn open_db_ro(c: &mut Criterion) { + // `with_key_value()` creates the `Outputs` + // table so the `open_db_ro` below doesn't panic. + let env = TmpEnv::new().with_key_value(); + let env_inner = env.env.env_inner(); let tx_ro = env_inner.tx_ro().unwrap(); c.bench_function(function_name!(), |b| { b.iter(|| { - black_box(env_inner.open_db_ro::(&tx_ro)).unwrap(); - // env_inner.open_tables(&tx_ro).unwrap(); - // TODO: waiting on PR 102 + env_inner.open_db_ro::(&tx_ro).unwrap(); }); }); } -/// Open all database tables in read/write mode. +/// [`EnvInner::open_db_rw`]. #[named] -fn open_tables_mut(c: &mut Criterion) { - let (env, _tempdir) = tmp_env(); - let env_inner = env.env_inner(); +fn open_db_rw(c: &mut Criterion) { + let env = TmpEnv::new(); + let env_inner = env.env.env_inner(); let tx_rw = env_inner.tx_rw().unwrap(); c.bench_function(function_name!(), |b| { b.iter(|| { - black_box(env_inner.open_db_rw::(&tx_rw)).unwrap(); - // env_inner.open_tables_mut(&mut tx_rw).unwrap(); - // TODO: waiting on PR 102 + env_inner.open_db_rw::(&tx_rw).unwrap(); + env_inner.open_tables_mut(&tx_rw).unwrap(); }); }); } -/// `Env` memory map resizes. +/// [`Env::resize`]. #[named] fn resize(c: &mut Criterion) { - let (env, _tempdir) = tmp_env(); + let env = TmpEnv::new(); - // Resize by the OS page size. - let page_size = page_size(); + // Resize env.by the OS page size. + let resize = Some(ResizeAlgorithm::FixedBytes(*PAGE_SIZE)); c.bench_function(function_name!(), |b| { b.iter(|| { // This test is only valid for `Env`'s that need to resize manually. if ConcreteEnv::MANUAL_RESIZE { - env.resize_map(black_box(Some(ResizeAlgorithm::FixedBytes(page_size)))); + env.env.resize_map(resize); } }); }); } -/// Access current memory map size of the database. +/// [`Env::current_map_size`]. #[named] fn current_map_size(c: &mut Criterion) { - let (env, _tempdir) = tmp_env(); + let env = TmpEnv::new(); c.bench_function(function_name!(), |b| { b.iter(|| { // This test is only valid for `Env`'s that need to resize manually. if ConcreteEnv::MANUAL_RESIZE { - black_box(env.current_map_size()); + black_box(env.env.current_map_size()); } }); }); } -/// Access on-disk size of the database. +/// [`Env::disk_size_bytes`]. #[named] fn disk_size_bytes(c: &mut Criterion) { - let (env, _tempdir) = tmp_env(); + let env = TmpEnv::new(); c.bench_function(function_name!(), |b| { b.iter(|| { - black_box(env.disk_size_bytes()).unwrap(); + black_box(env.env.disk_size_bytes()).unwrap(); }); }); } diff --git a/benches/criterion/cuprate-database/benches/env_multi_thread.rs b/benches/criterion/cuprate-database/benches/env_multi_thread.rs deleted file mode 100644 index ec796c8..0000000 --- a/benches/criterion/cuprate-database/benches/env_multi_thread.rs +++ /dev/null @@ -1,162 +0,0 @@ -//! Same as `env.rs` but multi-threaded. -//! TODO: create multi-threaded benchmarks - -//---------------------------------------------------------------------------------------------------- Import -use criterion::{black_box, criterion_group, criterion_main, Criterion}; - -use function_name::named; - -use cuprate_database::{ - config::Config, - resize::{page_size, ResizeAlgorithm}, - tables::Outputs, - ConcreteEnv, Env, EnvInner, TxRo, TxRw, -}; - -use cuprate_database_benchmark::tmp_env_all_threads; - -//---------------------------------------------------------------------------------------------------- Criterion -criterion_group! { - benches, - open, - env_inner, - tx_ro, - tx_rw, - open_tables, - open_tables_mut, - resize, - current_map_size, - disk_size_bytes, -} -criterion_main!(benches); - -//---------------------------------------------------------------------------------------------------- Env benchmarks -/// [`Env::open`]. -#[named] -fn open(c: &mut Criterion) { - let tempdir = tempfile::tempdir().unwrap(); - let config = Config::low_power(Some(tempdir.path().into())); - - c.bench_function(function_name!(), |b| { - b.iter_with_large_drop(|| { - ConcreteEnv::open(config.clone()).unwrap(); - }); - }); -} - -/// [`Env::env_inner`]. -#[named] -fn env_inner(c: &mut Criterion) { - let (env, _tempdir) = tmp_env_all_threads(); - - c.bench_function(function_name!(), |b| { - b.iter(|| { - black_box(env.env_inner()); - }); - }); -} - -/// Create and commit read-only transactions. -#[named] -fn tx_ro(c: &mut Criterion) { - let (env, _tempdir) = tmp_env_all_threads(); - let env_inner = env.env_inner(); - - c.bench_function(function_name!(), |b| { - b.iter(|| { - let tx_ro = black_box(env_inner.tx_ro()).unwrap(); - TxRo::commit(black_box(tx_ro)).unwrap(); - }); - }); -} - -/// Create and commit read/write transactions. -#[named] -fn tx_rw(c: &mut Criterion) { - let (env, _tempdir) = tmp_env_all_threads(); - let env_inner = env.env_inner(); - - c.bench_function(function_name!(), |b| { - b.iter(|| { - let tx_rw = black_box(env_inner.tx_rw()).unwrap(); - TxRw::commit(black_box(tx_rw)).unwrap(); - }); - }); -} - -/// Open all database tables in read-only mode. -#[named] -fn open_tables(c: &mut Criterion) { - let (env, _tempdir) = tmp_env_all_threads(); - let env_inner = env.env_inner(); - let tx_ro = env_inner.tx_ro().unwrap(); - - c.bench_function(function_name!(), |b| { - b.iter(|| { - black_box(env_inner.open_db_ro::(&tx_ro)).unwrap(); - // env_inner.open_tables(&tx_ro).unwrap(); - // TODO: waiting on PR 102 - }); - }); -} - -/// Open all database tables in read/write mode. -#[named] -fn open_tables_mut(c: &mut Criterion) { - let (env, _tempdir) = tmp_env_all_threads(); - let env_inner = env.env_inner(); - let tx_rw = env_inner.tx_rw().unwrap(); - - c.bench_function(function_name!(), |b| { - b.iter(|| { - black_box(env_inner.open_db_rw::(&tx_rw)).unwrap(); - // env_inner.open_tables_mut(&mut tx_rw).unwrap(); - // TODO: waiting on PR 102 - }); - }); -} - -/// `Env` memory map resizes. -#[named] -fn resize(c: &mut Criterion) { - let (env, _tempdir) = tmp_env_all_threads(); - - // Resize by the OS page size. - let page_size = page_size(); - - c.bench_function(function_name!(), |b| { - b.iter(|| { - // This test is only valid for `Env`'s that need to resize manually. - if ConcreteEnv::MANUAL_RESIZE { - env.resize_map(black_box(Some(ResizeAlgorithm::FixedBytes(page_size)))); - } - }); - }); -} - -/// Access current memory map size of the database. -#[named] -fn current_map_size(c: &mut Criterion) { - let (env, _tempdir) = tmp_env_all_threads(); - - c.bench_function(function_name!(), |b| { - b.iter(|| { - // This test is only valid for `Env`'s that need to resize manually. - if ConcreteEnv::MANUAL_RESIZE { - black_box(env.current_map_size()); - } - }); - }); -} - -/// Access on-disk size of the database. -#[named] -fn disk_size_bytes(c: &mut Criterion) { - let (env, _tempdir) = tmp_env_all_threads(); - - c.bench_function(function_name!(), |b| { - b.iter(|| { - black_box(env.disk_size_bytes()).unwrap(); - }); - }); -} diff --git a/benches/criterion/cuprate-database/benches/main.rs b/benches/criterion/cuprate-database/benches/main.rs index 74865f2..cd9f360 100644 --- a/benches/criterion/cuprate-database/benches/main.rs +++ b/benches/criterion/cuprate-database/benches/main.rs @@ -1,84 +1,6 @@ //! TODO -//---------------------------------------------------------------------------------------------------- Lints -// Forbid lints. -// Our code, and code generated (e.g macros) cannot overrule these. -#![forbid( - // `unsafe` is allowed but it _must_ be - // commented with `SAFETY: reason`. - clippy::undocumented_unsafe_blocks, - - // Never. - unused_unsafe, - redundant_semicolons, - unused_allocation, - coherence_leak_check, - while_true, - clippy::missing_docs_in_private_items, - - // Maybe can be put into `#[deny]`. - unconditional_recursion, - for_loops_over_fallibles, - unused_braces, - unused_doc_comments, - unused_labels, - keyword_idents, - non_ascii_idents, - variant_size_differences, - single_use_lifetimes, - - // Probably can be put into `#[deny]`. - future_incompatible, - let_underscore, - break_with_label_and_loop, - duplicate_macro_attributes, - exported_private_dependencies, - large_assignments, - overlapping_range_endpoints, - semicolon_in_expressions_from_macros, - noop_method_call, - unreachable_pub, -)] -// Deny lints. -// Some of these are `#[allow]`'ed on a per-case basis. -#![deny( - clippy::all, - clippy::correctness, - clippy::suspicious, - clippy::style, - clippy::complexity, - clippy::perf, - clippy::pedantic, - clippy::nursery, - clippy::cargo, - unused_mut, - missing_docs, - deprecated, - unused_comparisons, - nonstandard_style -)] -#![allow(unreachable_code, unused_variables, dead_code, unused_imports)] // TODO: remove -#![allow( - // FIXME: this lint affects crates outside of - // `database/` for some reason, allow for now. - clippy::cargo_common_metadata, - - // FIXME: adding `#[must_use]` onto everything - // might just be more annoying than useful... - // although it is sometimes nice. - clippy::must_use_candidate, - - // TODO: should be removed after all `todo!()`'s are gone. - clippy::diverging_sub_expression, - - clippy::module_name_repetitions, - clippy::module_inception, - clippy::redundant_pub_crate, - clippy::option_if_let_else, - clippy::significant_drop_tightening, -)] -// Allow some lints when running in debug mode. -#![cfg_attr(debug_assertions, allow(clippy::todo, clippy::multiple_crate_versions))] +#![expect(unused_crate_dependencies)] mod db; mod env; diff --git a/benches/criterion/cuprate-database/benches/service.rs b/benches/criterion/cuprate-database/benches/service.rs deleted file mode 100644 index 9c4a74f..0000000 --- a/benches/criterion/cuprate-database/benches/service.rs +++ /dev/null @@ -1,25 +0,0 @@ -//! `cuprate_database::service` benchmarks. - -//---------------------------------------------------------------------------------------------------- Import -use criterion::{black_box, criterion_group, criterion_main, Criterion}; - -use function_name::named; - -use cuprate_database::{ - config::Config, - resize::{page_size, ResizeAlgorithm}, - tables::Outputs, - ConcreteEnv, Env, EnvInner, TxRo, TxRw, -}; - -use cuprate_database_benchmark::tmp_env_all_threads; - -//---------------------------------------------------------------------------------------------------- Criterion -criterion_group! { - benches, -} -criterion_main!(benches); - -//---------------------------------------------------------------------------------------------------- Benchmarks - -// TODO diff --git a/benches/criterion/cuprate-database/benches/storable.rs b/benches/criterion/cuprate-database/benches/storable.rs index b427e26..9962b3e 100644 --- a/benches/criterion/cuprate-database/benches/storable.rs +++ b/benches/criterion/cuprate-database/benches/storable.rs @@ -1,16 +1,14 @@ -//! `trait Storable` benchmarks. +//! [`Storable`] benchmarks. -//---------------------------------------------------------------------------------------------------- Import use criterion::{black_box, criterion_group, criterion_main, Criterion}; use function_name::named; -use cuprate_database::{ - types::{Output, PreRctOutputId}, - Storable, -}; +use cuprate_blockchain::types::{Output, PreRctOutputId}; +use cuprate_database::Storable; + +use cuprate_criterion_database::{KEY, VALUE}; -//---------------------------------------------------------------------------------------------------- Criterion criterion_group! { benches, pre_rct_output_id_as_bytes, @@ -20,28 +18,12 @@ criterion_group! { } criterion_main!(benches); -//---------------------------------------------------------------------------------------------------- Constants -/// 16 bytes. -const PRE_RCT_OUTPUT_ID: PreRctOutputId = PreRctOutputId { - amount: 1, - amount_index: 123, -}; - -/// 48 bytes. -const OUTPUT: Output = Output { - key: [35; 32], - height: 45_761_798, - output_flags: 0, - tx_idx: 2_353_487, -}; - -//---------------------------------------------------------------------------------------------------- Storable benchmarks /// [`PreRctOutputId`] cast as bytes. #[named] fn pre_rct_output_id_as_bytes(c: &mut Criterion) { c.bench_function(function_name!(), |b| { b.iter(|| { - black_box(Storable::as_bytes(black_box(&PRE_RCT_OUTPUT_ID))); + black_box(Storable::as_bytes(black_box(&KEY))); }); }); } @@ -49,7 +31,7 @@ fn pre_rct_output_id_as_bytes(c: &mut Criterion) { /// [`PreRctOutputId`] cast from bytes. #[named] fn pre_rct_output_id_from_bytes(c: &mut Criterion) { - let bytes = Storable::as_bytes(&PRE_RCT_OUTPUT_ID); + let bytes = Storable::as_bytes(&KEY); c.bench_function(function_name!(), |b| { b.iter(|| { @@ -63,7 +45,7 @@ fn pre_rct_output_id_from_bytes(c: &mut Criterion) { fn output_as_bytes(c: &mut Criterion) { c.bench_function(function_name!(), |b| { b.iter(|| { - black_box(Storable::as_bytes(black_box(&OUTPUT))); + black_box(Storable::as_bytes(black_box(&VALUE))); }); }); } @@ -71,7 +53,7 @@ fn output_as_bytes(c: &mut Criterion) { /// [`Output`] cast from bytes. #[named] fn output_from_bytes(c: &mut Criterion) { - let bytes = Storable::as_bytes(&OUTPUT); + let bytes = Storable::as_bytes(&VALUE); c.bench_function(function_name!(), |b| { b.iter(|| { diff --git a/benches/criterion/cuprate-database/src/constants.rs b/benches/criterion/cuprate-database/src/constants.rs new file mode 100644 index 0000000..bcb1919 --- /dev/null +++ b/benches/criterion/cuprate-database/src/constants.rs @@ -0,0 +1,17 @@ +//! General constants. + +use cuprate_blockchain::types::{Output, OutputFlags, PreRctOutputId}; + +/// The (1st) key. +pub const KEY: PreRctOutputId = PreRctOutputId { + amount: 1, + amount_index: 123, +}; + +/// The expected value. +pub const VALUE: Output = Output { + key: [35; 32], + height: 45_761_798, + output_flags: OutputFlags::empty(), + tx_idx: 2_353_487, +}; diff --git a/benches/criterion/cuprate-database/src/helper.rs b/benches/criterion/cuprate-database/src/helper.rs deleted file mode 100644 index ecf2fd1..0000000 --- a/benches/criterion/cuprate-database/src/helper.rs +++ /dev/null @@ -1,30 +0,0 @@ -//! TODO - -// TODO: set-up env based on config - -//---------------------------------------------------------------------------------------------------- Import -use cuprate_database::{config::Config, ConcreteEnv, Env}; - -//---------------------------------------------------------------------------------------------------- Tests -/// Create an `Env` in a temporarily directory. -/// The directory is automatically removed after the `TempDir` is dropped. -/// -/// TODO: changing this to `-> impl Env` causes lifetime errors... -#[allow(clippy::missing_panics_doc)] -pub fn tmp_env() -> (ConcreteEnv, tempfile::TempDir) { - let tempdir = tempfile::tempdir().unwrap(); - let config = Config::low_power(Some(tempdir.path().into())); - let env = ConcreteEnv::open(config).unwrap(); - - (env, tempdir) -} - -/// Same as [`tmp_env`] but uses all system threads. -#[allow(clippy::missing_panics_doc)] -pub fn tmp_env_all_threads() -> (ConcreteEnv, tempfile::TempDir) { - let tempdir = tempfile::tempdir().unwrap(); - let config = Config::fast(Some(tempdir.path().into())); - let env = ConcreteEnv::open(config).unwrap(); - - (env, tempdir) -} diff --git a/benches/criterion/cuprate-database/src/lib.rs b/benches/criterion/cuprate-database/src/lib.rs index 569aacb..8f75f4e 100644 --- a/benches/criterion/cuprate-database/src/lib.rs +++ b/benches/criterion/cuprate-database/src/lib.rs @@ -1,83 +1,9 @@ //! TODO -//---------------------------------------------------------------------------------------------------- Lints -// Forbid lints. -// Our code, and code generated (e.g macros) cannot overrule these. -#![forbid( - // `unsafe` is allowed but it _must_ be - // commented with `SAFETY: reason`. - clippy::undocumented_unsafe_blocks, +#![allow(unused_crate_dependencies, reason = "used in benchmarks")] - // Never. - unused_unsafe, - redundant_semicolons, - unused_allocation, - coherence_leak_check, - while_true, - clippy::missing_docs_in_private_items, +mod constants; +mod tmp_env; - // Maybe can be put into `#[deny]`. - unconditional_recursion, - for_loops_over_fallibles, - unused_braces, - unused_doc_comments, - unused_labels, - keyword_idents, - non_ascii_idents, - variant_size_differences, - single_use_lifetimes, - - // Probably can be put into `#[deny]`. - future_incompatible, - let_underscore, - break_with_label_and_loop, - duplicate_macro_attributes, - exported_private_dependencies, - large_assignments, - overlapping_range_endpoints, - semicolon_in_expressions_from_macros, - noop_method_call, - unreachable_pub, -)] -// Deny lints. -// Some of these are `#[allow]`'ed on a per-case basis. -#![deny( - clippy::all, - clippy::correctness, - clippy::suspicious, - clippy::style, - clippy::complexity, - clippy::perf, - clippy::pedantic, - clippy::nursery, - clippy::cargo, - unused_mut, - missing_docs, - deprecated, - unused_comparisons, - nonstandard_style -)] -#![allow(unreachable_code, unused_variables, dead_code, unused_imports)] // TODO: remove -#![allow( - // FIXME: this lint affects crates outside of - // `database/` for some reason, allow for now. - clippy::cargo_common_metadata, - - // FIXME: adding `#[must_use]` onto everything - // might just be more annoying than useful... - // although it is sometimes nice. - clippy::must_use_candidate, - - // TODO: should be removed after all `todo!()`'s are gone. - clippy::diverging_sub_expression, - - clippy::module_name_repetitions, - clippy::module_inception, - clippy::redundant_pub_crate, - clippy::option_if_let_else, -)] -// Allow some lints when running in debug mode. -#![cfg_attr(debug_assertions, allow(clippy::todo, clippy::multiple_crate_versions))] - -mod helper; -pub use helper::{tmp_env, tmp_env_all_threads}; +pub use constants::{KEY, VALUE}; +pub use tmp_env::TmpEnv; diff --git a/benches/criterion/cuprate-database/src/tmp_env.rs b/benches/criterion/cuprate-database/src/tmp_env.rs new file mode 100644 index 0000000..d5d263e --- /dev/null +++ b/benches/criterion/cuprate-database/src/tmp_env.rs @@ -0,0 +1,87 @@ +//! An [`Env`] inside a [`TempDir`]. + +use tempfile::TempDir; + +use cuprate_blockchain::tables::Outputs; +use cuprate_database::{config::ConfigBuilder, ConcreteEnv, DatabaseRw, Env, EnvInner, TxRw}; + +use crate::constants::{KEY, VALUE}; + +/// A temporary in-memory [`Env`]. +/// +/// This is a [`ConcreteEnv`] that uses [`TempDir`] as the +/// backing file location - this is an in-memory file on Linux. +pub struct TmpEnv { + pub env: ConcreteEnv, + pub tempdir: TempDir, +} + +impl Default for TmpEnv { + fn default() -> Self { + Self::new() + } +} + +impl TmpEnv { + /// Create an `Env` in a temporary directory. + /// + /// The directory is automatically removed after the [`TempDir`] is dropped. + #[expect(clippy::missing_panics_doc)] + pub fn new() -> Self { + let tempdir = tempfile::tempdir().unwrap(); + let path = tempdir.path().to_path_buf().into(); + let config = ConfigBuilder::new(path).low_power().build(); + let env = ConcreteEnv::open(config).unwrap(); + + Self { env, tempdir } + } + + /// Same as [`Self::new`] but uses all system threads for the [`Env`]. + #[expect(clippy::missing_panics_doc)] + pub fn new_all_threads() -> Self { + let tempdir = tempfile::tempdir().unwrap(); + let path = tempdir.path().to_path_buf().into(); + let config = ConfigBuilder::new(path).fast().build(); + let env = ConcreteEnv::open(config).unwrap(); + + Self { env, tempdir } + } + + /// Inserts [`KEY`] and [`VALUE`] inside the [`Outputs`] table. + #[must_use] + pub fn with_key_value(self) -> Self { + let env_inner = self.env.env_inner(); + let tx_rw = env_inner.tx_rw().unwrap(); + let mut table = env_inner.open_db_rw::(&tx_rw).unwrap(); + + table.put(&KEY, &VALUE).unwrap(); + drop(table); + tx_rw.commit().unwrap(); + + drop(env_inner); + self + } + + /// Inserts [`VALUE`] inside the [`Outputs`] table 100 times. + /// + /// The key is an incrementing [`KEY`], i.e. the keys are + /// `KEY + {0..99}`, each one has [`VALUE`] as the value. + #[must_use] + pub fn with_key_value_100(self) -> Self { + let env_inner = self.env.env_inner(); + let tx_rw = env_inner.tx_rw().unwrap(); + let mut table = env_inner.open_db_rw::(&tx_rw).unwrap(); + + let mut key = KEY; + for _ in 0..100 { + table.put(&key, &VALUE).unwrap(); + key.amount += 1; + } + + drop(table); + tx_rw.commit().unwrap(); + + drop(env_inner); + self + } +} From 0aa5f77c5e30cdb7ffe5265af17c6085f5627cf4 Mon Sep 17 00:00:00 2001 From: "hinto.janai" Date: Tue, 22 Oct 2024 17:08:06 -0400 Subject: [PATCH 3/5] fix cargo --- Cargo.lock | 1 + benches/criterion/cuprate-database/Cargo.toml | 17 ++++++++++++++--- .../criterion/cuprate-database/benches/db.rs | 1 + .../criterion/cuprate-database/benches/env.rs | 1 + .../cuprate-database/benches/storable.rs | 2 ++ 5 files changed, 19 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 20cb0ed..a371015 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -748,6 +748,7 @@ dependencies = [ "cuprate-database", "cuprate-helper", "function_name", + "rand", "tempfile", ] diff --git a/benches/criterion/cuprate-database/Cargo.toml b/benches/criterion/cuprate-database/Cargo.toml index 5629771..345448b 100644 --- a/benches/criterion/cuprate-database/Cargo.toml +++ b/benches/criterion/cuprate-database/Cargo.toml @@ -14,13 +14,24 @@ heed = ["cuprate-database/heed", "cuprate-blockchain/heed"] redb = ["cuprate-database/redb", "cuprate-blockchain/redb"] [dependencies] +# FIXME: +# Some crates/features that are unused here but +# needed in other crates are pulled in, see: +# - +# +# Remove: +# - rand +# - cuprate-blockchain/asynch +# - cuprate-blockchain/tx + criterion = { workspace = true } cuprate-database = { path = "../../../storage/database" } -cuprate-blockchain = { path = "../../../storage/blockchain" } -cuprate-helper = { path = "../../../helper", features = ["fs", "thread"] } +cuprate-blockchain = { path = "../../../storage/blockchain", features = ["service"] } +cuprate-helper = { path = "../../../helper", features = ["asynch", "fs", "thread", "tx"] } function_name = { workspace = true } -tempfile = { workspace = true} +tempfile = { workspace = true } +rand = { workspace = true, features = ["std", "std_rng"] } [[bench]] name = "main" diff --git a/benches/criterion/cuprate-database/benches/db.rs b/benches/criterion/cuprate-database/benches/db.rs index 78a6b58..45934ff 100644 --- a/benches/criterion/cuprate-database/benches/db.rs +++ b/benches/criterion/cuprate-database/benches/db.rs @@ -19,6 +19,7 @@ //! //! Writes are single-threaded, so they only use [`TmpEnv::new`]. +#![allow(unused_crate_dependencies, unused_attributes)] #![expect(clippy::significant_drop_tightening, clippy::needless_pass_by_value)] // TODO diff --git a/benches/criterion/cuprate-database/benches/env.rs b/benches/criterion/cuprate-database/benches/env.rs index cc7ffae..75b8793 100644 --- a/benches/criterion/cuprate-database/benches/env.rs +++ b/benches/criterion/cuprate-database/benches/env.rs @@ -1,6 +1,7 @@ //! Same as `env.rs` but multi-threaded. //! TODO: create multi-threaded benchmarks +#![allow(unused_crate_dependencies, unused_attributes)] #![expect(clippy::significant_drop_tightening)] // TODO diff --git a/benches/criterion/cuprate-database/benches/storable.rs b/benches/criterion/cuprate-database/benches/storable.rs index 9962b3e..60d3263 100644 --- a/benches/criterion/cuprate-database/benches/storable.rs +++ b/benches/criterion/cuprate-database/benches/storable.rs @@ -1,5 +1,7 @@ //! [`Storable`] benchmarks. +#![allow(unused_crate_dependencies, unused_attributes)] + use criterion::{black_box, criterion_group, criterion_main, Criterion}; use function_name::named; From 8ae208b9f08e95ff48244b132c58d63230a8ef3a Mon Sep 17 00:00:00 2001 From: "hinto.janai" Date: Tue, 22 Oct 2024 20:36:14 -0400 Subject: [PATCH 4/5] fix benches --- .../criterion/cuprate-database/benches/db.rs | 398 ++++-------------- .../criterion/cuprate-database/benches/env.rs | 67 +-- .../cuprate-database/benches/main.rs | 2 - .../cuprate-database/benches/storable.rs | 5 +- benches/criterion/cuprate-database/src/lib.rs | 2 - .../criterion/cuprate-database/src/tmp_env.rs | 23 +- 6 files changed, 140 insertions(+), 357 deletions(-) diff --git a/benches/criterion/cuprate-database/benches/db.rs b/benches/criterion/cuprate-database/benches/db.rs index 45934ff..e0d4945 100644 --- a/benches/criterion/cuprate-database/benches/db.rs +++ b/benches/criterion/cuprate-database/benches/db.rs @@ -4,27 +4,9 @@ //! - [`cuprate_database::DatabaseRo`] //! - [`cuprate_database::DatabaseRw`] //! - [`cuprate_database::DatabaseIter`] -//! -//! There are 2 flavors of (read-only) benchmarks: -//! - Single threaded that uses [`TmpEnv::new`] -//! - Multi threaded that uses [`TmpEnv::new_all_threads`] -//! -//! They benchmark the same thing, just with different -//! amount of threads. This is done as 1 "inner" function -//! that contains the logic and 2 others to setup the [`TmpEnv`] -//! with different amounts of threads, e.g.: -//! - [`ro_get`] (inner benchmark logic) -//! - [`ro_get_single_thread`] (just calls `ro_get` with 1 thread) -//! - [`ro_get_multi_thread`] (just calls `ro_get` with all threads) -//! -//! Writes are single-threaded, so they only use [`TmpEnv::new`]. #![allow(unused_crate_dependencies, unused_attributes)] -#![expect(clippy::significant_drop_tightening, clippy::needless_pass_by_value)] - -// TODO -use cuprate_helper as _; -use tempfile as _; +#![expect(clippy::significant_drop_tightening)] use std::time::Instant; @@ -40,45 +22,30 @@ use cuprate_database::{DatabaseIter, DatabaseRo, DatabaseRw, Env, EnvInner}; use cuprate_criterion_database::{TmpEnv, KEY, VALUE}; criterion_group! { - benches, - + name = benches; + config = Criterion::default(); + targets = // `DatabaseRo` - ro_get_single_thread, - ro_get_multi_thread, - ro_len_single_thread, - ro_len_multi_thread, - ro_first_single_thread, - ro_first_multi_thread, - ro_last_single_thread, - ro_last_multi_thread, - ro_is_empty_single_thread, - ro_is_empty_multi_thread, - ro_contains_single_thread, - ro_contains_multi_thread, + ro_get, + ro_len, + ro_first, + ro_last, + ro_is_empty, + ro_contains, // `DatabaseRo` with a `TxRw` - rw_get_single_thread, - rw_get_multi_thread, - rw_len_single_thread, - rw_len_multi_thread, - rw_first_single_thread, - rw_first_multi_thread, - rw_last_single_thread, - rw_last_multi_thread, - rw_is_empty_single_thread, - rw_is_empty_multi_thread, - rw_contains_single_thread, - rw_contains_multi_thread, + rw_get, + rw_len, + rw_first, + rw_last, + rw_is_empty, + rw_contains, // `DatabaseIter` - get_range_single_thread, - get_range_multi_thread, - iter_single_thread, - iter_multi_thread, - keys_single_thread, - keys_multi_thread, - values_single_thread, - values_multi_thread, + get_range, + iter, + keys, + values, // `DatabaseRw` put, @@ -87,353 +54,210 @@ criterion_group! { pop_last, take, } - criterion_main!(benches); -//---------------------------------------------------------------------------------------------------- DatabaseRo::get +//---------------------------------------------------------------------------------------------------- DatabaseRo // Read-only table operations. // This uses `TxRw + TablesMut` briefly to insert values, then // uses `TxRo + Tables` for the actual operation. // // See further below for using `TxRw + TablesMut` on the same operations. -fn ro_get(env: TmpEnv, name: &'static str, c: &mut Criterion) { +/// [`DatabaseRo::get`] +#[named] +fn ro_get(c: &mut Criterion) { + let env = TmpEnv::new().with_key_value(); let env_inner = env.env.env_inner(); let tx_ro = env_inner.tx_ro().unwrap(); let table = env_inner.open_db_ro::(&tx_ro).unwrap(); - c.bench_function(name, |b| { + c.bench_function(function_name!(), |b| { b.iter(|| { - let _value: Output = table.get(black_box(&KEY)).unwrap(); + let _: Output = table.get(black_box(&KEY)).unwrap(); }); }); } -/// [`DatabaseRo::get`] (single-thread). +/// [`DatabaseRo::len`] #[named] -fn ro_get_single_thread(c: &mut Criterion) { +fn ro_len(c: &mut Criterion) { let env = TmpEnv::new().with_key_value(); - ro_get(env, function_name!(), c); -} - -/// [`DatabaseRo::get`] (multi-thread). -#[named] -fn ro_get_multi_thread(c: &mut Criterion) { - let env = TmpEnv::new_all_threads().with_key_value(); - ro_get(env, function_name!(), c); -} - -//---------------------------------------------------------------------------------------------------- DatabaseRo::len -fn ro_len(env: TmpEnv, name: &'static str, c: &mut Criterion) { let env_inner = env.env.env_inner(); let tx_ro = env_inner.tx_ro().unwrap(); let table = env_inner.open_db_ro::(&tx_ro).unwrap(); - c.bench_function(name, |b| { + c.bench_function(function_name!(), |b| { b.iter(|| { black_box(table.len()).unwrap(); }); }); } -/// [`DatabaseRo::len`] (single-thread). +/// [`DatabaseRo::first`] #[named] -fn ro_len_single_thread(c: &mut Criterion) { +fn ro_first(c: &mut Criterion) { let env = TmpEnv::new().with_key_value(); - ro_len(env, function_name!(), c); -} - -/// [`DatabaseRo::len`] (multi-thread). -#[named] -fn ro_len_multi_thread(c: &mut Criterion) { - let env = TmpEnv::new_all_threads().with_key_value(); - ro_len(env, function_name!(), c); -} - -//---------------------------------------------------------------------------------------------------- DatabaseRo::first -fn ro_first(env: TmpEnv, name: &'static str, c: &mut Criterion) { let env_inner = env.env.env_inner(); let tx_ro = env_inner.tx_ro().unwrap(); let table = env_inner.open_db_ro::(&tx_ro).unwrap(); - c.bench_function(name, |b| { + c.bench_function(function_name!(), |b| { b.iter(|| { let (_, _): (PreRctOutputId, Output) = black_box(table.first()).unwrap(); }); }); } -/// [`DatabaseRo::first`] (single-thread). -#[named] -fn ro_first_single_thread(c: &mut Criterion) { - let env = TmpEnv::new().with_key_value(); - ro_first(env, function_name!(), c); -} - -/// [`DatabaseRo::first`] (multi-thread). -#[named] -fn ro_first_multi_thread(c: &mut Criterion) { - let env = TmpEnv::new_all_threads().with_key_value(); - ro_first(env, function_name!(), c); -} - -//---------------------------------------------------------------------------------------------------- DatabaseRo::last /// [`DatabaseRo::last`] -fn ro_last(env: TmpEnv, name: &'static str, c: &mut Criterion) { +#[named] +fn ro_last(c: &mut Criterion) { + let env = TmpEnv::new().with_key_value(); let env_inner = env.env.env_inner(); let tx_ro = env_inner.tx_ro().unwrap(); let table = env_inner.open_db_ro::(&tx_ro).unwrap(); - c.bench_function(name, |b| { + c.bench_function(function_name!(), |b| { b.iter(|| { let (_, _): (PreRctOutputId, Output) = black_box(table.last()).unwrap(); }); }); } -/// [`DatabaseRo::last`] (single-thread). -#[named] -fn ro_last_single_thread(c: &mut Criterion) { - let env = TmpEnv::new().with_key_value(); - ro_last(env, function_name!(), c); -} - -/// [`DatabaseRo::last`] (multi-thread). -#[named] -fn ro_last_multi_thread(c: &mut Criterion) { - let env = TmpEnv::new_all_threads().with_key_value(); - ro_last(env, function_name!(), c); -} - -//---------------------------------------------------------------------------------------------------- DatabaseRo::is_empty /// [`DatabaseRo::is_empty`] -fn ro_is_empty(env: TmpEnv, name: &'static str, c: &mut Criterion) { +#[named] +fn ro_is_empty(c: &mut Criterion) { + let env = TmpEnv::new().with_key_value(); let env_inner = env.env.env_inner(); let tx_ro = env_inner.tx_ro().unwrap(); let table = env_inner.open_db_ro::(&tx_ro).unwrap(); - c.bench_function(name, |b| { + c.bench_function(function_name!(), |b| { b.iter(|| { black_box(table.is_empty()).unwrap(); }); }); } -/// [`DatabaseRo::is_empty`] (single-thread). -#[named] -fn ro_is_empty_single_thread(c: &mut Criterion) { - let env = TmpEnv::new().with_key_value(); - ro_is_empty(env, function_name!(), c); -} - -/// [`DatabaseRo::is_empty`] (multi-thread). -#[named] -fn ro_is_empty_multi_thread(c: &mut Criterion) { - let env = TmpEnv::new_all_threads().with_key_value(); - ro_is_empty(env, function_name!(), c); -} - -//---------------------------------------------------------------------------------------------------- DatabaseRo::contains /// [`DatabaseRo::contains`] -fn ro_contains(env: TmpEnv, name: &'static str, c: &mut Criterion) { +#[named] +fn ro_contains(c: &mut Criterion) { + let env = TmpEnv::new().with_key_value(); let env_inner = env.env.env_inner(); let tx_ro = env_inner.tx_ro().unwrap(); let table = env_inner.open_db_ro::(&tx_ro).unwrap(); - c.bench_function(name, |b| { + c.bench_function(function_name!(), |b| { b.iter(|| { table.contains(black_box(&KEY)).unwrap(); }); }); } -/// [`DatabaseRo::contains`] (single-thread). -#[named] -fn ro_contains_single_thread(c: &mut Criterion) { - let env = TmpEnv::new().with_key_value(); - ro_contains(env, function_name!(), c); -} - -/// [`DatabaseRo::contains`] (multi-thread). -#[named] -fn ro_contains_multi_thread(c: &mut Criterion) { - let env = TmpEnv::new_all_threads().with_key_value(); - ro_contains(env, function_name!(), c); -} - -//---------------------------------------------------------------------------------------------------- DatabaseRw::get +//---------------------------------------------------------------------------------------------------- DatabaseRo (TxRw) // These are the same benchmarks as above, but it uses a // `TxRw` and a `TablesMut` instead to ensure our read/write tables // using read operations perform the same as normal read-only tables. -fn rw_get(env: TmpEnv, name: &'static str, c: &mut Criterion) { +/// [`DatabaseRw::get`] +#[named] +fn rw_get(c: &mut Criterion) { + let env = TmpEnv::new().with_key_value(); let env_inner = env.env.env_inner(); let tx_rw = env_inner.tx_rw().unwrap(); let table = env_inner.open_db_rw::(&tx_rw).unwrap(); - c.bench_function(name, |b| { + c.bench_function(function_name!(), |b| { b.iter(|| { - let _value: Output = table.get(black_box(&KEY)).unwrap(); + let _: Output = table.get(black_box(&KEY)).unwrap(); }); }); } -/// [`DatabaseRw::get`] (single-thread). +/// [`DatabaseRw::len`] #[named] -fn rw_get_single_thread(c: &mut Criterion) { +fn rw_len(c: &mut Criterion) { let env = TmpEnv::new().with_key_value(); - rw_get(env, function_name!(), c); -} - -/// [`DatabaseRw::get`] (multi-thread). -#[named] -fn rw_get_multi_thread(c: &mut Criterion) { - let env = TmpEnv::new_all_threads().with_key_value(); - rw_get(env, function_name!(), c); -} - -//---------------------------------------------------------------------------------------------------- DatabaseRw::len -fn rw_len(env: TmpEnv, name: &'static str, c: &mut Criterion) { let env_inner = env.env.env_inner(); let tx_rw = env_inner.tx_rw().unwrap(); let table = env_inner.open_db_rw::(&tx_rw).unwrap(); - c.bench_function(name, |b| { + c.bench_function(function_name!(), |b| { b.iter(|| { black_box(table.len()).unwrap(); }); }); } -/// [`DatabaseRw::len`] (single-thread). +/// [`DatabaseRw::first`] #[named] -fn rw_len_single_thread(c: &mut Criterion) { +fn rw_first(c: &mut Criterion) { let env = TmpEnv::new().with_key_value(); - rw_len(env, function_name!(), c); -} - -/// [`DatabaseRw::len`] (multi-thread). -#[named] -fn rw_len_multi_thread(c: &mut Criterion) { - let env = TmpEnv::new_all_threads().with_key_value(); - rw_len(env, function_name!(), c); -} - -//---------------------------------------------------------------------------------------------------- DatabaseRw::first -fn rw_first(env: TmpEnv, name: &'static str, c: &mut Criterion) { let env_inner = env.env.env_inner(); let tx_rw = env_inner.tx_rw().unwrap(); let table = env_inner.open_db_rw::(&tx_rw).unwrap(); - c.bench_function(name, |b| { + c.bench_function(function_name!(), |b| { b.iter(|| { let (_, _): (PreRctOutputId, Output) = black_box(table.first()).unwrap(); }); }); } -/// [`DatabaseRw::first`] (single-thread). +/// [`DatabaseRw::last`] #[named] -fn rw_first_single_thread(c: &mut Criterion) { +fn rw_last(c: &mut Criterion) { let env = TmpEnv::new().with_key_value(); - rw_first(env, function_name!(), c); -} - -/// [`DatabaseRw::first`] (multi-thread). -#[named] -fn rw_first_multi_thread(c: &mut Criterion) { - let env = TmpEnv::new_all_threads().with_key_value(); - rw_first(env, function_name!(), c); -} - -//---------------------------------------------------------------------------------------------------- DatabaseRw::last -fn rw_last(env: TmpEnv, name: &'static str, c: &mut Criterion) { let env_inner = env.env.env_inner(); let tx_rw = env_inner.tx_rw().unwrap(); let table = env_inner.open_db_rw::(&tx_rw).unwrap(); - c.bench_function(name, |b| { + c.bench_function(function_name!(), |b| { b.iter(|| { let (_, _): (PreRctOutputId, Output) = black_box(table.last()).unwrap(); }); }); } -/// [`DatabaseRw::last`] (single-thread). +/// [`DatabaseRw::is_empty`] #[named] -fn rw_last_single_thread(c: &mut Criterion) { +fn rw_is_empty(c: &mut Criterion) { let env = TmpEnv::new().with_key_value(); - rw_last(env, function_name!(), c); -} - -/// [`DatabaseRw::last`] (multi-thread). -#[named] -fn rw_last_multi_thread(c: &mut Criterion) { - let env = TmpEnv::new_all_threads().with_key_value(); - rw_last(env, function_name!(), c); -} - -//---------------------------------------------------------------------------------------------------- DatabaseRw::is_empty -fn rw_is_empty(env: TmpEnv, name: &'static str, c: &mut Criterion) { let env_inner = env.env.env_inner(); let tx_rw = env_inner.tx_rw().unwrap(); let table = env_inner.open_db_rw::(&tx_rw).unwrap(); - c.bench_function(name, |b| { + c.bench_function(function_name!(), |b| { b.iter(|| { black_box(table.is_empty()).unwrap(); }); }); } -/// [`DatabaseRw::is_empty`] (single-thread). +/// [`DatabaseRw::contains`] #[named] -fn rw_is_empty_single_thread(c: &mut Criterion) { +fn rw_contains(c: &mut Criterion) { let env = TmpEnv::new().with_key_value(); - rw_is_empty(env, function_name!(), c); -} - -/// [`DatabaseRw::is_empty`] (multi-thread). -#[named] -fn rw_is_empty_multi_thread(c: &mut Criterion) { - let env = TmpEnv::new_all_threads().with_key_value(); - rw_is_empty(env, function_name!(), c); -} - -//---------------------------------------------------------------------------------------------------- DatabaseRw::contains -fn rw_contains(env: TmpEnv, name: &'static str, c: &mut Criterion) { let env_inner = env.env.env_inner(); let tx_rw = env_inner.tx_rw().unwrap(); let table = env_inner.open_db_rw::(&tx_rw).unwrap(); - c.bench_function(name, |b| { + c.bench_function(function_name!(), |b| { b.iter(|| { table.contains(black_box(&KEY)).unwrap(); }); }); } -/// [`DatabaseRw::contains`] (single-thread). +//---------------------------------------------------------------------------------------------------- DatabaseIter +/// [`DatabaseIter::get_range`] #[named] -fn rw_contains_single_thread(c: &mut Criterion) { - let env = TmpEnv::new().with_key_value(); - rw_contains(env, function_name!(), c); -} - -/// [`DatabaseRw::contains`] (multi-thread). -#[named] -fn rw_contains_multi_thread(c: &mut Criterion) { - let env = TmpEnv::new_all_threads().with_key_value(); - rw_contains(env, function_name!(), c); -} - -//---------------------------------------------------------------------------------------------------- DatabaseIter::get_range -fn get_range(env: TmpEnv, name: &'static str, c: &mut Criterion) { +fn get_range(c: &mut Criterion) { + let env = TmpEnv::new().with_key_value_100(); let env_inner = env.env.env_inner(); let tx_ro = env_inner.tx_ro().unwrap(); let table = env_inner.open_db_ro::(&tx_ro).unwrap(); - c.bench_function(name, |b| { + c.bench_function(function_name!(), |b| { b.iter(|| { let range = table.get_range(black_box(..)).unwrap(); for result in range { @@ -443,27 +267,15 @@ fn get_range(env: TmpEnv, name: &'static str, c: &mut Criterion) { }); } -/// [`DatabaseIter::get_range`] (single-thread). +/// [`DatabaseIter::iter`] #[named] -fn get_range_single_thread(c: &mut Criterion) { +fn iter(c: &mut Criterion) { let env = TmpEnv::new().with_key_value_100(); - get_range(env, function_name!(), c); -} - -/// [`DatabaseIter::get_range`] (multi-thread). -#[named] -fn get_range_multi_thread(c: &mut Criterion) { - let env = TmpEnv::new_all_threads().with_key_value_100(); - get_range(env, function_name!(), c); -} - -//---------------------------------------------------------------------------------------------------- DatabaseIter::iter -fn iter(env: TmpEnv, name: &'static str, c: &mut Criterion) { let env_inner = env.env.env_inner(); let tx_ro = env_inner.tx_ro().unwrap(); let table = env_inner.open_db_ro::(&tx_ro).unwrap(); - c.bench_function(name, |b| { + c.bench_function(function_name!(), |b| { b.iter(|| { let iter = black_box(table.iter()).unwrap(); for result in iter { @@ -473,28 +285,15 @@ fn iter(env: TmpEnv, name: &'static str, c: &mut Criterion) { }); } -/// [`DatabaseIter::iter`] (single-thread). +/// [`DatabaseIter::keys`] #[named] -fn iter_single_thread(c: &mut Criterion) { +fn keys(c: &mut Criterion) { let env = TmpEnv::new().with_key_value_100(); - iter(env, function_name!(), c); -} - -/// [`DatabaseIter::iter`] (multi-thread). -#[named] -fn iter_multi_thread(c: &mut Criterion) { - let env = TmpEnv::new_all_threads().with_key_value_100(); - iter(env, function_name!(), c); -} - -//---------------------------------------------------------------------------------------------------- DatabaseIter::keys -/// [`DatabaseRo::keys`] -fn keys(env: TmpEnv, name: &'static str, c: &mut Criterion) { let env_inner = env.env.env_inner(); let tx_ro = env_inner.tx_ro().unwrap(); let table = env_inner.open_db_ro::(&tx_ro).unwrap(); - c.bench_function(name, |b| { + c.bench_function(function_name!(), |b| { b.iter(|| { let keys = black_box(table.keys()).unwrap(); for result in keys { @@ -504,28 +303,15 @@ fn keys(env: TmpEnv, name: &'static str, c: &mut Criterion) { }); } -/// [`DatabaseIter::keys`] (single-thread). +/// [`DatabaseIter::values`] #[named] -fn keys_single_thread(c: &mut Criterion) { +fn values(c: &mut Criterion) { let env = TmpEnv::new().with_key_value_100(); - keys(env, function_name!(), c); -} - -/// [`DatabaseIter::iter`] (multi-thread). -#[named] -fn keys_multi_thread(c: &mut Criterion) { - let env = TmpEnv::new_all_threads().with_key_value_100(); - keys(env, function_name!(), c); -} - -//---------------------------------------------------------------------------------------------------- DatabaseIter::values -/// [`DatabaseRo::values`] -fn values(env: TmpEnv, name: &'static str, c: &mut Criterion) { let env_inner = env.env.env_inner(); let tx_ro = env_inner.tx_ro().unwrap(); let table = env_inner.open_db_ro::(&tx_ro).unwrap(); - c.bench_function(name, |b| { + c.bench_function(function_name!(), |b| { b.iter(|| { let values = black_box(table.values()).unwrap(); for result in values { @@ -535,21 +321,7 @@ fn values(env: TmpEnv, name: &'static str, c: &mut Criterion) { }); } -/// [`DatabaseIter::values`] (single-thread). -#[named] -fn values_single_thread(c: &mut Criterion) { - let env = TmpEnv::new().with_key_value_100(); - values(env, function_name!(), c); -} - -/// [`DatabaseIter::iter`] (multi-thread). -#[named] -fn values_multi_thread(c: &mut Criterion) { - let env = TmpEnv::new_all_threads().with_key_value_100(); - values(env, function_name!(), c); -} - -//---------------------------------------------------------------------------------------------------- DatabaseRw::put +//---------------------------------------------------------------------------------------------------- DatabaseRw /// [`DatabaseRw::put`] #[named] fn put(c: &mut Criterion) { @@ -568,7 +340,6 @@ fn put(c: &mut Criterion) { }); } -//---------------------------------------------------------------------------------------------------- DatabaseRw::delete /// [`DatabaseRw::delete`] #[named] fn delete(c: &mut Criterion) { @@ -598,7 +369,6 @@ fn delete(c: &mut Criterion) { }); } -//---------------------------------------------------------------------------------------------------- DatabaseRw::pop_first /// [`DatabaseRw::pop_first`] #[named] fn pop_first(c: &mut Criterion) { @@ -628,7 +398,6 @@ fn pop_first(c: &mut Criterion) { }); } -//---------------------------------------------------------------------------------------------------- DatabaseRw::pop_last /// [`DatabaseRw::pop_last`] #[named] fn pop_last(c: &mut Criterion) { @@ -658,11 +427,10 @@ fn pop_last(c: &mut Criterion) { }); } -//---------------------------------------------------------------------------------------------------- DatabaseRw::take /// [`DatabaseRw::take`] #[named] fn take(c: &mut Criterion) { - let env = TmpEnv::new_all_threads(); + let env = TmpEnv::new(); let env_inner = env.env.env_inner(); let tx_rw = env_inner.tx_rw().unwrap(); let mut table = env_inner.open_db_rw::(&tx_rw).unwrap(); diff --git a/benches/criterion/cuprate-database/benches/env.rs b/benches/criterion/cuprate-database/benches/env.rs index 75b8793..e7213d0 100644 --- a/benches/criterion/cuprate-database/benches/env.rs +++ b/benches/criterion/cuprate-database/benches/env.rs @@ -1,19 +1,13 @@ -//! Same as `env.rs` but multi-threaded. -//! TODO: create multi-threaded benchmarks +//! [`Env`] benchmarks. #![allow(unused_crate_dependencies, unused_attributes)] #![expect(clippy::significant_drop_tightening)] -// TODO -use cuprate_helper as _; -use tempfile as _; - use criterion::{black_box, criterion_group, criterion_main, Criterion}; use function_name::named; -use cuprate_blockchain::tables::{OpenTables, Outputs}; +use cuprate_blockchain::tables::Outputs; use cuprate_database::{ - config::ConfigBuilder, resize::{ResizeAlgorithm, PAGE_SIZE}, ConcreteEnv, Env, EnvInner, TxRo, TxRw, }; @@ -21,33 +15,43 @@ use cuprate_database::{ use cuprate_criterion_database::TmpEnv; criterion_group! { - benches, - open, + name = benches; + config = Criterion::default(); + targets = + // open, env_inner, tx_ro, tx_rw, open_db_ro, open_db_rw, + create_db, resize, current_map_size, disk_size_bytes, } criterion_main!(benches); -/// [`Env::open`]. -#[named] -fn open(c: &mut Criterion) { - let tempdir = tempfile::tempdir().unwrap(); - let config = ConfigBuilder::new(tempdir.path().to_path_buf().into()) - .low_power() - .build(); - - c.bench_function(function_name!(), |b| { - b.iter_with_large_drop(|| { - ConcreteEnv::open(config.clone()).unwrap(); - }); - }); -} +// FIXME: This function is hard to time due to: +// - heed errors +// - "too many open files" errors +// +// /// [`Env::open`]. +// #[named] +// fn open(c: &mut Criterion) { +// c.bench_function(function_name!(), |b| { +// b.iter_custom(|_| { +// let tempdir = tempfile::tempdir().unwrap(); +// let config = ConfigBuilder::new(tempdir.path().to_path_buf().into()).build(); +// +// let now = std::time::Instant::now(); +// ConcreteEnv::open(config).unwrap(); +// let elapsed = now.elapsed(); +// +// tempdir.close().unwrap(); +// elapsed +// }); +// }); +// } /// [`Env::env_inner`]. #[named] @@ -115,7 +119,20 @@ fn open_db_rw(c: &mut Criterion) { c.bench_function(function_name!(), |b| { b.iter(|| { env_inner.open_db_rw::(&tx_rw).unwrap(); - env_inner.open_tables_mut(&tx_rw).unwrap(); + }); + }); +} + +/// [`EnvInner::create_db`]. +#[named] +fn create_db(c: &mut Criterion) { + let env = TmpEnv::new(); + let env_inner = env.env.env_inner(); + let tx_rw = env_inner.tx_rw().unwrap(); + + c.bench_function(function_name!(), |b| { + b.iter(|| { + env_inner.create_db::(&tx_rw).unwrap(); }); }); } diff --git a/benches/criterion/cuprate-database/benches/main.rs b/benches/criterion/cuprate-database/benches/main.rs index cd9f360..0dba969 100644 --- a/benches/criterion/cuprate-database/benches/main.rs +++ b/benches/criterion/cuprate-database/benches/main.rs @@ -1,5 +1,3 @@ -//! TODO - #![expect(unused_crate_dependencies)] mod db; diff --git a/benches/criterion/cuprate-database/benches/storable.rs b/benches/criterion/cuprate-database/benches/storable.rs index 60d3263..e2add7d 100644 --- a/benches/criterion/cuprate-database/benches/storable.rs +++ b/benches/criterion/cuprate-database/benches/storable.rs @@ -3,7 +3,6 @@ #![allow(unused_crate_dependencies, unused_attributes)] use criterion::{black_box, criterion_group, criterion_main, Criterion}; - use function_name::named; use cuprate_blockchain::types::{Output, PreRctOutputId}; @@ -12,7 +11,9 @@ use cuprate_database::Storable; use cuprate_criterion_database::{KEY, VALUE}; criterion_group! { - benches, + name = benches; + config = Criterion::default(); + targets = pre_rct_output_id_as_bytes, pre_rct_output_id_from_bytes, output_as_bytes, diff --git a/benches/criterion/cuprate-database/src/lib.rs b/benches/criterion/cuprate-database/src/lib.rs index 8f75f4e..2c527dc 100644 --- a/benches/criterion/cuprate-database/src/lib.rs +++ b/benches/criterion/cuprate-database/src/lib.rs @@ -1,5 +1,3 @@ -//! TODO - #![allow(unused_crate_dependencies, reason = "used in benchmarks")] mod constants; diff --git a/benches/criterion/cuprate-database/src/tmp_env.rs b/benches/criterion/cuprate-database/src/tmp_env.rs index d5d263e..1a05e66 100644 --- a/benches/criterion/cuprate-database/src/tmp_env.rs +++ b/benches/criterion/cuprate-database/src/tmp_env.rs @@ -3,7 +3,9 @@ use tempfile::TempDir; use cuprate_blockchain::tables::Outputs; -use cuprate_database::{config::ConfigBuilder, ConcreteEnv, DatabaseRw, Env, EnvInner, TxRw}; +use cuprate_database::{ + config::ConfigBuilder, resize::PAGE_SIZE, ConcreteEnv, DatabaseRw, Env, EnvInner, TxRw, +}; use crate::constants::{KEY, VALUE}; @@ -33,16 +35,15 @@ impl TmpEnv { let config = ConfigBuilder::new(path).low_power().build(); let env = ConcreteEnv::open(config).unwrap(); - Self { env, tempdir } - } - - /// Same as [`Self::new`] but uses all system threads for the [`Env`]. - #[expect(clippy::missing_panics_doc)] - pub fn new_all_threads() -> Self { - let tempdir = tempfile::tempdir().unwrap(); - let path = tempdir.path().to_path_buf().into(); - let config = ConfigBuilder::new(path).fast().build(); - let env = ConcreteEnv::open(config).unwrap(); + // Resize to a very large map to prevent resize errors. + if ConcreteEnv::MANUAL_RESIZE { + // SAFETY: no write transactions exist yet. + unsafe { + env.env_inner() + .resize(PAGE_SIZE.get() * 1024 * 1024 * 1024) + .unwrap(); + } + } Self { env, tempdir } } From 615cef90ee79baa5a2ec18ff5c45ff0969ceb28f Mon Sep 17 00:00:00 2001 From: "hinto.janai" Date: Thu, 24 Oct 2024 19:50:20 -0400 Subject: [PATCH 5/5] storage: remove todo `println!()` --- storage/database/src/backend/heed/env.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/storage/database/src/backend/heed/env.rs b/storage/database/src/backend/heed/env.rs index 568379e..d934a1b 100644 --- a/storage/database/src/backend/heed/env.rs +++ b/storage/database/src/backend/heed/env.rs @@ -78,11 +78,12 @@ impl Drop for ConcreteEnv { // TODO: use tracing. // - let result = self.env.read().unwrap().clear_stale_readers(); - match result { - Ok(n) => println!("LMDB stale readers cleared: {n}"), - Err(e) => println!("LMDB stale reader clear error: {e:?}"), - } + drop(self.env.read().unwrap().clear_stale_readers()); + // let result = self.env.read().unwrap().clear_stale_readers(); + // match result { + // Ok(n) => println!("LMDB stale readers cleared: {n}"), + // Err(e) => println!("LMDB stale reader clear error: {e:?}"), + // } } }