mirror of
https://github.com/tailscale/tailscale.git
synced 2025-02-20 11:58:39 +00:00
internal/deephash: re-use map iteration values
This requires changes to the Go toolchain. The changes are upstream at https://golang.org/cl/320929. They haven't been pulled into our fork yet. No need to allocate new iteration scratch values for every map. name old time/op new time/op delta Hash-8 13.6µs ± 0% 13.5µs ± 0% -1.01% (p=0.008 n=5+5) HashMapAcyclic-8 21.2µs ± 1% 21.1µs ± 2% ~ (p=0.310 n=5+5) name old alloc/op new alloc/op delta Hash-8 1.58kB ± 0% 1.46kB ± 0% -7.60% (p=0.008 n=5+5) HashMapAcyclic-8 152B ± 0% 128B ± 0% -15.79% (p=0.008 n=5+5) name old allocs/op new allocs/op delta Hash-8 49.0 ± 0% 43.0 ± 0% -12.24% (p=0.008 n=5+5) HashMapAcyclic-8 4.00 ± 0% 2.00 ± 0% -50.00% (p=0.008 n=5+5) Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
This commit is contained in:
parent
a2d7a2aeb1
commit
09afb8e35b
@ -200,6 +200,7 @@ type mapHasher struct {
|
|||||||
ebuf [sha256.Size]byte // scratch buffer
|
ebuf [sha256.Size]byte // scratch buffer
|
||||||
s256 hash.Hash // sha256 hash.Hash
|
s256 hash.Hash // sha256 hash.Hash
|
||||||
bw *bufio.Writer // to hasher into ebuf
|
bw *bufio.Writer // to hasher into ebuf
|
||||||
|
val valueCache // re-usable values for map iteration
|
||||||
}
|
}
|
||||||
|
|
||||||
func (mh *mapHasher) Reset() {
|
func (mh *mapHasher) Reset() {
|
||||||
@ -228,10 +229,22 @@ var mapHasherPool = &sync.Pool{
|
|||||||
mh := new(mapHasher)
|
mh := new(mapHasher)
|
||||||
mh.s256 = sha256.New()
|
mh.s256 = sha256.New()
|
||||||
mh.bw = bufio.NewWriter(mh.s256)
|
mh.bw = bufio.NewWriter(mh.s256)
|
||||||
|
mh.val = make(valueCache)
|
||||||
return mh
|
return mh
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type valueCache map[reflect.Type]reflect.Value
|
||||||
|
|
||||||
|
func (c valueCache) get(t reflect.Type) reflect.Value {
|
||||||
|
v, ok := c[t]
|
||||||
|
if !ok {
|
||||||
|
v = reflect.New(t).Elem()
|
||||||
|
c[t] = v
|
||||||
|
}
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
// hashMapAcyclic is the faster sort-free version of map hashing. If
|
// hashMapAcyclic is the faster sort-free version of map hashing. If
|
||||||
// it detects a cycle it returns false and guarantees that nothing was
|
// it detects a cycle it returns false and guarantees that nothing was
|
||||||
// written to w.
|
// written to w.
|
||||||
@ -240,8 +253,8 @@ func hashMapAcyclic(w *bufio.Writer, v reflect.Value, visited map[uintptr]bool)
|
|||||||
defer mapHasherPool.Put(mh)
|
defer mapHasherPool.Put(mh)
|
||||||
mh.Reset()
|
mh.Reset()
|
||||||
iter := v.MapRange()
|
iter := v.MapRange()
|
||||||
k := reflect.New(v.Type().Key()).Elem()
|
k := mh.val.get(v.Type().Key())
|
||||||
e := reflect.New(v.Type().Elem()).Elem()
|
e := mh.val.get(v.Type().Elem())
|
||||||
for iter.Next() {
|
for iter.Next() {
|
||||||
key := iterKey(iter, k)
|
key := iterKey(iter, k)
|
||||||
val := iterVal(iter, e)
|
val := iterVal(iter, e)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user