]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: use bytes.IndexByte in findnull
authorJosh Bleecher Snyder <josharian@gmail.com>
Wed, 14 Feb 2018 01:54:05 +0000 (17:54 -0800)
committerJosh Bleecher Snyder <josharian@gmail.com>
Thu, 1 Mar 2018 20:34:07 +0000 (20:34 +0000)
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 <josharian@gmail.com>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>

misc/cgo/test/basic.go
misc/cgo/test/cgo_test.go
src/runtime/error.go
src/runtime/string.go

index 3ceb4ce8470d4dac938c5741dcc19932db6616d4..2655a66e38173c28d244857157d36e926cfa909f 100644 (file)
@@ -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)
index cfacb9c40d09f6f1d5c5d7da37e26673b8fc6984..01ab7eba5ec7a2e22e2a1beca1169d3047f26ef7 100644 (file)
@@ -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) }
index e1291e15435d53fc79b95f34c0e52065bc2f020d..2435f98b7af2a394c03b50154d2f9e7b62bb7cff 100644 (file)
@@ -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
index 5c838959953b3e1d8d172a278f378dd905312a30..0ea162235cdc58dfd200e56bf24edde8550123bd 100644 (file)
@@ -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 {