aboutsummaryrefslogtreecommitdiff
path: root/src/runtime/string.go
diff options
context:
space:
mode:
authorIlya Tocar <ilya.tocar@intel.com>2018-03-01 16:52:27 -0600
committerBrad Fitzpatrick <bradfitz@golang.org>2018-03-09 19:37:39 +0000
commit91102bf723c2e0912cbc4621f03827c0c3062128 (patch)
tree95b04f92026b9beff1aa89d089e34fdc2185882e /src/runtime/string.go
parent4902778607938459fe07d22b8445250fd7987917 (diff)
downloadgo-91102bf723c2e0912cbc4621f03827c0c3062128.tar.gz
go-91102bf723c2e0912cbc4621f03827c0c3062128.zip
runtime: use bytes.IndexByte in findnull
bytes.IndexByte is heavily optimized. Use it in findnull. This is second attempt, similar to CL97523. In this version we never call IndexByte on region of memory, that crosses page boundary. A bit slower than CL97523, but still fast: name old time/op new time/op delta GoString-6 164ns ± 2% 118ns ± 0% -28.00% (p=0.000 n=10+6) findnull is also used in gostringnocopy, which is used in many hot spots in the runtime. Fixes #23830 Change-Id: Id843dd4f65a34309d92bdd8df229e484d26b0cb2 Reviewed-on: https://go-review.googlesource.com/98015 Run-TryBot: Ilya Tocar <ilya.tocar@intel.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
Diffstat (limited to 'src/runtime/string.go')
-rw-r--r--src/runtime/string.go34
1 files changed, 28 insertions, 6 deletions
diff --git a/src/runtime/string.go b/src/runtime/string.go
index 5c83895995..e958f763cf 100644
--- a/src/runtime/string.go
+++ b/src/runtime/string.go
@@ -4,7 +4,10 @@
package runtime
-import "unsafe"
+import (
+ "internal/bytealg"
+ "unsafe"
+)
// The constant is known to the compiler.
// There is no fundamental theory behind this number.
@@ -407,12 +410,31 @@ func findnull(s *byte) int {
if s == nil {
return 0
}
- p := (*[maxAlloc/2 - 1]byte)(unsafe.Pointer(s))
- l := 0
- for p[l] != 0 {
- l++
+
+ // pageSize is the unit we scan at a time looking for NULL.
+ // It must be the minimum page size for any architecture Go
+ // runs on. It's okay (just a minor performance loss) if the
+ // actual system page size is larger than this value.
+ const pageSize = 4096
+
+ offset := 0
+ ptr := unsafe.Pointer(s)
+ // IndexByteString uses wide reads, so we need to be careful
+ // with page boundaries. Call IndexByteString on
+ // [ptr, endOfPage) interval.
+ safeLen := int(pageSize - uintptr(ptr)%pageSize)
+
+ for {
+ t := *(*string)(unsafe.Pointer(&stringStruct{ptr, safeLen}))
+ // Check one page at a time.
+ if i := bytealg.IndexByteString(t, 0); i != -1 {
+ return offset + i
+ }
+ // Move to next page
+ ptr = unsafe.Pointer(uintptr(ptr) + uintptr(safeLen))
+ offset += safeLen
+ safeLen = pageSize
}
- return l
}
func findnullw(s *uint16) int {