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: add merkle update benchmark #27

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
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
5 changes: 5 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ harness = false
name = "mine"
harness = false

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

[[bench]]
name = "dict_from_slice"
harness = false
Expand Down Expand Up @@ -94,6 +98,7 @@ serde_json = "1"
iai-callgrind = "0.14"
paste = "1.0.15"


[features]
default = ["base64", "serde", "models", "sync"]
sync = ["dep:scc"]
Expand Down
8 changes: 6 additions & 2 deletions benches/callgrind_usage_cell.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use everscale_types::cell::RefsIter;
use everscale_types::prelude::*;
use iai_callgrind::{library_benchmark, library_benchmark_group, main};
use iai_callgrind::{
library_benchmark, library_benchmark_group, main, FlamegraphConfig, LibraryBenchmarkConfig,
};
use std::collections::HashSet;
use std::hint::black_box;

Expand Down Expand Up @@ -91,4 +93,6 @@ library_benchmark_group!(
benchmarks = traverse_cell_ordinary, traverse_cell_storage_cell, traverse_cell_storage_cell_with_capacity
);

main!(library_benchmark_groups = traverse_cell);
main!(config =LibraryBenchmarkConfig::default()
.flamegraph(FlamegraphConfig::default());
library_benchmark_groups = traverse_cell);
93 changes: 93 additions & 0 deletions benches/merkle_update.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
use everscale_types::cell::{Cell, CellBuilder, HashBytes, UsageTree, UsageTreeMode};
use everscale_types::dict::Dict;
use everscale_types::merkle::{MerkleUpdate, MerkleUpdateBuilder};
use iai_callgrind::{
library_benchmark, library_benchmark_group, main, FlamegraphConfig, LibraryBenchmarkConfig,
};
use rand::prelude::{SliceRandom, StdRng};
use rand::{Rng, SeedableRng};

fn size_for_different_dicts() -> (Dict<HashBytes, Cell>, Vec<HashBytes>) {
let value = (0..10000)
.map(|x| (x, Dict::<u32, u32>::new()))
.collect::<Vec<_>>();

let value = Dict::try_from_sorted_slice(&value)
.unwrap()
.into_root()
.unwrap();

let size = 1_000_000;

let mut rng = StdRng::seed_from_u64(1337);
let mut keys: Vec<HashBytes> = (0..size)
.map(|_| {
let mut key = [0u8; 32];
rng.fill(&mut key[..]);
HashBytes::from(key)
})
.collect();
keys.sort_unstable();

let num_keys = 1000;

let keys_to_check = keys
.choose_multiple(&mut rng, num_keys)
.copied()
.collect::<Vec<_>>();

let keys_inner = keys.iter().map(|k| (*k, value.clone())).collect::<Vec<_>>();
let dict = Dict::try_from_sorted_slice(&keys_inner).unwrap();
drop(keys);

(dict, keys_to_check)
}

fn build_update(
dict: &Dict<HashBytes, Cell>,
keys_to_check: &[HashBytes],
) -> (Cell, Cell, UsageTree) {
let old_cell = CellBuilder::build_from(dict).unwrap();
let usage_tree = UsageTree::new(UsageTreeMode::OnLoad);
let old_dict_cell_tracked = usage_tree.track(&old_cell);

let mut dict = old_dict_cell_tracked
.parse::<Dict<HashBytes, Cell>>()
.unwrap();

for (idx, key) in keys_to_check.iter().enumerate() {
let mut cell = CellBuilder::new();
cell.store_u32(idx as _).unwrap();
let cell = cell.build().unwrap();
dict.set(key, cell.clone()).unwrap();
}

let new_dict_cell = CellBuilder::build_from(dict).unwrap();

(old_cell, new_dict_cell, usage_tree)
}

fn prepare() -> (Cell, Cell, UsageTree) {
let (dict, keys_to_check) = size_for_different_dicts();
build_update(&dict, &keys_to_check)
}

#[library_benchmark]
#[bench::base(setup=prepare)]
fn merkle_update((prev, new, usage_tree): (Cell, Cell, UsageTree)) {
let mut merkle = MerkleUpdateBuilder::new(prev.as_ref(), new.as_ref(), usage_tree);
let update = merkle.build().unwrap();

std::mem::forget(update);
std::mem::forget(prev);
std::mem::forget(new);
}

library_benchmark_group!(

name = merkle;
benchmarks = merkle_update
);
main!(config =LibraryBenchmarkConfig::default()
.flamegraph(FlamegraphConfig::default());
library_benchmark_groups = merkle);
4 changes: 4 additions & 0 deletions src/cell/usage_tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,10 @@ impl UsageTreeWithSubtrees {
pub fn add_subtree(&mut self, root: &DynCell) -> bool {
self.subtrees.insert(*root.repr_hash())
}

pub(crate) fn len(&self) -> usize {
self.state.len()
}
}

#[cfg(not(feature = "sync"))]
Expand Down
24 changes: 24 additions & 0 deletions src/merkle/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ mod __checks {
pub trait MerkleFilter {
/// Returns how the cell should be included in the Merkle proof or update.
fn check(&self, cell: &HashBytes) -> FilterAction;

/// Returns the number of elements in the filter, if known.
fn size_hint(&self) -> Option<usize>;
}

/// Merkle filter action.
Expand All @@ -48,6 +51,11 @@ impl<T: MerkleFilter + ?Sized> MerkleFilter for &T {
fn check(&self, cell: &HashBytes) -> FilterAction {
<T as MerkleFilter>::check(self, cell)
}

#[inline]
fn size_hint(&self) -> Option<usize> {
<T as MerkleFilter>::size_hint(self)
}
}

impl MerkleFilter for UsageTree {
Expand All @@ -58,6 +66,10 @@ impl MerkleFilter for UsageTree {
FilterAction::Skip
}
}

fn size_hint(&self) -> Option<usize> {
Some(UsageTree::len(self))
}
}

impl MerkleFilter for UsageTreeWithSubtrees {
Expand All @@ -70,6 +82,10 @@ impl MerkleFilter for UsageTreeWithSubtrees {
FilterAction::Skip
}
}

fn size_hint(&self) -> Option<usize> {
Some(self.len())
}
}

impl<S: BuildHasher> MerkleFilter for HashSet<HashBytes, S> {
Expand All @@ -80,6 +96,10 @@ impl<S: BuildHasher> MerkleFilter for HashSet<HashBytes, S> {
FilterAction::Skip
}
}

fn size_hint(&self) -> Option<usize> {
Some(self.len())
}
}

impl<S: BuildHasher> MerkleFilter for HashSet<&HashBytes, S> {
Expand All @@ -90,4 +110,8 @@ impl<S: BuildHasher> MerkleFilter for HashSet<&HashBytes, S> {
FilterAction::Skip
}
}

fn size_hint(&self) -> Option<usize> {
Some(self.len())
}
}
4 changes: 4 additions & 0 deletions src/merkle/proof.rs
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,10 @@ impl MerkleProof {
FilterAction::Skip
}
}

fn size_hint(&self) -> Option<usize> {
Some(self.cells.len())
}
}

let mut stack = vec![root.references()];
Expand Down
Loading
Loading