diff --git a/.travis.yml b/.travis.yml index a878ee064..b38c5ff5c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -39,3 +39,4 @@ script: - cd parity-util-mem/ && cargo test --features=jemalloc-global && cd .. - cd parity-util-mem/ && cargo test --features=mimalloc-global && cd .. - cd rlp/ && cargo test --no-default-features && cargo check --benches && cd .. + - cd triehash/ && cargo check --benches && cd .. diff --git a/triehash/Cargo.toml b/triehash/Cargo.toml index 2d207cc4b..453815c6c 100644 --- a/triehash/Cargo.toml +++ b/triehash/Cargo.toml @@ -5,13 +5,21 @@ authors = ["Parity Technologies "] description = "In-memory patricia trie operations" repository = "https://github.com/paritytech/parity-common" license = "GPL-3.0" +edition = "2018" [dependencies] hash-db = "0.15" rlp = { version = "0.4", path = "../rlp" } [dev-dependencies] +criterion = "0.3" keccak-hasher = "0.15" -tiny-keccak = "1.4.2" -ethereum-types = { version = "0.7", path = "../ethereum-types" } +tiny-keccak = "1.5" +trie-standardmap = "0.15" hex-literal = "0.2" +ethereum-types = { version = "0.7", path = "../ethereum-types" } + +[[bench]] +name = "triehash" +path = "benches/triehash.rs" +harness = false diff --git a/triehash/benches/triehash.rs b/triehash/benches/triehash.rs index 433ea74ce..8930f473e 100644 --- a/triehash/benches/triehash.rs +++ b/triehash/benches/triehash.rs @@ -14,25 +14,16 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -#![feature(test)] - -extern crate ethereum_types; -extern crate keccak_hasher; -extern crate test; -extern crate tiny_keccak; -extern crate trie_standardmap; -extern crate triehash; - +use criterion::{criterion_group, criterion_main, Criterion}; use ethereum_types::H256; use keccak_hasher::KeccakHasher; -use test::Bencher; use tiny_keccak::keccak256; -use trie_standardmap::{Alphabet, ValueMode, StandardMap}; +use trie_standardmap::{Alphabet, StandardMap, ValueMode}; use triehash::trie_root; fn random_word(alphabet: &[u8], min_count: usize, diff_count: usize, seed: &mut H256) -> Vec { assert!(min_count + diff_count <= 32); - *seed = H256(keccak256(&seed)); + *seed = H256(keccak256(seed.as_bytes())); let r = min_count + (seed[31] as usize % (diff_count + 1)); let mut ret: Vec = Vec::with_capacity(r); for i in 0..r { @@ -43,107 +34,91 @@ fn random_word(alphabet: &[u8], min_count: usize, diff_count: usize, seed: &mut fn random_bytes(min_count: usize, diff_count: usize, seed: &mut H256) -> Vec { assert!(min_count + diff_count <= 32); - *seed = H256(keccak256(&seed)); + *seed = H256(keccak256(seed.as_bytes())); let r = min_count + (seed[31] as usize % (diff_count + 1)); seed[0..r].to_vec() } fn random_value(seed: &mut H256) -> Vec { - *seed = H256(keccak256(&seed)); + *seed = H256(keccak256(seed.as_bytes())); match seed[0] % 2 { 1 => vec![seed[31];1], - _ => seed.to_vec(), + _ => seed.as_bytes().to_vec(), } } -#[bench] -fn triehash_insertions_32_mir_1k(b: &mut Bencher) { - let st = StandardMap { - alphabet: Alphabet::All, - min_key: 32, - journal_key: 0, - value_mode: ValueMode::Mirror, - count: 1000, - }; - let d = st.make(); - b.iter(&mut ||{ - let _ = trie_root::(d.clone()).clone(); +fn bench_insertions(c: &mut Criterion) { + c.bench_function("32_mir_1k", |b| { + let st = StandardMap { + alphabet: Alphabet::All, + min_key: 32, + journal_key: 0, + value_mode: ValueMode::Mirror, + count: 1000, + }; + let d = st.make(); + b.iter(|| trie_root::(d.clone())); }); -} -#[bench] -fn triehash_insertions_32_ran_1k(b: &mut Bencher) { - let st = StandardMap { - alphabet: Alphabet::All, - min_key: 32, - journal_key: 0, - value_mode: ValueMode::Random, - count: 1000, - }; - let d = st.make(); - b.iter(&mut ||{ - let _ = trie_root::(d.clone()).clone(); + c.bench_function("32_ran_1k", |b| { + let st = StandardMap { + alphabet: Alphabet::All, + min_key: 32, + journal_key: 0, + value_mode: ValueMode::Random, + count: 1000, + }; + let d = st.make(); + b.iter(|| trie_root::(d.clone())); }); -} -#[bench] -fn triehash_insertions_six_high(b: &mut Bencher) { - let mut d: Vec<(Vec, Vec)> = Vec::new(); - let mut seed = H256::new(); - for _ in 0..1000 { - let k = random_bytes(6, 0, &mut seed); - let v = random_value(&mut seed); - d.push((k, v)) - } - - b.iter(&||{ - let _ = trie_root::(d.clone()); - }) -} + c.bench_function("six_high", |b| { + let mut d: Vec<(Vec, Vec)> = Vec::new(); + let mut seed = H256::default(); + for _ in 0..1000 { + let k = random_bytes(6, 0, &mut seed); + let v = random_value(&mut seed); + d.push((k, v)) + } + b.iter(|| trie_root::(d.clone())); + }); -#[bench] -fn triehash_insertions_six_mid(b: &mut Bencher) { - let alphabet = b"@QWERTYUIOPASDFGHJKLZXCVBNM[/]^_"; - let mut d: Vec<(Vec, Vec)> = Vec::new(); - let mut seed = H256::new(); - for _ in 0..1000 { - let k = random_word(alphabet, 6, 0, &mut seed); - let v = random_value(&mut seed); - d.push((k, v)) - } - b.iter(||{ - let _ = trie_root::(d.clone()); - }) -} + c.bench_function("six_mid", |b| { + let alphabet = b"@QWERTYUIOPASDFGHJKLZXCVBNM[/]^_"; + let mut d: Vec<(Vec, Vec)> = Vec::new(); + let mut seed = H256::default(); + for _ in 0..1000 { + let k = random_word(alphabet, 6, 0, &mut seed); + let v = random_value(&mut seed); + d.push((k, v)) + } + b.iter(|| trie_root::(d.clone())); + }); -#[bench] -fn triehash_insertions_random_mid(b: &mut Bencher) { - let alphabet = b"@QWERTYUIOPASDFGHJKLZXCVBNM[/]^_"; - let mut d: Vec<(Vec, Vec)> = Vec::new(); - let mut seed = H256::new(); - for _ in 0..1000 { - let k = random_word(alphabet, 1, 5, &mut seed); - let v = random_value(&mut seed); - d.push((k, v)) - } + c.bench_function("random_mid", |b| { + let alphabet = b"@QWERTYUIOPASDFGHJKLZXCVBNM[/]^_"; + let mut d: Vec<(Vec, Vec)> = Vec::new(); + let mut seed = H256::default(); + for _ in 0..1000 { + let k = random_word(alphabet, 1, 5, &mut seed); + let v = random_value(&mut seed); + d.push((k, v)) + } + b.iter(|| trie_root::(d.clone())); + }); - b.iter(||{ - let _ = trie_root::(d.clone()); - }) + c.bench_function("six_low", |b| { + let alphabet = b"abcdef"; + let mut d: Vec<(Vec, Vec)> = Vec::new(); + let mut seed = H256::default(); + for _ in 0..1000 { + let k = random_word(alphabet, 6, 0, &mut seed); + let v = random_value(&mut seed); + d.push((k, v)) + } + b.iter(|| trie_root::(d.clone())); + }); } -#[bench] -fn triehash_insertions_six_low(b: &mut Bencher) { - let alphabet = b"abcdef"; - let mut d: Vec<(Vec, Vec)> = Vec::new(); - let mut seed = H256::new(); - for _ in 0..1000 { - let k = random_word(alphabet, 6, 0, &mut seed); - let v = random_value(&mut seed); - d.push((k, v)) - } - - b.iter(||{ - let _ = trie_root::(d.clone()); - }) -} +criterion_group!(benches, bench_insertions); +criterion_main!(benches); diff --git a/triehash/src/lib.rs b/triehash/src/lib.rs index 3d42626db..94bcbfaed 100644 --- a/triehash/src/lib.rs +++ b/triehash/src/lib.rs @@ -18,17 +18,10 @@ //! //! This module should be used to generate trie root hash. -extern crate hash_db; -extern crate rlp; -#[cfg(test)] -extern crate keccak_hasher; -#[cfg(test)] -#[macro_use] -extern crate hex_literal; - -use std::collections::BTreeMap; use std::cmp; +use std::collections::BTreeMap; use std::iter::once; + use hash_db::Hasher; use rlp::RlpStream; @@ -96,7 +89,6 @@ where H: Hasher, ::Out: cmp::Ord, { - // first put elements into btree to sort them and to remove duplicates let input = input .into_iter() @@ -240,20 +232,16 @@ where stream.begin_list(17); // if first key len is equal to prefix_len, move to next element - let mut begin = match pre_len == key.len() { - true => 1, - false => 0 - }; + let mut begin = if pre_len == key.len() { 1 } else { 0 }; // iterate over all possible nibbles for i in 0..16 { // count how many successive elements have same next nibble - let len = match begin < input.len() { - true => input[begin..].iter() - .take_while(| pair | pair.0.as_ref()[pre_len] == i ) - .count(), - false => 0 - }; + let len = input + .iter() + .skip(begin) + .take_while(|pair| pair.0.as_ref()[pre_len] == i) + .count(); // if at least 1 successive element has the same nibble // append their suffixes @@ -265,10 +253,11 @@ where } // if fist key len is equal prefix, append its value - match pre_len == key.len() { - true => { stream.append(&value); }, - false => { stream.append_empty_data(); } - }; + if pre_len == key.len() { + stream.append(&value); + } else { + stream.append_empty_data(); + } } fn hash256aux(input: &[(A, B)], pre_len: usize, stream: &mut RlpStream) @@ -288,10 +277,10 @@ where #[cfg(test)] mod tests { - extern crate ethereum_types; use super::{trie_root, shared_prefix_len, hex_prefix_encode}; use keccak_hasher::KeccakHasher; - use self::ethereum_types::H256; + use ethereum_types::H256; + use hex_literal::hex; #[test] fn test_hex_prefix_encode() { @@ -328,23 +317,28 @@ mod tests { #[test] fn simple_test() { - assert_eq!(trie_root::(vec![ - (b"A", b"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" as &[u8]) - ]), H256::from(hex!("d23786fb4a010da3ce639d66d5e904a11dbc02746d1ce25029e53290cabf28ab")).as_ref()); + assert_eq!( + trie_root::(vec![ + (b"A", b"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" as &[u8]) + ]), + H256::from(hex!("d23786fb4a010da3ce639d66d5e904a11dbc02746d1ce25029e53290cabf28ab")).as_ref(), + ); } #[test] fn test_triehash_out_of_order() { - assert!(trie_root::(vec![ - (vec![0x01u8, 0x23], vec![0x01u8, 0x23]), - (vec![0x81u8, 0x23], vec![0x81u8, 0x23]), - (vec![0xf1u8, 0x23], vec![0xf1u8, 0x23]), - ]) == - trie_root::(vec![ - (vec![0x01u8, 0x23], vec![0x01u8, 0x23]), - (vec![0xf1u8, 0x23], vec![0xf1u8, 0x23]), // last two tuples are swapped - (vec![0x81u8, 0x23], vec![0x81u8, 0x23]), - ])); + assert_eq!( + trie_root::(vec![ + (vec![0x01u8, 0x23], vec![0x01u8, 0x23]), + (vec![0x81u8, 0x23], vec![0x81u8, 0x23]), + (vec![0xf1u8, 0x23], vec![0xf1u8, 0x23]), + ]), + trie_root::(vec![ + (vec![0x01u8, 0x23], vec![0x01u8, 0x23]), + (vec![0xf1u8, 0x23], vec![0xf1u8, 0x23]), // last two tuples are swapped + (vec![0x81u8, 0x23], vec![0x81u8, 0x23]), + ]), + ); } #[test]