internal/deephash: use MapIter.Set{Key,Value}

To get the benefit of this optimization requires help from the Go toolchain.
The changes are upstream at https://golang.org/cl/320929,
and have been pulled into the Tailscale fork at
728ecc58fd.
It also requires building with the build tag tailscale_go.

name              old time/op    new time/op    delta
Hash-8              14.0µs ± 0%    13.6µs ± 0%   -2.88%  (p=0.008 n=5+5)
HashMapAcyclic-8    24.3µs ± 1%    21.2µs ± 1%  -12.47%  (p=0.008 n=5+5)

name              old alloc/op   new alloc/op   delta
Hash-8              2.16kB ± 0%    1.58kB ± 0%  -27.01%  (p=0.008 n=5+5)
HashMapAcyclic-8    2.53kB ± 0%    0.15kB ± 0%  -93.99%  (p=0.008 n=5+5)

name              old allocs/op  new allocs/op  delta
Hash-8                77.0 ± 0%      49.0 ± 0%  -36.36%  (p=0.008 n=5+5)
HashMapAcyclic-8       202 ± 0%         4 ± 0%  -98.02%  (p=0.008 n=5+5)

Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>

setkey
This commit is contained in:
Josh Bleecher Snyder 2021-05-17 12:46:17 -07:00 committed by Josh Bleecher Snyder
parent 020e904f4e
commit a2d7a2aeb1
3 changed files with 42 additions and 2 deletions

View File

@ -240,12 +240,16 @@ func hashMapAcyclic(w *bufio.Writer, v reflect.Value, visited map[uintptr]bool)
defer mapHasherPool.Put(mh)
mh.Reset()
iter := v.MapRange()
k := reflect.New(v.Type().Key()).Elem()
e := reflect.New(v.Type().Elem()).Elem()
for iter.Next() {
key := iterKey(iter, k)
val := iterVal(iter, e)
mh.startEntry()
if !print(mh.bw, iter.Key(), visited) {
if !print(mh.bw, key, visited) {
return false
}
if !print(mh.bw, iter.Value(), visited) {
if !print(mh.bw, val, visited) {
return false
}
mh.endEntry()

View File

@ -0,0 +1,17 @@
// Copyright (c) 2021 Tailscale Inc & AUTHORS All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !tailscale_go
package deephash
import "reflect"
func iterKey(iter *reflect.MapIter, scratch reflect.Value) reflect.Value {
return iter.Key()
}
func iterVal(iter *reflect.MapIter, scratch reflect.Value) reflect.Value {
return iter.Value()
}

View File

@ -0,0 +1,19 @@
// Copyright (c) 2021 Tailscale Inc & AUTHORS All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build tailscale_go
package deephash
import "reflect"
func iterKey(iter *reflect.MapIter, scratch reflect.Value) reflect.Value {
iter.SetKey(scratch)
return scratch
}
func iterVal(iter *reflect.MapIter, scratch reflect.Value) reflect.Value {
iter.SetValue(scratch)
return scratch
}