mirror of
https://github.com/hinto-janai/cuprate.git
synced 2024-12-23 03:59:37 +00:00
Merge branch 'blockchain-benches' into criterion
This commit is contained in:
commit
7b31745db3
8 changed files with 287 additions and 0 deletions
15
Cargo.lock
generated
15
Cargo.lock
generated
|
@ -820,6 +820,21 @@ dependencies = [
|
|||
"function_name",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cuprate-criterion-blockchain"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"criterion",
|
||||
"cuprate-blockchain",
|
||||
"cuprate-helper",
|
||||
"cuprate-test-utils",
|
||||
"cuprate-types",
|
||||
"function_name",
|
||||
"rand",
|
||||
"serde_json",
|
||||
"tempfile",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cuprate-criterion-example"
|
||||
version = "0.0.0"
|
||||
|
|
|
@ -14,6 +14,7 @@ members = [
|
|||
"benches/criterion/cuprate-database",
|
||||
"benches/criterion/cuprate-cryptonight",
|
||||
"benches/criterion/cuprate-rpc-types",
|
||||
"benches/criterion/cuprate-blockchain",
|
||||
|
||||
# Consensus
|
||||
"consensus",
|
||||
|
|
28
benches/criterion/cuprate-blockchain/Cargo.toml
Normal file
28
benches/criterion/cuprate-blockchain/Cargo.toml
Normal file
|
@ -0,0 +1,28 @@
|
|||
[package]
|
||||
name = "cuprate-criterion-blockchain"
|
||||
version = "0.0.0"
|
||||
edition = "2021"
|
||||
description = "Criterion benchmarking for cuprate-blockchain"
|
||||
license = "MIT"
|
||||
authors = ["hinto-janai"]
|
||||
repository = "https://github.com/Cuprate/cuprate/tree/main/benches/criterion/cuprate-blockchain"
|
||||
keywords = ["cuprate", "blockchain", "criterion", "benchmark"]
|
||||
|
||||
[dependencies]
|
||||
cuprate-blockchain = { path = "../../../storage/blockchain" }
|
||||
cuprate-test-utils = { path = "../../../test-utils" }
|
||||
cuprate-types = { path = "../../../types", default-features = false }
|
||||
cuprate-helper = { path = "../../../helper", features = ["cast"] }
|
||||
|
||||
criterion = { workspace = true }
|
||||
function_name = { workspace = true }
|
||||
serde_json = { workspace = true, features = ["default"] }
|
||||
tempfile = { workspace = true }
|
||||
rand = { workspace = true }
|
||||
|
||||
[[bench]]
|
||||
name = "main"
|
||||
harness = false
|
||||
|
||||
[lints]
|
||||
workspace = true
|
140
benches/criterion/cuprate-blockchain/benches/block.rs
Normal file
140
benches/criterion/cuprate-blockchain/benches/block.rs
Normal file
|
@ -0,0 +1,140 @@
|
|||
//! Benchmarks for [`block`] and [`alt_block`] functions.
|
||||
|
||||
#![allow(unused_attributes, unused_crate_dependencies)]
|
||||
|
||||
use std::{num::NonZeroU64, time::Instant};
|
||||
|
||||
use criterion::{black_box, criterion_group, criterion_main, Criterion};
|
||||
use cuprate_helper::cast::usize_to_u64;
|
||||
use function_name::named;
|
||||
|
||||
use cuprate_blockchain::{
|
||||
cuprate_database::{Env, EnvInner},
|
||||
ops::{alt_block, block},
|
||||
tables::OpenTables,
|
||||
};
|
||||
use cuprate_test_utils::data::{BLOCK_V16_TX0, BLOCK_V1_TX2, BLOCK_V9_TX3};
|
||||
use cuprate_types::{AltBlockInformation, ChainId, VerifiedBlockInformation};
|
||||
|
||||
use cuprate_criterion_blockchain::generate_fake_blocks;
|
||||
|
||||
criterion_group! {
|
||||
name = benches;
|
||||
config = Criterion::default();
|
||||
targets =
|
||||
add_block_v1_tx2,
|
||||
add_block_v9_tx3,
|
||||
add_block_v16_tx0,
|
||||
add_alt_block_v1_tx2,
|
||||
add_alt_block_v9_tx3,
|
||||
add_alt_block_v16_tx0,
|
||||
}
|
||||
criterion_main!(benches);
|
||||
|
||||
/// Inner function for benchmarking [`block::add_block`].
|
||||
#[expect(clippy::significant_drop_tightening)]
|
||||
fn add_block_inner(c: &mut Criterion, function_name: &str, block: &VerifiedBlockInformation) {
|
||||
let env = cuprate_criterion_blockchain::TmpEnv::new();
|
||||
|
||||
c.bench_function(function_name, |b| {
|
||||
// We use `iter_custom` because we need to generate an
|
||||
// appropriate amount of blocks and only time the `add_block`.
|
||||
b.iter_custom(|count| {
|
||||
let blocks = black_box(generate_fake_blocks(block, count));
|
||||
|
||||
let env_inner = env.env.env_inner();
|
||||
let tx_rw = env_inner.tx_rw().unwrap();
|
||||
let mut tables = env_inner.open_tables_mut(&tx_rw).unwrap();
|
||||
|
||||
let start = Instant::now();
|
||||
for block in &blocks {
|
||||
let block = black_box(block);
|
||||
black_box(block::add_block(block, &mut tables)).unwrap();
|
||||
}
|
||||
start.elapsed()
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
#[named]
|
||||
fn add_block_v1_tx2(c: &mut Criterion) {
|
||||
add_block_inner(c, function_name!(), &BLOCK_V1_TX2);
|
||||
}
|
||||
|
||||
#[named]
|
||||
fn add_block_v9_tx3(c: &mut Criterion) {
|
||||
add_block_inner(c, function_name!(), &BLOCK_V9_TX3);
|
||||
}
|
||||
|
||||
#[named]
|
||||
fn add_block_v16_tx0(c: &mut Criterion) {
|
||||
add_block_inner(c, function_name!(), &BLOCK_V16_TX0);
|
||||
}
|
||||
|
||||
/// Inner function for benchmarking [`alt_block::add_alt_block`].
|
||||
#[expect(clippy::significant_drop_tightening)]
|
||||
fn add_alt_block_inner(c: &mut Criterion, function_name: &str, block: &VerifiedBlockInformation) {
|
||||
let env = cuprate_criterion_blockchain::TmpEnv::new();
|
||||
|
||||
// We must have at least 1 block or else `add_alt_block` will panic.
|
||||
{
|
||||
let env_inner = env.env.env_inner();
|
||||
let tx_rw = env_inner.tx_rw().unwrap();
|
||||
let mut tables = env_inner.open_tables_mut(&tx_rw).unwrap();
|
||||
|
||||
let mut block = BLOCK_V1_TX2.clone();
|
||||
block.height = 0;
|
||||
|
||||
block::add_block(&block, &mut tables).unwrap();
|
||||
}
|
||||
|
||||
c.bench_function(function_name, |b| {
|
||||
// We use `iter_custom` because we need to generate an
|
||||
// appropriate amount of blocks and only time the `add_block`.
|
||||
b.iter_custom(|count| {
|
||||
// Map the block to a fake alt block.
|
||||
let blocks = generate_fake_blocks(block, count)
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
.map(|(i, b)| AltBlockInformation {
|
||||
block: b.block,
|
||||
block_blob: b.block_blob,
|
||||
txs: b.txs,
|
||||
block_hash: b.block_hash,
|
||||
pow_hash: b.pow_hash,
|
||||
height: b.height + 1,
|
||||
weight: b.weight,
|
||||
long_term_weight: b.long_term_weight,
|
||||
cumulative_difficulty: b.cumulative_difficulty,
|
||||
chain_id: ChainId(NonZeroU64::new(usize_to_u64(i) + 1).unwrap()),
|
||||
})
|
||||
.collect::<Vec<AltBlockInformation>>();
|
||||
|
||||
let env_inner = env.env.env_inner();
|
||||
let tx_rw = env_inner.tx_rw().unwrap();
|
||||
let mut tables = env_inner.open_tables_mut(&tx_rw).unwrap();
|
||||
|
||||
let start = Instant::now();
|
||||
for block in &blocks {
|
||||
let block = black_box(block);
|
||||
black_box(alt_block::add_alt_block(block, &mut tables)).unwrap();
|
||||
}
|
||||
start.elapsed()
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
#[named]
|
||||
fn add_alt_block_v1_tx2(c: &mut Criterion) {
|
||||
add_alt_block_inner(c, function_name!(), &BLOCK_V1_TX2);
|
||||
}
|
||||
|
||||
#[named]
|
||||
fn add_alt_block_v9_tx3(c: &mut Criterion) {
|
||||
add_alt_block_inner(c, function_name!(), &BLOCK_V9_TX3);
|
||||
}
|
||||
|
||||
#[named]
|
||||
fn add_alt_block_v16_tx0(c: &mut Criterion) {
|
||||
add_alt_block_inner(c, function_name!(), &BLOCK_V16_TX0);
|
||||
}
|
7
benches/criterion/cuprate-blockchain/benches/main.rs
Normal file
7
benches/criterion/cuprate-blockchain/benches/main.rs
Normal file
|
@ -0,0 +1,7 @@
|
|||
#![allow(unused_crate_dependencies)]
|
||||
|
||||
mod block;
|
||||
|
||||
criterion::criterion_main! {
|
||||
block::benches,
|
||||
}
|
36
benches/criterion/cuprate-blockchain/src/blocks.rs
Normal file
36
benches/criterion/cuprate-blockchain/src/blocks.rs
Normal file
|
@ -0,0 +1,36 @@
|
|||
use rand::Rng;
|
||||
|
||||
use cuprate_helper::cast::u64_to_usize;
|
||||
use cuprate_types::VerifiedBlockInformation;
|
||||
|
||||
/// Generate fake [`VerifiedBlockInformation`]s.
|
||||
///
|
||||
/// This function generates fake blocks,
|
||||
/// cloning the `base` block `count` amount of times,
|
||||
/// starting at height `0` and sequentially incrementing,
|
||||
/// i.e. block height `{0,1,2,...}`.
|
||||
///
|
||||
/// Each block has a random [`VerifiedBlockInformation::block_hash`].
|
||||
///
|
||||
/// # Hack
|
||||
/// This is used for these benchmarks because
|
||||
/// [`cuprate_blockchain::ops::block::add_block`]
|
||||
/// asserts that blocks with non-sequential heights cannot be added.
|
||||
/// To get around this, we manually edit the block heights.
|
||||
///
|
||||
/// The hash must also be faked as
|
||||
/// [`cuprate_blockchain::ops::blockchain::chain_height`]
|
||||
/// which is used for an [`assert`] relies on the `hash -> height` table.
|
||||
pub fn generate_fake_blocks(
|
||||
base: &VerifiedBlockInformation,
|
||||
count: u64,
|
||||
) -> Vec<VerifiedBlockInformation> {
|
||||
(0..count)
|
||||
.map(|height| {
|
||||
let mut block = base.clone();
|
||||
block.height = u64_to_usize(height);
|
||||
block.block_hash = rand::thread_rng().r#gen();
|
||||
block
|
||||
})
|
||||
.collect()
|
||||
}
|
7
benches/criterion/cuprate-blockchain/src/lib.rs
Normal file
7
benches/criterion/cuprate-blockchain/src/lib.rs
Normal file
|
@ -0,0 +1,7 @@
|
|||
#![allow(unused_crate_dependencies, reason = "used in benchmarks")]
|
||||
|
||||
mod blocks;
|
||||
mod tmp_env;
|
||||
|
||||
pub use blocks::generate_fake_blocks;
|
||||
pub use tmp_env::TmpEnv;
|
53
benches/criterion/cuprate-blockchain/src/tmp_env.rs
Normal file
53
benches/criterion/cuprate-blockchain/src/tmp_env.rs
Normal file
|
@ -0,0 +1,53 @@
|
|||
//! An [`Env`] inside a [`TempDir`].
|
||||
|
||||
use tempfile::TempDir;
|
||||
|
||||
use cuprate_blockchain::{
|
||||
config::ReaderThreads,
|
||||
cuprate_database::{config::ConfigBuilder, resize::PAGE_SIZE, ConcreteEnv, Env},
|
||||
};
|
||||
|
||||
/// 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 db_config = ConfigBuilder::new(path).low_power().build();
|
||||
let reader_threads = ReaderThreads::One;
|
||||
let config = cuprate_blockchain::config::Config {
|
||||
db_config,
|
||||
reader_threads,
|
||||
};
|
||||
let env = cuprate_blockchain::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 }
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue