move benchmark to criterion

This commit is contained in:
hinto.janai 2024-04-16 16:53:24 -04:00
parent e0f5dc6043
commit 6120a6c505
No known key found for this signature in database
GPG key ID: D47CE05FA175A499
13 changed files with 587 additions and 569 deletions

256
Cargo.lock generated
View file

@ -40,6 +40,15 @@ dependencies = [
"zerocopy", "zerocopy",
] ]
[[package]]
name = "aho-corasick"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
dependencies = [
"memchr",
]
[[package]] [[package]]
name = "allocator-api2" name = "allocator-api2"
version = "0.2.16" version = "0.2.16"
@ -61,6 +70,12 @@ dependencies = [
"libc", "libc",
] ]
[[package]]
name = "anes"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299"
[[package]] [[package]]
name = "anstream" name = "anstream"
version = "0.6.13" version = "0.6.13"
@ -109,12 +124,6 @@ dependencies = [
"windows-sys 0.52.0", "windows-sys 0.52.0",
] ]
[[package]]
name = "anyhow"
version = "1.0.81"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0952808a6c2afd1aa8947271f3a60f1a6763c7b912d210184c5149b5cf147247"
[[package]] [[package]]
name = "async-lock" name = "async-lock"
version = "3.3.0" version = "3.3.0"
@ -332,6 +341,12 @@ dependencies = [
"pkg-config", "pkg-config",
] ]
[[package]]
name = "cast"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5"
[[package]] [[package]]
name = "cc" name = "cc"
version = "1.0.88" version = "1.0.88"
@ -365,6 +380,33 @@ dependencies = [
"windows-targets 0.52.4", "windows-targets 0.52.4",
] ]
[[package]]
name = "ciborium"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e"
dependencies = [
"ciborium-io",
"ciborium-ll",
"serde",
]
[[package]]
name = "ciborium-io"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757"
[[package]]
name = "ciborium-ll"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9"
dependencies = [
"ciborium-io",
"half",
]
[[package]] [[package]]
name = "cipher" name = "cipher"
version = "0.4.4" version = "0.4.4"
@ -470,6 +512,40 @@ dependencies = [
"cfg-if", "cfg-if",
] ]
[[package]]
name = "criterion"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2b12d017a929603d80db1831cd3a24082f8137ce19c69e6447f54f5fc8d692f"
dependencies = [
"anes",
"cast",
"ciborium",
"clap",
"criterion-plot",
"is-terminal",
"itertools",
"num-traits",
"once_cell",
"oorandom",
"regex",
"serde",
"serde_derive",
"serde_json",
"tinytemplate",
"walkdir",
]
[[package]]
name = "criterion-plot"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1"
dependencies = [
"cast",
"itertools",
]
[[package]] [[package]]
name = "crossbeam" name = "crossbeam"
version = "0.8.4" version = "0.8.4"
@ -620,17 +696,10 @@ dependencies = [
name = "cuprate-database-benchmark" name = "cuprate-database-benchmark"
version = "0.0.0" version = "0.0.0"
dependencies = [ dependencies = [
"anyhow", "criterion",
"cfg-if",
"clap",
"cuprate-database", "cuprate-database",
"cuprate-helper", "cuprate-helper",
"rayon", "tempfile",
"serde",
"serde_json",
"strum",
"toml_edit 0.22.9",
"tracing",
] ]
[[package]] [[package]]
@ -1091,6 +1160,16 @@ dependencies = [
"tracing", "tracing",
] ]
[[package]]
name = "half"
version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888"
dependencies = [
"cfg-if",
"crunchy",
]
[[package]] [[package]]
name = "hashbrown" name = "hashbrown"
version = "0.12.3" version = "0.12.3"
@ -1425,6 +1504,26 @@ version = "2.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3"
[[package]]
name = "is-terminal"
version = "0.4.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f23ff5ef2b80d608d61efee834934d862cd92461afc0560dedf493e4c033738b"
dependencies = [
"hermit-abi",
"libc",
"windows-sys 0.52.0",
]
[[package]]
name = "itertools"
version = "0.10.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473"
dependencies = [
"either",
]
[[package]] [[package]]
name = "itoa" name = "itoa"
version = "1.0.10" version = "1.0.10"
@ -1792,6 +1891,12 @@ version = "1.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
[[package]]
name = "oorandom"
version = "11.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575"
[[package]] [[package]]
name = "openssl" name = "openssl"
version = "0.10.64" version = "0.10.64"
@ -2049,7 +2154,7 @@ version = "3.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d37c51ca738a55da99dc0c4a34860fd675453b8b36209178c2249bb13651284" checksum = "6d37c51ca738a55da99dc0c4a34860fd675453b8b36209178c2249bb13651284"
dependencies = [ dependencies = [
"toml_edit 0.21.1", "toml_edit",
] ]
[[package]] [[package]]
@ -2264,6 +2369,29 @@ dependencies = [
"syn 2.0.52", "syn 2.0.52",
] ]
[[package]]
name = "regex"
version = "1.10.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c"
dependencies = [
"aho-corasick",
"memchr",
"regex-automata",
"regex-syntax",
]
[[package]]
name = "regex-automata"
version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
]
[[package]] [[package]]
name = "regex-syntax" name = "regex-syntax"
version = "0.8.2" version = "0.8.2"
@ -2439,6 +2567,15 @@ version = "1.0.17"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1"
[[package]]
name = "same-file"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
dependencies = [
"winapi-util",
]
[[package]] [[package]]
name = "schannel" name = "schannel"
version = "0.1.23" version = "0.1.23"
@ -2526,15 +2663,6 @@ dependencies = [
"serde", "serde",
] ]
[[package]]
name = "serde_spanned"
version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eb3622f419d1296904700073ea6cc23ad690adbd66f13ea683df73298736f0c1"
dependencies = [
"serde",
]
[[package]] [[package]]
name = "serde_urlencoded" name = "serde_urlencoded"
version = "0.7.1" version = "0.7.1"
@ -2662,28 +2790,6 @@ version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ee073c9e4cd00e28217186dbe12796d692868f432bf2e97ee73bed0c56dfa01" checksum = "5ee073c9e4cd00e28217186dbe12796d692868f432bf2e97ee73bed0c56dfa01"
[[package]]
name = "strum"
version = "0.26.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5d8cec3501a5194c432b2b7976db6b7d10ec95c253208b45f83f7136aa985e29"
dependencies = [
"strum_macros",
]
[[package]]
name = "strum_macros"
version = "0.26.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c6cf59daf282c0a494ba14fd21610a0325f9f90ec9d1231dea26bcb1d696c946"
dependencies = [
"heck 0.4.1",
"proc-macro2",
"quote",
"rustversion",
"syn 2.0.52",
]
[[package]] [[package]]
name = "subtle" name = "subtle"
version = "2.5.0" version = "2.5.0"
@ -2847,6 +2953,16 @@ dependencies = [
"crunchy", "crunchy",
] ]
[[package]]
name = "tinytemplate"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc"
dependencies = [
"serde",
"serde_json",
]
[[package]] [[package]]
name = "tinyvec" name = "tinyvec"
version = "1.6.0" version = "1.6.0"
@ -2948,9 +3064,6 @@ name = "toml_datetime"
version = "0.6.5" version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1"
dependencies = [
"serde",
]
[[package]] [[package]]
name = "toml_edit" name = "toml_edit"
@ -2960,20 +3073,7 @@ checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1"
dependencies = [ dependencies = [
"indexmap 2.2.5", "indexmap 2.2.5",
"toml_datetime", "toml_datetime",
"winnow 0.5.40", "winnow",
]
[[package]]
name = "toml_edit"
version = "0.22.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e40bb779c5187258fd7aad0eb68cb8706a0a81fa712fbea808ab43c4b8374c4"
dependencies = [
"indexmap 2.2.5",
"serde",
"serde_spanned",
"toml_datetime",
"winnow 0.6.5",
] ]
[[package]] [[package]]
@ -3156,6 +3256,16 @@ dependencies = [
"libc", "libc",
] ]
[[package]]
name = "walkdir"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
dependencies = [
"same-file",
"winapi-util",
]
[[package]] [[package]]
name = "want" name = "want"
version = "0.3.1" version = "0.3.1"
@ -3263,6 +3373,15 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-util"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596"
dependencies = [
"winapi",
]
[[package]] [[package]]
name = "winapi-x86_64-pc-windows-gnu" name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0" version = "0.4.0"
@ -3448,15 +3567,6 @@ dependencies = [
"memchr", "memchr",
] ]
[[package]]
name = "winnow"
version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dffa400e67ed5a4dd237983829e66475f0a4a26938c4b04c21baede6262215b8"
dependencies = [
"memchr",
]
[[package]] [[package]]
name = "winreg" name = "winreg"
version = "0.50.0" version = "0.50.0"

