]> Cypherpunks repositories - gostls13.git/commitdiff
reflect, runtime: optimize Name method
authorDavid Crawshaw <crawshaw@golang.org>
Tue, 28 Jun 2016 01:37:19 +0000 (21:37 -0400)
committerDavid Crawshaw <crawshaw@golang.org>
Tue, 28 Jun 2016 12:28:05 +0000 (12:28 +0000)
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 <iant@golang.org>
src/reflect/type.go
src/runtime/type.go

index 5b800fc341e777d0922e331553d4507831602885..bedfba45b11578fbbc0c9d4e7dfc3735523b451c 100644 (file)
@@ -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)))
 }
 
index 49d3855e4d0abe3b7bf63cf667539356dd3729ae..5ef11a4fc4d4649cfd0a27539631ad157ab0a42a 100644 (file)
@@ -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 {