1
0
mirror of https://github.com/golang/go synced 2024-11-26 07:17:59 -07:00

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 <mzh@golangcn.org>
Run-TryBot: Meng Zhuo <mzh@golangcn.org>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Keith Randall <khr@golang.org>
This commit is contained in:
Meng Zhuo 2021-03-15 19:48:39 +08:00
parent f02a26bed0
commit 78f9015236

View File

@ -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)
}
// 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 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)
}
func mix32(a, b uint32) (uint32, uint32) {
c := uint64(a^uint32(hashkey[1])) * uint64(b^uint32(hashkey[2]))
return uint32(c), uint32(c >> 32)
}