View file

@ -47,6 +47,7 @@ clap = { version = "4.5.4", default-features = false }
chrono = { version = "0.4.31", default-features = false } chrono = { version = "0.4.31", default-features = false }
crypto-bigint = { version = "0.5.5", default-features = false } crypto-bigint = { version = "0.5.5", default-features = false }
crossbeam = { version = "0.8.4", default-features = false } crossbeam = { version = "0.8.4", default-features = false }
criterion = { version = "0.5.1", default-features = false }
curve25519-dalek = { version = "4.1.1", default-features = false } curve25519-dalek = { version = "4.1.1", default-features = false }
dalek-ff-group = { git = "https://github.com/Cuprate/serai.git", rev = "347d4cf", default-features = false } dalek-ff-group = { git = "https://github.com/Cuprate/serai.git", rev = "347d4cf", default-features = false }
dirs = { version = "5.0.1", default-features = false } dirs = { version = "5.0.1", default-features = false }

View file

@ -2,7 +2,7 @@
name = "cuprate-database-benchmark" name = "cuprate-database-benchmark"
version = "0.0.0" version = "0.0.0"
edition = "2021" edition = "2021"
description = "Benchmarking binary for Cuprate's database(s)" description = "Benchmarking for Cuprate's database abstraction"
license = "MIT" license = "MIT"
authors = ["hinto-janai"] authors = ["hinto-janai"]
repository = "https://github.com/Cuprate/cuprate/tree/main/database/benchmark" repository = "https://github.com/Cuprate/cuprate/tree/main/database/benchmark"
@ -12,16 +12,12 @@ keywords = ["cuprate", "database", "benchmark"]
default = [] default = []
[dependencies] [dependencies]
anyhow = { workspace = true } criterion = { workspace = true }
cfg-if = { workspace = true } cuprate-database = { path = "../", features = ["default"] }
clap = { workspace = true, features = ["default", "derive", "cargo"] }
cuprate-database = { path = "../", features = ["default", "serde"] }
cuprate-helper = { path = "../../helper", features = ["fs", "thread"] } cuprate-helper = { path = "../../helper", features = ["fs", "thread"] }
serde = { workspace = true, features = ["default", "derive"] } # cuprate-types = { path = "../../types", features = ["service"] }
serde_json = { workspace = true, features = ["default"] } tempfile = { version = "3.10.0" }
strum = { workspace = true, features = ["default", "derive"] }
tracing = { workspace = true }
toml_edit = { workspace = true, features = ["default", "serde"] }
rayon = { workspace = true, optional = true }
[dev-dependencies] [[bench]]
name = "lib"
harness = false

