Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: make benchmarks more reproducible #23

Merged
merged 1 commit into from
Nov 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 25 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ license = "MIT OR Apache-2.0"
name = "boc"
harness = false

[[bench]]
name = "mine"
harness = false

[[bench]]
name = "dict_from_slice"
harness = false
Expand All @@ -29,8 +33,26 @@ harness = false
name = "usage_cell"
harness = false

# callgrind benchmarks

[[bench]]
name = "mine"
name = "callgrind_boc"
harness = false

[[bench]]
name = "callgrind_dict_from_slice"
harness = false

[[bench]]
name = "callgrind_dict"
harness = false

[[bench]]
name = "callgrind_slice_uniform"
harness = false

[[bench]]
name = "callgrind_usage_cell"
harness = false

[workspace]
Expand Down Expand Up @@ -69,6 +91,8 @@ rand = "0.8"
rand_xorshift = "0.3"
serde = { version = "1", features = ["derive"] }
serde_json = "1"
iai-callgrind = "0.14"
paste = "1.0.15"

[features]
default = ["base64", "serde", "models", "sync"]
Expand Down
45 changes: 18 additions & 27 deletions benches/boc.rs

Large diffs are not rendered by default.

74 changes: 74 additions & 0 deletions benches/callgrind_boc.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
use everscale_types::boc::Boc;
use everscale_types::cell::Cell;
use iai_callgrind::{library_benchmark, library_benchmark_group, main};
use std::hint::black_box;

#[macro_export]
macro_rules! decl_boc_benches {
($(
$name:literal
),* $(,)?) => {
// generate setup functions for raw bytes
$(
paste::paste! {
fn [<$name _setup>]() -> &'static [u8] {
include_bytes!(concat!("data/", $name))
}
}
)*

// generate setup functions for cells
$(
paste::paste! {
fn [<$name _setup_de>]() -> Cell {
let bytes = include_bytes!(concat!("data/", $name));
Boc::decode(&bytes).unwrap()
}
}
)*

// generate benchmark functions attributes for decode / encode
paste::paste! {
#[library_benchmark]
$(
#[bench::[<$name>](setup = [<$name _setup>])]
)*
fn deserialize_boc(input: &[u8]) {
let result = Boc::decode(input);
_ = black_box(result);
}

#[library_benchmark]
$(
#[bench::[<$name>](setup = [<$name _setup_de>])]
)*
fn serialize_boc(input: Cell) {
let result = Boc::encode(&input);
_ = black_box(result);
std::mem::forget(input);
}
}
};
}

decl_boc_benches![
"external_message",
"internal_message_empty",
"internal_message_with_body",
"internal_message_with_deploy",
"masterchain_block",
"masterchain_key_block",
"shard_block_empty",
"shard_block_with_messages",
"masterchain_block_proof",
"shard_block_proof"
];

library_benchmark_group!(
name = benches;
benchmarks =
deserialize_boc,
serialize_boc
);

main!(library_benchmark_groups = benches);
35 changes: 35 additions & 0 deletions benches/callgrind_dict.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
use everscale_types::{cell::*, dict::*};
use iai_callgrind::{library_benchmark, library_benchmark_group, main};
use rand::distributions::{Distribution, Standard};
use rand::{Rng, SeedableRng};
use std::hint::black_box;

fn build_dict<K, V>(num_elements: usize) -> Dict<K, V>
where
Standard: Distribution<K> + Distribution<V>,
K: Store + DictKey,
V: Store,
{
let mut rng = rand_xorshift::XorShiftRng::from_seed([0u8; 16]);

let mut result = Dict::<K, V>::new();
for _ in 0..num_elements {
let key = rng.gen::<K>();
let value = rng.gen::<V>();
result.set(key, value).unwrap();
}
result
}

#[library_benchmark]
#[bench::small(10)]
#[bench::medium(100)]
#[bench::large(1000)]
#[bench::xlarge(10000)]
fn bench_build_dict_u64_u64(num_elements: usize) -> Dict<u64, u64> {
black_box(build_dict(num_elements))
}

library_benchmark_group!(name = build_dict; benchmarks = bench_build_dict_u64_u64);

main!(library_benchmark_groups = build_dict);
63 changes: 63 additions & 0 deletions benches/callgrind_dict_from_slice.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
use everscale_types::{cell::*, dict::*};
use iai_callgrind::{library_benchmark, library_benchmark_group, main};
use rand::distributions::{Distribution, Standard};
use rand::{Rng, SeedableRng};
use std::hint::black_box;

fn build_dict_inserts<K, V>(num_elements: usize) -> Dict<K, V>
where
Standard: Distribution<K> + Distribution<V>,
K: Store + DictKey,
V: Store,
{
let mut rng = rand_xorshift::XorShiftRng::from_seed([0u8; 16]);

let mut result = Dict::<K, V>::new();
for _ in 0..num_elements {
let key = rng.gen::<K>();
let value = rng.gen::<V>();
result.add(key, value).unwrap();
}
result
}

fn build_dict_leaves<K, V>(num_elements: usize) -> Dict<K, V>
where
Standard: Distribution<K> + Distribution<V>,
K: Store + DictKey + Ord,
V: Store,
{
let mut rng = rand_xorshift::XorShiftRng::from_seed([0u8; 16]);

let mut values = (0..num_elements)
.map(|_| (rng.gen::<K>(), rng.gen::<V>()))
.collect::<Vec<_>>();
values.sort_by(|(l, _), (r, _)| l.cmp(r));

Dict::<K, V>::try_from_sorted_slice(&values).unwrap()
}

#[library_benchmark]
#[bench::small(10)]
#[bench::medium(100)]
#[bench::large(1000)]
#[bench::xlarge(10000)]
fn bench_build_dict_u64_u64_inserts(num_elements: usize) -> Dict<u64, u64> {
black_box(build_dict_inserts(num_elements))
}

#[library_benchmark]
#[bench::small(10)]
#[bench::medium(100)]
#[bench::large(1000)]
#[bench::xlarge(10000)]
fn bench_build_dict_u64_u64_leaves(num_elements: usize) -> Dict<u64, u64> {
black_box(build_dict_leaves(num_elements))
}

library_benchmark_group!(
name = build_dict;
benchmarks = bench_build_dict_u64_u64_inserts, bench_build_dict_u64_u64_leaves
);

main!(library_benchmark_groups = build_dict);
24 changes: 24 additions & 0 deletions benches/callgrind_slice_uniform.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
use everscale_types::prelude::*;
use iai_callgrind::{library_benchmark, library_benchmark_group, main};
use std::hint::black_box;

#[library_benchmark]
#[bench::small(2)]
#[bench::medium(4)]
#[bench::large(8)]
#[bench::xlarge(10)]
fn test(bits: u32) {
let mut builder = CellBuilder::new();
builder.store_zeros(2u16.pow(bits) - 1u16).unwrap();
let cell = builder.build().unwrap();

let slice = cell.as_slice().unwrap();
black_box(slice.test_uniform());
}

library_benchmark_group!(
name = test_uniform;
benchmarks = test
);

main!(library_benchmark_groups = test_uniform);
94 changes: 94 additions & 0 deletions benches/callgrind_usage_cell.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
use everscale_types::cell::RefsIter;
use everscale_types::prelude::*;
use iai_callgrind::{library_benchmark, library_benchmark_group, main};
use std::collections::HashSet;
use std::hint::black_box;

const BOC: &str = "te6ccgECCAEAAWQAAnPP9noJKCEBL3oZerOiIcNghuL96V3wIcuYOWQdvNC+2fqCEIJDQAAAAAAAAAAAAAAAAZa8xB6QABNAAgEAUO3QlUyMI4dEepUMw3Ou6oSqq8+1lyHkjOGFK6DAn6TXAAAAAAAAAAABFP8A9KQT9LzyyAsDAgEgBwQC5vJx1wEBwADyeoMI1xjtRNCDB9cB1ws/yPgozxYjzxbJ+QADcdcBAcMAmoMH1wFRE7ry4GTegEDXAYAg1wGAINcBVBZ1+RDyqPgju/J5Zr74I4EHCKCBA+ioUiC8sfJ0AiCCEEzuZGy64w8ByMv/yz/J7VQGBQA+ghAWnj4Ruo4R+AACkyDXSpd41wHUAvsA6NGTMvI84gCYMALXTND6QIMG1wFx1wF41wHXTPgAcIAQBKoCFLHIywVQBc8WUAP6AstpItAhzzEh10mghAm5mDNwAcsAWM8WlzBxAcsAEsziyQH7AAAE0jA=";

#[library_benchmark]
fn traverse_cell_ordinary() {
let cell = Boc::decode_base64(BOC).unwrap();

let mut visitor = Visitor::new();
black_box(visitor.add_cell(cell.as_ref()));
}

#[library_benchmark]
fn traverse_cell_storage_cell() {
let cell = Boc::decode_base64(BOC).unwrap();
let usage_tree = UsageTree::new(UsageTreeMode::OnDataAccess);
let cell = usage_tree.track(&cell);

let mut visitor = Visitor::new();
black_box(visitor.add_cell(cell.as_ref()));
}

#[library_benchmark]
fn traverse_cell_storage_cell_with_capacity() {
let cell = Boc::decode_base64(BOC).unwrap();
let usage_tree = UsageTree::with_mode_and_capacity(UsageTreeMode::OnDataAccess, 100);
let cell = usage_tree.track(&cell);

let mut visitor = Visitor::new();
black_box(visitor.add_cell(cell.as_ref()));
}

struct Visitor<'a> {
visited: ahash::HashSet<&'a HashBytes>,
stack: Vec<RefsIter<'a>>,
}

impl<'a> Visitor<'a> {
fn new() -> Self {
Self {
visited: HashSet::with_hasher(ahash::RandomState::with_seed(0)),
stack: Vec::new(),
}
}
}

impl<'a> Visitor<'a> {
fn add_cell(&mut self, cell: &'a DynCell) -> bool {
if !self.visited.insert(cell.repr_hash()) {
return true;
}

self.stack.clear();
self.stack.push(cell.references());
self.reduce_stack()
}

fn reduce_stack(&mut self) -> bool {
'outer: while let Some(item) = self.stack.last_mut() {
for cell in item.by_ref() {
if !self.visited.insert(cell.repr_hash()) {
continue;
}

let mut slice = cell.as_slice().unwrap();
slice.load_bit().ok();
slice.load_u32().ok();
slice.load_small_uint(5).ok();
slice.load_reference().ok();

let next = cell.references();
if next.peek().is_some() {
self.stack.push(next);
continue 'outer;
}
}

self.stack.pop();
}

true
}
}

library_benchmark_group!(
name = traverse_cell;
benchmarks = traverse_cell_ordinary, traverse_cell_storage_cell, traverse_cell_storage_cell_with_capacity
);

main!(library_benchmark_groups = traverse_cell);
Binary file added benches/data/external_message
Binary file not shown.
Binary file added benches/data/internal_message_empty
Binary file not shown.
Binary file added benches/data/internal_message_with_body
Binary file not shown.
Binary file added benches/data/internal_message_with_deploy
Binary file not shown.
Binary file added benches/data/masterchain_block
Binary file not shown.
Binary file added benches/data/masterchain_block_proof
Binary file not shown.
Binary file added benches/data/masterchain_key_block
Binary file not shown.
Binary file added benches/data/shard_block_empty
Binary file not shown.
Binary file added benches/data/shard_block_proof
Binary file not shown.
Binary file added benches/data/shard_block_with_messages
Binary file not shown.
Loading