runtime: replace stringStruct with unsafe.String where appropriate

Simplify the code a bit, no significant performance changes.

name                             old time/op    new time/op    delta
HashStringSpeed-8                  9.64ns ±11%    8.91ns ± 9%   -7.60%  (p=0.007 n=10+10)
HashStringArraySpeed-8             19.8ns ± 3%    19.5ns ± 2%     ~     (p=0.085 n=10+10)
MapStringKeysEight_16-8            10.7ns ± 3%    10.2ns ± 2%   -4.48%  (p=0.000 n=10+10)
MapStringKeysEight_32-8            8.89ns ± 3%    8.71ns ± 3%     ~     (p=0.082 n=9+10)
MapStringKeysEight_64-8            8.84ns ± 2%    8.60ns ± 3%   -2.73%  (p=0.004 n=9+10)
MapStringKeysEight_1M-8            8.90ns ± 3%    8.62ns ± 3%   -3.15%  (p=0.000 n=10+10)
MapStringConversion/32/simple-8    8.62ns ± 3%    8.61ns ± 2%     ~     (p=0.895 n=10+10)
MapStringConversion/32/struct-8    8.53ns ± 2%    8.63ns ± 2%     ~     (p=0.123 n=10+10)
MapStringConversion/32/array-8     8.54ns ± 2%    8.50ns ± 1%     ~     (p=0.590 n=9+9)
MapStringConversion/64/simple-8    8.44ns ± 2%    8.38ns ± 2%     ~     (p=0.353 n=10+10)
MapStringConversion/64/struct-8    8.41ns ± 2%    8.48ns ± 2%     ~     (p=0.143 n=10+10)
MapStringConversion/64/array-8     8.42ns ± 2%    8.44ns ± 2%     ~     (p=0.739 n=10+10)
MapInterfaceString-8               13.6ns ±26%    13.6ns ±20%     ~     (p=0.736 n=10+9)
AppendGrowString-8                 38.9ms ± 9%    40.2ms ±13%     ~     (p=0.481 n=10+10)
CompareStringEqual-8               3.03ns ± 2%    2.86ns ± 3%   -5.58%  (p=0.000 n=10+10)
CompareStringIdentical-8           1.20ns ± 3%    1.01ns ± 4%  -16.16%  (p=0.000 n=10+10)
CompareStringSameLength-8          2.11ns ± 3%    1.85ns ± 3%  -12.33%  (p=0.000 n=10+10)
CompareStringDifferentLength-8     0.30ns ± 0%    0.30ns ± 0%     ~     (p=0.508 n=10+9)
CompareStringBigUnaligned-8        43.0µs ± 1%    42.8µs ± 2%     ~     (p=0.165 n=10+10)
CompareStringBig-8                 43.2µs ± 2%    43.4µs ± 2%     ~     (p=0.661 n=9+10)
ConcatStringAndBytes-8             15.1ns ± 1%    14.9ns ± 1%   -1.57%  (p=0.001 n=8+10)
SliceByteToString/1-8              2.45ns ± 2%    2.39ns ± 2%   -2.64%  (p=0.000 n=10+10)
SliceByteToString/2-8              10.9ns ± 2%    10.8ns ± 4%     ~     (p=0.060 n=10+10)
SliceByteToString/4-8              11.9ns ± 0%    11.8ns ± 1%   -0.97%  (p=0.000 n=8+8)
SliceByteToString/8-8              13.9ns ± 1%    13.9ns ± 1%   +0.57%  (p=0.009 n=9+9)
SliceByteToString/16-8             18.0ns ± 3%    18.6ns ± 5%   +2.78%  (p=0.001 n=9+10)
SliceByteToString/32-8             20.1ns ± 3%    20.5ns ± 5%   +2.10%  (p=0.034 n=10+10)
SliceByteToString/64-8             24.3ns ± 3%    24.9ns ± 3%   +2.28%  (p=0.001 n=9+10)
SliceByteToString/128-8            33.8ns ± 1%    34.5ns ± 4%     ~     (p=0.264 n=8+10)

Updates #54854

Change-Id: I7ce57a92c5f590fa8cb31a48969d281147eb05f1
Reviewed-on: https://go-review.googlesource.com/c/go/+/428759
Reviewed-by: hopehook <hopehook@golangcn.org>
Reviewed-by: Keith Randall <khr@google.com>
Run-TryBot: Ian Lance Taylor <iant@google.com>
Auto-Submit: Ian Lance Taylor <iant@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Run-TryBot: Cuong Manh Le <cuong.manhle.vn@gmail.com>
Reviewed-by: Ian Lance Taylor <iant@google.com>
This commit is contained in:
Cuong Manh Le 2022-09-07 13:23:10 +07:00 committed by Gopher Robot
parent d36466fe2a
commit 7ffbcd1987
4 changed files with 23 additions and 46 deletions

