From 296b008b9f5787ec159a13f6141cbbd6c55d30b4 Mon Sep 17 00:00:00 2001 From: Joe Tsai Date: Sat, 27 Aug 2022 15:37:36 -0700 Subject: [PATCH] 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 --- util/deephash/deephash.go | 80 +++++++++++++++++++-------------------- 1 file changed, 39 insertions(+), 41 deletions(-) diff --git a/util/deephash/deephash.go b/util/deephash/deephash.go index 1e3cb79b2..621d3e69d 100644 --- a/util/deephash/deephash.go +++ b/util/deephash/deephash.go @@ -312,25 +312,10 @@ func genTypeHasher(ti *typeInfo) typeHasherFunc { switch t.Kind() { case reflect.String: 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: - et := t.Elem() - eti := getTypeInfo(et) - return genHashArray(t, eti) + return makeArrayHasher(t) + case reflect.Slice: + return makeSliceHasher(t) case reflect.Struct: return genHashStructFields(t) case reflect.Map: @@ -442,37 +427,50 @@ func makeMemHasher(n uintptr) typeHasherFunc { } } -func genHashArrayElements(n int, eti *typeInfo) typeHasherFunc { - nb := eti.rtype.Size() // byte size of each array element +func makeArrayHasher(t reflect.Type) typeHasherFunc { + 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) { + once.Do(init) for i := 0; i < n; i++ { - pe := p.arrayIndex(i, nb) - eti.hasher()(h, pe) + hashElem(h, p.arrayIndex(i, nb)) } } } -func genHashArray(t reflect.Type, eti *typeInfo) typeHasherFunc { - n := t.Len() - return genHashArrayElements(n, eti) -} - -func genHashSliceElements(eti *typeInfo) typeHasherFunc { - return sliceElementHasher{eti}.hash -} +func makeSliceHasher(t reflect.Type) typeHasherFunc { + nb := t.Elem().Size() // byte size of each slice element + 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) + } + } -type sliceElementHasher struct { - eti *typeInfo -} + var once sync.Once + var hashElem typeHasherFunc + init := func() { + hashElem = getTypeInfo(t.Elem()).hasher() + } -func (seh sliceElementHasher) hash(h *hasher, p pointer) { - pa := p.sliceArray() - vLen := p.sliceLen() - h.HashUint64(uint64(vLen)) - nb := seh.eti.rtype.Size() - for i := 0; i < vLen; i++ { - pe := pa.arrayIndex(i, nb) - seh.eti.hasher()(h, pe) + return func(h *hasher, p pointer) { + pa := p.sliceArray() + once.Do(init) + n := p.sliceLen() + h.HashUint64(uint64(n)) + for i := 0; i < n; i++ { + pe := pa.arrayIndex(i, nb) + hashElem(h, pe) + } } }