mirror of
https://github.com/hinto-janai/cuprate.git
synced 2025-02-03 19:56:35 +00:00
Compare commits
No commits in common. "8ae208b9f08e95ff48244b132c58d63230a8ef3a" and "7a94952e144ace471f733afe039741663ee4f981" have entirely different histories.
8ae208b9f0
...
7a94952e14
15 changed files with 1352 additions and 407 deletions
13
Cargo.lock
generated
13
Cargo.lock
generated
|
@ -739,19 +739,6 @@ 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",
|
||||
"rand",
|
||||
"tempfile",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cuprate-criterion-example"
|
||||
version = "0.0.0"
|
||||
|
|
|
@ -9,7 +9,6 @@ members = [
|
|||
"benches/benchmark/example",
|
||||
"benches/criterion/example",
|
||||
"benches/criterion/cuprate-json-rpc",
|
||||
"benches/criterion/cuprate-database",
|
||||
# Consensus
|
||||
"consensus",
|
||||
"consensus/fast-sync",
|
||||
|
|
|
@ -20,13 +20,6 @@ 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();
|
||||
|
||||
|
@ -34,8 +27,7 @@ fn main() {
|
|||
|
||||
cfg_if! {
|
||||
if #[cfg(not(any(feature = "example")))] {
|
||||
println!("No feature specified. Use `--features $BENCHMARK_FEATURE` when building.");
|
||||
return;
|
||||
compile_error!("No feature specified. Use `--features $BENCHMARK_FEATURE` when building.");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,41 +1,24 @@
|
|||
[package]
|
||||
name = "cuprate-criterion-database"
|
||||
name = "cuprate-database-benchmark"
|
||||
version = "0.0.0"
|
||||
edition = "2021"
|
||||
description = "Criterion benchmarking for cuprate-database"
|
||||
description = "Benchmarking for Cuprate's database abstraction"
|
||||
license = "MIT"
|
||||
authors = ["hinto-janai"]
|
||||
repository = "https://github.com/Cuprate/cuprate/tree/main/benches/criterion/cuprate-database"
|
||||
repository = "https://github.com/Cuprate/cuprate/tree/main/database/benchmark"
|
||||
keywords = ["cuprate", "database", "benchmark"]
|
||||
|
||||
[features]
|
||||
default = ["heed"]
|
||||
heed = ["cuprate-database/heed", "cuprate-blockchain/heed"]
|
||||
redb = ["cuprate-database/redb", "cuprate-blockchain/redb"]
|
||||
default = []
|
||||
|
||||
[dependencies]
|
||||
# FIXME:
|
||||
# Some crates/features that are unused here but
|
||||
# needed in other crates are pulled in, see:
|
||||
# - <https://github.com/Cuprate/cuprate/issues/325>
|
||||
#
|
||||
# Remove:
|
||||
# - rand
|
||||
# - cuprate-blockchain/asynch
|
||||
# - cuprate-blockchain/tx
|
||||
|
||||
criterion = { workspace = true }
|
||||
cuprate-database = { path = "../../../storage/database" }
|
||||
cuprate-blockchain = { path = "../../../storage/blockchain", features = ["service"] }
|
||||
cuprate-helper = { path = "../../../helper", features = ["asynch", "fs", "thread", "tx"] }
|
||||
|
||||
function_name = { workspace = true }
|
||||
tempfile = { workspace = true }
|
||||
rand = { workspace = true, features = ["std", "std_rng"] }
|
||||
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
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
harness = false
|
|
@ -1,61 +1,61 @@
|
|||
//! Database operations.
|
||||
//!
|
||||
//! This module tests the functions from:
|
||||
//! - [`cuprate_database::DatabaseRo`]
|
||||
//! - [`cuprate_database::DatabaseRw`]
|
||||
//! - [`cuprate_database::DatabaseIter`]
|
||||
|
||||
#![allow(unused_crate_dependencies, unused_attributes)]
|
||||
#![expect(clippy::significant_drop_tightening)]
|
||||
//! `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_blockchain::{
|
||||
use cuprate_database::{
|
||||
tables::Outputs,
|
||||
types::{Output, PreRctOutputId},
|
||||
DatabaseIter, DatabaseRo, DatabaseRw, Env, EnvInner, TxRw,
|
||||
};
|
||||
use cuprate_database::{DatabaseIter, DatabaseRo, DatabaseRw, Env, EnvInner};
|
||||
|
||||
use cuprate_criterion_database::{TmpEnv, KEY, VALUE};
|
||||
use cuprate_database_benchmark::tmp_env;
|
||||
|
||||
//---------------------------------------------------------------------------------------------------- Criterion
|
||||
criterion_group! {
|
||||
name = benches;
|
||||
config = Criterion::default();
|
||||
targets =
|
||||
// `DatabaseRo`
|
||||
benches,
|
||||
ro_get,
|
||||
ro_len,
|
||||
ro_first,
|
||||
ro_last,
|
||||
ro_is_empty,
|
||||
ro_contains,
|
||||
|
||||
// `DatabaseRo` with a `TxRw`
|
||||
rw_get,
|
||||
rw_len,
|
||||
rw_first,
|
||||
rw_last,
|
||||
rw_is_empty,
|
||||
rw_contains,
|
||||
|
||||
// `DatabaseIter`
|
||||
get_range,
|
||||
iter,
|
||||
keys,
|
||||
values,
|
||||
|
||||
// `DatabaseRw`
|
||||
put,
|
||||
delete,
|
||||
pop_first,
|
||||
pop_last,
|
||||
take,
|
||||
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
|
||||
|
@ -66,14 +66,21 @@ criterion_main!(benches);
|
|||
/// [`DatabaseRo::get`]
|
||||
#[named]
|
||||
fn ro_get(c: &mut Criterion) {
|
||||
let env = TmpEnv::new().with_key_value();
|
||||
let env_inner = env.env.env_inner();
|
||||
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::<Outputs>(&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::<Outputs>(&tx_ro).unwrap();
|
||||
|
||||
c.bench_function(function_name!(), |b| {
|
||||
b.iter(|| {
|
||||
let _: Output = table.get(black_box(&KEY)).unwrap();
|
||||
let _value: Output = table.get(black_box(&KEY)).unwrap();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -81,8 +88,15 @@ fn ro_get(c: &mut Criterion) {
|
|||
/// [`DatabaseRo::len`]
|
||||
#[named]
|
||||
fn ro_len(c: &mut Criterion) {
|
||||
let env = TmpEnv::new().with_key_value();
|
||||
let env_inner = env.env.env_inner();
|
||||
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::<Outputs>(&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::<Outputs>(&tx_ro).unwrap();
|
||||
|
||||
|
@ -96,8 +110,15 @@ fn ro_len(c: &mut Criterion) {
|
|||
/// [`DatabaseRo::first`]
|
||||
#[named]
|
||||
fn ro_first(c: &mut Criterion) {
|
||||
let env = TmpEnv::new().with_key_value();
|
||||
let env_inner = env.env.env_inner();
|
||||
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::<Outputs>(&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::<Outputs>(&tx_ro).unwrap();
|
||||
|
||||
|
@ -111,8 +132,15 @@ fn ro_first(c: &mut Criterion) {
|
|||
/// [`DatabaseRo::last`]
|
||||
#[named]
|
||||
fn ro_last(c: &mut Criterion) {
|
||||
let env = TmpEnv::new().with_key_value();
|
||||
let env_inner = env.env.env_inner();
|
||||
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::<Outputs>(&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::<Outputs>(&tx_ro).unwrap();
|
||||
|
||||
|
@ -126,8 +154,15 @@ fn ro_last(c: &mut Criterion) {
|
|||
/// [`DatabaseRo::is_empty`]
|
||||
#[named]
|
||||
fn ro_is_empty(c: &mut Criterion) {
|
||||
let env = TmpEnv::new().with_key_value();
|
||||
let env_inner = env.env.env_inner();
|
||||
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::<Outputs>(&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::<Outputs>(&tx_ro).unwrap();
|
||||
|
||||
|
@ -141,8 +176,15 @@ fn ro_is_empty(c: &mut Criterion) {
|
|||
/// [`DatabaseRo::contains`]
|
||||
#[named]
|
||||
fn ro_contains(c: &mut Criterion) {
|
||||
let env = TmpEnv::new().with_key_value();
|
||||
let env_inner = env.env.env_inner();
|
||||
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::<Outputs>(&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::<Outputs>(&tx_ro).unwrap();
|
||||
|
||||
|
@ -153,31 +195,45 @@ fn ro_contains(c: &mut Criterion) {
|
|||
});
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------------------------- DatabaseRo (TxRw)
|
||||
//---------------------------------------------------------------------------------------------------- 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.
|
||||
|
||||
/// [`DatabaseRw::get`]
|
||||
/// [`DatabaseRo::get`]
|
||||
#[named]
|
||||
fn rw_get(c: &mut Criterion) {
|
||||
let env = TmpEnv::new().with_key_value();
|
||||
let env_inner = env.env.env_inner();
|
||||
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::<Outputs>(&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::<Outputs>(&tx_rw).unwrap();
|
||||
|
||||
c.bench_function(function_name!(), |b| {
|
||||
b.iter(|| {
|
||||
let _: Output = table.get(black_box(&KEY)).unwrap();
|
||||
let _value: Output = table.get(black_box(&KEY)).unwrap();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/// [`DatabaseRw::len`]
|
||||
/// [`DatabaseRo::len`]
|
||||
#[named]
|
||||
fn rw_len(c: &mut Criterion) {
|
||||
let env = TmpEnv::new().with_key_value();
|
||||
let env_inner = env.env.env_inner();
|
||||
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::<Outputs>(&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::<Outputs>(&tx_rw).unwrap();
|
||||
|
||||
|
@ -188,11 +244,18 @@ fn rw_len(c: &mut Criterion) {
|
|||
});
|
||||
}
|
||||
|
||||
/// [`DatabaseRw::first`]
|
||||
/// [`DatabaseRo::first`]
|
||||
#[named]
|
||||
fn rw_first(c: &mut Criterion) {
|
||||
let env = TmpEnv::new().with_key_value();
|
||||
let env_inner = env.env.env_inner();
|
||||
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::<Outputs>(&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::<Outputs>(&tx_rw).unwrap();
|
||||
|
||||
|
@ -203,11 +266,18 @@ fn rw_first(c: &mut Criterion) {
|
|||
});
|
||||
}
|
||||
|
||||
/// [`DatabaseRw::last`]
|
||||
/// [`DatabaseRo::last`]
|
||||
#[named]
|
||||
fn rw_last(c: &mut Criterion) {
|
||||
let env = TmpEnv::new().with_key_value();
|
||||
let env_inner = env.env.env_inner();
|
||||
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::<Outputs>(&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::<Outputs>(&tx_rw).unwrap();
|
||||
|
||||
|
@ -218,11 +288,18 @@ fn rw_last(c: &mut Criterion) {
|
|||
});
|
||||
}
|
||||
|
||||
/// [`DatabaseRw::is_empty`]
|
||||
/// [`DatabaseRo::is_empty`]
|
||||
#[named]
|
||||
fn rw_is_empty(c: &mut Criterion) {
|
||||
let env = TmpEnv::new().with_key_value();
|
||||
let env_inner = env.env.env_inner();
|
||||
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::<Outputs>(&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::<Outputs>(&tx_rw).unwrap();
|
||||
|
||||
|
@ -233,11 +310,18 @@ fn rw_is_empty(c: &mut Criterion) {
|
|||
});
|
||||
}
|
||||
|
||||
/// [`DatabaseRw::contains`]
|
||||
/// [`DatabaseRo::contains`]
|
||||
#[named]
|
||||
fn rw_contains(c: &mut Criterion) {
|
||||
let env = TmpEnv::new().with_key_value();
|
||||
let env_inner = env.env.env_inner();
|
||||
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::<Outputs>(&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::<Outputs>(&tx_rw).unwrap();
|
||||
|
||||
|
@ -248,85 +332,12 @@ fn rw_contains(c: &mut Criterion) {
|
|||
});
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------------------------- DatabaseIter
|
||||
/// [`DatabaseIter::get_range`]
|
||||
#[named]
|
||||
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::<Outputs>(&tx_ro).unwrap();
|
||||
|
||||
c.bench_function(function_name!(), |b| {
|
||||
b.iter(|| {
|
||||
let range = table.get_range(black_box(..)).unwrap();
|
||||
for result in range {
|
||||
let _: Output = black_box(result.unwrap());
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/// [`DatabaseIter::iter`]
|
||||
#[named]
|
||||
fn iter(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::<Outputs>(&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());
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/// [`DatabaseIter::keys`]
|
||||
#[named]
|
||||
fn keys(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::<Outputs>(&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());
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/// [`DatabaseIter::values`]
|
||||
#[named]
|
||||
fn values(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::<Outputs>(&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());
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------------------------- DatabaseRw
|
||||
/// [`DatabaseRw::put`]
|
||||
#[named]
|
||||
fn put(c: &mut Criterion) {
|
||||
let env = TmpEnv::new();
|
||||
let env_inner = env.env.env_inner();
|
||||
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::<Outputs>(&tx_rw).unwrap();
|
||||
|
||||
|
@ -343,8 +354,8 @@ fn put(c: &mut Criterion) {
|
|||
/// [`DatabaseRw::delete`]
|
||||
#[named]
|
||||
fn delete(c: &mut Criterion) {
|
||||
let env = TmpEnv::new();
|
||||
let env_inner = env.env.env_inner();
|
||||
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::<Outputs>(&tx_rw).unwrap();
|
||||
|
||||
|
@ -372,8 +383,8 @@ fn delete(c: &mut Criterion) {
|
|||
/// [`DatabaseRw::pop_first`]
|
||||
#[named]
|
||||
fn pop_first(c: &mut Criterion) {
|
||||
let env = TmpEnv::new();
|
||||
let env_inner = env.env.env_inner();
|
||||
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::<Outputs>(&tx_rw).unwrap();
|
||||
|
||||
|
@ -401,8 +412,8 @@ fn pop_first(c: &mut Criterion) {
|
|||
/// [`DatabaseRw::pop_last`]
|
||||
#[named]
|
||||
fn pop_last(c: &mut Criterion) {
|
||||
let env = TmpEnv::new();
|
||||
let env_inner = env.env.env_inner();
|
||||
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::<Outputs>(&tx_rw).unwrap();
|
||||
|
||||
|
@ -427,18 +438,146 @@ fn pop_last(c: &mut Criterion) {
|
|||
});
|
||||
}
|
||||
|
||||
/// [`DatabaseRw::take`]
|
||||
// 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::<Outputs>(&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 take(c: &mut Criterion) {
|
||||
let env = TmpEnv::new();
|
||||
let env_inner = env.env.env_inner();
|
||||
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::<Outputs>(&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::<Outputs>(&tx_ro).unwrap();
|
||||
|
||||
c.bench_function(function_name!(), |b| {
|
||||
b.iter(|| {
|
||||
table.put(&KEY, &VALUE).unwrap();
|
||||
let _: Output = black_box(table.take(&black_box(KEY)).unwrap());
|
||||
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::<Outputs>(&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::<Outputs>(&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::<Outputs>(&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::<Outputs>(&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::<Outputs>(&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::<Outputs>(&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());
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
584
benches/criterion/cuprate-database/benches/db_multi_thread.rs
Normal file
584
benches/criterion/cuprate-database/benches/db_multi_thread.rs
Normal file
|
@ -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::<Outputs>(&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::<Outputs>(&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::<Outputs>(&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::<Outputs>(&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::<Outputs>(&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::<Outputs>(&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::<Outputs>(&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::<Outputs>(&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::<Outputs>(&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::<Outputs>(&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::<Outputs>(&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::<Outputs>(&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::<Outputs>(&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::<Outputs>(&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::<Outputs>(&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::<Outputs>(&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::<Outputs>(&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::<Outputs>(&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::<Outputs>(&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::<Outputs>(&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::<Outputs>(&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::<Outputs>(&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::<Outputs>(&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::<Outputs>(&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::<Outputs>(&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::<Outputs>(&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::<Outputs>(&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::<Outputs>(&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::<Outputs>(&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::<Outputs>(&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::<Outputs>(&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::<Outputs>(&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::<Outputs>(&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::<Outputs>(&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::<Outputs>(&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::<Outputs>(&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::<Outputs>(&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());
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
|
@ -1,75 +1,65 @@
|
|||
//! [`Env`] benchmarks.
|
||||
|
||||
#![allow(unused_crate_dependencies, unused_attributes)]
|
||||
#![expect(clippy::significant_drop_tightening)]
|
||||
//! `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_blockchain::tables::Outputs;
|
||||
use cuprate_database::{
|
||||
resize::{ResizeAlgorithm, PAGE_SIZE},
|
||||
config::Config,
|
||||
resize::{page_size, ResizeAlgorithm},
|
||||
tables::Outputs,
|
||||
ConcreteEnv, Env, EnvInner, TxRo, TxRw,
|
||||
};
|
||||
|
||||
use cuprate_criterion_database::TmpEnv;
|
||||
use cuprate_database_benchmark::tmp_env;
|
||||
|
||||
//---------------------------------------------------------------------------------------------------- Criterion
|
||||
criterion_group! {
|
||||
name = benches;
|
||||
config = Criterion::default();
|
||||
targets =
|
||||
// open,
|
||||
benches,
|
||||
open,
|
||||
env_inner,
|
||||
tx_ro,
|
||||
tx_rw,
|
||||
open_db_ro,
|
||||
open_db_rw,
|
||||
create_db,
|
||||
open_tables,
|
||||
open_tables_mut,
|
||||
resize,
|
||||
current_map_size,
|
||||
disk_size_bytes,
|
||||
}
|
||||
criterion_main!(benches);
|
||||
|
||||
// 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`].
|
||||
//---------------------------------------------------------------------------------------------------- Env benchmarks
|
||||
/// [`Env::open`].
|
||||
#[named]
|
||||
fn env_inner(c: &mut Criterion) {
|
||||
let env = TmpEnv::new();
|
||||
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(|| {
|
||||
drop(black_box(env.env.env_inner()));
|
||||
b.iter_with_large_drop(|| {
|
||||
ConcreteEnv::open(config.clone()).unwrap();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/// [`EnvInner::tx_ro`].
|
||||
/// [`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 = TmpEnv::new();
|
||||
let env_inner = env.env.env_inner();
|
||||
let (env, _tempdir) = tmp_env();
|
||||
let env_inner = env.env_inner();
|
||||
|
||||
c.bench_function(function_name!(), |b| {
|
||||
b.iter(|| {
|
||||
|
@ -79,11 +69,11 @@ fn tx_ro(c: &mut Criterion) {
|
|||
});
|
||||
}
|
||||
|
||||
/// [`EnvInner::tx_rw`].
|
||||
/// Create and commit read/write transactions.
|
||||
#[named]
|
||||
fn tx_rw(c: &mut Criterion) {
|
||||
let env = TmpEnv::new();
|
||||
let env_inner = env.env.env_inner();
|
||||
let (env, _tempdir) = tmp_env();
|
||||
let env_inner = env.env_inner();
|
||||
|
||||
c.bench_function(function_name!(), |b| {
|
||||
b.iter(|| {
|
||||
|
@ -93,91 +83,79 @@ fn tx_rw(c: &mut Criterion) {
|
|||
});
|
||||
}
|
||||
|
||||
/// [`EnvInner::open_db_ro`].
|
||||
/// Open all database tables in read-only mode.
|
||||
#[named]
|
||||
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();
|
||||
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(|| {
|
||||
env_inner.open_db_ro::<Outputs>(&tx_ro).unwrap();
|
||||
black_box(env_inner.open_db_ro::<Outputs>(&tx_ro)).unwrap();
|
||||
// env_inner.open_tables(&tx_ro).unwrap();
|
||||
// TODO: waiting on PR 102
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/// [`EnvInner::open_db_rw`].
|
||||
/// Open all database tables in read/write mode.
|
||||
#[named]
|
||||
fn open_db_rw(c: &mut Criterion) {
|
||||
let env = TmpEnv::new();
|
||||
let env_inner = env.env.env_inner();
|
||||
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(|| {
|
||||
env_inner.open_db_rw::<Outputs>(&tx_rw).unwrap();
|
||||
black_box(env_inner.open_db_rw::<Outputs>(&tx_rw)).unwrap();
|
||||
// env_inner.open_tables_mut(&mut tx_rw).unwrap();
|
||||
// TODO: waiting on PR 102
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/// [`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::<Outputs>(&tx_rw).unwrap();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/// [`Env::resize`].
|
||||
/// `Env` memory map resizes.
|
||||
#[named]
|
||||
fn resize(c: &mut Criterion) {
|
||||
let env = TmpEnv::new();
|
||||
let (env, _tempdir) = tmp_env();
|
||||
|
||||
// Resize env.by the OS page size.
|
||||
let resize = Some(ResizeAlgorithm::FixedBytes(*PAGE_SIZE));
|
||||
// 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.env.resize_map(resize);
|
||||
env.resize_map(black_box(Some(ResizeAlgorithm::FixedBytes(page_size))));
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/// [`Env::current_map_size`].
|
||||
/// Access current memory map size of the database.
|
||||
#[named]
|
||||
fn current_map_size(c: &mut Criterion) {
|
||||
let env = TmpEnv::new();
|
||||
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.env.current_map_size());
|
||||
black_box(env.current_map_size());
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/// [`Env::disk_size_bytes`].
|
||||
/// Access on-disk size of the database.
|
||||
#[named]
|
||||
fn disk_size_bytes(c: &mut Criterion) {
|
||||
let env = TmpEnv::new();
|
||||
let (env, _tempdir) = tmp_env();
|
||||
|
||||
c.bench_function(function_name!(), |b| {
|
||||
b.iter(|| {
|
||||
black_box(env.env.disk_size_bytes()).unwrap();
|
||||
black_box(env.disk_size_bytes()).unwrap();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
162
benches/criterion/cuprate-database/benches/env_multi_thread.rs
Normal file
162
benches/criterion/cuprate-database/benches/env_multi_thread.rs
Normal file
|
@ -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::<Outputs>(&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::<Outputs>(&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();
|
||||
});
|
||||
});
|
||||
}
|
|
@ -1,4 +1,84 @@
|
|||
#![expect(unused_crate_dependencies)]
|
||||
//! 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;
|
||||
|
|
25
benches/criterion/cuprate-database/benches/service.rs
Normal file
25
benches/criterion/cuprate-database/benches/service.rs
Normal file
|
@ -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
|
|
@ -1,19 +1,18 @@
|
|||
//! [`Storable`] benchmarks.
|
||||
|
||||
#![allow(unused_crate_dependencies, unused_attributes)]
|
||||
//! `trait Storable` benchmarks.
|
||||
|
||||
//---------------------------------------------------------------------------------------------------- Import
|
||||
use criterion::{black_box, criterion_group, criterion_main, Criterion};
|
||||
|
||||
use function_name::named;
|
||||
|
||||
use cuprate_blockchain::types::{Output, PreRctOutputId};
|
||||
use cuprate_database::Storable;
|
||||
|
||||
use cuprate_criterion_database::{KEY, VALUE};
|
||||
use cuprate_database::{
|
||||
types::{Output, PreRctOutputId},
|
||||
Storable,
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------------------------------------- Criterion
|
||||
criterion_group! {
|
||||
name = benches;
|
||||
config = Criterion::default();
|
||||
targets =
|
||||
benches,
|
||||
pre_rct_output_id_as_bytes,
|
||||
pre_rct_output_id_from_bytes,
|
||||
output_as_bytes,
|
||||
|
@ -21,12 +20,28 @@ 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(&KEY)));
|
||||
black_box(Storable::as_bytes(black_box(&PRE_RCT_OUTPUT_ID)));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -34,7 +49,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(&KEY);
|
||||
let bytes = Storable::as_bytes(&PRE_RCT_OUTPUT_ID);
|
||||
|
||||
c.bench_function(function_name!(), |b| {
|
||||
b.iter(|| {
|
||||
|
@ -48,7 +63,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(&VALUE)));
|
||||
black_box(Storable::as_bytes(black_box(&OUTPUT)));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -56,7 +71,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(&VALUE);
|
||||
let bytes = Storable::as_bytes(&OUTPUT);
|
||||
|
||||
c.bench_function(function_name!(), |b| {
|
||||
b.iter(|| {
|
||||
|
|
|
@ -1,17 +0,0 @@
|
|||
//! 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,
|
||||
};
|
30
benches/criterion/cuprate-database/src/helper.rs
Normal file
30
benches/criterion/cuprate-database/src/helper.rs
Normal file
|
@ -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)
|
||||
}
|
|
@ -1,7 +1,83 @@
|
|||
#![allow(unused_crate_dependencies, reason = "used in benchmarks")]
|
||||
//! TODO
|
||||
|
||||
mod constants;
|
||||
mod tmp_env;
|
||||
//---------------------------------------------------------------------------------------------------- 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,
|
||||
|
||||
pub use constants::{KEY, VALUE};
|
||||
pub use tmp_env::TmpEnv;
|
||||
// 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};
|
||||
|
|
|
@ -1,88 +0,0 @@
|
|||
//! An [`Env`] inside a [`TempDir`].
|
||||
|
||||
use tempfile::TempDir;
|
||||
|
||||
use cuprate_blockchain::tables::Outputs;
|
||||
use cuprate_database::{
|
||||
config::ConfigBuilder, resize::PAGE_SIZE, 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();
|
||||
|
||||
// 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 }
|
||||
}
|
||||
|
||||
/// 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::<Outputs>(&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::<Outputs>(&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
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue