[ethash] remove mem::uninitialized (#10861)
* [ethash] replace mem::uninitialized with MaybeUninit * [ethash] replace another occurence of mem::uninitialized * [ethash] remove last mem::uninitialized * [ethash] clean up benches * [ethash] update outdated comment * [ethash] compile error on big endian targets * [ethash] extract 32 into a constant * [ethash] rename the constant to KECCAK_LEN * [ethash] bench quick_get_difficulty * [ethash] remove MaybeUninit completely * [ethash] replace ptr::copy_nonoverlapping with copy_from_slice * [ethash] s/header_len/hash_len * [ethash] remove duplication in bench * [ethash] add a config for basic benches * [ethash] fix a typo in bench fn name * [ethash] remove needless cast
This commit is contained in:
parent
d850eb0dd5
commit
5a131175e8
@ -21,22 +21,39 @@ extern crate ethash;
|
||||
use criterion::Criterion;
|
||||
use ethash::{NodeCacheBuilder, OptimizeFor};
|
||||
|
||||
const HASH: [u8; 32] = [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];
|
||||
const HASH: [u8; 32] = [
|
||||
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,
|
||||
];
|
||||
const MIX_HASH: [u8; 32] = [
|
||||
0x1f, 0xff, 0x04, 0xce, 0xc9, 0x41, 0x73, 0xfd,
|
||||
0x59, 0x1e, 0x3d, 0x89, 0x60, 0xce, 0x6b, 0xdf,
|
||||
0x8b, 0x19, 0x71, 0x04, 0x8c, 0x71, 0xff, 0x93,
|
||||
0x7b, 0xb2, 0xd3, 0x2a, 0x64, 0x31, 0xab, 0x6d,
|
||||
];
|
||||
const NONCE: u64 = 0xd7b3ac70a301a249;
|
||||
|
||||
criterion_group!(
|
||||
basic,
|
||||
bench_light_compute_memmap,
|
||||
bench_light_compute_memory,
|
||||
bench_light_new_round_trip_memmap,
|
||||
bench_light_new_round_trip_memory,
|
||||
bench_light_from_file_round_trip_memory,
|
||||
bench_light_from_file_round_trip_memmap
|
||||
);
|
||||
criterion_group! {
|
||||
name = basic;
|
||||
config = dont_take_an_eternity_to_run();
|
||||
targets = bench_light_compute_memmap,
|
||||
bench_light_compute_memory,
|
||||
bench_light_new_round_trip_memmap,
|
||||
bench_light_new_round_trip_memory,
|
||||
bench_light_from_file_round_trip_memory,
|
||||
bench_light_from_file_round_trip_memmap,
|
||||
bench_quick_get_difficulty,
|
||||
}
|
||||
criterion_main!(basic);
|
||||
|
||||
fn dont_take_an_eternity_to_run() -> Criterion {
|
||||
Criterion::default().nresamples(1_000)
|
||||
.without_plots()
|
||||
.sample_size(10)
|
||||
}
|
||||
|
||||
fn bench_light_compute_memmap(b: &mut Criterion) {
|
||||
use std::env;
|
||||
|
||||
@ -52,13 +69,13 @@ fn bench_light_compute_memory(b: &mut Criterion) {
|
||||
let builder = NodeCacheBuilder::new(OptimizeFor::Cpu, u64::max_value());
|
||||
let light = builder.light(&env::temp_dir(), 486382);
|
||||
|
||||
b.bench_function("bench_light_compute_memmap", move |b| b.iter(|| light.compute(&HASH, NONCE, u64::max_value())));
|
||||
b.bench_function("bench_light_compute_memory", move |b| b.iter(|| light.compute(&HASH, NONCE, u64::max_value())));
|
||||
}
|
||||
|
||||
fn bench_light_new_round_trip_memmap(b: &mut Criterion) {
|
||||
use std::env;
|
||||
|
||||
b.bench_function("bench_light_compute_memmap", move |b| b.iter(|| {
|
||||
b.bench_function("bench_light_new_round_trip_memmap", move |b| b.iter(|| {
|
||||
let builder = NodeCacheBuilder::new(OptimizeFor::Memory, u64::max_value());
|
||||
let light = builder.light(&env::temp_dir(), 486382);
|
||||
light.compute(&HASH, NONCE, u64::max_value());
|
||||
@ -68,7 +85,7 @@ fn bench_light_new_round_trip_memmap(b: &mut Criterion) {
|
||||
fn bench_light_new_round_trip_memory(b: &mut Criterion) {
|
||||
use std::env;
|
||||
|
||||
b.bench_function("bench_light_compute_memmap", move |b| b.iter(|| {
|
||||
b.bench_function("bench_light_new_round_trip_memory", move |b| b.iter(|| {
|
||||
let builder = NodeCacheBuilder::new(OptimizeFor::Cpu, u64::max_value());
|
||||
let light = builder.light(&env::temp_dir(), 486382);
|
||||
light.compute(&HASH, NONCE, u64::max_value());
|
||||
@ -86,7 +103,7 @@ fn bench_light_from_file_round_trip_memory(b: &mut Criterion) {
|
||||
dummy.to_file().unwrap();
|
||||
}
|
||||
|
||||
b.bench_function("bench_light_compute_memmap", move |b| b.iter(|| {
|
||||
b.bench_function("bench_light_from_file_round_trip_memory", move |b| b.iter(|| {
|
||||
let builder = NodeCacheBuilder::new(OptimizeFor::Cpu, u64::max_value());
|
||||
let light = builder.light_from_file(&dir, 486382).unwrap();
|
||||
light.compute(&HASH, NONCE, u64::max_value());
|
||||
@ -105,9 +122,21 @@ fn bench_light_from_file_round_trip_memmap(b: &mut Criterion) {
|
||||
dummy.to_file().unwrap();
|
||||
}
|
||||
|
||||
b.bench_function("bench_light_compute_memmap", move |b| b.iter(|| {
|
||||
b.bench_function("bench_light_from_file_round_trip_memmap", move |b| b.iter(|| {
|
||||
let builder = NodeCacheBuilder::new(OptimizeFor::Memory, u64::max_value());
|
||||
let light = builder.light_from_file(&dir, 486382).unwrap();
|
||||
light.compute(&HASH, NONCE, u64::max_value());
|
||||
}));
|
||||
}
|
||||
|
||||
fn bench_quick_get_difficulty(b: &mut Criterion) {
|
||||
b.bench_function("bench_quick_get_difficulty", move |b| b.iter(|| {
|
||||
let d = ethash::quick_get_difficulty(&HASH, NONCE, &MIX_HASH, false);
|
||||
let boundary_good = [
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x3e, 0x9b, 0x6c, 0x69, 0xbc, 0x2c, 0xe2, 0xa2,
|
||||
0x4a, 0x8e, 0x95, 0x69, 0xef, 0xc7, 0xd7, 0x1b, 0x33, 0x35, 0xdf, 0x36, 0x8c, 0x9a,
|
||||
0xe9, 0x7e, 0x53, 0x84,
|
||||
];
|
||||
assert_eq!(d[..], boundary_good[..]);
|
||||
}));
|
||||
}
|
||||
|
@ -26,7 +26,7 @@ use seed_compute::SeedHashCompute;
|
||||
use shared::*;
|
||||
use std::io;
|
||||
|
||||
use std::{mem, ptr};
|
||||
use std::mem;
|
||||
use std::path::Path;
|
||||
|
||||
const MIX_WORDS: usize = ETHASH_MIX_BYTES / 4;
|
||||
@ -135,22 +135,16 @@ pub fn quick_get_difficulty(header_hash: &H256, nonce: u64, mix_hash: &H256, pro
|
||||
let seed = keccak_f800_short(*header_hash, nonce, [0u32; 8]);
|
||||
keccak_f800_long(*header_hash, seed, mem::transmute(*mix_hash))
|
||||
} else {
|
||||
// This is safe - the `keccak_512` call below reads the first 40 bytes (which we explicitly set
|
||||
// with two `copy_nonoverlapping` calls) but writes the first 64, and then we explicitly write
|
||||
// the next 32 bytes before we read the whole thing with `keccak_256`.
|
||||
//
|
||||
// This cannot be elided by the compiler as it doesn't know the implementation of
|
||||
// `keccak_512`.
|
||||
let mut buf: [u8; 64 + 32] = mem::uninitialized();
|
||||
let mut buf = [0u8; 64 + 32];
|
||||
|
||||
ptr::copy_nonoverlapping(header_hash.as_ptr(), buf.as_mut_ptr(), 32);
|
||||
ptr::copy_nonoverlapping(&nonce as *const u64 as *const u8, buf[32..].as_mut_ptr(), 8);
|
||||
let hash_len = header_hash.len();
|
||||
buf[..hash_len].copy_from_slice(header_hash);
|
||||
buf[hash_len..hash_len + mem::size_of::<u64>()].copy_from_slice(&nonce.to_ne_bytes());
|
||||
|
||||
keccak_512::unchecked(buf.as_mut_ptr(), 64, buf.as_ptr(), 40);
|
||||
ptr::copy_nonoverlapping(mix_hash.as_ptr(), buf[64..].as_mut_ptr(), 32);
|
||||
buf[64..].copy_from_slice(mix_hash);
|
||||
|
||||
// This is initialized in `keccak_256`
|
||||
let mut hash: [u8; 32] = mem::uninitialized();
|
||||
let mut hash = [0u8; 32];
|
||||
keccak_256::unchecked(hash.as_mut_ptr(), hash.len(), buf.as_ptr(), buf.len());
|
||||
|
||||
hash
|
||||
@ -205,17 +199,11 @@ fn hash_compute(light: &Light, full_size: usize, header_hash: &H256, nonce: u64)
|
||||
let mut buf: MixBuf = MixBuf {
|
||||
half_mix: unsafe {
|
||||
// Pack `header_hash` and `nonce` together
|
||||
// We explicitly write the first 40 bytes, leaving the last 24 as uninitialized. Then
|
||||
// `keccak_512` reads the first 40 bytes (4th parameter) and overwrites the entire array,
|
||||
// leaving it fully initialized.
|
||||
let mut out: [u8; NODE_BYTES] = mem::uninitialized();
|
||||
let mut out = [0u8; NODE_BYTES];
|
||||
|
||||
ptr::copy_nonoverlapping(header_hash.as_ptr(), out.as_mut_ptr(), header_hash.len());
|
||||
ptr::copy_nonoverlapping(
|
||||
&nonce as *const u64 as *const u8,
|
||||
out[header_hash.len()..].as_mut_ptr(),
|
||||
mem::size_of::<u64>(),
|
||||
);
|
||||
let hash_len = header_hash.len();
|
||||
out[..hash_len].copy_from_slice(header_hash);
|
||||
out[hash_len..hash_len + mem::size_of::<u64>()].copy_from_slice(&nonce.to_ne_bytes());
|
||||
|
||||
// compute keccak-512 hash and replicate across mix
|
||||
keccak_512::unchecked(
|
||||
@ -227,8 +215,7 @@ fn hash_compute(light: &Light, full_size: usize, header_hash: &H256, nonce: u64)
|
||||
|
||||
Node { bytes: out }
|
||||
},
|
||||
// This is fully initialized before being read, see `let mut compress = ...` below
|
||||
compress_bytes: unsafe { mem::uninitialized() },
|
||||
compress_bytes: [0u8; MIX_WORDS],
|
||||
};
|
||||
|
||||
let mut mix: [_; MIX_NODES] = [buf.half_mix.clone(), buf.half_mix.clone()];
|
||||
@ -277,12 +264,16 @@ fn hash_compute(light: &Light, full_size: usize, header_hash: &H256, nonce: u64)
|
||||
let mix_words: [u32; MIX_WORDS] = unsafe { mem::transmute(mix) };
|
||||
|
||||
{
|
||||
// This is an uninitialized buffer to begin with, but we iterate precisely `compress.len()`
|
||||
// times and set each index, leaving the array fully initialized. THIS ONLY WORKS ON LITTLE-
|
||||
// ENDIAN MACHINES. See a future PR to make this and the rest of the code work correctly on
|
||||
// We iterate precisely `compress.len()` times and set each index,
|
||||
// leaving the array fully initialized. THIS ONLY WORKS ON LITTLE-ENDIAN MACHINES.
|
||||
// See a future PR to make this and the rest of the code work correctly on
|
||||
// big-endian arches like mips.
|
||||
let compress: &mut [u32; MIX_WORDS / 4] =
|
||||
unsafe { make_const_array!(MIX_WORDS / 4, &mut buf.compress_bytes) };
|
||||
#[cfg(target_endian = "big")]
|
||||
{
|
||||
compile_error!("parity-ethereum currently only supports little-endian targets");
|
||||
}
|
||||
|
||||
// Compress mix
|
||||
debug_assert_eq!(MIX_WORDS / 4, 8);
|
||||
|
Loading…
Reference in New Issue
Block a user