View file

@ -292,21 +292,19 @@ func (l *dlogger) s(x string) *dlogger {
if !dlogEnabled { if !dlogEnabled {
return l return l
} }
str := stringStructOf(&x)
strData := unsafe.StringData(x)
datap := &firstmoduledata datap := &firstmoduledata
if len(x) > 4 && datap.etext <= uintptr(str.str) && uintptr(str.str) < datap.end { if len(x) > 4 && datap.etext <= uintptr(unsafe.Pointer(strData)) && uintptr(unsafe.Pointer(strData)) < datap.end {
// String constants are in the rodata section, which // String constants are in the rodata section, which
// isn't recorded in moduledata. But it has to be // isn't recorded in moduledata. But it has to be
// somewhere between etext and end. // somewhere between etext and end.
l.w.byte(debugLogConstString) l.w.byte(debugLogConstString)
l.w.uvarint(uint64(str.len)) l.w.uvarint(uint64(len(x)))
l.w.uvarint(uint64(uintptr(str.str) - datap.etext)) l.w.uvarint(uint64(uintptr(unsafe.Pointer(strData)) - datap.etext))
} else { } else {
l.w.byte(debugLogString) l.w.byte(debugLogString)
var b []byte b := unsafe.Slice(strData, len(x))
bb := (*slice)(unsafe.Pointer(&b))
bb.array = str.str
bb.len, bb.cap = str.len, str.len
if len(b) > debugLogStringLimit { if len(b) > debugLogStringLimit {
b = b[:debugLogStringLimit] b = b[:debugLogStringLimit]
} }

View file

@ -156,8 +156,7 @@ func dumpslice(b []byte) {
} }
func dumpstr(s string) { func dumpstr(s string) {
sp := stringStructOf(&s) dumpmemrange(unsafe.Pointer(unsafe.StringData(s)), uintptr(len(s)))
dumpmemrange(sp.str, uintptr(sp.len))
} }
// dump information for a type // dump information for a type
@ -197,14 +196,12 @@ func dumptype(t *_type) {
if x := t.uncommon(); x == nil || t.nameOff(x.pkgpath).name() == "" { if x := t.uncommon(); x == nil || t.nameOff(x.pkgpath).name() == "" {
dumpstr(t.string()) dumpstr(t.string())
} else { } else {
pkgpathstr := t.nameOff(x.pkgpath).name() pkgpath := t.nameOff(x.pkgpath).name()
pkgpath := stringStructOf(&pkgpathstr) name := t.name()
namestr := t.name() dumpint(uint64(uintptr(len(pkgpath)) + 1 + uintptr(len(name))))
name := stringStructOf(&namestr) dwrite(unsafe.Pointer(unsafe.StringData(pkgpath)), uintptr(len(pkgpath)))
dumpint(uint64(uintptr(pkgpath.len) + 1 + uintptr(name.len)))
dwrite(pkgpath.str, uintptr(pkgpath.len))
dwritebyte('.') dwritebyte('.')
dwrite(name.str, uintptr(name.len)) dwrite(unsafe.Pointer(unsafe.StringData(name)), uintptr(len(name)))
} }
dumpbool(t.kind&kindDirectIface == 0 || t.ptrdata != 0) dumpbool(t.kind&kindDirectIface == 0 || t.ptrdata != 0)
} }

View file

@ -78,7 +78,7 @@ func concatstring5(buf *tmpBuf, a0, a1, a2, a3, a4 string) string {
// n is the length of the slice. // n is the length of the slice.
// Buf is a fixed-size buffer for the result, // Buf is a fixed-size buffer for the result,
// it is not nil if the result does not escape. // it is not nil if the result does not escape.
func slicebytetostring(buf *tmpBuf, ptr *byte, n int) (str string) { func slicebytetostring(buf *tmpBuf, ptr *byte, n int) string {
if n == 0 { if n == 0 {
// Turns out to be a relatively common case. // Turns out to be a relatively common case.
// Consider that you want to parse out data between parens in "foo()bar", // Consider that you want to parse out data between parens in "foo()bar",
@ -102,9 +102,7 @@ func slicebytetostring(buf *tmpBuf, ptr *byte, n int) (str string) {
if goarch.BigEndian { if goarch.BigEndian {
p = add(p, 7) p = add(p, 7)
} }
stringStructOf(&str).str = p return unsafe.String((*byte)(p), 1)
stringStructOf(&str).len = 1
return
} }
var p unsafe.Pointer var p unsafe.Pointer
@ -113,16 +111,14 @@ func slicebytetostring(buf *tmpBuf, ptr *byte, n int) (str string) {
} else { } else {
p = mallocgc(uintptr(n), nil, false) p = mallocgc(uintptr(n), nil, false)
} }
stringStructOf(&str).str = p
stringStructOf(&str).len = n
memmove(p, unsafe.Pointer(ptr), uintptr(n)) memmove(p, unsafe.Pointer(ptr), uintptr(n))
return return unsafe.String((*byte)(p), n)
} }
// stringDataOnStack reports whether the string's data is // stringDataOnStack reports whether the string's data is
// stored on the current goroutine's stack. // stored on the current goroutine's stack.
func stringDataOnStack(s string) bool { func stringDataOnStack(s string) bool {
ptr := uintptr(stringStructOf(&s).str) ptr := uintptr(unsafe.Pointer(unsafe.StringData(s)))
stk := getg().stack stk := getg().stack
return stk.lo <= ptr && ptr < stk.hi return stk.lo <= ptr && ptr < stk.hi
} }
@ -151,7 +147,7 @@ func rawstringtmp(buf *tmpBuf, l int) (s string, b []byte) {
// where k is []byte, T1 to Tn is a nesting of struct and array literals. // where k is []byte, T1 to Tn is a nesting of struct and array literals.
// - Used for "<"+string(b)+">" concatenation where b is []byte. // - Used for "<"+string(b)+">" concatenation where b is []byte.
// - Used for string(b)=="foo" comparison where b is []byte. // - Used for string(b)=="foo" comparison where b is []byte.
func slicebytetostringtmp(ptr *byte, n int) (str string) { func slicebytetostringtmp(ptr *byte, n int) string {
if raceenabled && n > 0 { if raceenabled && n > 0 {
racereadrangepc(unsafe.Pointer(ptr), racereadrangepc(unsafe.Pointer(ptr),
uintptr(n), uintptr(n),
@ -164,9 +160,7 @@ func slicebytetostringtmp(ptr *byte, n int) (str string) {
if asanenabled && n > 0 { if asanenabled && n > 0 {
asanread(unsafe.Pointer(ptr), uintptr(n)) asanread(unsafe.Pointer(ptr), uintptr(n))
} }
stringStructOf(&str).str = unsafe.Pointer(ptr) return unsafe.String(ptr, n)
stringStructOf(&str).len = n
return
} }
func stringtoslicebyte(buf *tmpBuf, s string) []byte { func stringtoslicebyte(buf *tmpBuf, s string) []byte {
@ -271,13 +265,7 @@ func intstring(buf *[4]byte, v int64) (s string) {
// b to set the string contents and then drop b. // b to set the string contents and then drop b.
func rawstring(size int) (s string, b []byte) { func rawstring(size int) (s string, b []byte) {
p := mallocgc(uintptr(size), nil, false) p := mallocgc(uintptr(size), nil, false)
return unsafe.String((*byte)(p), size), unsafe.Slice((*byte)(p), size)
stringStructOf(&s).str = p
stringStructOf(&s).len = size
*(*slice)(unsafe.Pointer(&b)) = slice{p, size, size}
return
} }
// rawbyteslice allocates a new byte slice. The byte slice is not zeroed. // rawbyteslice allocates a new byte slice. The byte slice is not zeroed.

View file

@ -454,7 +454,7 @@ func (n name) readvarint(off int) (int, int) {
} }
} }
func (n name) name() (s string) { func (n name) name() string {
if n.bytes == nil { if n.bytes == nil {
return "" return ""
} }
@ -462,22 +462,16 @@ func (n name) name() (s string) {
if l == 0 { if l == 0 {
return "" return ""
} }
hdr := (*stringStruct)(unsafe.Pointer(&s)) return unsafe.String(n.data(1+i), l)
hdr.str = unsafe.Pointer(n.data(1 + i))
hdr.len = l
return
} }
func (n name) tag() (s string) { func (n name) tag() string {
if *n.data(0)&(1<<1) == 0 { if *n.data(0)&(1<<1) == 0 {
return "" return ""
} }
i, l := n.readvarint(1) i, l := n.readvarint(1)
i2, l2 := n.readvarint(1 + i + l) i2, l2 := n.readvarint(1 + i + l)
hdr := (*stringStruct)(unsafe.Pointer(&s)) return unsafe.String(n.data(1+i+l+i2), l2)
hdr.str = unsafe.Pointer(n.data(1 + i + l + i2))
hdr.len = l2
return
} }
func (n name) pkgPath() string { func (n name) pkgPath() string {