feat: set up codspeed (#13372)

This commit is contained in:
DaniPopes
2024-12-20 13:21:51 +02:00
committed by GitHub
parent 3966130844
commit a4f86b0e2d
34 changed files with 318 additions and 398 deletions

23
.github/scripts/codspeed-build.sh vendored Executable file
View File

@ -0,0 +1,23 @@
#!/usr/bin/env bash
set -eo pipefail
# TODO: Benchmarks run WAY too slow due to excessive amount of iterations.
cmd=(cargo codspeed build --profile profiling)
excludes=(
# Unnecessary
--exclude reth-libmdbx
# Build is too slow
--exclude reth-network
# Built separately
--exclude reth-transaction-pool
# TODO: some benchmarks panic: https://github.com/paradigmxyz/reth/actions/runs/12307046814/job/34349955788
--exclude reth-db
--exclude reth-trie-parallel
--exclude reth-engine-tree
)
"${cmd[@]}" --features test-utils --workspace "${excludes[@]}"
# TODO: Slow benchmarks due to too many iterations
## "${cmd[@]}" -p reth-transaction-pool --features test-utils,arbitrary

View File

@ -1,4 +1,4 @@
# Runs benchmarks on serialization/deserialization of storage values and keys. # Runs benchmarks.
on: on:
pull_request: pull_request:
@ -9,7 +9,6 @@ on:
env: env:
CARGO_TERM_COLOR: always CARGO_TERM_COLOR: always
BASELINE: base BASELINE: base
IAI_CALLGRIND_RUNNER: iai-callgrind-runner
concurrency: concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
@ -17,47 +16,26 @@ concurrency:
name: bench name: bench
jobs: jobs:
iai: codspeed:
runs-on: runs-on:
group: Reth group: Reth
# Only run benchmarks in merge groups and on main
if: github.event_name != 'pull_request'
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: Install Valgrind with:
run: sudo apt update && sudo apt install valgrind submodules: true
- uses: rui314/setup-mold@v1
- uses: dtolnay/rust-toolchain@stable - uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2 - uses: Swatinem/rust-cache@v2
with: with:
cache-on-failure: true cache-on-failure: true
- name: Install cargo-binstall - name: Install cargo-codspeed
uses: taiki-e/install-action@cargo-binstall uses: taiki-e/install-action@v2
- name: Install iai-callgrind-runner
run: |
echo "::group::Install"
version=$(cargo metadata --format-version=1 |\
jq '.packages[] | select(.name == "iai-callgrind").version' |\
tr -d '"'
)
cargo binstall iai-callgrind-runner --version $version --no-confirm --no-symlinks --force
echo "::endgroup::"
echo "::group::Verification"
which iai-callgrind-runner
echo "::endgroup::"
- name: Checkout base
uses: actions/checkout@v4
with: with:
ref: ${{ github.base_ref || 'main' }} tool: cargo-codspeed
# On `main` branch, generates test vectors and serializes them to disk using `serde-json`. - name: Build the benchmark target(s)
- name: Generate test vectors run: ./.github/scripts/codspeed-build.sh
run: cargo run --bin reth --features dev -- test-vectors tables - name: Run the benchmarks
# Runs iai and stores `main` baseline report for comparison later on $BASELINE. uses: CodSpeedHQ/action@v3
- name: Save baseline
run: cargo bench -p reth-db --bench iai --profile profiling --features test-utils -- --save-baseline=$BASELINE
- name: Checkout PR
uses: actions/checkout@v4
with: with:
clean: false run: cargo codspeed run --workspace
# Runs iai on incoming merge using previously generated test-vectors and compares the report against `main` report. token: ${{ secrets.CODSPEED_TOKEN }}
- name: Compare PR benchmarks
run: cargo bench -p reth-db --bench iai --profile profiling --features test-utils -- --baseline=$BASELINE

2
.gitignore vendored
View File

@ -19,7 +19,7 @@ target/
testdata/micro/db testdata/micro/db
# Generated data for stage benchmarks # Generated data for stage benchmarks
crates/stages/testdata crates/stages/stages/testdata
# Prometheus data dir # Prometheus data dir
data/ data/

93
Cargo.lock generated
View File

@ -1843,6 +1843,30 @@ version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "afb84c814227b90d6895e01398aee0d8033c00e7466aca416fb6a8e0eb19d8a7" checksum = "afb84c814227b90d6895e01398aee0d8033c00e7466aca416fb6a8e0eb19d8a7"
[[package]]
name = "codspeed"
version = "2.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "450a0e9df9df1c154156f4344f99d8f6f6e69d0fc4de96ef6e2e68b2ec3bce97"
dependencies = [
"colored",
"libc",
"serde_json",
]
[[package]]
name = "codspeed-criterion-compat"
version = "2.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8eb1a6cb9c20e177fde58cdef97c1c7c9264eb1424fe45c4fccedc2fb078a569"
dependencies = [
"codspeed",
"colored",
"criterion",
"futures",
"tokio",
]
[[package]] [[package]]
name = "coins-bip32" name = "coins-bip32"
version = "0.12.0" version = "0.12.0"
@ -1900,6 +1924,16 @@ version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990"
[[package]]
name = "colored"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cbf2150cce219b664a8a70df7a1f933836724b503f8a413af9365b4dcc4d90b8"
dependencies = [
"lazy_static",
"windows-sys 0.48.0",
]
[[package]] [[package]]
name = "combine" name = "combine"
version = "4.6.7" version = "4.6.7"
@ -3934,42 +3968,6 @@ dependencies = [
"tracing", "tracing",
] ]
[[package]]
name = "iai-callgrind"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22275f8051874cd2f05b2aa1e0098d5cbec34df30ff92f1a1e2686a4cefed870"
dependencies = [
"bincode",
"derive_more",
"iai-callgrind-macros",
"iai-callgrind-runner",
]
[[package]]
name = "iai-callgrind-macros"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e8e6677dc52bd798b988e62ffd6831bf7eb46e4348cb1c74c1164954ebd0e5a1"
dependencies = [
"derive_more",
"proc-macro-error2",
"proc-macro2",
"quote",
"serde",
"serde_json",
"syn 2.0.90",
]
[[package]]
name = "iai-callgrind-runner"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a02dd95fe4949513b45a328b5b18f527ee02e96f3428b48090aa7cf9043ab0b8"
dependencies = [
"serde",
]
[[package]] [[package]]
name = "iana-time-zone" name = "iana-time-zone"
version = "0.1.61" version = "0.1.61"
@ -6998,10 +6996,9 @@ dependencies = [
"arbitrary", "arbitrary",
"assert_matches", "assert_matches",
"bytes", "bytes",
"criterion", "codspeed-criterion-compat",
"derive_more", "derive_more",
"eyre", "eyre",
"iai-callgrind",
"metrics", "metrics",
"page_size", "page_size",
"parking_lot", "parking_lot",
@ -7391,7 +7388,7 @@ dependencies = [
"alloy-rlp", "alloy-rlp",
"alloy-rpc-types-engine", "alloy-rpc-types-engine",
"assert_matches", "assert_matches",
"criterion", "codspeed-criterion-compat",
"crossbeam-channel", "crossbeam-channel",
"derive_more", "derive_more",
"futures", "futures",
@ -7912,7 +7909,7 @@ version = "1.1.4"
dependencies = [ dependencies = [
"bitflags 2.6.0", "bitflags 2.6.0",
"byteorder", "byteorder",
"criterion", "codspeed-criterion-compat",
"dashmap 6.1.0", "dashmap 6.1.0",
"derive_more", "derive_more",
"indexmap 2.6.0", "indexmap 2.6.0",
@ -7979,7 +7976,7 @@ dependencies = [
"alloy-rlp", "alloy-rlp",
"aquamarine", "aquamarine",
"auto_impl", "auto_impl",
"criterion", "codspeed-criterion-compat",
"derive_more", "derive_more",
"discv5", "discv5",
"enr", "enr",
@ -8762,7 +8759,7 @@ dependencies = [
"bincode", "bincode",
"bytes", "bytes",
"c-kzg", "c-kzg",
"criterion", "codspeed-criterion-compat",
"derive_more", "derive_more",
"modular-bitfield", "modular-bitfield",
"once_cell", "once_cell",
@ -9287,7 +9284,7 @@ dependencies = [
"alloy-rlp", "alloy-rlp",
"assert_matches", "assert_matches",
"bincode", "bincode",
"criterion", "codspeed-criterion-compat",
"futures-util", "futures-util",
"itertools 0.13.0", "itertools 0.13.0",
"num-traits", "num-traits",
@ -9514,7 +9511,7 @@ dependencies = [
"assert_matches", "assert_matches",
"auto_impl", "auto_impl",
"bitflags 2.6.0", "bitflags 2.6.0",
"criterion", "codspeed-criterion-compat",
"futures-util", "futures-util",
"metrics", "metrics",
"parking_lot", "parking_lot",
@ -9560,7 +9557,7 @@ dependencies = [
"alloy-rlp", "alloy-rlp",
"alloy-trie", "alloy-trie",
"auto_impl", "auto_impl",
"criterion", "codspeed-criterion-compat",
"itertools 0.13.0", "itertools 0.13.0",
"metrics", "metrics",
"proptest", "proptest",
@ -9593,7 +9590,7 @@ dependencies = [
"arbitrary", "arbitrary",
"bincode", "bincode",
"bytes", "bytes",
"criterion", "codspeed-criterion-compat",
"derive_more", "derive_more",
"hash-db", "hash-db",
"itertools 0.13.0", "itertools 0.13.0",
@ -9643,7 +9640,7 @@ version = "1.1.4"
dependencies = [ dependencies = [
"alloy-primitives", "alloy-primitives",
"alloy-rlp", "alloy-rlp",
"criterion", "codspeed-criterion-compat",
"derive_more", "derive_more",
"itertools 0.13.0", "itertools 0.13.0",
"metrics", "metrics",
@ -9671,7 +9668,7 @@ dependencies = [
"alloy-rlp", "alloy-rlp",
"arbitrary", "arbitrary",
"assert_matches", "assert_matches",
"criterion", "codspeed-criterion-compat",
"itertools 0.13.0", "itertools 0.13.0",
"pretty_assertions", "pretty_assertions",
"proptest", "proptest",

View File

@ -601,8 +601,7 @@ toml = "0.8"
# misc-testing # misc-testing
arbitrary = "1.3" arbitrary = "1.3"
assert_matches = "1.5.0" assert_matches = "1.5.0"
criterion = "0.5" criterion = { package = "codspeed-criterion-compat", version = "2.7" }
iai-callgrind = "0.14"
pprof = "0.14" pprof = "0.14"
proptest = "1.4" proptest = "1.4"
proptest-derive = "0.5" proptest-derive = "0.5"

View File

@ -77,7 +77,8 @@ test-utils = [
"reth-db-api/test-utils", "reth-db-api/test-utils",
"reth-provider/test-utils", "reth-provider/test-utils",
"reth-trie-db/test-utils", "reth-trie-db/test-utils",
"reth-trie/test-utils" "reth-trie/test-utils",
"reth-trie-parallel/test-utils"
] ]
optimism = [ optimism = [
"reth-primitives/optimism", "reth-primitives/optimism",

View File

@ -120,6 +120,8 @@ test-utils = [
"reth-static-file", "reth-static-file",
"reth-tracing", "reth-tracing",
"reth-trie/test-utils", "reth-trie/test-utils",
"reth-trie-db/test-utils", "reth-trie-sparse/test-utils",
"reth-prune-types?/test-utils", "reth-prune-types?/test-utils",
"reth-trie-db/test-utils",
"reth-trie-parallel/test-utils",
] ]

View File

@ -7,7 +7,7 @@ use revm_primitives::{
Account, AccountInfo, AccountStatus, Address, EvmState, EvmStorage, EvmStorageSlot, HashMap, Account, AccountInfo, AccountStatus, Address, EvmState, EvmStorage, EvmStorageSlot, HashMap,
B256, U256, B256, U256,
}; };
use std::thread; use std::{hint::black_box, thread};
/// Creates a mock state with the specified number of accounts for benchmarking /// Creates a mock state with the specified number of accounts for benchmarking
fn create_bench_state(num_accounts: usize) -> EvmState { fn create_bench_state(num_accounts: usize) -> EvmState {
@ -47,7 +47,7 @@ impl StdStateRootTask {
fn run(self) { fn run(self) {
while let Ok(state) = self.rx.recv() { while let Ok(state) = self.rx.recv() {
criterion::black_box(state); black_box(state);
} }
} }
} }
@ -64,7 +64,7 @@ impl CrossbeamStateRootTask {
fn run(self) { fn run(self) {
while let Ok(state) = self.rx.recv() { while let Ok(state) = self.rx.recv() {
criterion::black_box(state); black_box(state);
} }
} }
} }

View File

@ -3,7 +3,7 @@
#![allow(missing_docs)] #![allow(missing_docs)]
use criterion::{black_box, criterion_group, criterion_main, BenchmarkId, Criterion}; use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion};
use reth_engine_tree::tree::root::{StateRootConfig, StateRootTask}; use reth_engine_tree::tree::root::{StateRootConfig, StateRootTask};
use reth_evm::system_calls::OnStateHook; use reth_evm::system_calls::OnStateHook;
use reth_primitives::{Account as RethAccount, StorageEntry}; use reth_primitives::{Account as RethAccount, StorageEntry};
@ -22,6 +22,7 @@ use revm_primitives::{
Account as RevmAccount, AccountInfo, AccountStatus, Address, EvmState, EvmStorageSlot, HashMap, Account as RevmAccount, AccountInfo, AccountStatus, Address, EvmState, EvmStorageSlot, HashMap,
B256, KECCAK_EMPTY, U256, B256, KECCAK_EMPTY, U256,
}; };
use std::hint::black_box;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
struct BenchParams { struct BenchParams {

View File

@ -975,6 +975,5 @@ mod tests {
&mut dest, &mut dest,
); );
} }
std::hint::black_box(());
} }
} }

View File

@ -69,12 +69,10 @@ fn validate_blob_tx(
// for now we just use the default SubPoolLimit // for now we just use the default SubPoolLimit
group.bench_function(group_id, |b| { group.bench_function(group_id, |b| {
let kzg_settings = kzg_settings.get();
b.iter_with_setup(setup, |(tx, blob_sidecar)| { b.iter_with_setup(setup, |(tx, blob_sidecar)| {
if let Err(err) = let r = tx.validate_blob(&blob_sidecar, kzg_settings);
std::hint::black_box(tx.validate_blob(&blob_sidecar, kzg_settings.get())) (r, tx, blob_sidecar)
{
println!("Validation failed: {err:?}");
}
}); });
}); });
} }

View File

@ -1,11 +1,10 @@
#![allow(missing_docs)] #![allow(missing_docs)]
use criterion::{criterion_main, measurement::WallTime, BenchmarkGroup, Criterion}; #![allow(unexpected_cfgs)]
#[cfg(not(target_os = "windows"))]
use pprof::criterion::{Output, PProfProfiler};
use reth_config::config::{EtlConfig, TransactionLookupConfig};
use reth_db::{test_utils::TempDatabase, Database, DatabaseEnv};
use alloy_primitives::BlockNumber; use alloy_primitives::BlockNumber;
use criterion::{criterion_main, measurement::WallTime, BenchmarkGroup, Criterion};
use reth_config::config::{EtlConfig, TransactionLookupConfig};
use reth_db::{test_utils::TempDatabase, Database, DatabaseEnv};
use reth_provider::{test_utils::MockNodeTypesWithDB, DatabaseProvider, DatabaseProviderFactory}; use reth_provider::{test_utils::MockNodeTypesWithDB, DatabaseProvider, DatabaseProviderFactory};
use reth_stages::{ use reth_stages::{
stages::{MerkleStage, SenderRecoveryStage, TransactionLookupStage}, stages::{MerkleStage, SenderRecoveryStage, TransactionLookupStage},
@ -22,25 +21,30 @@ use setup::StageRange;
// Expanded form of `criterion_group!` // Expanded form of `criterion_group!`
// //
// This is currently needed to only instantiate the tokio runtime once. // This is currently needed to only instantiate the tokio runtime once.
#[cfg(not(codspeed))]
fn benches() { fn benches() {
#[cfg(not(target_os = "windows"))] #[cfg(not(windows))]
let mut criterion = Criterion::default() use pprof::criterion::{Output, PProfProfiler};
.with_profiler(PProfProfiler::new(1000, Output::Flamegraph(None)))
.configure_from_args();
let runtime = Runtime::new().unwrap(); let criterion = Criterion::default();
let _guard = runtime.enter(); #[cfg(not(windows))]
let criterion = criterion.with_profiler(PProfProfiler::new(1000, Output::Flamegraph(None)));
#[cfg(target_os = "windows")] run_benches(&mut criterion.configure_from_args());
let mut criterion = Criterion::default().configure_from_args();
transaction_lookup(&mut criterion, &runtime);
account_hashing(&mut criterion, &runtime);
senders(&mut criterion, &runtime);
merkle(&mut criterion, &runtime);
} }
fn run_benches(criterion: &mut Criterion) {
let runtime = Runtime::new().unwrap();
let _guard = runtime.enter();
transaction_lookup(criterion, &runtime);
account_hashing(criterion, &runtime);
senders(criterion, &runtime);
merkle(criterion, &runtime);
}
#[cfg(not(codspeed))]
criterion_main!(benches); criterion_main!(benches);
#[cfg(codspeed)]
criterion_main!(run_benches);
const DEFAULT_NUM_BLOCKS: u64 = 10_000; const DEFAULT_NUM_BLOCKS: u64 = 10_000;

View File

@ -88,6 +88,12 @@ where
// Helper for generating testdata for the benchmarks. // Helper for generating testdata for the benchmarks.
// Returns the path to the database file. // Returns the path to the database file.
pub(crate) fn txs_testdata(num_blocks: u64) -> TestStageDB { pub(crate) fn txs_testdata(num_blocks: u64) -> TestStageDB {
// This is way too slow.
#[allow(unexpected_cfgs)]
if cfg!(codspeed) {
std::process::exit(0);
}
let txs_range = 100..150; let txs_range = 100..150;
// number of storage changes per transition // number of storage changes per transition

View File

@ -69,7 +69,6 @@ pprof = { workspace = true, features = [
"criterion", "criterion",
] } ] }
criterion.workspace = true criterion.workspace = true
iai-callgrind.workspace = true
arbitrary = { workspace = true, features = ["derive"] } arbitrary = { workspace = true, features = ["derive"] }
proptest.workspace = true proptest.workspace = true
@ -125,11 +124,6 @@ name = "criterion"
required-features = ["test-utils"] required-features = ["test-utils"]
harness = false harness = false
[[bench]]
name = "iai"
required-features = ["test-utils"]
harness = false
[[bench]] [[bench]]
name = "get" name = "get"
required-features = ["test-utils"] required-features = ["test-utils"]

View File

@ -3,7 +3,7 @@
use std::{path::Path, sync::Arc}; use std::{path::Path, sync::Arc};
use criterion::{ use criterion::{
black_box, criterion_group, criterion_main, measurement::WallTime, BenchmarkGroup, Criterion, criterion_group, criterion_main, measurement::WallTime, BenchmarkGroup, Criterion,
}; };
use pprof::criterion::{Output, PProfProfiler}; use pprof::criterion::{Output, PProfProfiler};
use reth_db::{tables::*, test_utils::create_test_rw_db_with_path}; use reth_db::{tables::*, test_utils::create_test_rw_db_with_path};
@ -71,12 +71,9 @@ where
b.iter_with_setup( b.iter_with_setup(
|| input.clone(), || input.clone(),
|input| { |input| {
{ for (k, _, _, _) in input {
for (k, _, _, _) in input { k.encode();
k.encode(); }
}
};
black_box(());
}, },
) )
}); });
@ -85,12 +82,9 @@ where
b.iter_with_setup( b.iter_with_setup(
|| input.clone(), || input.clone(),
|input| { |input| {
{ for (_, k, _, _) in input {
for (_, k, _, _) in input { let _ = <T as Table>::Key::decode(&k);
let _ = <T as Table>::Key::decode(&k); }
}
};
black_box(());
}, },
) )
}); });
@ -99,12 +93,9 @@ where
b.iter_with_setup( b.iter_with_setup(
|| input.clone(), || input.clone(),
|input| { |input| {
{ for (_, _, v, _) in input {
for (_, _, v, _) in input { v.compress();
v.compress(); }
}
};
black_box(());
}, },
) )
}); });
@ -113,12 +104,9 @@ where
b.iter_with_setup( b.iter_with_setup(
|| input.clone(), || input.clone(),
|input| { |input| {
{ for (_, _, _, v) in input {
for (_, _, _, v) in input { let _ = <T as Table>::Value::decompress(&v);
let _ = <T as Table>::Value::decompress(&v); }
}
};
black_box(());
}, },
) )
}); });
@ -148,14 +136,10 @@ where
// Create TX // Create TX
let tx = db.tx_mut().expect("tx"); let tx = db.tx_mut().expect("tx");
let mut crsr = tx.cursor_write::<T>().expect("cursor"); let mut crsr = tx.cursor_write::<T>().expect("cursor");
for (k, _, v, _) in input {
black_box({ crsr.append(k, v).expect("submit");
for (k, _, v, _) in input { }
crsr.append(k, v).expect("submit"); tx.inner.commit().unwrap()
}
tx.inner.commit().unwrap()
});
}, },
) )
}); });
@ -171,15 +155,12 @@ where
// Create TX // Create TX
let tx = db.tx_mut().expect("tx"); let tx = db.tx_mut().expect("tx");
let mut crsr = tx.cursor_write::<T>().expect("cursor"); let mut crsr = tx.cursor_write::<T>().expect("cursor");
for index in RANDOM_INDEXES {
let (k, _, v, _) = input.get(index).unwrap().clone();
crsr.insert(k, v).expect("submit");
}
black_box({ tx.inner.commit().unwrap()
for index in RANDOM_INDEXES {
let (k, _, v, _) = input.get(index).unwrap().clone();
crsr.insert(k, v).expect("submit");
}
tx.inner.commit().unwrap()
});
}, },
) )
}); });
@ -190,15 +171,11 @@ where
b.iter(|| { b.iter(|| {
// Create TX // Create TX
let tx = db.tx().expect("tx"); let tx = db.tx().expect("tx");
let mut cursor = tx.cursor_read::<T>().expect("cursor");
{ let walker = cursor.walk(Some(input.first().unwrap().0.clone())).unwrap();
let mut cursor = tx.cursor_read::<T>().expect("cursor"); for element in walker {
let walker = cursor.walk(Some(input.first().unwrap().0.clone())).unwrap(); element.unwrap();
for element in walker { }
element.unwrap();
}
};
black_box(());
}) })
}); });
@ -208,14 +185,10 @@ where
b.iter(|| { b.iter(|| {
// Create TX // Create TX
let tx = db.tx().expect("tx"); let tx = db.tx().expect("tx");
for index in RANDOM_INDEXES {
{ let mut cursor = tx.cursor_read::<T>().expect("cursor");
for index in RANDOM_INDEXES { cursor.seek_exact(input.get(index).unwrap().0.clone()).unwrap();
let mut cursor = tx.cursor_read::<T>().expect("cursor"); }
cursor.seek_exact(input.get(index).unwrap().0.clone()).unwrap();
}
};
black_box(());
}) })
}); });
} }
@ -245,14 +218,10 @@ where
// Create TX // Create TX
let tx = db.tx_mut().expect("tx"); let tx = db.tx_mut().expect("tx");
let mut crsr = tx.cursor_dup_write::<T>().expect("cursor"); let mut crsr = tx.cursor_dup_write::<T>().expect("cursor");
for (k, _, v, _) in input {
black_box({ crsr.append_dup(k, v).expect("submit");
for (k, _, v, _) in input { }
crsr.append_dup(k, v).expect("submit"); tx.inner.commit().unwrap()
}
tx.inner.commit().unwrap()
});
}, },
) )
}); });
@ -268,12 +237,10 @@ where
|(input, db)| { |(input, db)| {
// Create TX // Create TX
let tx = db.tx_mut().expect("tx"); let tx = db.tx_mut().expect("tx");
for index in RANDOM_INDEXES { for index in RANDOM_INDEXES {
let (k, _, v, _) = input.get(index).unwrap().clone(); let (k, _, v, _) = input.get(index).unwrap().clone();
tx.put::<T>(k, v).unwrap(); tx.put::<T>(k, v).unwrap();
} }
tx.inner.commit().unwrap(); tx.inner.commit().unwrap();
}, },
) )
@ -286,14 +253,11 @@ where
// Create TX // Create TX
let tx = db.tx().expect("tx"); let tx = db.tx().expect("tx");
{ let mut cursor = tx.cursor_dup_read::<T>().expect("cursor");
let mut cursor = tx.cursor_dup_read::<T>().expect("cursor"); let walker = cursor.walk_dup(None, Some(T::SubKey::default())).unwrap();
let walker = cursor.walk_dup(None, Some(T::SubKey::default())).unwrap(); for element in walker {
for element in walker { element.unwrap();
element.unwrap(); }
}
};
black_box(());
}) })
}); });

