about summary refs log tree commit diff
diff options
context:
space:
mode:
authorUlrik Sverdrup <bluss@users.noreply.github.com>2015-07-25 11:55:26 +0200
committerUlrik Sverdrup <bluss@users.noreply.github.com>2015-07-25 12:26:18 +0200
commitf910d27f87419e17cc59034265f6795db5247dfa (patch)
tree3788c2facf00f062af3de5164250d5a401d6f2b1
parent381d2ed70d3f3c2913e19a950dee0da0149dae1d (diff)
downloadrust-f910d27f87419e17cc59034265f6795db5247dfa.tar.gz
rust-f910d27f87419e17cc59034265f6795db5247dfa.zip
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.
-rw-r--r--src/libcore/hash/sip.rs17
1 files changed, 16 insertions, 1 deletions
diff --git a/src/libcore/hash/sip.rs b/src/libcore/hash/sip.rs
index d26e9ab7072..fae14da22c4 100644
--- a/src/libcore/hash/sip.rs
+++ b/src/libcore/hash/sip.rs
@@ -10,6 +10,7 @@
 
 //! An implementation of SipHash 2-4.
 
+use ptr;
 use prelude::*;
 use super::Hasher;
 
@@ -65,6 +66,20 @@ macro_rules! u8to64_le {
     });
 }
 
+/// Load a full u64 word from a byte stream, in LE order. Use
+/// `copy_nonoverlapping` to let the compiler generate the most efficient way
+/// to load u64 from a possibly unaligned address.
+///
+/// Unsafe because: unchecked indexing at i..i+8
+#[inline]
+unsafe fn load_u64_le(buf: &[u8], i: usize) -> u64 {
+    debug_assert!(i + 8 <= buf.len());
+    let mut data = 0u64;
+    ptr::copy_nonoverlapping(buf.get_unchecked(i),
+                             &mut data as *mut _ as *mut u8, 8);
+    data.to_le()
+}
+
 macro_rules! rotl {
     ($x:expr, $b:expr) =>
     (($x << $b) | ($x >> (64_i32.wrapping_sub($b))))
@@ -151,7 +166,7 @@ impl SipHasher {
 
         let mut i = needed;
         while i < end {
-            let mi = u8to64_le!(msg, i);
+            let mi = unsafe { load_u64_le(msg, i) };
 
             self.v3 ^= mi;
             compress!(self.v0, self.v1, self.v2, self.v3);