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

[ethash] remove mem::uninitialized #10861

Merged
merged 17 commits into from
Jul 12, 2019
Merged

[ethash] remove mem::uninitialized #10861

merged 17 commits into from
Jul 12, 2019

Conversation

ordian
Copy link
Collaborator

@ordian ordian commented Jul 8, 2019

Part of #10842. Supersedes #10853.

Closes #10842.

@ordian ordian added A0-pleasereview 🤓 Pull request needs code review. M4-core ⛓ Core client code / Rust. labels Jul 8, 2019
@ordian ordian added this to the 2.7 milestone Jul 8, 2019
@@ -233,8 +233,7 @@ fn hash_compute(light: &Light, full_size: usize, header_hash: &H256, nonce: u64)

Node { bytes: out.assume_init() }
},
// This is fully initialized before being read, see `let mut compress = ...` below
compress_bytes: unsafe { mem::uninitialized() },
compress_bytes: [0u8; MIX_WORDS],
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❯ cargo bench --features=bench -- compute
bench_light_compute_memmap                                                                            
                        time:   [980.59 us 986.10 us 992.69 us]
                        change: [-3.7744% -1.4892% +0.5632%] (p = 0.20 > 0.05)
                        No change in performance detected.
Found 6 outliers among 100 measurements (6.00%)
  4 (4.00%) high mild
  2 (2.00%) high severe

bench_light_compute_memory                                                                             
                        time:   [1.0336 ms 1.0410 ms 1.0493 ms]
                        change: [-3.9993% -2.0714% +0.0881%] (p = 0.05 > 0.05)
                        No change in performance detected.
Found 9 outliers among 100 measurements (9.00%)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Amazing, must have been part of one of the LLVM upgrades since this code was written. I absolutely benchmarked it before and 0-initialising it was significantly slower. Wonder if there's anywhere else where we can remove uninit entirely now.

@ordian ordian requested a review from eira-fransham July 8, 2019 15:25
Copy link
Contributor

@eira-fransham eira-fransham left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a single minor comment, this appears to be perfect.


// This is initialized in `keccak_256` below.
let mut hash = mem::MaybeUninit::<[u8; 32]>::uninit();
keccak_256::unchecked(hash.as_mut_ptr() as *mut u8, 32, buf.as_ptr(), buf.len());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you extract 32 to a constant so you don't have to ensure that the 32 in the definition of hash and the 32 in the unchecked call are the same? Before you could do .len but that's now impossible because of MaybeUninit.

// 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");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great, this should have been done long ago. Re-reading the code, I think it might actually work on little-endian as long as you don't copy across the files we're reading from from little- to big-endian or vice-versa, although I can't be certain. Might be worth testing.

@@ -152,9 +152,10 @@ pub fn quick_get_difficulty(header_hash: &H256, nonce: u64, mix_hash: &H256, pro

let buf = buf.assume_init();

const HASH_BYTES_LENGTH: usize = 32;
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm bad at naming, so any other suggestions are welcome :)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It'll do

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe KECCAK_LEN?

Copy link
Contributor

@eira-fransham eira-fransham Jul 9, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, because KECCAK_LEN would be the total length right? We run keccak with different lengths during this function. At least HASH_BYTES_LEN is generic enough that it doesn't imply that we always run it with this length, it's just a barrier against typos.

* master:
  Run cargo fix on a few of the worst offenders (#10854)
  removed redundant fork choice abstraction (#10849)
  Extract state-db from ethcore (#10858)
  Fix fork choice (#10837)
  Move more code into state-account (#10840)
  Remove compiler warning (#10865)
  [ethash] use static_assertions crate (#10860)
@ordian
Copy link
Collaborator Author

ordian commented Jul 9, 2019

Ok, so I've removed uninit completely, and running cargo bench --features=bench -- compute in ethash folder doesn't show any significant difference, but it would be nice if you could confirm this.

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());
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm using here to_ne_bytes to preserve the previous behavior, but I guess it still only works for little-endian targets (don't have a machine to test this though).

@ordian ordian changed the title [ethash] replace mem::uninitialized with mem::MaybeUninit [ethash] remove mem::uninitialized Jul 9, 2019
@dvdplm
Copy link
Collaborator

dvdplm commented Jul 9, 2019

would be nice if you could confirm this.

The benches on this branch:

     Running /Users/dvd/dev/parity/parity-ethereum/target/release/deps/basic-b975ddb423643e79
bench_light_compute_memmap
                        time:   [865.81 us 875.33 us 887.64 us]
                        change: [-7.0523% -2.5074% +1.7495%] (p = 0.30 > 0.05)
                        No change in performance detected.
Found 16 outliers among 100 measurements (16.00%)
  5 (5.00%) high mild
  11 (11.00%) high severe

bench_light_compute_memory
                        time:   [868.18 us 878.94 us 891.67 us]
                        change: [-4.1526% -1.4291% +1.4194%] (p = 0.33 > 0.05)
                        No change in performance detected.
Found 10 outliers among 100 measurements (10.00%)
  5 (5.00%) high mild
  5 (5.00%) high severe

However, the same bench command on master is… weird. Here's the output:

     Running /Users/dvd/dev/parity/parity-ethereum/target/release/deps/basic-b975ddb423643e79
bench_light_compute_memmap
                        time:   [858.62 us 869.47 us 882.64 us]
                        change: [-4.8265% -1.4632% +1.5786%] (p = 0.41 > 0.05)
                        No change in performance detected.
Found 12 outliers among 100 measurements (12.00%)
  4 (4.00%) high mild
  8 (8.00%) high severe

bench_light_compute_memmap
                        time:   [858.14 us 867.39 us 878.12 us]
                        change: [-1.7316% +0.9385% +3.9310%] (p = 0.54 > 0.05)
                        No change in performance detected.
Found 13 outliers among 100 measurements (13.00%)
  10 (10.00%) high mild
  3 (3.00%) high severe

Benchmarking bench_light_compute_memmap: Collecting 100 samples in estimated 2948.4 s (5050 iterations)^C

Notice the ~3000s estimate and the duplicate bench names.

@ordian
Copy link
Collaborator Author

ordian commented Jul 9, 2019

the duplicate bench names

fixed in this PR in 5ef9344

Notice the ~3000s estimate

yeah, I guess we can force criterion to do less iterations, added 7c2d729. At this point I'm starting to think about splitting the PR into bench and non-bench part, but it's small enough so far.

@ordian ordian merged commit 5a13117 into master Jul 12, 2019
@ordian ordian deleted the MaybeUninit branch July 12, 2019 08:04
dvdplm added a commit that referenced this pull request Jul 12, 2019
* master:
  whisper is no longer a part of parity-ethereum repo (#10855)
  [ethash] remove mem::uninitialized (#10861)
  Docker images renaming (#10863)
  Move the substate module into ethcore/executive (#10867)
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
A0-pleasereview 🤓 Pull request needs code review. M4-core ⛓ Core client code / Rust.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Remove all uses of mem::uninitialized
3 participants