diff options
author | Cherry Zhang <cherryyz@google.com> | 2021-04-24 12:41:17 -0400 |
---|---|---|
committer | Cherry Zhang <cherryyz@google.com> | 2021-04-30 00:08:50 +0000 |
commit | 02ab8d1a1dc82ce019969221313bfa28911f54a1 (patch) | |
tree | a77a0e691546e7ccdb6177dd564e7b17fb8bd43d /src/runtime/mgcmark.go | |
parent | a9705e157beb51574233e23cc2e2a412d4681a15 (diff) | |
download | go-02ab8d1a1dc82ce019969221313bfa28911f54a1.tar.gz go-02ab8d1a1dc82ce019969221313bfa28911f54a1.zip |
cmd/compile, runtime: emit only GC data for stack objects
Currently, for stack objects, the compiler emits metadata that
includes the offset and type descriptor for each object. The type
descriptor symbol has many fields, and it references many other
symbols, e.g. field/element types, equality functions, names.
Observe that what we actually need at runtime is only the GC
metadata that are needed to scan the object, and the GC metadata
are "leaf" symbols (which doesn't reference other symbols). Emit
only the GC data instead. This avoids bringing live the type
descriptor as well as things referenced by it (if it is not
otherwise live).
This reduces binary sizes:
old new
hello (println) 1187776 1133856 (-4.5%)
hello (fmt) 1902448 1844416 (-3.1%)
cmd/compile 22670432 22438576 (-1.0%)
cmd/link 6346272 6225408 (-1.9%)
No significant change in compiler speed.
name old time/op new time/op delta
Template 184ms ± 2% 186ms ± 5% ~ (p=0.905 n=9+10)
Unicode 78.4ms ± 5% 76.3ms ± 3% -2.60% (p=0.009 n=10+10)
GoTypes 1.09s ± 1% 1.08s ± 1% -0.73% (p=0.027 n=10+8)
Compiler 85.6ms ± 3% 84.6ms ± 4% ~ (p=0.143 n=10+10)
SSA 7.23s ± 1% 7.25s ± 1% ~ (p=0.780 n=10+9)
Flate 116ms ± 5% 115ms ± 6% ~ (p=0.912 n=10+10)
GoParser 201ms ± 4% 195ms ± 1% ~ (p=0.089 n=10+10)
Reflect 455ms ± 1% 458ms ± 2% ~ (p=0.050 n=9+9)
Tar 155ms ± 2% 155ms ± 3% ~ (p=0.436 n=10+10)
XML 202ms ± 2% 200ms ± 2% ~ (p=0.053 n=10+9)
Change-Id: I33a7f383d79afba1a482cac6da0cf5b7de9c0ec4
Reviewed-on: https://go-review.googlesource.com/c/go/+/313514
Trust: Cherry Zhang <cherryyz@google.com>
Reviewed-by: Than McIntosh <thanm@google.com>
Diffstat (limited to 'src/runtime/mgcmark.go')
-rw-r--r-- | src/runtime/mgcmark.go | 28 |
1 files changed, 14 insertions, 14 deletions
diff --git a/src/runtime/mgcmark.go b/src/runtime/mgcmark.go index 719b21055b..1fd0732d62 100644 --- a/src/runtime/mgcmark.go +++ b/src/runtime/mgcmark.go @@ -792,24 +792,24 @@ func scanstack(gp *g, gcw *gcWork) { if obj == nil { continue } - t := obj.typ - if t == nil { + r := obj.r + if r == nil { // We've already scanned this object. continue } - obj.setType(nil) // Don't scan it again. + obj.setRecord(nil) // Don't scan it again. if stackTraceDebug { printlock() - print(" live stkobj at", hex(state.stack.lo+uintptr(obj.off)), "of type", t.string()) + print(" live stkobj at", hex(state.stack.lo+uintptr(obj.off)), "of size", obj.size) if conservative { print(" (conservative)") } println() printunlock() } - gcdata := t.gcdata + gcdata := r.gcdata var s *mspan - if t.kind&kindGCProg != 0 { + if r.useGCProg() { // This path is pretty unlikely, an object large enough // to have a GC program allocated on the stack. // We need some space to unpack the program into a straight @@ -819,15 +819,15 @@ func scanstack(gp *g, gcw *gcWork) { // to change from a Lempel-Ziv style program to something else. // Or we can forbid putting objects on stacks if they require // a gc program (see issue 27447). - s = materializeGCProg(t.ptrdata, gcdata) + s = materializeGCProg(r.ptrdata(), gcdata) gcdata = (*byte)(unsafe.Pointer(s.startAddr)) } b := state.stack.lo + uintptr(obj.off) if conservative { - scanConservative(b, t.ptrdata, gcdata, gcw, &state) + scanConservative(b, r.ptrdata(), gcdata, gcw, &state) } else { - scanblock(b, t.ptrdata, gcdata, gcw, &state) + scanblock(b, r.ptrdata(), gcdata, gcw, &state) } if s != nil { @@ -843,10 +843,10 @@ func scanstack(gp *g, gcw *gcWork) { if stackTraceDebug { for i := 0; i < x.nobj; i++ { obj := &x.obj[i] - if obj.typ == nil { // reachable + if obj.r == nil { // reachable continue } - println(" dead stkobj at", hex(gp.stack.lo+uintptr(obj.off)), "of type", obj.typ.string()) + println(" dead stkobj at", hex(gp.stack.lo+uintptr(obj.off)), "of size", obj.r.size) // Note: not necessarily really dead - only reachable-from-ptr dead. } } @@ -927,7 +927,7 @@ func scanframeworker(frame *stkframe, state *stackScanState, gcw *gcWork) { // varp is 0 for defers, where there are no locals. // In that case, there can't be a pointer to its args, either. // (And all args would be scanned above anyway.) - for _, obj := range objs { + for i, obj := range objs { off := obj.off base := frame.varp // locals base pointer if off >= 0 { @@ -939,9 +939,9 @@ func scanframeworker(frame *stkframe, state *stackScanState, gcw *gcWork) { continue } if stackTraceDebug { - println("stkobj at", hex(ptr), "of type", obj.typ.string()) + println("stkobj at", hex(ptr), "of size", obj.size) } - state.addObject(ptr, obj.typ) + state.addObject(ptr, &objs[i]) } } } |