View file

@ -0,0 +1,204 @@
//! TODO
//---------------------------------------------------------------------------------------------------- Import
use criterion::{black_box, criterion_group, criterion_main, Criterion};
use cuprate_database::{ConcreteEnv, Env, EnvInner, TxRo, TxRw};
use crate::tmp_concrete_env;
//----------------------------------------------------------------------------------------------------
/// [`Env::open`].
fn open(c: &mut Criterion) {
c.bench_function("tmp_concrete_env", |b| b.iter(|| tmp_concrete_env()));
}
/// Create and commit read-only transactions.
fn tx_ro(c: &mut Criterion) {
let (env, _tempdir) = tmp_concrete_env();
let env_inner = env.env_inner();
c.bench_function("tx_ro", |b| {
b.iter(|| {
let tx_ro = env_inner.tx_ro().unwrap();
TxRo::commit(tx_ro).unwrap();
})
});
}
/// Create and commit read/write transactions.
fn tx_rw(c: &mut Criterion) {
let (env, _tempdir) = tmp_concrete_env();
let env_inner = env.env_inner();
c.bench_function("tx_rw", |b| {
b.iter(|| {
let tx_rw = env_inner.tx_rw().unwrap();
TxRw::commit(tx_rw).unwrap();
})
});
}
/// Open all database tables in read-only mode.
fn open_tables(c: &mut Criterion) {
let (env, _tempdir) = tmp_concrete_env();
let env_inner = env.env_inner();
let tx_ro = env_inner.tx_ro().unwrap();
c.bench_function("open_tables", |b| {
b.iter(|| {
env_inner.open_tables(&tx_ro).unwrap();
})
});
}
/// Open all database tables in read/write mode.
fn open_tables_mut(c: &mut Criterion) {
let (env, _tempdir) = tmp_concrete_env();
let env_inner = env.env_inner();
let mut tx_rw = env_inner.tx_ro().unwrap();
c.bench_function("open_tables_mut", |b| {
b.iter(|| {
env_inner.open_tables_mut(&mut tx_rw).unwrap();
})
});
}
/// Test `Env` resizes.
#[test]
fn resize() {
// This test is only valid for `Env`'s that need to resize manually.
if !ConcreteEnv::MANUAL_RESIZE {
return;
}
let (env, _tempdir) = tmp_concrete_env();
// Resize by the OS page size.
let page_size = crate::resize::page_size();
let old_size = env.current_map_size();
env.resize_map(Some(ResizeAlgorithm::FixedBytes(page_size)));
// Assert it resized exactly by the OS page size.
let new_size = env.current_map_size();
assert_eq!(new_size, old_size + page_size.get());
}
/// Test that `Env`'s that don't manually resize.
#[test]
#[should_panic = "unreachable"]
fn non_manual_resize_1() {
if ConcreteEnv::MANUAL_RESIZE {
unreachable!();
} else {
let (env, _tempdir) = tmp_concrete_env();
env.resize_map(None);
}
}
#[test]
#[should_panic = "unreachable"]
fn non_manual_resize_2() {
if ConcreteEnv::MANUAL_RESIZE {
unreachable!();
} else {
let (env, _tempdir) = tmp_concrete_env();
env.current_map_size();
}
}
/// Test all `DatabaseR{o,w}` operations.
#[test]
fn db_read_write() {
let (env, _tempdir) = tmp_concrete_env();
let env_inner = env.env_inner();
let mut tx_rw = env_inner.tx_rw().unwrap();
let mut table = env_inner.open_db_rw::<Outputs>(&mut tx_rw).unwrap();
/// 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,
};
/// Assert 2 `Output`'s are equal, and that accessing
/// their fields don't result in an unaligned panic.
fn assert_same(output: Output) {
assert_eq!(output, VALUE);
assert_eq!(output.key, VALUE.key);
assert_eq!(output.height, VALUE.height);
assert_eq!(output.output_flags, VALUE.output_flags);
assert_eq!(output.tx_idx, VALUE.tx_idx);
}
// Insert `0..100` keys.
let mut key = KEY;
for i in 0..100 {
table.put(&key, &VALUE).unwrap();
key.amount += 1;
}
// Assert the 1st key is there.
{
let value: Output = table.get(&KEY).unwrap();
assert_same(value);
}
// Assert the whole range is there.
{
let range = table.get_range(..).unwrap();
let mut i = 0;
for result in range {
let value: Output = result.unwrap();
assert_same(value);
i += 1;
}
assert_eq!(i, 100);
}
// `get_range()` tests.
let mut key = KEY;
key.amount += 100;
let range = KEY..key;
// Assert count is correct.
assert_eq!(100, table.get_range(range.clone()).unwrap().count());
// Assert each returned value from the iterator is owned.
{
let mut iter = table.get_range(range.clone()).unwrap();
let value: Output = iter.next().unwrap().unwrap(); // 1. take value out
drop(iter); // 2. drop the `impl Iterator + 'a`
assert_same(value); // 3. assert even without the iterator, the value is alive
}
// Assert each value is the same.
{
let mut iter = table.get_range(range).unwrap();
for _ in 0..100 {
let value: Output = iter.next().unwrap().unwrap();
assert_same(value);
}
}
// Assert deleting works.
table.delete(&KEY).unwrap();
let value = table.get(&KEY);
assert!(matches!(value, Err(RuntimeError::KeyNotFound)));
}
pub fn criterion_benchmark(c: &mut Criterion) {
c.bench_function("fib 20", |b| b.iter(|| fibonacci(black_box(20))));
}
criterion_group!(benches, criterion_benchmark);
criterion_main!(benches);

View file

@ -0,0 +1,88 @@
//! 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))]
use criterion::criterion_main;
mod env;
criterion_main! {
env::benches,
}

View file

@ -1,141 +0,0 @@
//! TODO
//---------------------------------------------------------------------------------------------------- Import
use std::{
borrow::Cow,
collections::BTreeSet,
path::{Path, PathBuf},
time::Instant,
};
use serde::{Deserialize, Serialize};
use strum::{
Display, EnumCount, EnumIs, EnumIter, EnumString, IntoStaticStr, VariantArray, VariantIterator,
};
use cuprate_database::ConcreteEnv;
use crate::config::Config;
//---------------------------------------------------------------------------------------------------- TODO
/// TODO
#[derive(
Clone,
Copy,
PartialEq,
PartialOrd,
Ord,
Eq,
Serialize,
Deserialize,
Debug,
Hash,
Display,
EnumCount,
EnumIs,
EnumIter,
EnumString,
IntoStaticStr,
VariantArray,
)]
pub(crate) enum Benchmark {
/// Maps to [`env_open`].
EnvOpen,
}
impl Benchmark {
/// Map [`Benchmark`] to the proper benchmark function.
#[inline(always)]
fn benchmark_fn(self) -> fn(&ConcreteEnv) {
match self {
Self::EnvOpen => env_open,
}
}
}
//---------------------------------------------------------------------------------------------------- Stats
/// TODO
#[derive(Clone, Copy, PartialEq, PartialOrd, Serialize, Deserialize, Debug)]
struct Stats {
/// Timings for [`env_open`].
env_open: Option<f32>,
}
impl Stats {
/// Create a new [`Stats`] with no benchmark timings.
const fn new() -> Self {
Self { env_open: None }
}
/// This maps [`Benchmark`]s to a specific field in [`Stats`]
/// which then gets updated to the passed `time`.
#[inline(always)]
fn update_benchmark_time(&mut self, benchmark: Benchmark, time: f32) {
*match benchmark {
Benchmark::EnvOpen => &mut self.env_open,
} = Some(time);
}
}
//---------------------------------------------------------------------------------------------------- TODO
/// TODO
pub(crate) struct Benchmarker {
/// TODO
env: ConcreteEnv,
/// TODO
config: Config,
/// TODO
stats: Stats,
}
//---------------------------------------------------------------------------------------------------- Drop
impl Drop for Benchmarker {
fn drop(&mut self) {
let stats_json = serde_json::to_string_pretty(&self.stats).unwrap();
println!("{stats_json}");
}
}
//---------------------------------------------------------------------------------------------------- Impl
impl Benchmarker {
/// TODO
#[cold]
#[inline(never)]
pub(crate) const fn new(env: ConcreteEnv, config: Config) -> Self {
Self {
env,
config,
stats: Stats::new(),
}
}
/// Start all benchmark that are selected by the user.
/// `main()` calls this once.
#[cold]
#[inline(never)]
pub(crate) fn bench_all(mut self) {
for benchmark in &self.config.benchmark_set {
bench(*benchmark, &self.env, &mut self.stats);
}
}
}
//---------------------------------------------------------------------------------------------------- Benchmark functions
/// TODO
#[inline(always)]
fn bench(benchmark: Benchmark, env: &ConcreteEnv, stats: &mut Stats) {
// Start the benchmark timer.
let instant = Instant::now();
// Benchmark.
benchmark.benchmark_fn()(env);
// Update the time.
stats.update_benchmark_time(benchmark, instant.elapsed().as_secs_f32());
}
/// TODO
#[inline(always)]
fn env_open(env: &ConcreteEnv) {
println!("TODO");
}

View file

@ -1,147 +0,0 @@
//! Command line argument parsing and handling.
//---------------------------------------------------------------------------------------------------- Use
use std::path::PathBuf;
use clap::{crate_name, Args, Parser, Subcommand};
use cuprate_helper::fs::cuprate_database_dir;
use crate::config::Config;
//---------------------------------------------------------------------------------------------------- Constants
//---------------------------------------------------------------------------------------------------- CLI Parser (clap)
/// `struct` encompassing all possible CLI argument values.
///
/// This gets called by `main()` once, at the very beginning and is responsible for:
/// - parsing/validating input values
/// - routing certain `--flags` to function paths (and exiting)
/// - possibly handing `Config` back off to `main()` for continued execution
#[derive(Clone, Default, PartialEq, Eq, PartialOrd, Ord, Parser)]
#[allow(clippy::struct_excessive_bools)]
pub struct Cli {
//------------------------------------------------------------------------------ Config options
/// Set filter level for console logs.
#[arg(
long,
value_name = "OFF|ERROR|INFO|WARN|DEBUG|TRACE",
verbatim_doc_comment
)]
pub(crate) log_level: Option<String>, // FIXME: tracing::Level{Filter} doesn't work with clap?
/// TODO
#[arg(long, value_name = "PATH", verbatim_doc_comment)]
pub(crate) config: Option<PathBuf>,
/// TODO
#[arg(long, value_name = "PATH", verbatim_doc_comment)]
pub(crate) db_config: Option<PathBuf>,
//------------------------------------------------------------------------------ Early Return
// These are flags that do something then immediately return.
//
// Regardless of other flags provided, these will force a return.
#[arg(long, verbatim_doc_comment)]
/// Print the configuration `cuprate-database-benchmark`
/// would have used, but don't actually startup.
///
/// This will go through the regular process of:
/// - Reading command-line
/// - Reading disk for config
///
/// and then print the config out as TOML, and exit.
pub(crate) dry_run: bool,
#[arg(long, verbatim_doc_comment)]
/// Print the PATH used by `cuprate-database`.
pub(crate) path: bool,
#[arg(long, verbatim_doc_comment)]
/// Delete all `cuprated-database` files that are on disk.
///
/// This deletes the PATH returned by `--path`, aka, the
/// directory that stores all database related files.
pub(crate) delete: bool,
#[arg(short, long)]
/// Print various stats and exit.
pub(crate) version: bool,
}
//---------------------------------------------------------------------------------------------------- CLI default
// impl Default for Cli {
// fn default() -> Self {
// Self {
// log_level: None,
// db_config: None,
// dry_run: false,
// path: false,
// delete: false,
// version: false,
// }
// }
// }
//---------------------------------------------------------------------------------------------------- CLI argument handling
impl Cli {
/// `main()` calls this once.
pub fn init() -> Self {
match Self::parse().handle_args() {
Ok(cli) => cli,
Err(exit_code) => std::process::exit(exit_code),
}
}
/// Handle all the values, routing code, and exiting early if needed.
///
/// The order of the `if`'s are the precedence of the `--flags`'s
/// themselves, e.g `--version` will execute over all else.
fn handle_args(self) -> Result<Self, i32> {
// TODO:
// Calling `exit()` on each branch could
// be replaced with something better,
// although exit codes must be maintained.
//-------------------------------------------------- Version.
if self.version {
todo!();
return Err(0);
}
//-------------------------------------------------- Path.
if self.path {
let path = cuprate_database_dir();
println!("{}", path.display());
return Err(0);
}
//-------------------------------------------------- Delete.
if self.delete {
let path = cuprate_database_dir();
if path.exists() {
println!(
"{}: PATH does not exist '{}'",
crate_name!(),
path.display()
);
return Err(0);
}
match std::fs::remove_dir_all(path) {
Ok(()) => {
println!("{}: deleted '{}'", crate_name!(), path.display());
return Err(0);
}
Err(e) => {
eprintln!("{} error: {} - {e}", crate_name!(), path.display());
return Err(1);
}
}
}
//-------------------------------------------------- Return `Config` to `main()`
Ok(self)
}
}

View file

@ -1,44 +0,0 @@
//! TODO
//---------------------------------------------------------------------------------------------------- Import
use std::{
borrow::Cow,
collections::BTreeSet,
path::{Path, PathBuf},
};
use serde::{Deserialize, Serialize};
use strum::IntoEnumIterator;
use crate::{bench::Benchmark, cli::Cli};
//---------------------------------------------------------------------------------------------------- Config
/// TODO
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Serialize, Deserialize)]
pub(crate) struct Config {
/// TODO
pub(crate) iterations: usize,
/// TODO
pub(crate) benchmark_set: BTreeSet<Benchmark>,
}
impl Config {
/// Create a new [`Config`] with sane default settings.
pub(crate) fn new() -> Self {
Self {
iterations: 100_000,
benchmark_set: Benchmark::iter().collect(),
}
}
/// TODO
pub(crate) fn merge(&mut self, cli: &Cli) {
todo!()
}
}
impl Default for Config {
fn default() -> Self {
Self::new()
}
}

View file

@ -1,10 +0,0 @@
//! General constants used throughout `cuprate-database`.
//---------------------------------------------------------------------------------------------------- Import
use cfg_if::cfg_if;
//---------------------------------------------------------------------------------------------------- Error Messages
//---------------------------------------------------------------------------------------------------- Tests
#[cfg(test)]
mod test {}

View file

@ -1,13 +0,0 @@
//! General free functions (related to the database).
//!
//! TODO.
//---------------------------------------------------------------------------------------------------- Import
//---------------------------------------------------------------------------------------------------- Free functions
//---------------------------------------------------------------------------------------------------- Tests
#[cfg(test)]
mod test {
// use super::*;
}

View file

@ -0,0 +1,20 @@
//! 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_concrete_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)
}

View file

@ -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_concrete_env;

View file

@ -1,129 +0,0 @@
//! `cuprate-database` testing & benchmarking binary.
//---------------------------------------------------------------------------------------------------- Lints
// Forbid lints.
// Our code, and code generated (e.g macros) cannot overrule these.
#![deny(
clippy::all,
clippy::correctness,
clippy::suspicious,
clippy::style,
clippy::complexity,
clippy::perf,
clippy::pedantic,
clippy::nursery,
clippy::cargo,
clippy::undocumented_unsafe_blocks,
unused_unsafe,
redundant_semicolons,
unused_allocation,
coherence_leak_check,
while_true,
clippy::missing_docs_in_private_items,
unconditional_recursion,
for_loops_over_fallibles,
unused_doc_comments,
unused_labels,
keyword_idents,
non_ascii_idents,
variant_size_differences,
single_use_lifetimes,
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,
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::inline_always,
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))]
//---------------------------------------------------------------------------------------------------- Public API
// Import private modules, export public types.
//
// Documentation for each module is located in the respective file.
mod bench;
mod cli;
mod config;
mod constants;
mod free;
//---------------------------------------------------------------------------------------------------- Private
//---------------------------------------------------------------------------------------------------- Import
use cuprate_database::Env;
use crate::{cli::Cli, config::Config};
//---------------------------------------------------------------------------------------------------- Main
fn main() {
// Handle CLI arguments.
let cli: Cli = if std::env::args_os().len() > 1 {
// Some arguments were passed, run all the `clap` code.
Cli::init()
} else {
// No arguments were passed, use the default.
Cli::default()
};
// Load the benchmark config.
let config = if let Some(path) = cli.config.as_ref() {
let bytes = std::fs::read(path).unwrap();
let mut disk: Config = toml_edit::de::from_slice(&bytes).unwrap();
disk.merge(&cli);
disk
} else {
Config::new()
};
// Load the database config.
let db_config = if let Some(path) = cli.db_config {
let bytes = std::fs::read(path).unwrap();
toml_edit::de::from_slice(&bytes).unwrap()
} else {
cuprate_database::config::Config::new(None)
};
// Print config before starting.
eprintln!("cuprate-database-benchmark configuration:\n{config:#?}");
// If `dry_run`, exit cleanly.
if cli.dry_run {
std::process::exit(0);
}
// Create database.
let env = cuprate_database::ConcreteEnv::open(db_config).unwrap();
// Start benchmarking/tests.
let mut benchmarker = crate::bench::Benchmarker::new(env, todo!());
benchmarker.bench_all();
}