View File

@ -3,7 +3,7 @@
use std::{collections::HashSet, path::Path, sync::Arc}; use std::{collections::HashSet, path::Path, sync::Arc};
use criterion::{ use criterion::{
black_box, criterion_group, criterion_main, measurement::WallTime, BenchmarkGroup, Criterion, criterion_group, criterion_main, measurement::WallTime, BenchmarkGroup, Criterion,
}; };
use pprof::criterion::{Output, PProfProfiler}; use pprof::criterion::{Output, PProfProfiler};
use proptest::{ use proptest::{
@ -20,6 +20,7 @@ use reth_db_api::{
transaction::DbTxMut, transaction::DbTxMut,
}; };
use reth_fs_util as fs; use reth_fs_util as fs;
use std::hint::black_box;
mod utils; mod utils;
use utils::*; use utils::*;
@ -46,6 +47,12 @@ pub fn hash_keys(c: &mut Criterion) {
group.sample_size(10); group.sample_size(10);
for size in [10_000, 100_000, 1_000_000] { for size in [10_000, 100_000, 1_000_000] {
// Too slow.
#[allow(unexpected_cfgs)]
if cfg!(codspeed) && size > 10_000 {
continue;
}
measure_table_insertion::<TransactionHashNumbers>(&mut group, size); measure_table_insertion::<TransactionHashNumbers>(&mut group, size);
} }
} }

