runtime: a better fallback hash

For arm and powerpc, as well as x86 without aes instructions.
Contains a mixture of ideas from cityhash and xxhash.

Compared to our old fallback on ARM, it's ~no slower on
small objects and up to ~50% faster on large objects.  More
importantly, it is a much better hash function and thus has
less chance of bad behavior.

Fixes #8737

benchmark                         old ns/op     new ns/op     delta
BenchmarkHash5                    173           181           +4.62%
BenchmarkHash16                   252           212           -15.87%
BenchmarkHash64                   575           419           -27.13%
BenchmarkHash1024                 7173          3995          -44.31%
BenchmarkHash65536                516940        313173        -39.42%
BenchmarkHashStringSpeed          300           279           -7.00%
BenchmarkHashBytesSpeed           478           424           -11.30%
BenchmarkHashInt32Speed           217           207           -4.61%
BenchmarkHashInt64Speed           262           231           -11.83%
BenchmarkHashStringArraySpeed     609           631           +3.61%

Change-Id: I0a9335028f32b10ad484966e3019987973afd3eb
Reviewed-on: https://go-review.googlesource.com/1360
Reviewed-by: Russ Cox <rsc@golang.org>
This commit is contained in:
Keith Randall 2014-12-10 17:02:58 -08:00
parent fbc56cf050
commit cda0ea1c0e
7 changed files with 229 additions and 32 deletions

View file

@ -72,8 +72,6 @@ var algarray = [alg_max]typeAlg{
alg_CPLX128: {c128hash, c128equal},
}
const nacl = GOOS == "nacl"
var useAeshash bool
// in asm_*.s
@ -82,22 +80,9 @@ func aeshash32(p unsafe.Pointer, s, h uintptr) uintptr
func aeshash64(p unsafe.Pointer, s, h uintptr) uintptr
func aeshashstr(p unsafe.Pointer, s, h uintptr) uintptr
func memhash(p unsafe.Pointer, s, h uintptr) uintptr {
if !nacl && useAeshash {
return aeshash(p, s, h)
}
h ^= c0
for s > 0 {
h = (h ^ uintptr(*(*byte)(p))) * c1
p = add(p, 1)
s--
}
return h
}
func strhash(a unsafe.Pointer, s, h uintptr) uintptr {
return memhash((*stringStruct)(a).str, uintptr(len(*(*string)(a))), h)
x := (*stringStruct)(a)
return memhash(x.str, uintptr(x.len), h)
}
// NOTE: Because NaN != NaN, a map can contain any
@ -267,10 +252,6 @@ func ifaceeq(p, q interface {
}
// Testing adapters for hash quality tests (see hash_test.go)
func haveGoodHash() bool {
return useAeshash
}
func stringHash(s string, seed uintptr) uintptr {
return algarray[alg_STRING].hash(noescape(unsafe.Pointer(&s)), unsafe.Sizeof(s), seed)
}
@ -315,7 +296,7 @@ const hashRandomBytes = ptrSize / 4 * 64
var aeskeysched [hashRandomBytes]byte
func init() {
if theGoos == "nacl" {
if GOOS == "nacl" {
return
}