From 28f2fa3fd58b128ce02142305f6074bed407019e Mon Sep 17 00:00:00 2001 From: behzad nouri Date: Wed, 9 Sep 2020 15:28:17 +0000 Subject: [PATCH] uses rust intrinsics to convert hashes to u64 (#12097) --- core/Cargo.toml | 3 +++ core/benches/crds_gossip_pull.rs | 26 ++++++++++++++++++++++++ core/src/crds_gossip_pull.rs | 34 ++++++++++++++++++++++++++------ 3 files changed, 57 insertions(+), 6 deletions(-) create mode 100644 core/benches/crds_gossip_pull.rs diff --git a/core/Cargo.toml b/core/Cargo.toml index cb2427c836..2eac2a2c66 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -94,6 +94,9 @@ name = "banking_stage" [[bench]] name = "blockstore" +[[bench]] +name = "crds_gossip_pull" + [[bench]] name = "gen_keys" diff --git a/core/benches/crds_gossip_pull.rs b/core/benches/crds_gossip_pull.rs new file mode 100644 index 0000000000..d040266a8f --- /dev/null +++ b/core/benches/crds_gossip_pull.rs @@ -0,0 +1,26 @@ +#![feature(test)] + +extern crate test; + +use rand::{thread_rng, Rng}; +use solana_core::crds_gossip_pull::CrdsFilter; +use solana_sdk::hash::{Hash, HASH_BYTES}; +use test::Bencher; + +#[bench] +fn bench_hash_as_u64(bencher: &mut Bencher) { + let mut rng = thread_rng(); + let hashes: Vec<_> = (0..1000) + .map(|_| { + let mut buf = [0u8; HASH_BYTES]; + rng.fill(&mut buf); + Hash::new(&buf) + }) + .collect(); + bencher.iter(|| { + hashes + .iter() + .map(CrdsFilter::hash_as_u64) + .collect::>() + }); +} diff --git a/core/src/crds_gossip_pull.rs b/core/src/crds_gossip_pull.rs index 5fdda80e42..946fee1a1a 100644 --- a/core/src/crds_gossip_pull.rs +++ b/core/src/crds_gossip_pull.rs @@ -22,6 +22,7 @@ use solana_sdk::pubkey::Pubkey; use std::cmp; use std::collections::VecDeque; use std::collections::{HashMap, HashSet}; +use std::convert::TryInto; pub const CRDS_GOSSIP_PULL_CRDS_TIMEOUT_MS: u64 = 15000; // The maximum age of a value received over pull responses @@ -74,12 +75,8 @@ impl CrdsFilter { ((num_items / max_items).log2().ceil()).max(0.0) as u32 } pub fn hash_as_u64(item: &Hash) -> u64 { - let arr = item.as_ref(); - let mut accum = 0; - for (i, val) in arr.iter().enumerate().take(8) { - accum |= (u64::from(*val)) << (i * 8) as u64; - } - accum + let buf = item.as_ref()[..8].try_into().unwrap(); + u64::from_le_bytes(buf) } pub fn test_mask_u64(&self, item: u64, ones: u64) -> bool { let bits = item | ones; @@ -543,6 +540,31 @@ mod test { use solana_sdk::hash::{hash, HASH_BYTES}; use solana_sdk::packet::PACKET_DATA_SIZE; + #[test] + fn test_hash_as_u64() { + let arr: Vec = (0..HASH_BYTES).map(|i| i as u8 + 1).collect(); + let hash = Hash::new(&arr); + assert_eq!(CrdsFilter::hash_as_u64(&hash), 0x807060504030201); + } + + #[test] + fn test_hash_as_u64_random() { + fn hash_as_u64_bitops(hash: &Hash) -> u64 { + let mut out = 0; + for (i, val) in hash.as_ref().iter().enumerate().take(8) { + out |= (u64::from(*val)) << (i * 8) as u64; + } + out + } + let mut rng = thread_rng(); + for _ in 0..100 { + let mut buf = [0u8; HASH_BYTES]; + rng.fill(&mut buf); + let hash = Hash::new(&buf); + assert_eq!(CrdsFilter::hash_as_u64(&hash), hash_as_u64_bitops(&hash)); + } + } + #[test] fn test_new_pull_with_stakes() { let mut crds = Crds::default();