aboutsummaryrefslogtreecommitdiff
path: root/src/reflect/value.go
diff options
context:
space:
mode:
authorqiulaidongfeng <2645477756@qq.com>2023-11-07 13:39:17 +0000
committerKeith Randall <khr@golang.org>2023-11-15 04:10:05 +0000
commit12051f7d95ef6e97d1be0cab8a3583ad38ec1dcd (patch)
tree7498483e6afbc8a87636b12d38719b5ee64a1b91 /src/reflect/value.go
parentb7cdc277e15eb2fc63f8377fd5a8e0b922db8532 (diff)
downloadgo-12051f7d95ef6e97d1be0cab8a3583ad38ec1dcd.tar.xz
reflect: optimize Value.IsZero for array types
For some types where the zero value is a value where all bits of this type are 0 optimize it goos: windows goarch: amd64 pkg: reflect cpu: AMD Ryzen 7 7840HS w/ Radeon 780M Graphics │ std.txt │ new.txt │ │ sec/op │ sec/op vs base │ IsZero/ArrayComparable-16 8.483n ± 0% 8.470n ± 2% ~ (p=0.542 n=10) IsZero/ArrayIncomparable-16 88.13n ± 1% 87.34n ± 2% ~ (p=0.110 n=10) IsZero/StructComparable-16 4.050n ± 2% 4.011n ± 1% ~ (p=0.093 n=10) IsZero/StructIncomparable-16 19.93n ± 1% 19.81n ± 1% ~ (p=0.493 n=10) IsZero/ArrayInt_4-16 4.445n ± 2% 4.478n ± 2% ~ (p=0.306 n=10) IsZero/ArrayInt_1024-16 3381.5n ± 3% 140.8n ± 1% -95.84% (p=0.000 n=10) IsZero/ArrayInt_1024_NoZero-16 1760.50n ± 3% 72.17n ± 1% -95.90% (p=0.000 n=10) IsZero/Struct4Int-16 4.495n ± 3% 4.478n ± 1% ~ (p=0.579 n=10) IsZero/ArrayStruct4Int_1024-16 1404.0n ± 3% 140.5n ± 0% -90.00% (p=0.000 n=10) IsZero/ArrayChanInt_1024-16 3437.0n ± 6% 140.5n ± 1% -95.91% (p=0.000 n=10) geomean 89.94n 27.38n -69.56% Change-Id: I835231a79b9cd89686d44c5b8c2fbe629ccd98ba GitHub-Last-Rev: 3abe118a108faf0070b56ba9098871746daa1ac1 GitHub-Pull-Request: golang/go#63661 Reviewed-on: https://go-review.googlesource.com/c/go/+/536855 Reviewed-by: Cherry Mui <cherryyz@google.com> Reviewed-by: Keith Randall <khr@golang.org> TryBot-Result: Gopher Robot <gobot@golang.org> Reviewed-by: Keith Randall <khr@google.com>
Diffstat (limited to 'src/reflect/value.go')
-rw-r--r--src/reflect/value.go45
1 files changed, 41 insertions, 4 deletions
diff --git a/src/reflect/value.go b/src/reflect/value.go
index ec75fcced9..0452b51d7b 100644
--- a/src/reflect/value.go
+++ b/src/reflect/value.go
@@ -1598,18 +1598,24 @@ func (v Value) IsZero() bool {
case Complex64, Complex128:
return v.Complex() == 0
case Array:
+ array := (*abi.ArrayType)(unsafe.Pointer(v.typ()))
+ // Avoid performance degradation of small benchmarks.
// If the type is comparable, then compare directly with zero.
- if v.typ().Equal != nil && v.typ().Size() <= maxZero {
+ if array.Equal != nil && array.Size() <= maxZero {
if v.flag&flagIndir == 0 {
return v.ptr == nil
}
// v.ptr doesn't escape, as Equal functions are compiler generated
// and never escape. The escape analysis doesn't know, as it is a
// function pointer call.
- return v.typ().Equal(noescape(v.ptr), unsafe.Pointer(&zeroVal[0]))
+ return array.Equal(noescape(v.ptr), unsafe.Pointer(&zeroVal[0]))
}
-
- n := v.Len()
+ if array.TFlag&abi.TFlagRegularMemory != 0 {
+ // For some types where the zero value is a value where all bits of this type are 0
+ // optimize it.
+ return isZero(unsafe.Slice(((*byte)(v.ptr)), array.Size()))
+ }
+ n := int(array.Len)
for i := 0; i < n; i++ {
if !v.Index(i).IsZero() {
return false
@@ -1644,6 +1650,37 @@ func (v Value) IsZero() bool {
}
}
+// isZero must have len(b)>256+7 to ensure at
+// least one 8-byte aligned [256]byte,
+// otherwise the access will be out of bounds.
+// For all zeros, performance is not as good as
+// return bytealg.Count(b, byte(0)) == len(b)
+func isZero(b []byte) bool {
+ const n = 32
+ const bit = n * 8
+ // Align memory addresses to 8 bytes
+ for uintptr(unsafe.Pointer(&b[0]))%8 != 0 {
+ if b[0] != 0 {
+ return false
+ }
+ b = b[1:]
+ }
+ for len(b)%bit != 0 {
+ if b[len(b)-1] != 0 {
+ return false
+ }
+ b = b[:len(b)-1]
+ }
+ w := unsafe.Slice((*uint64)(unsafe.Pointer(&b[0])), len(b)/8)
+ for len(w) >= n {
+ if w[0] != 0 || w[1] != 0 || w[2] != 0 || w[3] != 0 || w[4] != 0 || w[5] != 0 || w[6] != 0 || w[7] != 0 || w[8] != 0 || w[9] != 0 || w[10] != 0 || w[11] != 0 || w[12] != 0 || w[13] != 0 || w[14] != 0 || w[15] != 0 || w[16] != 0 || w[17] != 0 || w[18] != 0 || w[19] != 0 || w[20] != 0 || w[21] != 0 || w[22] != 0 || w[23] != 0 || w[24] != 0 || w[25] != 0 || w[26] != 0 || w[27] != 0 || w[28] != 0 || w[29] != 0 || w[30] != 0 || w[31] != 0 {
+ return false
+ }
+ w = w[n:]
+ }
+ return true
+}
+
// SetZero sets v to be the zero value of v's type.
// It panics if [Value.CanSet] returns false.
func (v Value) SetZero() {