Skip to content
This repository has been archived by the owner on Nov 6, 2020. It is now read-only.

Commit

Permalink
progpow: remove some bounds checking from the main loop
Browse files Browse the repository at this point in the history
  • Loading branch information
andresilva committed Oct 18, 2018
1 parent 41006c8 commit 6d6465a
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 19 deletions.
5 changes: 0 additions & 5 deletions ethash/benches/ethash.rs
Expand Up @@ -12,7 +12,6 @@ use tempdir::TempDir;
use rustc_hex::FromHex;
use ethash::{NodeCacheBuilder, OptimizeFor};
use ethash::compute::light_compute;
use ethash::shared;

fn bench_hashimoto_light(c: &mut Criterion) {
let builder = NodeCacheBuilder::new(OptimizeFor::Memory);
Expand All @@ -31,7 +30,6 @@ fn bench_progpow_light(c: &mut Criterion) {
let builder = NodeCacheBuilder::new(OptimizeFor::Memory);
let tempdir = TempDir::new("").unwrap();
let cache = builder.new_cache(tempdir.into_path(), 0);
let data_size = shared::get_data_size(0) as u64;

let h = FromHex::from_hex("c9149cc0386e689d789a1c2f3d5d169a61a6218ed30e74414dc736e442ef3d1f").unwrap();
let mut hash = [0; 32];
Expand All @@ -43,7 +41,6 @@ fn bench_progpow_light(c: &mut Criterion) {
progpow::progpow(
hash,
0,
data_size,
0,
cache.as_ref(),
&c_dag,
Expand All @@ -56,7 +53,6 @@ fn bench_progpow_optimal_light(c: &mut Criterion) {
let builder = NodeCacheBuilder::new(OptimizeFor::Memory);
let tempdir = TempDir::new("").unwrap();
let cache = builder.new_cache(tempdir.into_path(), 0);
let data_size = shared::get_data_size(0) as u64;
let c_dag = progpow::generate_cdag(cache.as_ref());

let h = FromHex::from_hex("c9149cc0386e689d789a1c2f3d5d169a61a6218ed30e74414dc736e442ef3d1f").unwrap();
Expand All @@ -68,7 +64,6 @@ fn bench_progpow_optimal_light(c: &mut Criterion) {
progpow::progpow(
hash,
0,
data_size,
0,
cache.as_ref(),
&c_dag,
Expand Down
45 changes: 31 additions & 14 deletions ethash/src/progpow.rs
Expand Up @@ -16,7 +16,7 @@

use compute::{FNV_PRIME, calculate_dag_item};
use keccak::H256;
use shared::{ETHASH_ACCESSES, ETHASH_MIX_BYTES, Node};
use shared::{ETHASH_ACCESSES, ETHASH_MIX_BYTES, Node, get_data_size};

const PROGPOW_LANES: usize = 32;
const PROGPOW_REGS: usize = 16;
Expand Down Expand Up @@ -230,7 +230,14 @@ fn progpow_init(seed: u64) -> (Kiss99, [u32; PROGPOW_REGS]) {

for i in (1..mix_seq.len()).rev() {
let j = rnd.next_u32() as usize % (i + 1);
mix_seq.swap(i, j);

unsafe {
// NOTE: `i` takes values from the range [1..15] and `j` takes
// values from the the range [0..i]. This way it is guaranteed that
// the indices are always within the range of `mix_seq` and we can
// skip the bounds checking.
std::ptr::swap(&mut mix_seq[i], &mut mix_seq[j]);
}
}

(rnd, mix_seq)
Expand Down Expand Up @@ -281,7 +288,14 @@ fn progpow_loop(
let dst = mix_seq[mix_seq_cnt % PROGPOW_REGS] as usize;
mix_seq_cnt += 1;

mix[l][dst] = merge(mix[l][dst], data32, rnd.next_u32());
unsafe {
// NOTE: `dst` is taken from `mix_seq` whose values are
// always defined in the range [0..15] (they are initialised
// in `progpow_init` and we bind it as immutable). Thus, it
// is guaranteed that the index is always within range of
// `mix[l][dst]`.
*mix[l].get_unchecked_mut(dst) = merge(*mix[l].get_unchecked(dst), data32, rnd.next_u32());
}
}
if i < PROGPOW_CNT_MATH {
// Random math
Expand All @@ -292,7 +306,10 @@ fn progpow_loop(
let dst = mix_seq[mix_seq_cnt % PROGPOW_REGS] as usize;
mix_seq_cnt += 1;

mix[l][dst] = merge(mix[l][dst], data32, rnd.next_u32());
unsafe {
// NOTE: same as above
*mix[l].get_unchecked_mut(dst) = merge(*mix[l].get_unchecked(dst), data32, rnd.next_u32());
}
}
}

Expand All @@ -301,14 +318,16 @@ fn progpow_loop(
mix[l][0] = merge(mix[l][0], data64 as u32, rnd.next_u32());

let dst = mix_seq[mix_seq_cnt % PROGPOW_REGS] as usize;
mix[l][dst] = merge(mix[l][dst], (data64 >> 32) as u32, rnd.next_u32());
unsafe {
// NOTE: same as above
*mix[l].get_unchecked_mut(dst) = merge(*mix[l].get_unchecked(dst), (data64 >> 32) as u32, rnd.next_u32());
}
}
}

pub fn progpow(
header_hash: H256,
nonce: u64,
size: u64,
block_number: u64,
cache: &[Node],
c_dag: &[u32; PROGPOW_CACHE_WORDS],
Expand All @@ -317,6 +336,11 @@ pub fn progpow(
let mut lane_results = [0u32; PROGPOW_LANES];
let mut result = [0u32; 8];

let data_size = get_data_size(block_number) / PROGPOW_MIX_BYTES;

// NOTE: this assert is required to aid the optimizer elide the non-zero remainder check in progpow_loop
assert!(data_size > 0);

// Initialize mix for all lanes
let seed = keccak_f800_short(header_hash, nonce, result);
for l in 0..mix.len() {
Expand All @@ -332,7 +356,7 @@ pub fn progpow(
&mut mix,
cache,
c_dag,
size as usize / PROGPOW_MIX_BYTES,
data_size,
);
}

Expand Down Expand Up @@ -360,7 +384,6 @@ pub fn progpow(
pub fn progpow_light(
header_hash: H256,
nonce: u64,
size: u64,
block_number: u64,
cache: &[Node],
) -> (H256, H256) {
Expand All @@ -369,7 +392,6 @@ pub fn progpow_light(
progpow(
header_hash,
nonce,
size,
block_number,
cache,
&c_dag,
Expand Down Expand Up @@ -397,7 +419,6 @@ mod test {
use keccak::H256;
use rustc_hex::FromHex;
use serde_json::{self, Value};
use shared::get_data_size;
use std::collections::VecDeque;
use super::*;

Expand Down Expand Up @@ -499,15 +520,13 @@ mod test {
let builder = NodeCacheBuilder::new(OptimizeFor::Memory);
let tempdir = TempDir::new("").unwrap();
let cache = builder.new_cache(tempdir.into_path(), 0);
let data_size = get_data_size(0) as u64;
let c_dag = generate_cdag(cache.as_ref());

let header_hash = [0; 32];

let (digest, result) = progpow(
header_hash,
0,
data_size,
0,
cache.as_ref(),
&c_dag,
Expand Down Expand Up @@ -562,13 +581,11 @@ mod test {
let builder = NodeCacheBuilder::new(OptimizeFor::Memory);
let tempdir = TempDir::new("").unwrap();
let cache = builder.new_cache(tempdir.path().to_owned(), test.block_number);
let data_size = get_data_size(test.block_number) as u64;
let c_dag = generate_cdag(cache.as_ref());

let (digest, result) = progpow(
test.header_hash,
test.nonce,
data_size,
test.block_number,
cache.as_ref(),
&c_dag,
Expand Down

0 comments on commit 6d6465a

Please sign in to comment.