Skip to content

Commit

Permalink
runtime: add deferreturn fast path for linked defers
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
mdempsky authored and gopherbot committed Aug 4, 2023
1 parent 55d08e5 commit 51cb12e
Showing 1 changed file with 8 additions and 0 deletions.
8 changes: 8 additions & 0 deletions src/runtime/panic.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down

0 comments on commit 51cb12e

Please sign in to comment.