diff options
author | Josh Bleecher Snyder <josharian@gmail.com> | 2021-05-07 18:39:36 -0700 |
---|---|---|
committer | Josh Bleecher Snyder <josharian@gmail.com> | 2021-09-13 20:17:24 +0000 |
commit | a0c409cbc82ea9999a03fa0bfe6d9a8953e780e0 (patch) | |
tree | bead00b729ae52e160d3411f173afd83ed476aca /src/reflect/all_test.go | |
parent | ac40c9872f6e8ef095dcc6ee556236782eee4f76 (diff) | |
download | go-a0c409cbc82ea9999a03fa0bfe6d9a8953e780e0.tar.gz go-a0c409cbc82ea9999a03fa0bfe6d9a8953e780e0.zip |
reflect: add fast paths for common, simple Kinds to DeepEqual
Though the normal equality check suffices, it allocates.
Handle common, simple kinds without allocating.
For some real world types compared with DeepEqual
in the Tailscale code base, the impact of these changes:
name old time/op new time/op delta
HostInfoEqual-8 25.9µs ± 0% 14.4µs ± 0% -44.32% (p=0.008 n=5+5)
name old alloc/op new alloc/op delta
HostInfoEqual-8 18.8kB ± 0% 12.6kB ± 0% -32.58% (p=0.008 n=5+5)
name old allocs/op new allocs/op delta
HostInfoEqual-8 548 ± 0% 90 ± 0% -83.58% (p=0.008 n=5+5)
For the benchmarks added in this commit:
name old time/op new time/op delta
DeepEqual/int8-8 40.1ns ± 4% 31.3ns ± 4% -21.79% (p=0.000 n=19+20)
DeepEqual/[]int8-8 169ns ± 1% 123ns ± 1% -27.05% (p=0.000 n=17+18)
DeepEqual/int16-8 39.9ns ± 2% 30.8ns ± 4% -22.81% (p=0.000 n=17+20)
DeepEqual/[]int16-8 172ns ± 0% 122ns ± 1% -28.91% (p=0.000 n=17+18)
DeepEqual/int32-8 40.4ns ± 3% 31.1ns ± 4% -23.07% (p=0.000 n=20+20)
DeepEqual/[]int32-8 180ns ± 1% 124ns ± 1% -31.06% (p=0.000 n=20+18)
DeepEqual/int64-8 40.1ns ± 2% 31.4ns ± 4% -21.82% (p=0.000 n=20+20)
DeepEqual/[]int64-8 180ns ± 1% 124ns ± 1% -31.47% (p=0.000 n=16+19)
DeepEqual/int-8 40.1ns ± 4% 30.9ns ± 3% -22.88% (p=0.000 n=20+18)
DeepEqual/[]int-8 180ns ± 0% 123ns ± 2% -31.59% (p=0.000 n=19+20)
DeepEqual/uint8-8 39.8ns ± 3% 31.9ns ± 5% -19.72% (p=0.000 n=20+20)
DeepEqual/[]uint8-8 168ns ± 1% 114ns ± 1% -32.48% (p=0.000 n=18+19)
DeepEqual/uint16-8 40.3ns ± 4% 31.4ns ± 6% -22.14% (p=0.000 n=20+20)
DeepEqual/[]uint16-8 173ns ± 1% 124ns ± 1% -28.20% (p=0.000 n=20+16)
DeepEqual/uint32-8 40.1ns ± 3% 30.7ns ± 3% -23.48% (p=0.000 n=20+20)
DeepEqual/[]uint32-8 180ns ± 1% 123ns ± 1% -31.56% (p=0.000 n=20+18)
DeepEqual/uint64-8 40.0ns ± 4% 31.3ns ± 4% -21.80% (p=0.000 n=19+19)
DeepEqual/[]uint64-8 180ns ± 1% 124ns ± 0% -31.45% (p=0.000 n=18+18)
DeepEqual/uint-8 39.8ns ± 3% 31.1ns ± 4% -21.95% (p=0.000 n=19+20)
DeepEqual/[]uint-8 181ns ± 1% 122ns ± 1% -32.33% (p=0.000 n=17+20)
DeepEqual/uintptr-8 40.3ns ± 3% 31.2ns ± 3% -22.66% (p=0.000 n=20+18)
DeepEqual/[]uintptr-8 181ns ± 1% 124ns ± 1% -31.46% (p=0.000 n=19+16)
DeepEqual/float32-8 40.3ns ± 2% 31.2ns ± 3% -22.52% (p=0.000 n=16+20)
DeepEqual/[]float32-8 180ns ± 1% 122ns ± 1% -32.18% (p=0.000 n=17+17)
DeepEqual/float64-8 40.6ns ± 3% 30.9ns ± 5% -23.91% (p=0.000 n=19+20)
DeepEqual/[]float64-8 182ns ± 2% 121ns ± 1% -33.33% (p=0.000 n=18+20)
DeepEqual/complex64-8 43.0ns ±11% 32.1ns ± 5% -25.33% (p=0.000 n=20+18)
DeepEqual/[]complex64-8 182ns ± 1% 122ns ± 2% -32.60% (p=0.000 n=18+19)
DeepEqual/complex128-8 42.4ns ± 4% 34.2ns ± 3% -19.35% (p=0.000 n=20+19)
DeepEqual/[]complex128-8 197ns ± 1% 122ns ± 1% -38.01% (p=0.000 n=19+19)
DeepEqual/bool-8 40.3ns ± 3% 32.9ns ± 5% -18.33% (p=0.000 n=20+20)
DeepEqual/[]bool-8 169ns ± 1% 124ns ± 1% -26.90% (p=0.000 n=18+19)
DeepEqual/string-8 41.4ns ± 3% 33.7ns ± 5% -18.50% (p=0.000 n=19+20)
DeepEqual/[]string-8 216ns ± 0% 128ns ± 1% -41.05% (p=0.000 n=19+17)
DeepEqual/[]uint8#01-8 507ns ± 1% 112ns ± 2% -77.92% (p=0.000 n=20+20)
DeepEqual/[][]uint8-8 613ns ± 1% 210ns ± 1% -65.76% (p=0.000 n=18+19)
DeepEqual/[6]uint8-8 228ns ± 1% 162ns ± 1% -29.00% (p=0.000 n=20+19)
DeepEqual/[][6]uint8-8 546ns ± 2% 269ns ± 1% -50.72% (p=0.000 n=20+19)
name old alloc/op new alloc/op delta
DeepEqual/int8-8 0.00B 0.00B ~ (all equal)
DeepEqual/[]int8-8 2.00B ± 0% 0.00B -100.00% (p=0.000 n=20+20)
DeepEqual/int16-8 0.00B 0.00B ~ (all equal)
DeepEqual/[]int16-8 4.00B ± 0% 0.00B -100.00% (p=0.000 n=20+20)
DeepEqual/int32-8 0.00B 0.00B ~ (all equal)
DeepEqual/[]int32-8 8.00B ± 0% 0.00B -100.00% (p=0.000 n=20+20)
DeepEqual/int64-8 0.00B 0.00B ~ (all equal)
DeepEqual/[]int64-8 16.0B ± 0% 0.0B -100.00% (p=0.000 n=20+20)
DeepEqual/int-8 0.00B 0.00B ~ (all equal)
DeepEqual/[]int-8 16.0B ± 0% 0.0B -100.00% (p=0.000 n=20+20)
DeepEqual/uint8-8 0.00B 0.00B ~ (all equal)
DeepEqual/[]uint8-8 2.00B ± 0% 0.00B -100.00% (p=0.000 n=20+20)
DeepEqual/uint16-8 0.00B 0.00B ~ (all equal)
DeepEqual/[]uint16-8 4.00B ± 0% 0.00B -100.00% (p=0.000 n=20+20)
DeepEqual/uint32-8 0.00B 0.00B ~ (all equal)
DeepEqual/[]uint32-8 8.00B ± 0% 0.00B -100.00% (p=0.000 n=20+20)
DeepEqual/uint64-8 0.00B 0.00B ~ (all equal)
DeepEqual/[]uint64-8 16.0B ± 0% 0.0B -100.00% (p=0.000 n=20+20)
DeepEqual/uint-8 0.00B 0.00B ~ (all equal)
DeepEqual/[]uint-8 16.0B ± 0% 0.0B -100.00% (p=0.000 n=20+20)
DeepEqual/uintptr-8 0.00B 0.00B ~ (all equal)
DeepEqual/[]uintptr-8 16.0B ± 0% 0.0B -100.00% (p=0.000 n=20+20)
DeepEqual/float32-8 0.00B 0.00B ~ (all equal)
DeepEqual/[]float32-8 8.00B ± 0% 0.00B -100.00% (p=0.000 n=20+20)
DeepEqual/float64-8 0.00B 0.00B ~ (all equal)
DeepEqual/[]float64-8 16.0B ± 0% 0.0B -100.00% (p=0.000 n=20+20)
DeepEqual/complex64-8 0.00B 0.00B ~ (all equal)
DeepEqual/[]complex64-8 16.0B ± 0% 0.0B -100.00% (p=0.000 n=20+20)
DeepEqual/complex128-8 0.00B 0.00B ~ (all equal)
DeepEqual/[]complex128-8 32.0B ± 0% 0.0B -100.00% (p=0.000 n=20+20)
DeepEqual/bool-8 0.00B 0.00B ~ (all equal)
DeepEqual/[]bool-8 2.00B ± 0% 0.00B -100.00% (p=0.000 n=20+20)
DeepEqual/string-8 0.00B 0.00B ~ (all equal)
DeepEqual/[]string-8 32.0B ± 0% 0.0B -100.00% (p=0.000 n=20+20)
DeepEqual/[]uint8#01-8 12.0B ± 0% 0.0B -100.00% (p=0.000 n=20+20)
DeepEqual/[][]uint8-8 12.0B ± 0% 0.0B -100.00% (p=0.000 n=20+20)
DeepEqual/[6]uint8-8 0.00B 0.00B ~ (all equal)
DeepEqual/[][6]uint8-8 12.0B ± 0% 0.0B -100.00% (p=0.000 n=20+20)
name old allocs/op new allocs/op delta
DeepEqual/int8-8 0.00 0.00 ~ (all equal)
DeepEqual/[]int8-8 2.00 ± 0% 0.00 -100.00% (p=0.000 n=20+20)
DeepEqual/int16-8 0.00 0.00 ~ (all equal)
DeepEqual/[]int16-8 2.00 ± 0% 0.00 -100.00% (p=0.000 n=20+20)
DeepEqual/int32-8 0.00 0.00 ~ (all equal)
DeepEqual/[]int32-8 2.00 ± 0% 0.00 -100.00% (p=0.000 n=20+20)
DeepEqual/int64-8 0.00 0.00 ~ (all equal)
DeepEqual/[]int64-8 2.00 ± 0% 0.00 -100.00% (p=0.000 n=20+20)
DeepEqual/int-8 0.00 0.00 ~ (all equal)
DeepEqual/[]int-8 2.00 ± 0% 0.00 -100.00% (p=0.000 n=20+20)
DeepEqual/uint8-8 0.00 0.00 ~ (all equal)
DeepEqual/[]uint8-8 2.00 ± 0% 0.00 -100.00% (p=0.000 n=20+20)
DeepEqual/uint16-8 0.00 0.00 ~ (all equal)
DeepEqual/[]uint16-8 2.00 ± 0% 0.00 -100.00% (p=0.000 n=20+20)
DeepEqual/uint32-8 0.00 0.00 ~ (all equal)
DeepEqual/[]uint32-8 2.00 ± 0% 0.00 -100.00% (p=0.000 n=20+20)
DeepEqual/uint64-8 0.00 0.00 ~ (all equal)
DeepEqual/[]uint64-8 2.00 ± 0% 0.00 -100.00% (p=0.000 n=20+20)
DeepEqual/uint-8 0.00 0.00 ~ (all equal)
DeepEqual/[]uint-8 2.00 ± 0% 0.00 -100.00% (p=0.000 n=20+20)
DeepEqual/uintptr-8 0.00 0.00 ~ (all equal)
DeepEqual/[]uintptr-8 2.00 ± 0% 0.00 -100.00% (p=0.000 n=20+20)
DeepEqual/float32-8 0.00 0.00 ~ (all equal)
DeepEqual/[]float32-8 2.00 ± 0% 0.00 -100.00% (p=0.000 n=20+20)
DeepEqual/float64-8 0.00 0.00 ~ (all equal)
DeepEqual/[]float64-8 2.00 ± 0% 0.00 -100.00% (p=0.000 n=20+20)
DeepEqual/complex64-8 0.00 0.00 ~ (all equal)
DeepEqual/[]complex64-8 2.00 ± 0% 0.00 -100.00% (p=0.000 n=20+20)
DeepEqual/complex128-8 0.00 0.00 ~ (all equal)
DeepEqual/[]complex128-8 2.00 ± 0% 0.00 -100.00% (p=0.000 n=20+20)
DeepEqual/bool-8 0.00 0.00 ~ (all equal)
DeepEqual/[]bool-8 2.00 ± 0% 0.00 -100.00% (p=0.000 n=20+20)
DeepEqual/string-8 0.00 0.00 ~ (all equal)
DeepEqual/[]string-8 2.00 ± 0% 0.00 -100.00% (p=0.000 n=20+20)
DeepEqual/[]uint8#01-8 12.0 ± 0% 0.0 -100.00% (p=0.000 n=20+20)
DeepEqual/[][]uint8-8 12.0 ± 0% 0.0 -100.00% (p=0.000 n=20+20)
DeepEqual/[6]uint8-8 0.00 0.00 ~ (all equal)
DeepEqual/[][6]uint8-8 12.0 ± 0% 0.0 -100.00% (p=0.000 n=20+20)
Change-Id: Ic21f0e2305f2cf5e6674c81b9ca609120b3006d9
Reviewed-on: https://go-review.googlesource.com/c/go/+/318169
Trust: Josh Bleecher Snyder <josharian@gmail.com>
Trust: Joe Tsai <joetsai@digital-static.net>
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
Run-TryBot: Joe Tsai <joetsai@digital-static.net>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Joe Tsai <joetsai@digital-static.net>
Diffstat (limited to 'src/reflect/all_test.go')
-rw-r--r-- | src/reflect/all_test.go | 82 |
1 files changed, 82 insertions, 0 deletions
diff --git a/src/reflect/all_test.go b/src/reflect/all_test.go index e92f71135c..5b147082bb 100644 --- a/src/reflect/all_test.go +++ b/src/reflect/all_test.go @@ -905,6 +905,9 @@ var deepEqualTests = []DeepEqualTest{ {error(nil), error(nil), true}, {map[int]string{1: "one", 2: "two"}, map[int]string{2: "two", 1: "one"}, true}, {fn1, fn2, true}, + {[]byte{1, 2, 3}, []byte{1, 2, 3}, true}, + {[]MyByte{1, 2, 3}, []MyByte{1, 2, 3}, true}, + {MyBytes{1, 2, 3}, MyBytes{1, 2, 3}, true}, // Inequalities {1, 2, false}, @@ -950,6 +953,9 @@ var deepEqualTests = []DeepEqualTest{ {&[3]interface{}{1, 2, 4}, &[3]interface{}{1, 2, "s"}, false}, {Basic{1, 0.5}, NotBasic{1, 0.5}, false}, {map[uint]string{1: "one", 2: "two"}, map[int]string{2: "two", 1: "one"}, false}, + {[]byte{1, 2, 3}, []MyByte{1, 2, 3}, false}, + {[]MyByte{1, 2, 3}, MyBytes{1, 2, 3}, false}, + {[]byte{1, 2, 3}, MyBytes{1, 2, 3}, false}, // Possible loops. {&loop1, &loop1, true}, @@ -1049,6 +1055,82 @@ func TestDeepEqualUnexportedMap(t *testing.T) { } } +var deepEqualPerfTests = []struct { + x, y interface{} +}{ + {x: int8(99), y: int8(99)}, + {x: []int8{99}, y: []int8{99}}, + {x: int16(99), y: int16(99)}, + {x: []int16{99}, y: []int16{99}}, + {x: int32(99), y: int32(99)}, + {x: []int32{99}, y: []int32{99}}, + {x: int64(99), y: int64(99)}, + {x: []int64{99}, y: []int64{99}}, + {x: int(999999), y: int(999999)}, + {x: []int{999999}, y: []int{999999}}, + + {x: uint8(99), y: uint8(99)}, + {x: []uint8{99}, y: []uint8{99}}, + {x: uint16(99), y: uint16(99)}, + {x: []uint16{99}, y: []uint16{99}}, + {x: uint32(99), y: uint32(99)}, + {x: []uint32{99}, y: []uint32{99}}, + {x: uint64(99), y: uint64(99)}, + {x: []uint64{99}, y: []uint64{99}}, + {x: uint(999999), y: uint(999999)}, + {x: []uint{999999}, y: []uint{999999}}, + {x: uintptr(999999), y: uintptr(999999)}, + {x: []uintptr{999999}, y: []uintptr{999999}}, + + {x: float32(1.414), y: float32(1.414)}, + {x: []float32{1.414}, y: []float32{1.414}}, + {x: float64(1.414), y: float64(1.414)}, + {x: []float64{1.414}, y: []float64{1.414}}, + + {x: complex64(1.414), y: complex64(1.414)}, + {x: []complex64{1.414}, y: []complex64{1.414}}, + {x: complex128(1.414), y: complex128(1.414)}, + {x: []complex128{1.414}, y: []complex128{1.414}}, + + {x: true, y: true}, + {x: []bool{true}, y: []bool{true}}, + + {x: "abcdef", y: "abcdef"}, + {x: []string{"abcdef"}, y: []string{"abcdef"}}, + + {x: []byte("abcdef"), y: []byte("abcdef")}, + {x: [][]byte{[]byte("abcdef")}, y: [][]byte{[]byte("abcdef")}}, + + {x: [6]byte{'a', 'b', 'c', 'a', 'b', 'c'}, y: [6]byte{'a', 'b', 'c', 'a', 'b', 'c'}}, + {x: [][6]byte{[6]byte{'a', 'b', 'c', 'a', 'b', 'c'}}, y: [][6]byte{[6]byte{'a', 'b', 'c', 'a', 'b', 'c'}}}, +} + +func TestDeepEqualAllocs(t *testing.T) { + for _, tt := range deepEqualPerfTests { + t.Run(ValueOf(tt.x).Type().String(), func(t *testing.T) { + got := testing.AllocsPerRun(100, func() { + if !DeepEqual(tt.x, tt.y) { + t.Errorf("DeepEqual(%v, %v)=false", tt.x, tt.y) + } + }) + if int(got) != 0 { + t.Errorf("DeepEqual(%v, %v) allocated %d times", tt.x, tt.y, int(got)) + } + }) + } +} + +func BenchmarkDeepEqual(b *testing.B) { + for _, bb := range deepEqualPerfTests { + b.Run(ValueOf(bb.x).Type().String(), func(b *testing.B) { + b.ReportAllocs() + for i := 0; i < b.N; i++ { + sink = DeepEqual(bb.x, bb.y) + } + }) + } +} + func check2ndField(x interface{}, offs uintptr, t *testing.T) { s := ValueOf(x) f := s.Type().Field(1) |