From a2d7a2aeb1ede9c6750d7db50234dca724fa7830 Mon Sep 17 00:00:00 2001 From: Josh Bleecher Snyder Date: Mon, 17 May 2021 12:46:17 -0700 Subject: [PATCH] internal/deephash: use MapIter.Set{Key,Value} MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 https://github.com/tailscale/go/commit/728ecc58fd5c010c04bb7c8a56d238167e7d888f. 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 setkey --- internal/deephash/deephash.go | 8 ++++++-- internal/deephash/mapiter.go | 17 +++++++++++++++++ internal/deephash/mapiter_future.go | 19 +++++++++++++++++++ 3 files changed, 42 insertions(+), 2 deletions(-) create mode 100644 internal/deephash/mapiter.go create mode 100644 internal/deephash/mapiter_future.go diff --git a/internal/deephash/deephash.go b/internal/deephash/deephash.go index 8706c199f..16b89ac4e 100644 --- a/internal/deephash/deephash.go +++ b/internal/deephash/deephash.go @@ -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() diff --git a/internal/deephash/mapiter.go b/internal/deephash/mapiter.go new file mode 100644 index 000000000..a45275dc0 --- /dev/null +++ b/internal/deephash/mapiter.go @@ -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() +} diff --git a/internal/deephash/mapiter_future.go b/internal/deephash/mapiter_future.go new file mode 100644 index 000000000..6e18dbd6a --- /dev/null +++ b/internal/deephash/mapiter_future.go @@ -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 +}