From d994d7a10cdee9455431d1f611196bee82a61b38 Mon Sep 17 00:00:00 2001 From: Vurich Date: Tue, 18 Jul 2017 14:14:42 +0200 Subject: [PATCH 1/8] Add benchmarks --- ethash/Cargo.toml | 3 +++ ethash/src/lib.rs | 27 +++++++++++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/ethash/Cargo.toml b/ethash/Cargo.toml index 0defcf3ae..417dc8426 100644 --- a/ethash/Cargo.toml +++ b/ethash/Cargo.toml @@ -10,3 +10,6 @@ log = "0.3" sha3 = { path = "../util/sha3" } primal = "0.2.3" parking_lot = "0.4" + +[features] +benches = [] \ No newline at end of file diff --git a/ethash/src/lib.rs b/ethash/src/lib.rs index 956da5b87..4791f481a 100644 --- a/ethash/src/lib.rs +++ b/ethash/src/lib.rs @@ -1,3 +1,5 @@ +#![cfg_attr(feature = "benches", feature(test))] + // Copyright 2015-2017 Parity Technologies (UK) Ltd. // This file is part of Parity. @@ -125,3 +127,28 @@ fn test_lru() { assert_eq!(ethash.cache.lock().recent_epoch.unwrap(), 2); assert_eq!(ethash.cache.lock().prev_epoch.unwrap(), 0); } + +#[cfg(feature = "benches")] +mod benchmarks { + extern crate test; + + use compute::{Light, light_compute, SeedHashCompute}; + use self::test::Bencher; + + #[bench] + fn bench_light_compute(b: &mut Bencher) { + let hash = [0xf5, 0x7e, 0x6f, 0x3a, 0xcf, 0xc0, 0xdd, 0x4b, 0x5b, 0xf2, 0xbe, 0xe4, 0x0a, 0xb3, 0x35, 0x8a, 0xa6, 0x87, 0x73, 0xa8, 0xd0, 0x9f, 0x5e, 0x59, 0x5e, 0xab, 0x55, 0x94, 0x05, 0x52, 0x7d, 0x72]; + let nonce = 0xd7b3ac70a301a249; + let light = Light::new(486382); + + b.iter(|| light_compute(&light, &hash, nonce)); + } + + #[bench] + fn bench_seedhash(b: &mut Bencher) { + let seed_compute = SeedHashCompute::new(); + let hash = [241, 175, 44, 134, 39, 121, 245, 239, 228, 236, 43, 160, 195, 152, 46, 7, 199, 5, 253, 147, 241, 206, 98, 43, 3, 104, 17, 40, 192, 79, 106, 162]; + + b.iter(|| seed_compute.get_seedhash(486382)); + } +} From 410ded5d45daca202f0243de788cf2c02cc34868 Mon Sep 17 00:00:00 2001 From: Vurich Date: Tue, 18 Jul 2017 14:17:01 +0200 Subject: [PATCH 2/8] Remove dead code from benchmarks --- ethash/src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/ethash/src/lib.rs b/ethash/src/lib.rs index 4791f481a..e154ac2f0 100644 --- a/ethash/src/lib.rs +++ b/ethash/src/lib.rs @@ -147,7 +147,6 @@ mod benchmarks { #[bench] fn bench_seedhash(b: &mut Bencher) { let seed_compute = SeedHashCompute::new(); - let hash = [241, 175, 44, 134, 39, 121, 245, 239, 228, 236, 43, 160, 195, 152, 46, 7, 199, 5, 253, 147, 241, 206, 98, 43, 3, 104, 17, 40, 192, 79, 106, 162]; b.iter(|| seed_compute.get_seedhash(486382)); } From d51958dbf5a66a432722e15addca0dc37c957681 Mon Sep 17 00:00:00 2001 From: Vurich Date: Tue, 18 Jul 2017 15:38:10 +0200 Subject: [PATCH 3/8] Speed up light_compute by ~9% --- Cargo.lock | 7 +++++++ ethash/Cargo.toml | 1 + ethash/src/compute.rs | 39 +++++++++++++++++++++++++++++++++------ ethash/src/lib.rs | 2 ++ 4 files changed, 43 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 63597b890..3e88b40cb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -254,6 +254,11 @@ name = "crossbeam" version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "crunchy" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "crypt32-sys" version = "0.2.0" @@ -360,6 +365,7 @@ dependencies = [ name = "ethash" version = "1.7.0" dependencies = [ + "crunchy 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "primal 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2943,6 +2949,7 @@ dependencies = [ "checksum core-foundation 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "20a6d0448d3a99d977ae4a2aa5a98d886a923e863e81ad9ff814645b6feb3bbd" "checksum core-foundation-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "05eed248dc504a5391c63794fe4fb64f46f071280afaa1b73308f3c0ce4574c5" "checksum crossbeam 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "0c5ea215664ca264da8a9d9c3be80d2eaf30923c259d03e870388eb927508f97" +"checksum crunchy 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b56bdac907d4b64254aed43964b11dd334bc46e0826a0e3add75caddfaf90175" "checksum crypt32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e34988f7e069e0b2f3bfc064295161e489b2d4e04a2e4248fb94360cdf00b4ec" "checksum ctrlc 1.1.1 (git+https://github.com/paritytech/rust-ctrlc.git)" = "" "checksum daemonize 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "271ec51b7e0bee92f0d04601422c73eb76ececf197026711c97ad25038a010cf" diff --git a/ethash/Cargo.toml b/ethash/Cargo.toml index 417dc8426..5f938be3d 100644 --- a/ethash/Cargo.toml +++ b/ethash/Cargo.toml @@ -10,6 +10,7 @@ log = "0.3" sha3 = { path = "../util/sha3" } primal = "0.2.3" parking_lot = "0.4" +crunchy = "0.1.0" [features] benches = [] \ No newline at end of file diff --git a/ethash/src/compute.rs b/ethash/src/compute.rs index 992578041..67b1ea678 100644 --- a/ethash/src/compute.rs +++ b/ethash/src/compute.rs @@ -287,12 +287,39 @@ fn hash_compute(light: &Light, full_size: usize, header_hash: &H256, nonce: u64) let num_full_pages = (full_size / page_size) as u32; let cache: &[Node] = &light.cache; // deref once for better performance - for i in 0..(ETHASH_ACCESSES as u32) { - let index = fnv_hash(f_mix.get_unchecked(0).as_words().get_unchecked(0) ^ i, *mix.get_unchecked(0).as_words().get_unchecked((i as usize) % MIX_WORDS)) % num_full_pages; - for n in 0..MIX_NODES { - let tmp_node = calculate_dag_item(index * MIX_NODES as u32 + n as u32, cache); - for w in 0..NODE_WORDS { - *mix.get_unchecked_mut(n).as_words_mut().get_unchecked_mut(w) = fnv_hash(*mix.get_unchecked(n).as_words().get_unchecked(w), *tmp_node.as_words().get_unchecked(w)); + debug_assert_eq!(ETHASH_ACCESSES, 64); + debug_assert_eq!(MIX_NODES, 2); + debug_assert_eq!(NODE_WORDS, 16); + + unroll! { + // ETHASH_ACCESSES + for i_usize in 0..64 { + let i = i_usize as u32; + + let index = fnv_hash( + f_mix.get_unchecked(0).as_words().get_unchecked(0) ^ i, + *mix.get_unchecked(0).as_words().get_unchecked(i_usize % MIX_WORDS) + ) % num_full_pages; + + unroll! { + // MIX_NODES + for n in 0..2 { + let tmp_node = calculate_dag_item( + index * MIX_NODES as u32 + n as u32, + cache, + ); + + unroll! { + // NODE_WORDS + for w in 0..16 { + *mix.get_unchecked_mut(n).as_words_mut().get_unchecked_mut(w) = + fnv_hash( + *mix.get_unchecked(n).as_words().get_unchecked(w), + *tmp_node.as_words().get_unchecked(w), + ); + } + } + } } } } diff --git a/ethash/src/lib.rs b/ethash/src/lib.rs index e154ac2f0..efe1950e3 100644 --- a/ethash/src/lib.rs +++ b/ethash/src/lib.rs @@ -22,6 +22,8 @@ extern crate primal; extern crate sha3; extern crate parking_lot; +#[macro_use] +extern crate crunchy; #[macro_use] extern crate log; mod compute; From 2cc1c92901e9d54d4cd83181ecf22c687c1326b1 Mon Sep 17 00:00:00 2001 From: Vurich Date: Wed, 19 Jul 2017 12:07:34 +0200 Subject: [PATCH 4/8] Unroll one more loop I also tried unrolling the 256-iteration loop further below, but it actually caused a slowdown (my guess is either branch prediction stopped kicking in or the instruction cache was being maculated). --- Cargo.lock | 6 +++--- ethash/src/compute.rs | 25 ++++++++++++++++--------- 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3e88b40cb..79217f7e2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -256,7 +256,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "crunchy" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -365,7 +365,7 @@ dependencies = [ name = "ethash" version = "1.7.0" dependencies = [ - "crunchy 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "crunchy 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "primal 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2949,7 +2949,7 @@ dependencies = [ "checksum core-foundation 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "20a6d0448d3a99d977ae4a2aa5a98d886a923e863e81ad9ff814645b6feb3bbd" "checksum core-foundation-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "05eed248dc504a5391c63794fe4fb64f46f071280afaa1b73308f3c0ce4574c5" "checksum crossbeam 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "0c5ea215664ca264da8a9d9c3be80d2eaf30923c259d03e870388eb927508f97" -"checksum crunchy 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b56bdac907d4b64254aed43964b11dd334bc46e0826a0e3add75caddfaf90175" +"checksum crunchy 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "803315676d3fc09db67636977586262e7d1a6c5bdb291810efd5ceb48a0d5d58" "checksum crypt32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e34988f7e069e0b2f3bfc064295161e489b2d4e04a2e4248fb94360cdf00b4ec" "checksum ctrlc 1.1.1 (git+https://github.com/paritytech/rust-ctrlc.git)" = "" "checksum daemonize 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "271ec51b7e0bee92f0d04601422c73eb76ececf197026711c97ad25038a010cf" diff --git a/ethash/src/compute.rs b/ethash/src/compute.rs index 67b1ea678..21dd0a7c7 100644 --- a/ethash/src/compute.rs +++ b/ethash/src/compute.rs @@ -298,7 +298,7 @@ fn hash_compute(light: &Light, full_size: usize, header_hash: &H256, nonce: u64) let index = fnv_hash( f_mix.get_unchecked(0).as_words().get_unchecked(0) ^ i, - *mix.get_unchecked(0).as_words().get_unchecked(i_usize % MIX_WORDS) + *mix.get_unchecked(0).as_words().get_unchecked(i as usize % MIX_WORDS) ) % num_full_pages; unroll! { @@ -324,14 +324,18 @@ fn hash_compute(light: &Light, full_size: usize, header_hash: &H256, nonce: u64) } } + debug_assert_eq!(MIX_WORDS / 4, 8); + // compress mix - for i in 0..(MIX_WORDS / 4) { - let w = i * 4; - let mut reduction = *mix.get_unchecked(0).as_words().get_unchecked(w + 0); - reduction = reduction.wrapping_mul(FNV_PRIME) ^ *mix.get_unchecked(0).as_words().get_unchecked(w + 1); - reduction = reduction.wrapping_mul(FNV_PRIME) ^ *mix.get_unchecked(0).as_words().get_unchecked(w + 2); - reduction = reduction.wrapping_mul(FNV_PRIME) ^ *mix.get_unchecked(0).as_words().get_unchecked(w + 3); - *mix.get_unchecked_mut(0).as_words_mut().get_unchecked_mut(i) = reduction; + unroll! { + for i in 0..8 { + let w = i * 4; + let mut reduction = *mix.get_unchecked(0).as_words().get_unchecked(w + 0); + reduction = reduction.wrapping_mul(FNV_PRIME) ^ *mix.get_unchecked(0).as_words().get_unchecked(w + 1); + reduction = reduction.wrapping_mul(FNV_PRIME) ^ *mix.get_unchecked(0).as_words().get_unchecked(w + 2); + reduction = reduction.wrapping_mul(FNV_PRIME) ^ *mix.get_unchecked(0).as_words().get_unchecked(w + 3); + *mix.get_unchecked_mut(0).as_words_mut().get_unchecked_mut(i) = reduction; + } } let mut mix_hash = [0u8; 32]; @@ -356,13 +360,15 @@ fn calculate_dag_item(node_index: u32, cache: &[Node]) -> Node { *ret.as_words_mut().get_unchecked_mut(0) ^= node_index; sha3::sha3_512(ret.bytes.as_mut_ptr(), ret.bytes.len(), ret.bytes.as_ptr(), ret.bytes.len()); - for i in 0..ETHASH_DATASET_PARENTS { + for i_usize in 0..ETHASH_DATASET_PARENTS { + let i = i_usize as u32; let parent_index = fnv_hash(node_index ^ i, *ret.as_words().get_unchecked(i as usize % NODE_WORDS)) % num_parent_nodes as u32; let parent = cache.get_unchecked(parent_index as usize); for w in 0..NODE_WORDS { *ret.as_words_mut().get_unchecked_mut(w) = fnv_hash(*ret.as_words().get_unchecked(w), *parent.as_words().get_unchecked(w)); } } + sha3::sha3_512(ret.bytes.as_mut_ptr(), ret.bytes.len(), ret.bytes.as_ptr(), ret.bytes.len()); ret } @@ -386,6 +392,7 @@ fn light_new(block_number: u64) -> Light { sha3::sha3_512(nodes.get_unchecked_mut(i).bytes.as_mut_ptr(), NODE_BYTES, nodes.get_unchecked(i - 1).bytes.as_ptr(), NODE_BYTES); } + // This _should_ get unrolled by the compiler, since it's not using the loop variable. for _ in 0..ETHASH_CACHE_ROUNDS { for i in 0..num_nodes { let idx = *nodes.get_unchecked_mut(i).as_words().get_unchecked(0) as usize % num_nodes; From 7d35f994d2dc689c8db36cfb81e3c65f8cf01635 Mon Sep 17 00:00:00 2001 From: Vurich Date: Wed, 19 Jul 2017 12:09:45 +0200 Subject: [PATCH 5/8] Style ungrumble --- ethash/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ethash/src/lib.rs b/ethash/src/lib.rs index efe1950e3..d8e4d39b4 100644 --- a/ethash/src/lib.rs +++ b/ethash/src/lib.rs @@ -1,5 +1,3 @@ -#![cfg_attr(feature = "benches", feature(test))] - // Copyright 2015-2017 Parity Technologies (UK) Ltd. // This file is part of Parity. @@ -16,6 +14,8 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . +#![cfg_attr(feature = "benches", feature(test))] + //! Ethash implementation //! See https://github.com/ethereum/wiki/wiki/Ethash extern crate primal; From ad1835e87c6d3e67fd4997743333c1c7973e89a4 Mon Sep 17 00:00:00 2001 From: Vurich Date: Wed, 19 Jul 2017 16:21:55 +0200 Subject: [PATCH 6/8] Unroll 1 more loop --- ethash/src/compute.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/ethash/src/compute.rs b/ethash/src/compute.rs index 21dd0a7c7..0db5200dc 100644 --- a/ethash/src/compute.rs +++ b/ethash/src/compute.rs @@ -397,8 +397,12 @@ fn light_new(block_number: u64) -> Light { for i in 0..num_nodes { let idx = *nodes.get_unchecked_mut(i).as_words().get_unchecked(0) as usize % num_nodes; let mut data = nodes.get_unchecked((num_nodes - 1 + i) % num_nodes).clone(); - for w in 0..NODE_WORDS { - *data.as_words_mut().get_unchecked_mut(w) ^= *nodes.get_unchecked(idx).as_words().get_unchecked(w); + + debug_assert_eq!(NODE_WORDS, 16); + unroll! { + for w in 0..16 { + *data.as_words_mut().get_unchecked_mut(w) ^= *nodes.get_unchecked(idx).as_words().get_unchecked(w); + } } sha3_512(&data.bytes, &mut nodes.get_unchecked_mut(i).bytes); } From 7208b9b525c2a1f4f1687081b3cd821f7ee37fa5 Mon Sep 17 00:00:00 2001 From: Vurich Date: Wed, 19 Jul 2017 18:14:10 +0200 Subject: [PATCH 7/8] Small fixes --- Cargo.lock | 6 +++--- ethash/src/compute.rs | 19 ++++++++++++++----- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 79217f7e2..5883b9484 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -256,7 +256,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "crunchy" -version = "0.1.1" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -365,7 +365,7 @@ dependencies = [ name = "ethash" version = "1.7.0" dependencies = [ - "crunchy 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "crunchy 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "primal 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2949,7 +2949,7 @@ dependencies = [ "checksum core-foundation 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "20a6d0448d3a99d977ae4a2aa5a98d886a923e863e81ad9ff814645b6feb3bbd" "checksum core-foundation-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "05eed248dc504a5391c63794fe4fb64f46f071280afaa1b73308f3c0ce4574c5" "checksum crossbeam 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "0c5ea215664ca264da8a9d9c3be80d2eaf30923c259d03e870388eb927508f97" -"checksum crunchy 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "803315676d3fc09db67636977586262e7d1a6c5bdb291810efd5ceb48a0d5d58" +"checksum crunchy 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e6aa9cb5f2d7bffc4eecfaf924fe450549dc4f0c3a6502298dc24f968b1eabbe" "checksum crypt32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e34988f7e069e0b2f3bfc064295161e489b2d4e04a2e4248fb94360cdf00b4ec" "checksum ctrlc 1.1.1 (git+https://github.com/paritytech/rust-ctrlc.git)" = "" "checksum daemonize 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "271ec51b7e0bee92f0d04601422c73eb76ececf197026711c97ad25038a010cf" diff --git a/ethash/src/compute.rs b/ethash/src/compute.rs index 0db5200dc..2fcaeb58f 100644 --- a/ethash/src/compute.rs +++ b/ethash/src/compute.rs @@ -360,12 +360,19 @@ fn calculate_dag_item(node_index: u32, cache: &[Node]) -> Node { *ret.as_words_mut().get_unchecked_mut(0) ^= node_index; sha3::sha3_512(ret.bytes.as_mut_ptr(), ret.bytes.len(), ret.bytes.as_ptr(), ret.bytes.len()); - for i_usize in 0..ETHASH_DATASET_PARENTS { - let i = i_usize as u32; + debug_assert_eq!(NODE_WORDS, 16); + for i in 0..ETHASH_DATASET_PARENTS as u32 { let parent_index = fnv_hash(node_index ^ i, *ret.as_words().get_unchecked(i as usize % NODE_WORDS)) % num_parent_nodes as u32; let parent = cache.get_unchecked(parent_index as usize); - for w in 0..NODE_WORDS { - *ret.as_words_mut().get_unchecked_mut(w) = fnv_hash(*ret.as_words().get_unchecked(w), *parent.as_words().get_unchecked(w)); + + unroll! { + for w in 0..16 { + *ret.as_words_mut().get_unchecked_mut(w) = + fnv_hash( + *ret.as_words().get_unchecked(w), + *parent.as_words().get_unchecked(w) + ); + } } } @@ -392,18 +399,20 @@ fn light_new(block_number: u64) -> Light { sha3::sha3_512(nodes.get_unchecked_mut(i).bytes.as_mut_ptr(), NODE_BYTES, nodes.get_unchecked(i - 1).bytes.as_ptr(), NODE_BYTES); } + debug_assert_eq!(NODE_WORDS, 16); + // This _should_ get unrolled by the compiler, since it's not using the loop variable. for _ in 0..ETHASH_CACHE_ROUNDS { for i in 0..num_nodes { let idx = *nodes.get_unchecked_mut(i).as_words().get_unchecked(0) as usize % num_nodes; let mut data = nodes.get_unchecked((num_nodes - 1 + i) % num_nodes).clone(); - debug_assert_eq!(NODE_WORDS, 16); unroll! { for w in 0..16 { *data.as_words_mut().get_unchecked_mut(w) ^= *nodes.get_unchecked(idx).as_words().get_unchecked(w); } } + sha3_512(&data.bytes, &mut nodes.get_unchecked_mut(i).bytes); } } From 0fa9c93f6f6ca6e3be580da8bb3e03f6315d6022 Mon Sep 17 00:00:00 2001 From: Vurich Date: Sat, 22 Jul 2017 14:49:02 +0200 Subject: [PATCH 8/8] Style reungrumble --- ethash/src/lib.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ethash/src/lib.rs b/ethash/src/lib.rs index d8e4d39b4..d870adc0e 100644 --- a/ethash/src/lib.rs +++ b/ethash/src/lib.rs @@ -14,10 +14,11 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -#![cfg_attr(feature = "benches", feature(test))] - //! Ethash implementation //! See https://github.com/ethereum/wiki/wiki/Ethash + +#![cfg_attr(feature = "benches", feature(test))] + extern crate primal; extern crate sha3; extern crate parking_lot;