diff --git a/eth2/utils/tree_hash/Cargo.toml b/eth2/utils/tree_hash/Cargo.toml index 948e0fe4f..3019c2ad0 100644 --- a/eth2/utils/tree_hash/Cargo.toml +++ b/eth2/utils/tree_hash/Cargo.toml @@ -4,9 +4,15 @@ version = "0.1.0" authors = ["Paul Hauner "] edition = "2018" +[[bench]] +name = "benches" +harness = false + [dev-dependencies] +criterion = "0.2" rand = "0.7" tree_hash_derive = { path = "../tree_hash_derive" } +types = { path = "../../types" } [dependencies] ethereum-types = "0.5" diff --git a/eth2/utils/tree_hash/benches/benches.rs b/eth2/utils/tree_hash/benches/benches.rs new file mode 100644 index 000000000..22e2a8784 --- /dev/null +++ b/eth2/utils/tree_hash/benches/benches.rs @@ -0,0 +1,56 @@ +#[macro_use] +extern crate lazy_static; + +use criterion::Criterion; +use criterion::{black_box, criterion_group, criterion_main, Benchmark}; +use tree_hash::TreeHash; +use types::test_utils::{generate_deterministic_keypairs, TestingBeaconStateBuilder}; +use types::{BeaconState, EthSpec, Keypair, MainnetEthSpec, MinimalEthSpec}; + +lazy_static! { + static ref KEYPAIRS: Vec = { generate_deterministic_keypairs(300_000) }; +} + +fn build_state(validator_count: usize) -> BeaconState { + let (state, _keypairs) = TestingBeaconStateBuilder::from_keypairs( + KEYPAIRS[0..validator_count].to_vec(), + &T::default_spec(), + ) + .build(); + + assert_eq!(state.validators.len(), validator_count); + assert_eq!(state.balances.len(), validator_count); + assert!(state.previous_epoch_attestations.is_empty()); + assert!(state.current_epoch_attestations.is_empty()); + assert!(state.eth1_data_votes.is_empty()); + assert!(state.historical_roots.is_empty()); + + state +} + +fn bench_suite(c: &mut Criterion, spec_desc: &str, validator_count: usize) { + let state = build_state::(validator_count); + + c.bench( + &format!("{}/{}_validators", spec_desc, validator_count), + Benchmark::new("genesis_state", move |b| { + b.iter_batched_ref( + || state.clone(), + |state| black_box(state.tree_hash_root()), + criterion::BatchSize::SmallInput, + ) + }) + .sample_size(10), + ); +} + +fn all_benches(c: &mut Criterion) { + bench_suite::(c, "minimal", 100_000); + bench_suite::(c, "minimal", 300_000); + + bench_suite::(c, "mainnet", 100_000); + bench_suite::(c, "mainnet", 300_000); +} + +criterion_group!(benches, all_benches,); +criterion_main!(benches); diff --git a/eth2/utils/tree_hash/examples/flamegraph_beacon_state.rs b/eth2/utils/tree_hash/examples/flamegraph_beacon_state.rs new file mode 100644 index 000000000..8a619ce77 --- /dev/null +++ b/eth2/utils/tree_hash/examples/flamegraph_beacon_state.rs @@ -0,0 +1,35 @@ +use tree_hash::TreeHash; +use types::test_utils::TestingBeaconStateBuilder; +use types::{BeaconState, EthSpec, MainnetEthSpec}; + +const TREE_HASH_LOOPS: usize = 1_000; +const VALIDATOR_COUNT: usize = 1_000; + +fn build_state(validator_count: usize) -> BeaconState { + let (state, _keypairs) = TestingBeaconStateBuilder::from_default_keypairs_file_if_exists( + validator_count, + &T::default_spec(), + ) + .build(); + + assert_eq!(state.validators.len(), validator_count); + assert_eq!(state.balances.len(), validator_count); + assert!(state.previous_epoch_attestations.is_empty()); + assert!(state.current_epoch_attestations.is_empty()); + assert!(state.eth1_data_votes.is_empty()); + assert!(state.historical_roots.is_empty()); + + state +} + +fn main() { + let state = build_state::(VALIDATOR_COUNT); + + // This vec is an attempt to ensure the compiler doesn't optimize-out the hashing. + let mut vec = Vec::with_capacity(TREE_HASH_LOOPS); + + for _ in 0..TREE_HASH_LOOPS { + let root = state.tree_hash_root(); + vec.push(root[0]); + } +}