mirror of
https://github.com/hl-archive-node/nanoreth.git
synced 2025-12-06 10:59:55 +00:00
feat(db): fuzzing & benchmark (#86)
* fuzz with test-fuzz * move fuzzing to db/codecs * add criterion & iai * print encoded size sum on criterion benchmark * fix BlockNumHash encode * add gh action for benchmarks * don't sum results * test ci values * Revert "test ci values" This reverts commit cc47fd80538b2c0073592f824c2693c927021f8f. * specify criterion version * add docs * remove benchmark job
This commit is contained in:
1
crates/.gitignore
vendored
Normal file
1
crates/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
target/
|
||||
@ -42,7 +42,7 @@ pub fn use_scale(_args: TokenStream, input: TokenStream) -> TokenStream {
|
||||
}
|
||||
|
||||
quote! {
|
||||
#[derive(parity_scale_codec::Encode, parity_scale_codec::Decode)]
|
||||
#[derive(parity_scale_codec::Encode, parity_scale_codec::Decode, serde::Serialize, serde::Deserialize)]
|
||||
#ast
|
||||
}
|
||||
.into()
|
||||
|
||||
@ -13,8 +13,7 @@ reth-primitives = { path = "../primitives" }
|
||||
|
||||
# codecs
|
||||
serde = { version = "1.0.*", default-features = false }
|
||||
postcard = { version = "1.0.2", features = ["heapless"] }
|
||||
heapless = "0.7.16"
|
||||
postcard = { version = "1.0.2", features = ["alloc"] }
|
||||
parity-scale-codec = { version = "3.2.1", features = ["bytes"] }
|
||||
|
||||
# misc
|
||||
@ -26,6 +25,19 @@ tempfile = { version = "3.3.0", optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
tempfile = "3.3.0"
|
||||
test-fuzz = "3.0.4"
|
||||
criterion = "0.4.0"
|
||||
iai = "0.1.1"
|
||||
|
||||
[features]
|
||||
test-utils = ["tempfile"]
|
||||
bench-postcard = ["bench"]
|
||||
bench = []
|
||||
|
||||
[[bench]]
|
||||
name = "encoding_crit"
|
||||
harness = false
|
||||
|
||||
[[bench]]
|
||||
name = "encoding_iai"
|
||||
harness = false
|
||||
15
crates/db/benches/README.md
Normal file
15
crates/db/benches/README.md
Normal file
@ -0,0 +1,15 @@
|
||||
# DB Benchmarks
|
||||
|
||||
## Codecs
|
||||
|
||||
Currently only benchmarking the encoding/decoding of `Header`. It can be benchmarked with two different codecs at the moment `main/scale` and `postcard`:
|
||||
|
||||
### Main/Scale:
|
||||
```bash
|
||||
$ cargo bench --features bench
|
||||
```
|
||||
|
||||
### Postcard:
|
||||
```bash
|
||||
$ cargo bench --features bench-postcard
|
||||
```
|
||||
32
crates/db/benches/encoding_crit.rs
Normal file
32
crates/db/benches/encoding_crit.rs
Normal file
@ -0,0 +1,32 @@
|
||||
use criterion::{black_box, criterion_group, criterion_main, Criterion};
|
||||
|
||||
/// Benchmarks the encoding and decoding of `Header` using criterion.
|
||||
macro_rules! impl_criterion_encoding_benchmark {
|
||||
($name:tt) => {
|
||||
pub fn criterion_benchmark(c: &mut Criterion) {
|
||||
let mut size = 0;
|
||||
c.bench_function(stringify!($name), |b| {
|
||||
b.iter(|| {
|
||||
let encoded_size = reth_db::kv::codecs::fuzz::Header::encode_and_decode(
|
||||
black_box(reth_primitives::Header::default()),
|
||||
)
|
||||
.0;
|
||||
|
||||
if size == 0 {
|
||||
size = encoded_size;
|
||||
}
|
||||
})
|
||||
});
|
||||
println!("Size (bytes): `{size}`");
|
||||
}
|
||||
|
||||
criterion_group!(benches, criterion_benchmark);
|
||||
criterion_main!(benches);
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "bench-postcard"))]
|
||||
impl_criterion_encoding_benchmark!(scale);
|
||||
|
||||
#[cfg(feature = "bench-postcard")]
|
||||
impl_criterion_encoding_benchmark!(postcard);
|
||||
20
crates/db/benches/encoding_iai.rs
Normal file
20
crates/db/benches/encoding_iai.rs
Normal file
@ -0,0 +1,20 @@
|
||||
use iai::{black_box, main};
|
||||
|
||||
/// Benchmarks the encoding and decoding of `Header` using iai.
|
||||
macro_rules! impl_iai_encoding_benchmark {
|
||||
($name:tt) => {
|
||||
fn $name() {
|
||||
reth_db::kv::codecs::fuzz::Header::encode_and_decode(black_box(
|
||||
reth_primitives::Header::default(),
|
||||
));
|
||||
}
|
||||
|
||||
main!($name);
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "bench-postcard"))]
|
||||
impl_iai_encoding_benchmark!(scale);
|
||||
|
||||
#[cfg(feature = "bench-postcard")]
|
||||
impl_iai_encoding_benchmark!(postcard);
|
||||
39
crates/db/src/kv/codecs/fuzz.rs
Normal file
39
crates/db/src/kv/codecs/fuzz.rs
Normal file
@ -0,0 +1,39 @@
|
||||
//! Implements fuzzing targets to be used by test-fuzz
|
||||
|
||||
/// Fuzzer generates a random instance of the object and proceeds to encode and decode it. It then
|
||||
/// makes sure that it matches the original object.
|
||||
macro_rules! impl_fuzzer {
|
||||
($($name:tt),+) => {
|
||||
$(
|
||||
/// Macro generated module to be used by test-fuzz and `bench` if it applies.
|
||||
#[allow(non_snake_case)]
|
||||
#[cfg(any(test, feature = "bench"))]
|
||||
pub mod $name {
|
||||
use reth_primitives::$name;
|
||||
use crate::kv::table;
|
||||
|
||||
/// Encodes and decodes table types returning its encoded size and the decoded object.
|
||||
pub fn encode_and_decode(obj: $name) -> (usize, $name) {
|
||||
let data = table::Encode::encode(obj);
|
||||
let size = data.len();
|
||||
(size, table::Decode::decode(data).expect("failed to decode"))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[allow(dead_code)]
|
||||
#[test_fuzz::test_fuzz]
|
||||
pub fn fuzz(obj: $name) {
|
||||
assert!(encode_and_decode(obj.clone()).1 == obj );
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test() {
|
||||
encode_and_decode($name::default());
|
||||
}
|
||||
}
|
||||
|
||||
)+
|
||||
};
|
||||
}
|
||||
|
||||
impl_fuzzer!(Header, Account);
|
||||
@ -1,2 +1,6 @@
|
||||
//! Integrates different codecs into table::Encode and table::Decode
|
||||
|
||||
pub mod fuzz;
|
||||
mod postcard;
|
||||
#[cfg(not(feature = "bench-postcard"))]
|
||||
mod scale;
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
#![allow(unused)]
|
||||
|
||||
use crate::kv::{Decode, Encode, KVError};
|
||||
use heapless::Vec;
|
||||
use postcard::{from_bytes, to_vec};
|
||||
use reth_primitives::Account;
|
||||
use postcard::{from_bytes, to_allocvec};
|
||||
use reth_primitives::*;
|
||||
|
||||
// Just add `Serialize` and `Deserialize`, and set impl_heapless_postcard!(T, MaxSize(T))
|
||||
//
|
||||
@ -16,20 +15,27 @@ use reth_primitives::Account;
|
||||
//
|
||||
// impl_heapless_postcard!(T, MaxSize(T))
|
||||
|
||||
macro_rules! impl_heapless_postcard {
|
||||
($name:tt, $static_size:tt) => {
|
||||
impl Encode for $name {
|
||||
type Encoded = Vec<u8, $static_size>;
|
||||
macro_rules! impl_postcard {
|
||||
($($name:tt),+) => {
|
||||
$(
|
||||
impl Encode for $name {
|
||||
type Encoded = Vec<u8>;
|
||||
|
||||
fn encode(self) -> Self::Encoded {
|
||||
to_vec(&self).expect("Failed to encode")
|
||||
fn encode(self) -> Self::Encoded {
|
||||
to_allocvec(&self).expect("Failed to encode")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Decode for $name {
|
||||
fn decode<B: Into<bytes::Bytes>>(value: B) -> Result<Self, KVError> {
|
||||
from_bytes(&value.into()).map_err(|_| KVError::InvalidValue)
|
||||
impl Decode for $name {
|
||||
fn decode<B: Into<bytes::Bytes>>(value: B) -> Result<Self, KVError> {
|
||||
from_bytes(&value.into()).map_err(|_| KVError::InvalidValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
)+
|
||||
};
|
||||
}
|
||||
|
||||
type VecU8 = Vec<u8>;
|
||||
|
||||
#[cfg(feature = "bench-postcard")]
|
||||
impl_postcard!(VecU8, Receipt, H256, U256, H160, u8, u16, u64, Header, Account, Log, TxType);
|
||||
|
||||
@ -24,7 +24,8 @@ use tx::Tx;
|
||||
mod error;
|
||||
pub use error::KVError;
|
||||
|
||||
mod codecs;
|
||||
// Made public so `benches` can access it.
|
||||
pub mod codecs;
|
||||
|
||||
/// Environment used when opening a MDBX environment. RO/RW.
|
||||
#[derive(Debug)]
|
||||
|
||||
@ -47,7 +47,7 @@ impl Encode for BlockNumHash {
|
||||
let mut rnum = [0; 40];
|
||||
|
||||
rnum[..8].copy_from_slice(&number.to_be_bytes());
|
||||
rnum[8..].copy_from_slice(&hash.encode());
|
||||
rnum[8..].copy_from_slice(hash.as_bytes());
|
||||
rnum
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,7 +3,7 @@ use reth_codecs::main_codec;
|
||||
|
||||
/// Account saved in database
|
||||
#[main_codec]
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
|
||||
pub struct Account {
|
||||
/// Nonce.
|
||||
pub nonce: u64,
|
||||
|
||||
Reference in New Issue
Block a user