mirror of
https://github.com/golang/go
synced 2024-10-02 22:25:08 +00:00
runtime: refactor fpunwindExpand to use provided buffer
fpunwindExpand currently allocates a new slice to hold the expanded call stack. In each place it's used, the resulting slice won't be needed immediately afterward, so the allocation is wasteful. Refactor fpunwindExpand to instead expand the call stack into a provided buffer. Change-Id: I05b26c191a8f76404c21ccbe3bd422325540425b Reviewed-on: https://go-review.googlesource.com/c/go/+/543715 Reviewed-by: Cherry Mui <cherryyz@google.com> Auto-Submit: Cherry Mui <cherryyz@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Michael Knyszek <mknyszek@google.com> Reviewed-by: Michael Pratt <mpratt@google.com>
This commit is contained in:
parent
f43d9c40f3
commit
b5bfb5a3ce
|
@ -147,20 +147,22 @@ func (t *traceStackTable) put(pcs []uintptr) uint64 {
|
|||
// releases all memory and resets state. It must only be called once the caller
|
||||
// can guarantee that there are no more writers to the table.
|
||||
func (t *traceStackTable) dump(gen uintptr) {
|
||||
stackBuf := make([]uintptr, traceStackSize)
|
||||
w := unsafeTraceWriter(gen, nil)
|
||||
if root := (*traceMapNode)(t.tab.root.Load()); root != nil {
|
||||
w = dumpStacksRec(root, w)
|
||||
w = dumpStacksRec(root, w, stackBuf)
|
||||
}
|
||||
w.flush().end()
|
||||
t.tab.reset()
|
||||
}
|
||||
|
||||
func dumpStacksRec(node *traceMapNode, w traceWriter) traceWriter {
|
||||
func dumpStacksRec(node *traceMapNode, w traceWriter, stackBuf []uintptr) traceWriter {
|
||||
stack := unsafe.Slice((*uintptr)(unsafe.Pointer(&node.data[0])), uintptr(len(node.data))/unsafe.Sizeof(uintptr(0)))
|
||||
|
||||
// N.B. This might allocate, but that's OK because we're not writing to the M's buffer,
|
||||
// but one we're about to create (with ensure).
|
||||
frames := makeTraceFrames(w.gen, fpunwindExpand(stack))
|
||||
n := fpunwindExpand(stackBuf, stack)
|
||||
frames := makeTraceFrames(w.gen, stackBuf[:n])
|
||||
|
||||
// The maximum number of bytes required to hold the encoded stack, given that
|
||||
// it contains N frames.
|
||||
|
@ -194,7 +196,7 @@ func dumpStacksRec(node *traceMapNode, w traceWriter) traceWriter {
|
|||
if child == nil {
|
||||
continue
|
||||
}
|
||||
w = dumpStacksRec((*traceMapNode)(child), w)
|
||||
w = dumpStacksRec((*traceMapNode)(child), w, stackBuf)
|
||||
}
|
||||
return w
|
||||
}
|
||||
|
@ -260,31 +262,36 @@ func fpTracebackPCs(fp unsafe.Pointer, pcBuf []uintptr) (i int) {
|
|||
return i
|
||||
}
|
||||
|
||||
// fpunwindExpand expands a call stack from pcBuf into dst,
|
||||
// returning the number of PCs written to dst.
|
||||
// pcBuf and dst should not overlap.
|
||||
//
|
||||
// fpunwindExpand checks if pcBuf contains logical frames (which include inlined
|
||||
// frames) or physical frames (produced by frame pointer unwinding) using a
|
||||
// sentinel value in pcBuf[0]. Logical frames are simply returned without the
|
||||
// sentinel. Physical frames are turned into logical frames via inline unwinding
|
||||
// and by applying the skip value that's stored in pcBuf[0].
|
||||
func fpunwindExpand(pcBuf []uintptr) []uintptr {
|
||||
func fpunwindExpand(dst, pcBuf []uintptr) int {
|
||||
if len(pcBuf) > 0 && pcBuf[0] == logicalStackSentinel {
|
||||
// pcBuf contains logical rather than inlined frames, skip has already been
|
||||
// applied, just return it without the sentinel value in pcBuf[0].
|
||||
return pcBuf[1:]
|
||||
return copy(dst, pcBuf[1:])
|
||||
}
|
||||
|
||||
var (
|
||||
n int
|
||||
lastFuncID = abi.FuncIDNormal
|
||||
newPCBuf = make([]uintptr, 0, traceStackSize)
|
||||
skip = pcBuf[0]
|
||||
// skipOrAdd skips or appends retPC to newPCBuf and returns true if more
|
||||
// pcs can be added.
|
||||
skipOrAdd = func(retPC uintptr) bool {
|
||||
if skip > 0 {
|
||||
skip--
|
||||
} else {
|
||||
newPCBuf = append(newPCBuf, retPC)
|
||||
} else if n < len(dst) {
|
||||
dst[n] = retPC
|
||||
n++
|
||||
}
|
||||
return len(newPCBuf) < cap(newPCBuf)
|
||||
return n < len(dst)
|
||||
}
|
||||
)
|
||||
|
||||
|
@ -312,7 +319,7 @@ outer:
|
|||
lastFuncID = sf.funcID
|
||||
}
|
||||
}
|
||||
return newPCBuf
|
||||
return n
|
||||
}
|
||||
|
||||
// startPCForTrace returns the start PC of a goroutine for tracing purposes.
|
||||
|
|
Loading…
Reference in a new issue