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:
joshieDo
2022-10-20 04:08:07 +08:00
committed by GitHub
parent 7e26ba5090
commit 630baf5d70
14 changed files with 396 additions and 23 deletions

249
Cargo.lock generated
View File

@ -170,6 +170,15 @@ dependencies = [
"serde",
]
[[package]]
name = "bincode"
version = "1.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad"
dependencies = [
"serde",
]
[[package]]
name = "bindgen"
version = "0.60.1"
@ -309,6 +318,37 @@ dependencies = [
"serde",
]
[[package]]
name = "camino"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "88ad0e1e3e88dd237a156ab9f571021b8a158caa0ae44b1968a241efb5144c1e"
dependencies = [
"serde",
]
[[package]]
name = "cargo-platform"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cbdb825da8a5df079a43676dbe042702f1707b1109f713a01420fbb4cc71fa27"
dependencies = [
"serde",
]
[[package]]
name = "cargo_metadata"
version = "0.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3abb7553d5b9b8421c6de7cb02606ff15e0c6eea7d8eadd75ef013fd636bec36"
dependencies = [
"camino",
"cargo-platform",
"semver 1.0.14",
"serde",
"serde_json",
]
[[package]]
name = "cast"
version = "0.3.0"
@ -655,6 +695,41 @@ dependencies = [
"cipher",
]
[[package]]
name = "darling"
version = "0.14.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4529658bdda7fd6769b8614be250cdcfc3aeb0ee72fe66f9e41e5e5eb73eac02"
dependencies = [
"darling_core",
"darling_macro",
]
[[package]]
name = "darling_core"
version = "0.14.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "649c91bc01e8b1eac09fb91e8dbc7d517684ca6be8ebc75bb9cafc894f9fdb6f"
dependencies = [
"fnv",
"ident_case",
"proc-macro2",
"quote",
"strsim",
"syn",
]
[[package]]
name = "darling_macro"
version = "0.14.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ddfc69c5bfcbd2fc09a0f38451d2daf0e372e367986a83906d1b0dbc88134fb5"
dependencies = [
"darling_core",
"quote",
"syn",
]
[[package]]
name = "der"
version = "0.6.0"
@ -1243,6 +1318,15 @@ dependencies = [
"digest 0.10.5",
]
[[package]]
name = "home"
version = "0.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "747309b4b440c06d57b0b25f2aee03ee9b5e5397d288c60e21fc709bb98a7408"
dependencies = [
"winapi",
]
[[package]]
name = "http"
version = "0.2.8"
@ -1317,6 +1401,24 @@ dependencies = [
"webpki-roots",
]
[[package]]
name = "iai"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "71a816c97c42258aa5834d07590b718b4c9a598944cd39a52dc25b351185d678"
[[package]]
name = "ident_case"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
[[package]]
name = "if_chain"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb56e1aa765b4b4f3aadfab769793b7087bb03a4ea4920644a6d238e2df5b9ed"
[[package]]
name = "impl-codec"
version = "0.6.0"
@ -1980,6 +2082,16 @@ version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099"
[[package]]
name = "pest"
version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dbc7bc69c062e492337d74d59b120c274fd3d261b6bf6d3207d499b4b379c41a"
dependencies = [
"thiserror",
"ucd-trie",
]
[[package]]
name = "pin-project"
version = "1.0.12"
@ -2302,7 +2414,8 @@ name = "reth-db"
version = "0.1.0"
dependencies = [
"bytes",
"heapless",
"criterion",
"iai",
"libmdbx",
"page_size",
"parity-scale-codec",
@ -2310,6 +2423,7 @@ dependencies = [
"reth-primitives",
"serde",
"tempfile",
"test-fuzz",
"thiserror",
]
@ -2849,7 +2963,16 @@ version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
dependencies = [
"semver-parser",
"semver-parser 0.7.0",
]
[[package]]
name = "semver"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6"
dependencies = [
"semver-parser 0.10.2",
]
[[package]]
@ -2857,6 +2980,9 @@ name = "semver"
version = "1.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e25dfac463d778e353db5be2449d1cce89bd6fd23c9f1ea21310ce6e5a1b29c4"
dependencies = [
"serde",
]
[[package]]
name = "semver-parser"
@ -2864,6 +2990,15 @@ version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
[[package]]
name = "semver-parser"
version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7"
dependencies = [
"pest",
]
[[package]]
name = "send_wrapper"
version = "0.4.0"
@ -2914,6 +3049,17 @@ dependencies = [
"opaque-debug",
]
[[package]]
name = "sha-1"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "028f48d513f9678cda28f6e4064755b3fbb2af6acd672f2c209b62323f7aea0f"
dependencies = [
"cfg-if",
"cpufeatures",
"digest 0.10.5",
]
[[package]]
name = "sha2"
version = "0.10.6"
@ -2997,7 +3143,7 @@ dependencies = [
"httparse",
"log",
"rand",
"sha-1",
"sha-1 0.9.8",
]
[[package]]
@ -3065,6 +3211,16 @@ dependencies = [
"syn",
]
[[package]]
name = "subprocess"
version = "0.2.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c2e86926081dda636c546d8c5e641661049d7562a68f5488be4a1f7f66f6086"
dependencies = [
"libc",
"winapi",
]
[[package]]
name = "substrate-bn"
version = "0.6.0"
@ -3124,6 +3280,63 @@ dependencies = [
"winapi-util",
]
[[package]]
name = "test-fuzz"
version = "3.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "125df852011c4f8f31df5620f4aea38ecddb5dfb4d9bc569b30485b15ffc3d4e"
dependencies = [
"serde",
"test-fuzz-internal",
"test-fuzz-macro",
"test-fuzz-runtime",
]
[[package]]
name = "test-fuzz-internal"
version = "3.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "58071dc2471840e9f374eeb0f6e405a31bccb3cc5d59bb4598f02cafc274b5c4"
dependencies = [
"cargo_metadata",
"proc-macro2",
"quote",
"serde",
"strum_macros",
]
[[package]]
name = "test-fuzz-macro"
version = "3.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "856bbca0314c328004691b9c0639fb198ca764d1ce0e20d4dd8b78f2697c2a6f"
dependencies = [
"darling",
"if_chain",
"lazy_static",
"proc-macro2",
"quote",
"subprocess",
"syn",
"test-fuzz-internal",
"toolchain_find",
"unzip-n",
]
[[package]]
name = "test-fuzz-runtime"
version = "3.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "303774eb17994c2ddb59c460369f4c3a55496f013380278d78eeebd2deb896ac"
dependencies = [
"bincode",
"hex",
"num-traits",
"serde",
"sha-1 0.10.0",
"test-fuzz-internal",
]
[[package]]
name = "textwrap"
version = "0.15.1"
@ -3246,6 +3459,19 @@ dependencies = [
"serde",
]
[[package]]
name = "toolchain_find"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e85654a10e7a07a47c6f19d93818f3f343e22927f2fa280c84f7c8042743413"
dependencies = [
"home",
"lazy_static",
"regex",
"semver 0.11.0",
"walkdir",
]
[[package]]
name = "tower-service"
version = "0.3.2"
@ -3306,6 +3532,12 @@ version = "1.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987"
[[package]]
name = "ucd-trie"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e79c4d996edb816c91e4308506774452e55e95c3c9de07b6729e17e15a5ef81"
[[package]]
name = "uint"
version = "0.9.4"
@ -3345,6 +3577,17 @@ version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a"
[[package]]
name = "unzip-n"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c2e7e85a0596447f0f2ac090e16bc4c516c6fe91771fb0c0ccf7fa3dae896b9c"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "vcell"
version = "0.1.3"

1
crates/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
target/

View File

@ -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()

View File

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

View 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
```

View 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);

View 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);

View 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);

View File

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

View File

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

View File

@ -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)]

View File

@ -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
}
}

View File

@ -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,