mirror of
https://github.com/tailscale/tailscale.git
synced 2025-08-22 19:09:58 +00:00
util/deephash: avoid using sync.Pool for reflect.MapIter (#5333)
In Go 1.19, the reflect.Value.MapRange method uses "function outlining" so that the allocation of reflect.MapIter is inlinable by the caller. If the iterator doesn't escape the caller, it can be stack allocated. See https://go.dev/cl/400675 Performance: name old time/op new time/op delta HashMapAcyclic-24 31.9µs ± 2% 32.1µs ± 1% ~ (p=0.075 n=10+10) name old alloc/op new alloc/op delta HashMapAcyclic-24 0.00B 0.00B ~ (all equal) Signed-off-by: Joe Tsai <joetsai@digital-static.net>
This commit is contained in:
@@ -918,8 +918,7 @@ func (h *hasher) hashValueWithType(v addressableValue, ti *typeInfo, forceCycleC
|
||||
|
||||
type mapHasher struct {
|
||||
h hasher
|
||||
valKey, valElem valueCache // re-usable values for map iteration
|
||||
iter reflect.MapIter // re-usable map iterator
|
||||
valKey, valElem valueCache // re-usable values for map iteration
|
||||
}
|
||||
|
||||
var mapHasherPool = &sync.Pool{
|
||||
@@ -948,10 +947,6 @@ func (h *hasher) hashMap(v addressableValue, ti *typeInfo, checkCycles bool) {
|
||||
mh := mapHasherPool.Get().(*mapHasher)
|
||||
defer mapHasherPool.Put(mh)
|
||||
|
||||
iter := &mh.iter
|
||||
iter.Reset(v.Value)
|
||||
defer iter.Reset(reflect.Value{}) // avoid pinning v from mh.iter when we return
|
||||
|
||||
var sum Sum
|
||||
if v.IsNil() {
|
||||
sum.sum[0] = 1 // something non-zero
|
||||
@@ -960,7 +955,7 @@ func (h *hasher) hashMap(v addressableValue, ti *typeInfo, checkCycles bool) {
|
||||
k := mh.valKey.get(v.Type().Key())
|
||||
e := mh.valElem.get(v.Type().Elem())
|
||||
mh.h.visitStack = h.visitStack // always use the parent's visit stack to avoid cycles
|
||||
for iter.Next() {
|
||||
for iter := v.MapRange(); iter.Next(); {
|
||||
k.SetIterKey(iter)
|
||||
e.SetIterValue(iter)
|
||||
mh.h.reset()
|
||||
|
Reference in New Issue
Block a user