util/deephash: move array and slice logic to separate function (#5463)

This helps pprof better identify which Go kinds take the most time
since the kind is always in the function name.

Signed-off-by: Joe Tsai <joetsai@digital-static.net>
This commit is contained in:
Joe Tsai 2022-08-27 15:37:36 -07:00 committed by GitHub
parent 31bf3874d6
commit 296b008b9f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -312,25 +312,10 @@ func genTypeHasher(ti *typeInfo) typeHasherFunc {
switch t.Kind() { switch t.Kind() {
case reflect.String: case reflect.String:
return (*hasher).hashString return (*hasher).hashString
case reflect.Slice:
et := t.Elem()
if typeIsMemHashable(et) {
return func(h *hasher, p pointer) {
pa := p.sliceArray()
vLen := p.sliceLen()
h.HashUint64(uint64(vLen))
if vLen == 0 {
return
}
h.HashBytes(pa.asMemory(et.Size() * uintptr(vLen)))
}
}
eti := getTypeInfo(et)
return genHashSliceElements(eti)
case reflect.Array: case reflect.Array:
et := t.Elem() return makeArrayHasher(t)
eti := getTypeInfo(et) case reflect.Slice:
return genHashArray(t, eti) return makeSliceHasher(t)
case reflect.Struct: case reflect.Struct:
return genHashStructFields(t) return genHashStructFields(t)
case reflect.Map: case reflect.Map:
@ -442,37 +427,50 @@ func makeMemHasher(n uintptr) typeHasherFunc {
} }
} }
func genHashArrayElements(n int, eti *typeInfo) typeHasherFunc { func makeArrayHasher(t reflect.Type) typeHasherFunc {
nb := eti.rtype.Size() // byte size of each array element var once sync.Once
var hashElem typeHasherFunc
init := func() {
hashElem = getTypeInfo(t.Elem()).hasher()
}
n := t.Len() // number of array elements
nb := t.Elem().Size() // byte size of each array element
return func(h *hasher, p pointer) { return func(h *hasher, p pointer) {
once.Do(init)
for i := 0; i < n; i++ { for i := 0; i < n; i++ {
pe := p.arrayIndex(i, nb) hashElem(h, p.arrayIndex(i, nb))
eti.hasher()(h, pe)
} }
} }
} }
func genHashArray(t reflect.Type, eti *typeInfo) typeHasherFunc { func makeSliceHasher(t reflect.Type) typeHasherFunc {
n := t.Len() nb := t.Elem().Size() // byte size of each slice element
return genHashArrayElements(n, eti) if typeIsMemHashable(t.Elem()) {
} return func(h *hasher, p pointer) {
pa := p.sliceArray()
n := p.sliceLen()
b := pa.asMemory(uintptr(n) * nb)
h.HashUint64(uint64(n))
h.HashBytes(b)
}
}
func genHashSliceElements(eti *typeInfo) typeHasherFunc { var once sync.Once
return sliceElementHasher{eti}.hash var hashElem typeHasherFunc
} init := func() {
hashElem = getTypeInfo(t.Elem()).hasher()
}
type sliceElementHasher struct { return func(h *hasher, p pointer) {
eti *typeInfo pa := p.sliceArray()
} once.Do(init)
n := p.sliceLen()
func (seh sliceElementHasher) hash(h *hasher, p pointer) { h.HashUint64(uint64(n))
pa := p.sliceArray() for i := 0; i < n; i++ {
vLen := p.sliceLen() pe := pa.arrayIndex(i, nb)
h.HashUint64(uint64(vLen)) hashElem(h, pe)
nb := seh.eti.rtype.Size() }
for i := 0; i < vLen; i++ {
pe := pa.arrayIndex(i, nb)
seh.eti.hasher()(h, pe)
} }
} }