aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorNick Ripley <nick.ripley@datadoghq.com>2023-11-19 20:01:57 -0500
committerGopher Robot <gobot@golang.org>2024-05-13 16:41:50 +0000
commitb5bfb5a3ce7c6d993dab40d9b92c06b873ecd404 (patch)
treeaf3cd8e4616578770aee5db27b422c8d6d985c18 /src
parentf43d9c40f382def04442898d7581402759bff36a (diff)
downloadgo-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.go29
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.