mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
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>
This commit is contained in:
parent
ac40c9872f
commit
a0c409cbc8
2 changed files with 102 additions and 1 deletions
|
|
@ -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)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue