Skip to content

Commit f910d27

Browse files
committed
siphash: Use ptr::copy_nonoverlapping for efficient data loading
Use `ptr::copy_nonoverlapping` (aka memcpy) to load an u64 from the byte stream. This is correct for any alignment, and the compiler will use the appropriate instruction to load the data. Use unchecked indexing. This results in a large improvement of throughput (hashed bytes / second) for long data. Maximum improvement benches at a 70% increase in throughput for large values (> 256 bytes) but already values of 16 bytes or larger improve. Introducing unchecked indexing is motivated to reach as good throughput as possible. Using ptr::copy_nonoverlapping without unchecked indexing would land the improvement some 20-30 pct units lower. We use a debug assertion so that the test suite checks our use of unchecked indexing.
1 parent 381d2ed commit f910d27

File tree

1 file changed

+16
-1
lines changed

1 file changed

+16
-1
lines changed

src/libcore/hash/sip.rs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
//! An implementation of SipHash 2-4.
1212
13+
use ptr;
1314
use prelude::*;
1415
use super::Hasher;
1516

@@ -65,6 +66,20 @@ macro_rules! u8to64_le {
6566
});
6667
}
6768

69+
/// Load a full u64 word from a byte stream, in LE order. Use
70+
/// `copy_nonoverlapping` to let the compiler generate the most efficient way
71+
/// to load u64 from a possibly unaligned address.
72+
///
73+
/// Unsafe because: unchecked indexing at i..i+8
74+
#[inline]
75+
unsafe fn load_u64_le(buf: &[u8], i: usize) -> u64 {
76+
debug_assert!(i + 8 <= buf.len());
77+
let mut data = 0u64;
78+
ptr::copy_nonoverlapping(buf.get_unchecked(i),
79+
&mut data as *mut _ as *mut u8, 8);
80+
data.to_le()
81+
}
82+
6883
macro_rules! rotl {
6984
($x:expr, $b:expr) =>
7085
(($x << $b) | ($x >> (64_i32.wrapping_sub($b))))
@@ -151,7 +166,7 @@ impl SipHasher {
151166

152167
let mut i = needed;
153168
while i < end {
154-
let mi = u8to64_le!(msg, i);
169+
let mi = unsafe { load_u64_le(msg, i) };
155170

156171
self.v3 ^= mi;
157172
compress!(self.v0, self.v1, self.v2, self.v3);

0 commit comments

Comments
 (0)