From 7365fac2dbd01960268ee051ed03d961258d4ef4 Mon Sep 17 00:00:00 2001 From: Josh Bleecher Snyder Date: Tue, 13 Feb 2018 17:54:05 -0800 Subject: [PATCH] runtime: use bytes.IndexByte in findnull MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit bytes.IndexByte is heavily optimized. Use it in findnull. name old time/op new time/op delta GoString-8 65.5ns ± 1% 40.2ns ± 1% -38.62% (p=0.000 n=19+19) findnull is also used in gostringnocopy, which is used in many hot spots in the runtime. Fixes #23830 Change-Id: I2e6cb279c7d8078f8844065de684cc3567fe89d7 Reviewed-on: https://go-review.googlesource.com/97523 Run-TryBot: Josh Bleecher Snyder Reviewed-by: Brad Fitzpatrick Reviewed-by: Ian Lance Taylor TryBot-Result: Gobot Gobot --- misc/cgo/test/basic.go | 14 ++++++++++++++ misc/cgo/test/cgo_test.go | 3 ++- src/runtime/error.go | 1 + src/runtime/string.go | 9 +++------ 4 files changed, 20 insertions(+), 7 deletions(-) diff --git a/misc/cgo/test/basic.go b/misc/cgo/test/basic.go index 3ceb4ce847..2655a66e38 100644 --- a/misc/cgo/test/basic.go +++ b/misc/cgo/test/basic.go @@ -31,6 +31,8 @@ struct S { int x; }; +const char *cstr = "abcefghijklmnopqrstuvwxyzABCEFGHIJKLMNOPQRSTUVWXYZ1234567890"; + extern enum E myConstFunc(struct S* const ctx, int const id, struct S **const filter); enum E myConstFunc(struct S *const ctx, int const id, struct S **const filter) { return 0; } @@ -149,6 +151,18 @@ func benchCgoCall(b *testing.B) { } } +var sinkString string + +func benchGoString(b *testing.B) { + for i := 0; i < b.N; i++ { + sinkString = C.GoString(C.cstr) + } + const want = "abcefghijklmnopqrstuvwxyzABCEFGHIJKLMNOPQRSTUVWXYZ1234567890" + if sinkString != want { + b.Fatalf("%q != %q", sinkString, want) + } +} + // Issue 2470. func testUnsignedInt(t *testing.T) { a := (int64)(C.UINT32VAL) diff --git a/misc/cgo/test/cgo_test.go b/misc/cgo/test/cgo_test.go index cfacb9c40d..01ab7eba5e 100644 --- a/misc/cgo/test/cgo_test.go +++ b/misc/cgo/test/cgo_test.go @@ -88,4 +88,5 @@ func Test6907Go(t *testing.T) { test6907Go(t) } func Test21897(t *testing.T) { test21897(t) } func Test22906(t *testing.T) { test22906(t) } -func BenchmarkCgoCall(b *testing.B) { benchCgoCall(b) } +func BenchmarkCgoCall(b *testing.B) { benchCgoCall(b) } +func BenchmarkGoString(b *testing.B) { benchGoString(b) } diff --git a/src/runtime/error.go b/src/runtime/error.go index e1291e1543..2435f98b7a 100644 --- a/src/runtime/error.go +++ b/src/runtime/error.go @@ -121,6 +121,7 @@ func printany(i interface{}) { // strings.IndexByte is implemented in runtime/asm_$goarch.s // but amusingly we need go:linkname to get access to it here in the runtime. //go:linkname stringsIndexByte strings.IndexByte +//go:noescape func stringsIndexByte(s string, c byte) int // panicwrap generates a panic for a call to a wrapped value method diff --git a/src/runtime/string.go b/src/runtime/string.go index 5c83895995..0ea162235c 100644 --- a/src/runtime/string.go +++ b/src/runtime/string.go @@ -407,12 +407,9 @@ 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++ - } - return l + ss := stringStruct{unsafe.Pointer(s), maxAlloc/2 - 1} + t := *(*string)(unsafe.Pointer(&ss)) + return stringsIndexByte(t, 0) } func findnullw(s *uint16) int { -- 2.50.0