View File

@ -1,102 +0,0 @@
#![allow(missing_docs, non_snake_case, unreachable_pub)]
use iai_callgrind::{
library_benchmark, library_benchmark_group, LibraryBenchmarkConfig, RegressionConfig,
};
use paste::paste;
use reth_db_api::table::{Compress, Decode, Decompress, Encode, Table};
mod utils;
use utils::*;
macro_rules! impl_iai_callgrind_inner {
(
$(($name:ident, $group_name:ident, $mod:ident, $compress:ident, $decompress:ident, $encode:ident, $decode:ident, $seqread:ident, $randread:ident, $seqwrite:ident, $randwrite:ident))+
) => {
use std::hint::black_box;
$(
#[library_benchmark]
pub fn $compress() {
for (_, _, v, _) in black_box(load_vectors::<reth_db::tables::$name>()) {
black_box(v.compress());
}
}
#[library_benchmark]
pub fn $decompress() {
for (_, _, _, comp) in black_box(load_vectors::<reth_db::tables::$name>()) {
let _ = black_box(<reth_db::tables::$name as Table>::Value::decompress(&comp));
}
}
#[library_benchmark]
pub fn $encode() {
for (k, _, _, _) in black_box(load_vectors::<reth_db::tables::$name>()) {
black_box(k.encode());
}
}
#[library_benchmark]
pub fn $decode() {
for (_, enc, _, _) in black_box(load_vectors::<reth_db::tables::$name>()) {
let _ = black_box(<reth_db::tables::$name as Table>::Key::decode(&enc));
}
}
#[allow(dead_code)]
pub const fn $seqread() {}
#[allow(dead_code)]
pub const fn $randread() {}
#[allow(dead_code)]
pub const fn $seqwrite() {}
#[allow(dead_code)]
pub const fn $randwrite() {}
library_benchmark_group!(
name = $group_name;
config = LibraryBenchmarkConfig::default()
.regression(
RegressionConfig::default().fail_fast(false)
);
benchmarks =
$compress,
$decompress,
$encode,
$decode,
);
)+
iai_callgrind::main!(
config = LibraryBenchmarkConfig::default();
library_benchmark_groups = $($group_name),+);
};
}
macro_rules! impl_iai_callgrind {
($($name:ident),+) => {
paste! {
impl_iai_callgrind_inner!(
$(
( $name, [<$name _group>],[<$name _mod>], [<$name _ValueCompress>], [<$name _ValueDecompress>], [<$name _ValueEncode>], [<$name _ValueDecode>], [<$name _SeqRead>], [<$name _RandomRead>], [<$name _SeqWrite>], [<$name _RandomWrite>])
)+
);
}
};
}
impl_iai_callgrind!(
CanonicalHeaders,
HeaderTerminalDifficulties,
HeaderNumbers,
Headers,
BlockBodyIndices,
BlockOmmers,
TransactionHashNumbers,
Transactions,
PlainStorageState,
PlainAccountState
);

