wyhash microoptimization

This commit is contained in:
dzaima 2022-08-05 03:08:39 +03:00
parent 98e3021efb
commit fd1ac7487c
4 changed files with 52 additions and 14 deletions

View File

@ -29,6 +29,7 @@ NOINLINE u64 bqn_hashArr(B x, const u64 secret[4]) { // TODO manual separation o
bytes = xia*sizeof(B);
break;
}
assert(bytes!=0);
u64 r = wyhash(data, bytes, shHash, secret);
if (isTemp) TFREE(data);
dec(x);

View File

@ -113,28 +113,39 @@ static inline uint64_t _wyr4(const uint8_t *p) {
return (((v >> 24) & 0xff)| ((v >> 8) & 0xff00)| ((v << 8) & 0xff0000)| ((v << 24) & 0xff000000));
}
#endif
static inline uint64_t _wyr3(const uint8_t *p, size_t k) { return (((uint64_t)p[0])<<16)|(((uint64_t)p[k>>1])<<8)|p[k-1];}
//wyhash main function
#ifdef __BMI2__
#include <x86intrin.h>
#endif
//wyhash main function; assumes len>0 and that it can read past the end of the input
FORCE_INLINE uint64_t wyhash(const void *key, size_t len, uint64_t seed, const uint64_t *secret){
const uint8_t *p=(const uint8_t *)key; seed^=*secret; uint64_t a, b;
if(_likely_(len<=16)){
if(_likely_(len>=4)){ a=(_wyr4(p)<<32)|_wyr4(p+((len>>3)<<2)); b=(_wyr4(p+len-4)<<32)|_wyr4(p+len-4-((len>>3)<<2)); }
else if(_likely_(len>0)){ a=_wyr3(p,len); b=0;}
else a=b=0;
}
else{
const uint8_t *p = (const uint8_t *)key; seed^=*secret; uint64_t a, b;
if (_likely_(len<=16)) {
#ifdef __BMI2__
if (len>8) { a = _wyr8(p); b = _bzhi_u64(_wyr8(p+8), (len-8)*8); }
else { a = 0; b = _bzhi_u64(_wyr8(p ), len *8); }
#else
if (len==16) { a = _wyr8(p); b = _wyr8(p+8); }
else {
if (len>=8) { a = _wyr8(p); p+= 8; }
else a = 0;
b = _wyr8(p) & (((uint64_t)1)<<((8*len)&63))-1;
}
#endif
} else {
size_t i=len;
if(_unlikely_(i>48)){
if (_unlikely_(i>48)){
uint64_t see1=seed, see2=seed;
do{
do {
seed=_wymix(_wyr8(p)^secret[1],_wyr8(p+8)^seed);
see1=_wymix(_wyr8(p+16)^secret[2],_wyr8(p+24)^see1);
see2=_wymix(_wyr8(p+32)^secret[3],_wyr8(p+40)^see2);
p+=48; i-=48;
}while(_likely_(i>48));
} while (_likely_(i>48));
seed^=see1^see2;
}
while(_unlikely_(i>16)){ seed=_wymix(_wyr8(p)^secret[1],_wyr8(p+8)^seed); i-=16; p+=16; }
while (_unlikely_(i>16)) { seed=_wymix(_wyr8(p)^secret[1],_wyr8(p+8)^seed); i-=16; p+=16; }
a=_wyr8(p+i-16); b=_wyr8(p+i-8);
}
return _wymix(secret[1]^len,_wymix(a^secret[1],b^seed));

View File

@ -10,9 +10,10 @@ test/moreCfgs.sh path/to/mlochbaum/BQN // run "2+2" in a bunch of configurations
./BQN test/equal.bqn // fuzz-test 𝕨≡𝕩
./BQN test/copy.bqn // fuzz-test creating new arrays with elements copied from another
./BQN test/bitcpy.bqn // fuzz-test bit_cpy; requires a CBQN build with -DTEST_BITCPY
./BQN test/hash.bqn // fuzz-test hashing
./BQN test/squeezeValid.bqn // fuzz-test squeezing giving a correct result; requires a CBQN build with -DEEQUAL_NEGZERO
./BQN test/squeezeExact.bqn // fuzz-test squeezing giving the exact smallest result; requires a CBQN build with -DEEQUAL_NEGZERO
./BQN test/random.bqn // various random tests
./BQN test/random.bqn // tests for various small things
make -C test/ffi // test FFI functionality; expects both regular and shared library CBQN builds to already exist
legacy utilities:

25
test/hash.bqn Normal file
View File

@ -0,0 +1,25 @@
# note: tests only bit/i8/i16/i32 arrays; no f64/c8/c16/c32/generic array tests
u 100×(•UnixTime+1|100וMonoTime)@
R (•MakeRand •Show u).Range
M (232)×+´
Test { 𝕊:
width 181632˜R 4
count 1+R (width=1)32256
data (width×count) R 2
n 1+R count
cast {width=1? ; 1width'i' •bit._cast}
iota data
shifts 1+count-n
exp >(-shifts)(width/)¨<n>count
got >1¨¨<˘>{
a Cast data𝕩iota
shifts (M•Hash n)¨ <a
}¨¯1iota
+´¨ exp(><)got
}
fails 00
{𝕊: fails+ Test@}¨1000
•Out "Collisions: " •Repr 0fails " (expected 0, assuming no actual hash collisions)"
•Out "Mismatches: " •Repr 1fails " (expected 0)"