From: David Crawshaw Date: Tue, 28 Jun 2016 01:37:19 +0000 (-0400) Subject: reflect, runtime: optimize Name method X-Git-Tag: go1.7rc1~39 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=ed9362f769626b1cdaf2eb1da63d5f25cadc979b;p=gostls13.git reflect, runtime: optimize Name method Several minor changes that remove a good chunk of the overhead added to the reflect Name method over the 1.7 cycle, as seen from the non-SSA architectures. In particular, there are ~20 fewer instructions in reflect.name.name on 386, and the method now qualifies for inlining. The simple JSON decoding benchmark on darwin/386: name old time/op new time/op delta CodeDecoder-8 49.2ms ± 0% 48.9ms ± 1% -0.77% (p=0.000 n=10+9) name old speed new speed delta CodeDecoder-8 39.4MB/s ± 0% 39.7MB/s ± 1% +0.77% (p=0.000 n=10+9) On darwin/amd64 the effect is less pronounced: name old time/op new time/op delta CodeDecoder-8 38.9ms ± 0% 38.7ms ± 1% -0.38% (p=0.005 n=10+10) name old speed new speed delta CodeDecoder-8 49.9MB/s ± 0% 50.1MB/s ± 1% +0.38% (p=0.006 n=10+10) Counterintuitively, I get much more useful benchmark data out of my MacBook Pro than a linux workstation with more expensive Intel chips. While the laptop has fewer cores and an active GUI, the single-threaded performance is significantly better (nearly 1.5x decoding throughput) so the differences are more pronounced. For #16117. Change-Id: I4e0cc1cc2d271d47d5127b1ee1ca926faf34cabf Reviewed-on: https://go-review.googlesource.com/24510 Reviewed-by: Ian Lance Taylor --- diff --git a/src/reflect/type.go b/src/reflect/type.go index 5b800fc341..bedfba45b1 100644 --- a/src/reflect/type.go +++ b/src/reflect/type.go @@ -466,15 +466,13 @@ func (n name) tagLen() int { func (n name) name() (s string) { if n.bytes == nil { - return "" - } - nl := n.nameLen() - if nl == 0 { - return "" + return } + b := (*[4]byte)(unsafe.Pointer(n.bytes)) + hdr := (*stringHeader)(unsafe.Pointer(&s)) - hdr.Data = unsafe.Pointer(n.data(3)) - hdr.Len = nl + hdr.Data = unsafe.Pointer(&b[3]) + hdr.Len = int(b[1])<<8 | int(b[2]) return s } @@ -662,16 +660,10 @@ type typeOff int32 // offset to an *rtype type textOff int32 // offset from top of text section func (t *rtype) nameOff(off nameOff) name { - if off == 0 { - return name{} - } return name{(*byte)(resolveNameOff(unsafe.Pointer(t), int32(off)))} } func (t *rtype) typeOff(off typeOff) *rtype { - if off == 0 { - return nil - } return (*rtype)(resolveTypeOff(unsafe.Pointer(t), int32(off))) } diff --git a/src/runtime/type.go b/src/runtime/type.go index 49d3855e4d..5ef11a4fc4 100644 --- a/src/runtime/type.go +++ b/src/runtime/type.go @@ -170,32 +170,29 @@ func resolveNameOff(ptrInModule unsafe.Pointer, off nameOff) name { return name{} } base := uintptr(ptrInModule) - var md *moduledata - for next := &firstmoduledata; next != nil; next = next.next { - if base >= next.types && base < next.etypes { - md = next - break - } - } - if md == nil { - reflectOffsLock() - res, found := reflectOffs.m[int32(off)] - reflectOffsUnlock() - if !found { - println("runtime: nameOff", hex(off), "base", hex(base), "not in ranges:") - for next := &firstmoduledata; next != nil; next = next.next { - println("\ttypes", hex(next.types), "etypes", hex(next.etypes)) + for md := &firstmoduledata; md != nil; md = md.next { + if base >= md.types && base < md.etypes { + res := md.types + uintptr(off) + if res > md.etypes { + println("runtime: nameOff", hex(off), "out of range", hex(md.types), "-", hex(md.etypes)) + throw("runtime: name offset out of range") } - throw("runtime: name offset base pointer out of range") + return name{(*byte)(unsafe.Pointer(res))} } - return name{(*byte)(res)} } - res := md.types + uintptr(off) - if res > md.etypes { - println("runtime: nameOff", hex(off), "out of range", hex(md.types), "-", hex(md.etypes)) - throw("runtime: name offset out of range") + + // No module found. see if it is a run time name. + reflectOffsLock() + res, found := reflectOffs.m[int32(off)] + reflectOffsUnlock() + if !found { + println("runtime: nameOff", hex(off), "base", hex(base), "not in ranges:") + for next := &firstmoduledata; next != nil; next = next.next { + println("\ttypes", hex(next.types), "etypes", hex(next.etypes)) + } + throw("runtime: name offset base pointer out of range") } - return name{(*byte)(unsafe.Pointer(res))} + return name{(*byte)(res)} } func (t *_type) nameOff(off nameOff) name {