View File

@ -60,15 +60,15 @@ pub mod test_utils {
use tempfile::TempDir; use tempfile::TempDir;
/// Error during database open /// Error during database open
pub const ERROR_DB_OPEN: &str = "Not able to open the database file."; pub const ERROR_DB_OPEN: &str = "could not open the database file";
/// Error during database creation /// Error during database creation
pub const ERROR_DB_CREATION: &str = "Not able to create the database file."; pub const ERROR_DB_CREATION: &str = "could not create the database file";
/// Error during database creation /// Error during database creation
pub const ERROR_STATIC_FILES_CREATION: &str = "Not able to create the static file path."; pub const ERROR_STATIC_FILES_CREATION: &str = "could not create the static file path";
/// Error during table creation /// Error during table creation
pub const ERROR_TABLE_CREATION: &str = "Not able to create tables in the database."; pub const ERROR_TABLE_CREATION: &str = "could not create tables in the database";
/// Error during tempdir creation /// Error during tempdir creation
pub const ERROR_TEMPDIR: &str = "Not able to create a temporary directory."; pub const ERROR_TEMPDIR: &str = "could not create a temporary directory";
/// A database will delete the db dir when dropped. /// A database will delete the db dir when dropped.
pub struct TempDatabase<DB> { pub struct TempDatabase<DB> {

View File

@ -1,10 +1,10 @@
#![allow(missing_docs)] #![allow(missing_docs)]
mod utils; mod utils;
use criterion::{black_box, criterion_group, criterion_main, Criterion}; use criterion::{criterion_group, criterion_main, Criterion};
use pprof::criterion::{Output, PProfProfiler}; use pprof::criterion::{Output, PProfProfiler};
use reth_libmdbx::{ffi::*, *}; use reth_libmdbx::{ffi::*, *};
use std::ptr; use std::{hint::black_box, ptr};
use utils::*; use utils::*;
/// Benchmark of iterator sequential read performance. /// Benchmark of iterator sequential read performance.

View File

@ -1,11 +1,11 @@
#![allow(missing_docs, unreachable_pub)] #![allow(missing_docs, unreachable_pub)]
mod utils; mod utils;
use criterion::{black_box, criterion_group, criterion_main, Criterion}; use criterion::{criterion_group, criterion_main, Criterion};
use rand::{prelude::SliceRandom, SeedableRng}; use rand::{prelude::SliceRandom, SeedableRng};
use rand_xorshift::XorShiftRng; use rand_xorshift::XorShiftRng;
use reth_libmdbx::{ffi::*, ObjectLength, WriteFlags}; use reth_libmdbx::{ffi::*, ObjectLength, WriteFlags};
use std::ptr; use std::{hint::black_box, ptr};
use utils::*; use utils::*;
fn bench_get_rand(c: &mut Criterion) { fn bench_get_rand(c: &mut Criterion) {

View File

@ -76,45 +76,45 @@ serde_json.workspace = true
[features] [features]
default = ["serde"] default = ["serde"]
serde = [ serde = [
"dep:serde", "dep:serde",
"reth-execution-types/serde", "reth-execution-types/serde",
"reth-eth-wire-types/serde", "reth-eth-wire-types/serde",
"reth-provider/serde", "reth-provider/serde",
"alloy-consensus/serde", "alloy-consensus/serde",
"alloy-eips/serde", "alloy-eips/serde",
"alloy-primitives/serde", "alloy-primitives/serde",
"bitflags/serde", "bitflags/serde",
"parking_lot/serde", "parking_lot/serde",
"rand?/serde", "rand?/serde",
"smallvec/serde", "smallvec/serde",
"reth-primitives-traits/serde", "reth-primitives-traits/serde",
"revm-interpreter/serde", "revm-interpreter/serde",
"revm-primitives/serde" "revm-primitives/serde",
] ]
test-utils = [ test-utils = [
"rand", "rand",
"paste", "paste",
"serde", "serde",
"reth-chain-state/test-utils", "reth-chain-state/test-utils",
"reth-chainspec/test-utils", "reth-chainspec/test-utils",
"reth-primitives/test-utils", "reth-primitives/test-utils",
"reth-provider/test-utils", "reth-provider/test-utils",
"reth-primitives-traits/test-utils", "reth-primitives-traits/test-utils",
] ]
arbitrary = [ arbitrary = [
"proptest", "proptest",
"reth-primitives/arbitrary", "reth-primitives/arbitrary",
"proptest-arbitrary-interop", "proptest-arbitrary-interop",
"reth-chainspec/arbitrary", "reth-chainspec/arbitrary",
"reth-eth-wire-types/arbitrary", "reth-eth-wire-types/arbitrary",
"alloy-consensus/arbitrary", "alloy-consensus/arbitrary",
"alloy-eips/arbitrary", "alloy-eips/arbitrary",
"alloy-primitives/arbitrary", "alloy-primitives/arbitrary",
"bitflags/arbitrary", "bitflags/arbitrary",
"reth-primitives-traits/arbitrary", "reth-primitives-traits/arbitrary",
"smallvec/arbitrary", "smallvec/arbitrary",
"revm-interpreter/arbitrary", "revm-interpreter/arbitrary",
"revm-primitives/arbitrary" "revm-primitives/arbitrary",
] ]
[[bench]] [[bench]]

View File

@ -1,9 +1,10 @@
#![allow(missing_docs)] #![allow(missing_docs)]
use criterion::{ use criterion::{
black_box, criterion_group, criterion_main, measurement::WallTime, BenchmarkGroup, Criterion, criterion_group, criterion_main, measurement::WallTime, BenchmarkGroup, Criterion,
}; };
use proptest::{prelude::*, strategy::ValueTree, test_runner::TestRunner}; use proptest::{prelude::*, strategy::ValueTree, test_runner::TestRunner};
use reth_transaction_pool::{blob_tx_priority, fee_delta}; use reth_transaction_pool::{blob_tx_priority, fee_delta};
use std::hint::black_box;
fn generate_test_data_fee_delta() -> (u128, u128) { fn generate_test_data_fee_delta() -> (u128, u128) {
let config = ProptestConfig::default(); let config = ProptestConfig::default();

View File

@ -75,19 +75,17 @@ fn txpool_reordering_bench<T: BenchTxPool>(
); );
group.bench_function(group_id, |b| { group.bench_function(group_id, |b| {
b.iter_with_setup(setup, |(mut txpool, new_txs)| { b.iter_with_setup(setup, |(mut txpool, new_txs)| {
{ // Reorder with new base fee
// Reorder with new base fee let bigger_base_fee = base_fee.saturating_add(10);
let bigger_base_fee = base_fee.saturating_add(10); txpool.reorder(bigger_base_fee);
txpool.reorder(bigger_base_fee);
// Reorder with new base fee after adding transactions. // Reorder with new base fee after adding transactions.
for new_tx in new_txs { for new_tx in new_txs {
txpool.add_transaction(new_tx); txpool.add_transaction(new_tx);
} }
let smaller_base_fee = base_fee.saturating_sub(10); let smaller_base_fee = base_fee.saturating_sub(10);
txpool.reorder(smaller_base_fee) txpool.reorder(smaller_base_fee);
}; txpool
std::hint::black_box(());
}); });
}); });
} }

View File

@ -161,7 +161,7 @@ fn truncate_pending(
group.bench_function(group_id, |b| { group.bench_function(group_id, |b| {
b.iter_with_setup(setup, |mut txpool| { b.iter_with_setup(setup, |mut txpool| {
txpool.truncate_pool(SubPoolLimit::default()); txpool.truncate_pool(SubPoolLimit::default());
std::hint::black_box(()); txpool
}); });
}); });
} }
@ -195,7 +195,7 @@ fn truncate_queued(
group.bench_function(group_id, |b| { group.bench_function(group_id, |b| {
b.iter_with_setup(setup, |mut txpool| { b.iter_with_setup(setup, |mut txpool| {
txpool.truncate_pool(SubPoolLimit::default()); txpool.truncate_pool(SubPoolLimit::default());
std::hint::black_box(()); txpool
}); });
}); });
} }
@ -229,7 +229,7 @@ fn truncate_basefee(
group.bench_function(group_id, |b| { group.bench_function(group_id, |b| {
b.iter_with_setup(setup, |mut txpool| { b.iter_with_setup(setup, |mut txpool| {
txpool.truncate_pool(SubPoolLimit::default()); txpool.truncate_pool(SubPoolLimit::default());
std::hint::black_box(()); txpool
}); });
}); });
} }

View File

@ -1,6 +1,6 @@
#![allow(missing_docs, unreachable_pub)] #![allow(missing_docs, unreachable_pub)]
use criterion::{ use criterion::{
black_box, criterion_group, criterion_main, measurement::WallTime, BenchmarkGroup, Criterion, criterion_group, criterion_main, measurement::WallTime, BenchmarkGroup, Criterion,
}; };
use proptest::{ use proptest::{
prelude::*, prelude::*,
@ -11,7 +11,7 @@ use reth_trie_common::{
prefix_set::{PrefixSet, PrefixSetMut}, prefix_set::{PrefixSet, PrefixSetMut},
Nibbles, Nibbles,
}; };
use std::collections::BTreeSet; use std::{collections::BTreeSet, hint::black_box};
/// Abstraction for aggregating nibbles and freezing it to a type /// Abstraction for aggregating nibbles and freezing it to a type
/// that can be later used for benching. /// that can be later used for benching.
@ -48,6 +48,12 @@ pub fn prefix_set_lookups(c: &mut Criterion) {
let mut group = c.benchmark_group("Prefix Set Lookups"); let mut group = c.benchmark_group("Prefix Set Lookups");
for size in [10, 100, 1_000, 10_000] { for size in [10, 100, 1_000, 10_000] {
// Too slow.
#[allow(unexpected_cfgs)]
if cfg!(codspeed) && size > 1_000 {
continue;
}
let test_data = generate_test_data(size); let test_data = generate_test_data(size);
use implementations::*; use implementations::*;

View File

@ -54,6 +54,14 @@ proptest-arbitrary-interop.workspace = true
[features] [features]
default = ["metrics"] default = ["metrics"]
metrics = ["reth-metrics", "dep:metrics", "reth-trie/metrics"] metrics = ["reth-metrics", "dep:metrics", "reth-trie/metrics"]
test-utils = [
"reth-trie/test-utils",
"reth-trie-common/test-utils",
"reth-db/test-utils",
"reth-primitives/test-utils",
"reth-provider/test-utils",
"reth-trie-db/test-utils",
]
[[bench]] [[bench]]
name = "root" name = "root"

View File

@ -20,6 +20,12 @@ pub fn calculate_state_root(c: &mut Criterion) {
group.sample_size(20); group.sample_size(20);
for size in [1_000, 3_000, 5_000, 10_000] { for size in [1_000, 3_000, 5_000, 10_000] {
// Too slow.
#[allow(unexpected_cfgs)]
if cfg!(codspeed) && size > 3_000 {
continue;
}
let (db_state, updated_state) = generate_test_data(size); let (db_state, updated_state) = generate_test_data(size);
let provider_factory = create_test_provider_factory(); let provider_factory = create_test_provider_factory();
{ {

View File

@ -41,6 +41,19 @@ proptest-arbitrary-interop.workspace = true
proptest.workspace = true proptest.workspace = true
rand.workspace = true rand.workspace = true
[features]
test-utils = [
"reth-primitives-traits/test-utils",
"reth-trie/test-utils",
"reth-trie-common/test-utils",
]
arbitrary = [
"reth-primitives-traits/arbitrary",
"reth-trie-common/arbitrary",
"alloy-primitives/arbitrary",
"smallvec/arbitrary",
]
[[bench]] [[bench]]
name = "root" name = "root"
harness = false harness = false

View File

@ -1,6 +1,4 @@
#![allow(missing_docs, unreachable_pub)] #![allow(missing_docs)]
use std::time::{Duration, Instant};
use alloy_primitives::{B256, U256}; use alloy_primitives::{B256, U256};
use criterion::{criterion_group, criterion_main, Criterion}; use criterion::{criterion_group, criterion_main, Criterion};
@ -11,7 +9,7 @@ use reth_testing_utils::generators;
use reth_trie::Nibbles; use reth_trie::Nibbles;
use reth_trie_sparse::RevealedSparseTrie; use reth_trie_sparse::RevealedSparseTrie;
pub fn update_rlp_node_level(c: &mut Criterion) { fn update_rlp_node_level(c: &mut Criterion) {
let mut rng = generators::rng(); let mut rng = generators::rng();
let mut group = c.benchmark_group("update rlp node level"); let mut group = c.benchmark_group("update rlp node level");
@ -53,20 +51,11 @@ pub fn update_rlp_node_level(c: &mut Criterion) {
group.bench_function( group.bench_function(
format!("size {size} | updated {updated_leaves}% | depth {depth}"), format!("size {size} | updated {updated_leaves}% | depth {depth}"),
|b| { |b| {
// Use `iter_custom` to avoid measuring clones and drops b.iter_batched_ref(
b.iter_custom(|iters| { || sparse.clone(),
let mut elapsed = Duration::ZERO; |cloned| cloned.update_rlp_node_level(depth),
criterion::BatchSize::PerIteration,
let mut cloned = sparse.clone(); )
for _ in 0..iters {
let start = Instant::now();
cloned.update_rlp_node_level(depth);
elapsed += start.elapsed();
cloned = sparse.clone();
}
elapsed
})
}, },
); );
} }

View File

@ -1,4 +1,4 @@
#![allow(missing_docs, unreachable_pub)] #![allow(missing_docs)]
use alloy_primitives::{map::B256HashMap, B256, U256}; use alloy_primitives::{map::B256HashMap, B256, U256};
use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion}; use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion};
@ -15,11 +15,17 @@ use reth_trie::{
use reth_trie_common::{HashBuilder, Nibbles}; use reth_trie_common::{HashBuilder, Nibbles};
use reth_trie_sparse::SparseTrie; use reth_trie_sparse::SparseTrie;
pub fn calculate_root_from_leaves(c: &mut Criterion) { fn calculate_root_from_leaves(c: &mut Criterion) {
let mut group = c.benchmark_group("calculate root from leaves"); let mut group = c.benchmark_group("calculate root from leaves");
group.sample_size(20); group.sample_size(20);
for size in [1_000, 5_000, 10_000, 100_000] { for size in [1_000, 5_000, 10_000, 100_000] {
// Too slow.
#[allow(unexpected_cfgs)]
if cfg!(codspeed) && size > 5_000 {
continue;
}
let state = generate_test_data(size); let state = generate_test_data(size);
// hash builder // hash builder
@ -29,6 +35,7 @@ pub fn calculate_root_from_leaves(c: &mut Criterion) {
hb.add_leaf(Nibbles::unpack(key), &alloy_rlp::encode_fixed_size(value)); hb.add_leaf(Nibbles::unpack(key), &alloy_rlp::encode_fixed_size(value));
} }
hb.root(); hb.root();
hb
}) })
}); });
@ -44,19 +51,32 @@ pub fn calculate_root_from_leaves(c: &mut Criterion) {
.unwrap(); .unwrap();
} }
sparse.root().unwrap(); sparse.root().unwrap();
sparse
}) })
}); });
} }
} }
pub fn calculate_root_from_leaves_repeated(c: &mut Criterion) { fn calculate_root_from_leaves_repeated(c: &mut Criterion) {
let mut group = c.benchmark_group("calculate root from leaves repeated"); let mut group = c.benchmark_group("calculate root from leaves repeated");
group.sample_size(20); group.sample_size(20);
for init_size in [1_000, 10_000, 100_000] { for init_size in [1_000, 10_000, 100_000] {
// Too slow.
#[allow(unexpected_cfgs)]
if cfg!(codspeed) && init_size > 10_000 {
continue;
}
let init_state = generate_test_data(init_size); let init_state = generate_test_data(init_size);
for update_size in [100, 1_000, 5_000, 10_000] { for update_size in [100, 1_000, 5_000, 10_000] {
// Too slow.
#[allow(unexpected_cfgs)]
if cfg!(codspeed) && update_size > 1_000 {
continue;
}
for num_updates in [1, 3, 5, 10] { for num_updates in [1, 3, 5, 10] {
let updates = let updates =
(0..num_updates).map(|_| generate_test_data(update_size)).collect::<Vec<_>>(); (0..num_updates).map(|_| generate_test_data(update_size)).collect::<Vec<_>>();

View File

@ -61,19 +61,20 @@ criterion.workspace = true
[features] [features]
metrics = ["reth-metrics", "dep:metrics"] metrics = ["reth-metrics", "dep:metrics"]
serde = [ serde = [
"alloy-primitives/serde", "alloy-primitives/serde",
"alloy-consensus/serde", "alloy-consensus/serde",
"alloy-trie/serde", "alloy-trie/serde",
"alloy-eips/serde", "alloy-eips/serde",
"revm/serde", "revm/serde",
"reth-trie-common/serde" "reth-trie-common/serde",
] ]
test-utils = [ test-utils = [
"triehash", "triehash",
"revm/test-utils", "revm/test-utils",
"reth-primitives/test-utils", "reth-primitives/test-utils",
"reth-trie-common/test-utils", "reth-trie-common/test-utils",
"reth-stages-types/test-utils" "reth-trie-sparse/test-utils",
"reth-stages-types/test-utils",
] ]
[[bench]] [[bench]]

View File

@ -10,6 +10,12 @@ pub fn hash_post_state(c: &mut Criterion) {
group.sample_size(20); group.sample_size(20);
for size in [100, 1_000, 3_000, 5_000, 10_000] { for size in [100, 1_000, 3_000, 5_000, 10_000] {
// Too slow.
#[allow(unexpected_cfgs)]
if cfg!(codspeed) && size > 1_000 {
continue;
}
let state = generate_test_data(size); let state = generate_test_data(size);
// sequence // sequence

View File

@ -1,10 +1,11 @@
#![allow(missing_docs, unreachable_pub)] #![allow(missing_docs, unreachable_pub)]
use alloy_primitives::B256; use alloy_primitives::B256;
use criterion::{black_box, criterion_group, criterion_main, Criterion}; use criterion::{criterion_group, criterion_main, Criterion};
use proptest::{prelude::*, strategy::ValueTree, test_runner::TestRunner}; use proptest::{prelude::*, strategy::ValueTree, test_runner::TestRunner};
use proptest_arbitrary_interop::arb; use proptest_arbitrary_interop::arb;
use reth_primitives::{Receipt, ReceiptWithBloom}; use reth_primitives::{Receipt, ReceiptWithBloom};
use reth_trie::triehash::KeccakHasher; use reth_trie::triehash::KeccakHasher;
use std::hint::black_box;
/// Benchmarks different implementations of the root calculation. /// Benchmarks different implementations of the root calculation.
pub fn trie_root_benchmark(c: &mut Criterion) { pub fn trie_root_benchmark(c: &mut Criterion) {

View File

@ -9,7 +9,7 @@
- We want Reth's serialized format to be able to trade off read/write speed for size, depending on who the user is. - We want Reth's serialized format to be able to trade off read/write speed for size, depending on who the user is.
- To achieve that, we created the [Encode/Decode/Compress/Decompress traits](https://github.com/paradigmxyz/reth/blob/0d9b9a392d4196793736522f3fc2ac804991b45d/crates/interfaces/src/db/table.rs#L9-L36) to make the (de)serialization of database `Table::Key` and `Table::Values` generic. - To achieve that, we created the [Encode/Decode/Compress/Decompress traits](https://github.com/paradigmxyz/reth/blob/0d9b9a392d4196793736522f3fc2ac804991b45d/crates/interfaces/src/db/table.rs#L9-L36) to make the (de)serialization of database `Table::Key` and `Table::Values` generic.
- This allows for [out-of-the-box benchmarking](https://github.com/paradigmxyz/reth/blob/0d9b9a392d4196793736522f3fc2ac804991b45d/crates/db/benches/encoding_iai.rs#L5) (using [Criterion](https://github.com/bheisler/criterion.rs) and [Iai](https://github.com/bheisler/iai)) - This allows for [out-of-the-box benchmarking](https://github.com/paradigmxyz/reth/blob/0d9b9a392d4196793736522f3fc2ac804991b45d/crates/db/benches/encoding_iai.rs#L5) (using [Criterion](https://github.com/bheisler/criterion.rs))
- It also enables [out-of-the-box fuzzing](https://github.com/paradigmxyz/reth/blob/0d9b9a392d4196793736522f3fc2ac804991b45d/crates/interfaces/src/db/codecs/fuzz/mod.rs) using [trailofbits/test-fuzz](https://github.com/trailofbits/test-fuzz). - It also enables [out-of-the-box fuzzing](https://github.com/paradigmxyz/reth/blob/0d9b9a392d4196793736522f3fc2ac804991b45d/crates/interfaces/src/db/codecs/fuzz/mod.rs) using [trailofbits/test-fuzz](https://github.com/trailofbits/test-fuzz).
- We implemented that trait for the following encoding formats: - We implemented that trait for the following encoding formats:
- [Ethereum-specific Compact Encoding](https://github.com/paradigmxyz/reth/blob/0d9b9a392d4196793736522f3fc2ac804991b45d/crates/codecs/derive/src/compact/mod.rs): A lot of Ethereum datatypes have unnecessary zeros when serialized, or optional (e.g. on empty hashes) which would be nice not to pay in storage costs. - [Ethereum-specific Compact Encoding](https://github.com/paradigmxyz/reth/blob/0d9b9a392d4196793736522f3fc2ac804991b45d/crates/codecs/derive/src/compact/mod.rs): A lot of Ethereum datatypes have unnecessary zeros when serialized, or optional (e.g. on empty hashes) which would be nice not to pay in storage costs.