diff options
author | Nick Ripley <nick.ripley@datadoghq.com> | 2023-11-19 20:01:57 -0500 |
---|---|---|
committer | Gopher Robot <gobot@golang.org> | 2024-05-13 16:41:50 +0000 |
commit | b5bfb5a3ce7c6d993dab40d9b92c06b873ecd404 (patch) | |
tree | af3cd8e4616578770aee5db27b422c8d6d985c18 /src | |
parent | f43d9c40f382def04442898d7581402759bff36a (diff) | |
download | go-b5bfb5a3ce7c6d993dab40d9b92c06b873ecd404.tar.gz go-b5bfb5a3ce7c6d993dab40d9b92c06b873ecd404.zip |
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>
Diffstat (limited to 'src')
-rw-r--r-- | src/runtime/tracestack.go | 29 |
1 files changed, 18 insertions, 11 deletions
diff --git a/src/runtime/tracestack.go b/src/runtime/tracestack.go index 04b935a2c9..477526d7cb 100644 --- a/src/runtime/tracestack.go +++ b/src/runtime/tracestack.go @@ -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. |