[ethash] remove manual unrolling (#11069)

* [ethash] remove unroll in calculate_dag_item

* [ethash] add keccak bench

* [ethash] remove unroll! completely

* [ethash] specify required-features for benches

* [ethcore/verification] specify required-features for benches

* [CI] simplify cargo-check-benches step
This commit is contained in:
Andronik Ordian 2019-09-24 11:45:28 +02:00 committed by GitHub
parent 2627288311
commit fc22c58408
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 39 additions and 52 deletions

View File

@ -100,9 +100,7 @@ cargo-check-benches:
stage: test stage: test
<<: *docker-cache-status <<: *docker-cache-status
script: script:
- time (cargo check --all --benches --exclude ethash --exclude verification --target $CARGO_TARGET --locked --verbose --color=always) - time cargo check --all --benches --target $CARGO_TARGET --locked --verbose --color=always
- time (cd ethash; cargo check --benches --features bench --target $CARGO_TARGET --locked --verbose --color=always)
- time (cd ethcore/verification; cargo check --benches --features bench --target $CARGO_TARGET --locked --verbose --color=always)
- sccache -s - sccache -s
cargo-audit: cargo-audit:
@ -344,7 +342,7 @@ publish-release-awss3-nightly: &publish-release-awss3
- linux-docker - linux-docker
publish-release-awss3-manually: publish-release-awss3-manually:
<<: *publish-release-awss3 <<: *publish-release-awss3
only: *releaseable_branches only: *releaseable_branches
when: manual when: manual

1
Cargo.lock generated
View File

@ -936,7 +936,6 @@ version = "1.12.0"
dependencies = [ dependencies = [
"common-types 0.1.0", "common-types 0.1.0",
"criterion 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "criterion 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"crunchy 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
"ethereum-types 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethereum-types 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"keccak-hash 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "keccak-hash 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",

View File

@ -6,7 +6,6 @@ authors = ["Parity Technologies <admin@parity.io>"]
[dependencies] [dependencies]
common-types = { path = "../ethcore/types" } common-types = { path = "../ethcore/types" }
crunchy = "0.1.0"
either = "1.0.0" either = "1.0.0"
ethereum-types = "0.6.0" ethereum-types = "0.6.0"
keccak-hash = "0.2.0" keccak-hash = "0.2.0"
@ -29,7 +28,9 @@ bench = []
[[bench]] [[bench]]
name = "basic" name = "basic"
harness = false harness = false
required-features = ['bench']
[[bench]] [[bench]]
name = "progpow" name = "progpow"
harness = false harness = false
required-features = ['bench']

View File

@ -20,7 +20,7 @@ extern crate ethash;
extern crate common_types; extern crate common_types;
use criterion::Criterion; use criterion::Criterion;
use ethash::NodeCacheBuilder; use ethash::{NodeCacheBuilder, keccak};
use common_types::engines::OptimizeFor; use common_types::engines::OptimizeFor;
const HASH: [u8; 32] = [ const HASH: [u8; 32] = [
@ -40,7 +40,8 @@ const NONCE: u64 = 0xd7b3ac70a301a249;
criterion_group! { criterion_group! {
name = basic; name = basic;
config = dont_take_an_eternity_to_run(); config = dont_take_an_eternity_to_run();
targets = bench_light_compute_memmap, targets = bench_keccak_512_inplace,
bench_light_compute_memmap,
bench_light_compute_memory, bench_light_compute_memory,
bench_light_new_round_trip_memmap, bench_light_new_round_trip_memmap,
bench_light_new_round_trip_memory, bench_light_new_round_trip_memory,
@ -56,6 +57,13 @@ fn dont_take_an_eternity_to_run() -> Criterion {
.sample_size(10) .sample_size(10)
} }
fn bench_keccak_512_inplace(b: &mut Criterion) {
b.bench_function("bench_keccak_512_inplace", move |b| b.iter(|| {
let mut data = [4u8; 64];
keccak::keccak_512::inplace(&mut data);
}));
}
fn bench_light_compute_memmap(b: &mut Criterion) { fn bench_light_compute_memmap(b: &mut Criterion) {
use std::env; use std::env;

View File

@ -21,7 +21,7 @@ use memmap::MmapMut;
use parking_lot::Mutex; use parking_lot::Mutex;
use seed_compute::SeedHashCompute; use seed_compute::SeedHashCompute;
use shared::{ETHASH_CACHE_ROUNDS, NODE_BYTES, NODE_DWORDS, Node, epoch, get_cache_size, to_hex}; use shared::{ETHASH_CACHE_ROUNDS, NODE_BYTES, Node, epoch, get_cache_size, to_hex};
use std::borrow::Cow; use std::borrow::Cow;
use std::fs; use std::fs;
@ -317,11 +317,6 @@ unsafe fn initialize_memory(memory: *mut Node, num_nodes: usize, ident: &H256) {
// Now this is initialized, we can treat it as a slice. // Now this is initialized, we can treat it as a slice.
let nodes: &mut [Node] = slice::from_raw_parts_mut(memory, num_nodes); let nodes: &mut [Node] = slice::from_raw_parts_mut(memory, num_nodes);
// For `unroll!`, see below. If the literal in `unroll!` is not the same as the RHS here then
// these have got out of sync! Don't let this happen!
debug_assert_eq!(NODE_DWORDS, 8);
// This _should_ get unrolled by the compiler, since it's not using the loop variable.
for _ in 0..ETHASH_CACHE_ROUNDS { for _ in 0..ETHASH_CACHE_ROUNDS {
for i in 0..num_nodes { for i in 0..num_nodes {
let data_idx = (num_nodes - 1 + i) % num_nodes; let data_idx = (num_nodes - 1 + i) % num_nodes;
@ -331,11 +326,8 @@ unsafe fn initialize_memory(memory: *mut Node, num_nodes: usize, ident: &H256) {
let mut data: Node = nodes.get_unchecked(data_idx).clone(); let mut data: Node = nodes.get_unchecked(data_idx).clone();
let rhs: &Node = nodes.get_unchecked(idx); let rhs: &Node = nodes.get_unchecked(idx);
unroll! { for (a, b) in data.as_dwords_mut().iter_mut().zip(rhs.as_dwords()) {
for w in 0..8 { *a ^= *b;
*data.as_dwords_mut().get_unchecked_mut(w) ^=
*rhs.as_dwords().get_unchecked(w);
}
} }
data data

View File

@ -239,24 +239,16 @@ fn hash_compute(light: &Light, full_size: usize, header_hash: &H256, nonce: u64)
fnv_hash(first_val ^ i, mix_words[i as usize % MIX_WORDS]) % num_full_pages fnv_hash(first_val ^ i, mix_words[i as usize % MIX_WORDS]) % num_full_pages
}; };
unroll! { // MIX_NODES
// MIX_NODES for n in 0..2 {
for n in 0..2 { let tmp_node = calculate_dag_item(
let tmp_node = calculate_dag_item( index * MIX_NODES as u32 + n as u32,
index * MIX_NODES as u32 + n as u32, cache,
cache, );
);
unroll! { // NODE_WORDS
// NODE_WORDS for (a, b) in mix[n].as_words_mut().iter_mut().zip(tmp_node.as_words()) {
for w in 0..16 { *a = fnv_hash(*a, *b);
mix[n].as_words_mut()[w] =
fnv_hash(
mix[n].as_words()[w],
tmp_node.as_words()[w],
);
}
}
} }
} }
} }
@ -277,16 +269,14 @@ fn hash_compute(light: &Light, full_size: usize, header_hash: &H256, nonce: u64)
// Compress mix // Compress mix
debug_assert_eq!(MIX_WORDS / 4, 8); debug_assert_eq!(MIX_WORDS / 4, 8);
unroll! { for i in 0..8 {
for i in 0..8 { let w = i * 4;
let w = i * 4;
let mut reduction = mix_words[w + 0]; let mut reduction = mix_words[w + 0];
reduction = reduction.wrapping_mul(FNV_PRIME) ^ mix_words[w + 1]; reduction = reduction.wrapping_mul(FNV_PRIME) ^ mix_words[w + 1];
reduction = reduction.wrapping_mul(FNV_PRIME) ^ mix_words[w + 2]; reduction = reduction.wrapping_mul(FNV_PRIME) ^ mix_words[w + 2];
reduction = reduction.wrapping_mul(FNV_PRIME) ^ mix_words[w + 3]; reduction = reduction.wrapping_mul(FNV_PRIME) ^ mix_words[w + 3];
compress[i] = reduction; compress[i] = reduction;
}
} }
} }
@ -312,7 +302,6 @@ fn hash_compute(light: &Light, full_size: usize, header_hash: &H256, nonce: u64)
ProofOfWork { mix_hash: mix_hash, value: value } ProofOfWork { mix_hash: mix_hash, value: value }
} }
// TODO: Use the `simd` crate
pub fn calculate_dag_item(node_index: u32, cache: &[Node]) -> Node { pub fn calculate_dag_item(node_index: u32, cache: &[Node]) -> Node {
let num_parent_nodes = cache.len(); let num_parent_nodes = cache.len();
let mut ret = cache[node_index as usize % num_parent_nodes].clone(); let mut ret = cache[node_index as usize % num_parent_nodes].clone();
@ -326,10 +315,8 @@ pub fn calculate_dag_item(node_index: u32, cache: &[Node]) -> Node {
num_parent_nodes as u32; num_parent_nodes as u32;
let parent = &cache[parent_index as usize]; let parent = &cache[parent_index as usize];
unroll! { for (a, b) in ret.as_words_mut().iter_mut().zip(parent.as_words()) {
for w in 0..16 { *a = fnv_hash(*a, *b);
ret.as_words_mut()[w] = fnv_hash(ret.as_words()[w], parent.as_words()[w]);
}
} }
} }

View File

@ -21,8 +21,6 @@ extern crate memmap;
extern crate parking_lot; extern crate parking_lot;
extern crate primal; extern crate primal;
#[macro_use]
extern crate crunchy;
#[macro_use] #[macro_use]
extern crate log; extern crate log;
#[macro_use] #[macro_use]
@ -44,6 +42,9 @@ mod compute;
mod seed_compute; mod seed_compute;
mod cache; mod cache;
#[cfg(feature = "bench")]
pub mod keccak;
#[cfg(not(feature = "bench"))]
mod keccak; mod keccak;
mod shared; mod shared;

View File

@ -9,6 +9,7 @@ license = "GPL-3.0"
[[bench]] [[bench]]
name = "verification" name = "verification"
harness = false harness = false
required-features = ['bench']
[dependencies] [dependencies]
blockchain = { package = "ethcore-blockchain", path = "../blockchain" } blockchain = { package = "ethcore-blockchain", path = "../blockchain" }