1
0
mirror of https://github.com/golang/go synced 2024-11-17 14:24:50 -07:00

runtime: add deferreturn fast path for linked defers

A consequence of go.dev/cl/513837 was that calling deferreturn would
now use the unwinder to find (just) the current frame, and it turns
out there are workloads where this has a significant performance
impact.

As a simple optimization, this CL adds a fast path for deferreturn to
detect when there are pending linked defers, which allows us to skip
invoking the unwinder entirely.

Notably, this still doesn't handle the corner case of calling
deferreturn in a function that uses linked defer when dynamically
there just aren't any defers pending. It also means that after
recovering from a panic and returning to a frame that used open-coded,
we still need to use the unwinder too.

I hope to further optimize defer handling to improve these cases too,
but this is an easy, short-term optimization that relieves the
performance impact to the affected workloads.

Change-Id: I11fa73649302199eadccc27b403b231db8f33db2
Reviewed-on: https://go-review.googlesource.com/c/go/+/515716
Auto-Submit: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
Reviewed-by: Keith Randall <khr@golang.org>
Reviewed-by: Keith Randall <khr@google.com>
This commit is contained in:
Matthew Dempsky 2023-08-03 13:52:00 -07:00 committed by Gopher Robot
parent 55d08e5010
commit 51cb12e83b

View File

@ -638,6 +638,14 @@ func (p *_panic) start(pc uintptr, sp unsafe.Pointer) {
if !p.deferreturn {
p.link = gp._panic
gp._panic = (*_panic)(noescape(unsafe.Pointer(p)))
} else {
// Fast path for deferreturn: if there's a pending linked defer
// for this frame, then we know there aren't any open-coded
// defers, and we don't need to find the parent frame either.
if d := gp._defer; d != nil && d.sp == uintptr(sp) {
p.sp = sp
return
}
}
// Initialize state machine, and find the first frame with a defer.