diff options
| author | Austin Clements <austin@google.com> | 2023-02-13 16:20:54 -0500 |
|---|---|---|
| committer | Austin Clements <austin@google.com> | 2023-03-10 17:59:32 +0000 |
| commit | 2d99109cfcaef22b6872dc2e07e4582586c032a2 (patch) | |
| tree | 958a2c7da4df9d94953e7c2f09aaff9e4c788129 /src/runtime/panic.go | |
| parent | da384766a053d851d912f04afaa1113b627a0822 (diff) | |
| download | go-2d99109cfcaef22b6872dc2e07e4582586c032a2.tar.xz | |
runtime: replace all callback uses of gentraceback with unwinder
This is a really nice simplification for all of these call sites.
It also achieves a nice performance improvement for stack copying:
goos: linux
goarch: amd64
pkg: runtime
cpu: Intel(R) Xeon(R) CPU E5-2690 v3 @ 2.60GHz
│ before │ after │
│ sec/op │ sec/op vs base │
StackCopyPtr-48 89.25m ± 1% 79.78m ± 1% -10.62% (p=0.000 n=20)
StackCopy-48 83.48m ± 2% 71.88m ± 1% -13.90% (p=0.000 n=20)
StackCopyNoCache-48 2.504m ± 2% 2.195m ± 1% -12.32% (p=0.000 n=20)
StackCopyWithStkobj-48 21.66m ± 1% 21.02m ± 2% -2.95% (p=0.000 n=20)
geomean 25.21m 22.68m -10.04%
Updates #54466.
Change-Id: I31715b7b6efd65726940041d3052bb1c0a1186f3
Reviewed-on: https://go-review.googlesource.com/c/go/+/468297
Run-TryBot: Austin Clements <austin@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Michael Pratt <mpratt@google.com>
Diffstat (limited to 'src/runtime/panic.go')
| -rw-r--r-- | src/runtime/panic.go | 133 |
1 files changed, 67 insertions, 66 deletions
diff --git a/src/runtime/panic.go b/src/runtime/panic.go index e7059af15f..ccc4643711 100644 --- a/src/runtime/panic.go +++ b/src/runtime/panic.go @@ -642,77 +642,78 @@ func addOneOpenDeferFrame(gp *g, pc uintptr, sp unsafe.Pointer) { sp = unsafe.Pointer(prevDefer.sp) } systemstack(func() { - gentraceback(pc, uintptr(sp), 0, gp, 0, nil, 0x7fffffff, - func(frame *stkframe, unused unsafe.Pointer) bool { - if prevDefer != nil && prevDefer.sp == frame.sp { - // Skip the frame for the previous defer that - // we just finished (and was used to set - // where we restarted the stack scan) - return true - } - f := frame.fn - fd := funcdata(f, _FUNCDATA_OpenCodedDeferInfo) - if fd == nil { - return true + var u unwinder + frames: + for u.initAt(pc, uintptr(sp), 0, gp, 0); u.valid(); u.next() { + frame := &u.frame + if prevDefer != nil && prevDefer.sp == frame.sp { + // Skip the frame for the previous defer that + // we just finished (and was used to set + // where we restarted the stack scan) + continue + } + f := frame.fn + fd := funcdata(f, _FUNCDATA_OpenCodedDeferInfo) + if fd == nil { + continue + } + // Insert the open defer record in the + // chain, in order sorted by sp. + d := gp._defer + var prev *_defer + for d != nil { + dsp := d.sp + if frame.sp < dsp { + break } - // Insert the open defer record in the - // chain, in order sorted by sp. - d := gp._defer - var prev *_defer - for d != nil { - dsp := d.sp - if frame.sp < dsp { - break + if frame.sp == dsp { + if !d.openDefer { + throw("duplicated defer entry") } - if frame.sp == dsp { - if !d.openDefer { - throw("duplicated defer entry") - } - // Don't add any record past an - // in-progress defer entry. We don't - // need it, and more importantly, we - // want to keep the invariant that - // there is no open defer entry - // passed an in-progress entry (see - // header comment). - if d.started { - return false - } - return true + // Don't add any record past an + // in-progress defer entry. We don't + // need it, and more importantly, we + // want to keep the invariant that + // there is no open defer entry + // passed an in-progress entry (see + // header comment). + if d.started { + break frames } - prev = d - d = d.link - } - if frame.fn.deferreturn == 0 { - throw("missing deferreturn") + continue frames } + prev = d + d = d.link + } + if frame.fn.deferreturn == 0 { + throw("missing deferreturn") + } - d1 := newdefer() - d1.openDefer = true - d1._panic = nil - // These are the pc/sp to set after we've - // run a defer in this frame that did a - // recover. We return to a special - // deferreturn that runs any remaining - // defers and then returns from the - // function. - d1.pc = frame.fn.entry() + uintptr(frame.fn.deferreturn) - d1.varp = frame.varp - d1.fd = fd - // Save the SP/PC associated with current frame, - // so we can continue stack trace later if needed. - d1.framepc = frame.pc - d1.sp = frame.sp - d1.link = d - if prev == nil { - gp._defer = d1 - } else { - prev.link = d1 - } - // Stop stack scanning after adding one open defer record - return false - }, - nil, 0) + d1 := newdefer() + d1.openDefer = true + d1._panic = nil + // These are the pc/sp to set after we've + // run a defer in this frame that did a + // recover. We return to a special + // deferreturn that runs any remaining + // defers and then returns from the + // function. + d1.pc = frame.fn.entry() + uintptr(frame.fn.deferreturn) + d1.varp = frame.varp + d1.fd = fd + // Save the SP/PC associated with current frame, + // so we can continue stack trace later if needed. + d1.framepc = frame.pc + d1.sp = frame.sp + d1.link = d + if prev == nil { + gp._defer = d1 + } else { + prev.link = d1 + } + // Stop stack scanning after adding one open defer record + break + } }) } |
