From: Meng Zhuo Date: Mon, 15 Mar 2021 11:48:39 +0000 (+0800) Subject: runtime: using wyhash for memhashFallback on 32bit platform X-Git-Tag: go1.17beta1~1112 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=78f9015236;p=gostls13.git runtime: using wyhash for memhashFallback on 32bit platform wyhash is a general hash function that: 1. Default hash function of Zig, Nim 2. Passed Smhasher, BigCrush and PractRand 3. Less code 4. 3~26% faster than internal hashmap name old time/op new time/op delta Hash5 67.8ns ± 0% 65.4ns ± 0% -3.45% (p=0.000 n=7+10) Hash16 82.5ns ± 0% 74.2ns ± 0% -10.12% (p=0.000 n=6+8) Hash64 121ns ± 0% 102ns ± 0% -15.82% (p=0.000 n=7+10) Hash1024 1.13µs ± 0% 0.89µs ± 0% -20.58% (p=0.000 n=10+9) Hash65536 68.9µs ± 0% 54.4µs ± 0% -21.04% (p=0.000 n=10+7) HashStringSpeed 103ns ± 2% 93ns ± 3% -10.24% (p=0.000 n=9+10) HashBytesSpeed 191ns ± 2% 180ns ± 1% -5.40% (p=0.000 n=10+8) HashInt32Speed 59.0ns ± 2% 59.1ns ± 1% ~ (p=0.655 n=9+8) HashInt64Speed 72.7ns ± 3% 66.1ns ± 5% -9.04% (p=0.000 n=10+10) HashStringArraySpeed 270ns ± 1% 222ns ± 2% -17.91% (p=0.000 n=10+10) FastrandHashiter 108ns ± 0% 109ns ± 1% +0.96% (p=0.002 n=10+10) name old speed new speed delta Hash5 73.8MB/s ± 0% 76.4MB/s ± 0% +3.58% (p=0.000 n=7+10) Hash16 194MB/s ± 0% 216MB/s ± 0% +11.25% (p=0.000 n=10+8) Hash64 530MB/s ± 0% 630MB/s ± 0% +18.74% (p=0.000 n=8+10) Hash1024 910MB/s ± 0% 1145MB/s ± 0% +25.88% (p=0.000 n=10+9) Hash65536 951MB/s ± 0% 1204MB/s ± 0% +26.64% (p=0.000 n=10+7) Update #43130 Change-Id: Id00c54b116a2411fcf675e95896fffb85f0e25b6 Reviewed-on: https://go-review.googlesource.com/c/go/+/280372 Trust: Meng Zhuo Run-TryBot: Meng Zhuo TryBot-Result: Go Bot Reviewed-by: Keith Randall --- diff --git a/src/runtime/hash32.go b/src/runtime/hash32.go index 7fa8eb7cab..7c22c76b87 100644 --- a/src/runtime/hash32.go +++ b/src/runtime/hash32.go @@ -3,8 +3,7 @@ // license that can be found in the LICENSE file. // Hashing algorithm inspired by -// xxhash: https://code.google.com/p/xxhash/ -// cityhash: https://code.google.com/p/cityhash/ +// wyhash: https://github.com/wangyi-fudan/wyhash/blob/ceb019b530e2c1c14d70b79bfa2bc49de7d95bc1/Modern%20Non-Cryptographic%20Hash%20Function%20and%20Pseudorandom%20Number%20Generator.pdf //go:build 386 || arm || mips || mipsle // +build 386 arm mips mipsle @@ -13,101 +12,52 @@ package runtime import "unsafe" -const ( - // Constants for multiplication: four random odd 32-bit numbers. - m1 = 3168982561 - m2 = 3339683297 - m3 = 832293441 - m4 = 2336365089 -) - -func memhashFallback(p unsafe.Pointer, seed, s uintptr) uintptr { - h := uint32(seed + s*hashkey[0]) -tail: - switch { - case s == 0: - case s < 4: - h ^= uint32(*(*byte)(p)) - h ^= uint32(*(*byte)(add(p, s>>1))) << 8 - h ^= uint32(*(*byte)(add(p, s-1))) << 16 - h = rotl_15(h*m1) * m2 - case s == 4: - h ^= readUnaligned32(p) - h = rotl_15(h*m1) * m2 - case s <= 8: - h ^= readUnaligned32(p) - h = rotl_15(h*m1) * m2 - h ^= readUnaligned32(add(p, s-4)) - h = rotl_15(h*m1) * m2 - case s <= 16: - h ^= readUnaligned32(p) - h = rotl_15(h*m1) * m2 - h ^= readUnaligned32(add(p, 4)) - h = rotl_15(h*m1) * m2 - h ^= readUnaligned32(add(p, s-8)) - h = rotl_15(h*m1) * m2 - h ^= readUnaligned32(add(p, s-4)) - h = rotl_15(h*m1) * m2 - default: - v1 := h - v2 := uint32(seed * hashkey[1]) - v3 := uint32(seed * hashkey[2]) - v4 := uint32(seed * hashkey[3]) - for s >= 16 { - v1 ^= readUnaligned32(p) - v1 = rotl_15(v1*m1) * m2 - p = add(p, 4) - v2 ^= readUnaligned32(p) - v2 = rotl_15(v2*m2) * m3 - p = add(p, 4) - v3 ^= readUnaligned32(p) - v3 = rotl_15(v3*m3) * m4 - p = add(p, 4) - v4 ^= readUnaligned32(p) - v4 = rotl_15(v4*m4) * m1 - p = add(p, 4) - s -= 16 - } - h = v1 ^ v2 ^ v3 ^ v4 - goto tail - } - h ^= h >> 17 - h *= m3 - h ^= h >> 13 - h *= m4 - h ^= h >> 16 - return uintptr(h) -} - func memhash32Fallback(p unsafe.Pointer, seed uintptr) uintptr { - h := uint32(seed + 4*hashkey[0]) - h ^= readUnaligned32(p) - h = rotl_15(h*m1) * m2 - h ^= h >> 17 - h *= m3 - h ^= h >> 13 - h *= m4 - h ^= h >> 16 - return uintptr(h) + a, b := mix32(uint32(seed), uint32(4^hashkey[0])) + t := readUnaligned32(p) + a ^= t + b ^= t + a, b = mix32(a, b) + a, b = mix32(a, b) + return uintptr(a ^ b) } func memhash64Fallback(p unsafe.Pointer, seed uintptr) uintptr { - h := uint32(seed + 8*hashkey[0]) - h ^= readUnaligned32(p) - h = rotl_15(h*m1) * m2 - h ^= readUnaligned32(add(p, 4)) - h = rotl_15(h*m1) * m2 - h ^= h >> 17 - h *= m3 - h ^= h >> 13 - h *= m4 - h ^= h >> 16 - return uintptr(h) + a, b := mix32(uint32(seed), uint32(8^hashkey[0])) + a ^= readUnaligned32(p) + b ^= readUnaligned32(add(p, 4)) + a, b = mix32(a, b) + a, b = mix32(a, b) + return uintptr(a ^ b) +} + +func memhashFallback(p unsafe.Pointer, seed, s uintptr) uintptr { + + a, b := mix32(uint32(seed), uint32(s^hashkey[0])) + if s == 0 { + return uintptr(a ^ b) + } + for ; s > 8; s -= 8 { + a ^= readUnaligned32(p) + b ^= readUnaligned32(add(p, 4)) + a, b = mix32(a, b) + p = add(p, 8) + } + if s >= 4 { + a ^= readUnaligned32(p) + b ^= readUnaligned32(add(p, s-4)) + } else { + t := uint32(*(*byte)(p)) + t |= uint32(*(*byte)(add(p, s>>1))) << 8 + t |= uint32(*(*byte)(add(p, s-1))) << 16 + b ^= t + } + a, b = mix32(a, b) + a, b = mix32(a, b) + return uintptr(a ^ b) } -// Note: in order to get the compiler to issue rotl instructions, we -// need to constant fold the shift amount by hand. -// TODO: convince the compiler to issue rotl instructions after inlining. -func rotl_15(x uint32) uint32 { - return (x << 15) | (x >> (32 - 15)) +func mix32(a, b uint32) (uint32, uint32) { + c := uint64(a^uint32(hashkey[1])) * uint64(b^uint32(hashkey[2])) + return uint32(c), uint32(c >> 32) }