Commit ed9362f7 authored by David Crawshaw's avatar David Crawshaw

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/24510Reviewed-by: 's avatarIan Lance Taylor <iant@golang.org>
parent b75b0630
...@@ -466,15 +466,13 @@ func (n name) tagLen() int { ...@@ -466,15 +466,13 @@ func (n name) tagLen() int {
func (n name) name() (s string) { func (n name) name() (s string) {
if n.bytes == nil { if n.bytes == nil {
return "" return
}
nl := n.nameLen()
if nl == 0 {
return ""
} }
b := (*[4]byte)(unsafe.Pointer(n.bytes))
hdr := (*stringHeader)(unsafe.Pointer(&s)) hdr := (*stringHeader)(unsafe.Pointer(&s))
hdr.Data = unsafe.Pointer(n.data(3)) hdr.Data = unsafe.Pointer(&b[3])
hdr.Len = nl hdr.Len = int(b[1])<<8 | int(b[2])
return s return s
} }
...@@ -662,16 +660,10 @@ type typeOff int32 // offset to an *rtype ...@@ -662,16 +660,10 @@ type typeOff int32 // offset to an *rtype
type textOff int32 // offset from top of text section type textOff int32 // offset from top of text section
func (t *rtype) nameOff(off nameOff) name { func (t *rtype) nameOff(off nameOff) name {
if off == 0 {
return name{}
}
return name{(*byte)(resolveNameOff(unsafe.Pointer(t), int32(off)))} return name{(*byte)(resolveNameOff(unsafe.Pointer(t), int32(off)))}
} }
func (t *rtype) typeOff(off typeOff) *rtype { func (t *rtype) typeOff(off typeOff) *rtype {
if off == 0 {
return nil
}
return (*rtype)(resolveTypeOff(unsafe.Pointer(t), int32(off))) return (*rtype)(resolveTypeOff(unsafe.Pointer(t), int32(off)))
} }
......
...@@ -170,32 +170,29 @@ func resolveNameOff(ptrInModule unsafe.Pointer, off nameOff) name { ...@@ -170,32 +170,29 @@ func resolveNameOff(ptrInModule unsafe.Pointer, off nameOff) name {
return name{} return name{}
} }
base := uintptr(ptrInModule) base := uintptr(ptrInModule)
var md *moduledata for md := &firstmoduledata; md != nil; md = md.next {
for next := &firstmoduledata; next != nil; next = next.next { if base >= md.types && base < md.etypes {
if base >= next.types && base < next.etypes { res := md.types + uintptr(off)
md = next if res > md.etypes {
break println("runtime: nameOff", hex(off), "out of range", hex(md.types), "-", hex(md.etypes))
} throw("runtime: name offset out of range")
}
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))
} }
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 { // No module found. see if it is a run time name.
println("runtime: nameOff", hex(off), "out of range", hex(md.types), "-", hex(md.etypes)) reflectOffsLock()
throw("runtime: name offset out of range") 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 { func (t *_type) nameOff(off nameOff) name {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment