auto merge of #13522 : seanmonstar/rust/sip, r=alexcrichton
work started from @gereeter's PR: https://github.com/mozilla/rust/pull/13114 but adjusted bits ``` before test hash::sip::tests::bench_u64 ... bench: 34 ns/iter (+/- 0) test hash::sip::tests::bench_str_under_8_bytes ... bench: 37 ns/iter (+/- 1) test hash::sip::tests::bench_str_of_8_bytes ... bench: 43 ns/iter (+/- 1) test hash::sip::tests::bench_str_over_8_bytes ... bench: 50 ns/iter (+/- 1) test hash::sip::tests::bench_long_str ... bench: 613 ns/iter (+/- 14) test hash::sip::tests::bench_compound_1 ... bench: 114 ns/iter (+/- 11) after test hash::sip::tests::bench_u64 ... bench: 25 ns/iter (+/- 0) test hash::sip::tests::bench_str_under_8_bytes ... bench: 31 ns/iter (+/- 0) test hash::sip::tests::bench_str_of_8_bytes ... bench: 36 ns/iter (+/- 0) test hash::sip::tests::bench_str_over_8_bytes ... bench: 40 ns/iter (+/- 0) test hash::sip::tests::bench_long_str ... bench: 600 ns/iter (+/- 14) test hash::sip::tests::bench_compound_1 ... bench: 64 ns/iter (+/- 6) ``` Notably it seems smaller keys will hash faster. A long string doesn't see much gains, but compound cuts in half (once compound used a `int` and `u64`).
This commit is contained in:
commit
e33228727e
@ -27,10 +27,12 @@
|
||||
use clone::Clone;
|
||||
use container::Container;
|
||||
use default::Default;
|
||||
use int;
|
||||
use io::{IoResult, Writer};
|
||||
use iter::Iterator;
|
||||
use result::Ok;
|
||||
use slice::ImmutableVector;
|
||||
use uint;
|
||||
|
||||
use super::{Hash, Hasher};
|
||||
|
||||
@ -43,7 +45,7 @@ pub struct SipState {
|
||||
v1: u64,
|
||||
v2: u64,
|
||||
v3: u64,
|
||||
tail: [u8, ..8], // unprocessed bytes
|
||||
tail: u64, // unprocessed bytes le
|
||||
ntail: uint, // how many bytes in tail are valid
|
||||
}
|
||||
|
||||
@ -60,7 +62,17 @@ macro_rules! u8to64_le (
|
||||
$buf[4+$i] as u64 << 32 |
|
||||
$buf[5+$i] as u64 << 40 |
|
||||
$buf[6+$i] as u64 << 48 |
|
||||
$buf[7+$i] as u64 << 56)
|
||||
$buf[7+$i] as u64 << 56);
|
||||
($buf:expr, $i:expr, $len:expr) =>
|
||||
({
|
||||
let mut t = 0;
|
||||
let mut out = 0u64;
|
||||
while t < $len {
|
||||
out |= $buf[t+$i] as u64 << t*8;
|
||||
t += 1;
|
||||
}
|
||||
out
|
||||
});
|
||||
)
|
||||
|
||||
macro_rules! rotl (
|
||||
@ -98,7 +110,7 @@ impl SipState {
|
||||
v1: 0,
|
||||
v2: 0,
|
||||
v3: 0,
|
||||
tail: [ 0, 0, 0, 0, 0, 0, 0, 0 ],
|
||||
tail: 0,
|
||||
ntail: 0,
|
||||
};
|
||||
state.reset();
|
||||
@ -124,15 +136,7 @@ impl SipState {
|
||||
let mut v2 = self.v2;
|
||||
let mut v3 = self.v3;
|
||||
|
||||
let mut b : u64 = (self.length as u64 & 0xff) << 56;
|
||||
|
||||
if self.ntail > 0 { b |= self.tail[0] as u64 << 0; }
|
||||
if self.ntail > 1 { b |= self.tail[1] as u64 << 8; }
|
||||
if self.ntail > 2 { b |= self.tail[2] as u64 << 16; }
|
||||
if self.ntail > 3 { b |= self.tail[3] as u64 << 24; }
|
||||
if self.ntail > 4 { b |= self.tail[4] as u64 << 32; }
|
||||
if self.ntail > 5 { b |= self.tail[5] as u64 << 40; }
|
||||
if self.ntail > 6 { b |= self.tail[6] as u64 << 48; }
|
||||
let b: u64 = ((self.length as u64 & 0xff) << 56) | self.tail;
|
||||
|
||||
v3 ^= b;
|
||||
compress!(v0, v1, v2, v3);
|
||||
@ -147,8 +151,38 @@ impl SipState {
|
||||
|
||||
v0 ^ v1 ^ v2 ^ v3
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn write_le(&mut self, n: u64, size: uint) {
|
||||
self.tail |= n << 8*self.ntail;
|
||||
self.ntail += size;
|
||||
|
||||
if self.ntail >= 8 {
|
||||
let m = self.tail;
|
||||
|
||||
self.v3 ^= m;
|
||||
compress!(self.v0, self.v1, self.v2, self.v3);
|
||||
compress!(self.v0, self.v1, self.v2, self.v3);
|
||||
self.v0 ^= m;
|
||||
|
||||
self.ntail -= 8;
|
||||
if self.ntail == 0 {
|
||||
self.tail = 0;
|
||||
} else {
|
||||
self.tail = n >> 64 - 8*self.ntail;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! make_write_le(
|
||||
($this:expr, $n:expr, $size:expr) => ({
|
||||
$this.write_le($n as u64, $size);
|
||||
$this.length += $size;
|
||||
Ok(())
|
||||
})
|
||||
)
|
||||
|
||||
impl Writer for SipState {
|
||||
#[inline]
|
||||
fn write(&mut self, msg: &[u8]) -> IoResult<()> {
|
||||
@ -159,24 +193,13 @@ impl Writer for SipState {
|
||||
|
||||
if self.ntail != 0 {
|
||||
needed = 8 - self.ntail;
|
||||
|
||||
if length < needed {
|
||||
let mut t = 0;
|
||||
while t < length {
|
||||
self.tail[self.ntail+t] = msg[t];
|
||||
t += 1;
|
||||
}
|
||||
self.tail |= u8to64_le!(msg, 0, length) << 8*self.ntail;
|
||||
self.ntail += length;
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let mut t = 0;
|
||||
while t < needed {
|
||||
self.tail[self.ntail+t] = msg[t];
|
||||
t += 1;
|
||||
}
|
||||
|
||||
let m = u8to64_le!(self.tail, 0);
|
||||
let m = self.tail | u8to64_le!(msg, 0, needed) << 8*self.ntail;
|
||||
|
||||
self.v3 ^= m;
|
||||
compress!(self.v0, self.v1, self.v2, self.v3);
|
||||
@ -203,15 +226,62 @@ impl Writer for SipState {
|
||||
i += 8;
|
||||
}
|
||||
|
||||
let mut t = 0u;
|
||||
while t < left {
|
||||
self.tail[t] = msg[i+t];
|
||||
t += 1
|
||||
}
|
||||
self.tail = u8to64_le!(msg, i, left);
|
||||
self.ntail = left;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn write_u8(&mut self, n: u8) -> IoResult<()> {
|
||||
make_write_le!(self, n, 1)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn write_le_u16(&mut self, n: u16) -> IoResult<()> {
|
||||
make_write_le!(self, n, 2)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn write_le_u32(&mut self, n: u32) -> IoResult<()> {
|
||||
make_write_le!(self, n, 4)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn write_le_u64(&mut self, n: u64) -> IoResult<()> {
|
||||
make_write_le!(self, n, 8)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn write_le_uint(&mut self, n: uint) -> IoResult<()> {
|
||||
make_write_le!(self, n, uint::BYTES)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn write_i8(&mut self, n: i8) -> IoResult<()> {
|
||||
make_write_le!(self, n, 1)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn write_le_i16(&mut self, n: i16) -> IoResult<()> {
|
||||
make_write_le!(self, n, 2)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn write_le_i32(&mut self, n: i32) -> IoResult<()> {
|
||||
make_write_le!(self, n, 4)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn write_le_i64(&mut self, n: i64) -> IoResult<()> {
|
||||
make_write_le!(self, n, 8)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn write_le_int(&mut self, n: int) -> IoResult<()> {
|
||||
make_write_le!(self, n, int::BYTES)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
impl Clone for SipState {
|
||||
@ -284,6 +354,8 @@ pub fn hash_with_keys<T: Hash<SipState>>(k0: u64, k1: u64, value: &T) -> u64 {
|
||||
state.result()
|
||||
}
|
||||
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
extern crate test;
|
||||
@ -517,26 +589,55 @@ mod tests {
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_str(b: &mut Bencher) {
|
||||
fn bench_str_under_8_bytes(b: &mut Bencher) {
|
||||
let s = "foo";
|
||||
b.iter(|| {
|
||||
assert_eq!(hash(&s), 16262950014981195938);
|
||||
})
|
||||
}
|
||||
|
||||
struct Compound {
|
||||
x: u8,
|
||||
y: u16,
|
||||
z: ~str,
|
||||
#[bench]
|
||||
fn bench_str_of_8_bytes(b: &mut Bencher) {
|
||||
let s = "foobar78";
|
||||
b.iter(|| {
|
||||
assert_eq!(hash(&s), 4898293253460910787);
|
||||
})
|
||||
}
|
||||
|
||||
impl<S: Writer> Hash<S> for Compound {
|
||||
#[inline]
|
||||
fn hash(&self, state: &mut S) {
|
||||
self.x.hash(state);
|
||||
self.y.hash(state);
|
||||
self.z.hash(state);
|
||||
}
|
||||
#[bench]
|
||||
fn bench_str_over_8_bytes(b: &mut Bencher) {
|
||||
let s = "foobarbaz0";
|
||||
b.iter(|| {
|
||||
assert_eq!(hash(&s), 10581415515220175264);
|
||||
})
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_long_str(b: &mut Bencher) {
|
||||
let s = "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor \
|
||||
incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud \
|
||||
exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute \
|
||||
irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla \
|
||||
pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui \
|
||||
officia deserunt mollit anim id est laborum.";
|
||||
b.iter(|| {
|
||||
assert_eq!(hash(&s), 17717065544121360093);
|
||||
})
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_u64(b: &mut Bencher) {
|
||||
let u = 16262950014981195938u64;
|
||||
b.iter(|| {
|
||||
assert_eq!(hash(&u), 5254097107239593357);
|
||||
})
|
||||
}
|
||||
|
||||
#[deriving(Hash)]
|
||||
struct Compound {
|
||||
x: u8,
|
||||
y: u64,
|
||||
z: ~str,
|
||||
}
|
||||
|
||||
#[bench]
|
||||
@ -547,7 +648,7 @@ mod tests {
|
||||
z: ~"foobarbaz",
|
||||
};
|
||||
b.iter(|| {
|
||||
assert_eq!(hash(&compound), 3581836382593270478);
|
||||
assert_eq!(hash(&compound), 15783192367317361799);
|
||||
})
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user