BubbleAssocCurrentBubble = bubbleAssocCurrentBubble
BubbleAssocOtherBubble = bubbleAssocOtherBubble
)
+
+type TraceStackTable traceStackTable
+
+func (t *TraceStackTable) Reset() {
+ t.tab.reset()
+}
+
+func TraceStack(gp *G, tab *TraceStackTable) {
+ traceStack(0, gp, (*traceStackTable)(tab))
+}
// matches the cached contents.
const debugCheckCache = false
+ // If true, skip checking the cache entirely.
+ const skipCache = false
+
if off == 0 {
return -1, 0
}
var checkVal int32
var checkPC uintptr
ck := pcvalueCacheKey(targetpc)
- {
+ if !skipCache {
mp := acquirem()
cache := &mp.pcvalueCache
// The cache can be used by the signal handler on this M. Avoid
ug.status = readgstatus(s.g) &^ _Gscan
ug.waitreason = s.g.waitreason
ug.inMarkAssist = s.g.inMarkAssist
- ug.stackID = traceStack(0, gp, gen)
+ ug.stackID = traceStack(0, gp, &trace.stackTab[gen%2])
}
resumeG(s)
casgstatus(me, _Gwaiting, _Grunning)
// It then returns a traceArg representing that stack which may be
// passed to write.
func (tl traceLocker) stack(skip int) traceArg {
- return traceArg(traceStack(skip, nil, tl.gen))
+ return traceArg(traceStack(skip, nil, &trace.stackTab[tl.gen%2]))
}
// startPC takes a start PC for a goroutine and produces a unique
// skip controls the number of leaf frames to omit in order to hide tracer internals
// from stack traces, see CL 5523.
//
-// Avoid calling this function directly. gen needs to be the current generation
-// that this stack trace is being written out for, which needs to be synchronized with
-// generations moving forward. Prefer traceEventWriter.stack.
-func traceStack(skip int, gp *g, gen uintptr) uint64 {
+// Avoid calling this function directly. Prefer traceEventWriter.stack.
+func traceStack(skip int, gp *g, tab *traceStackTable) uint64 {
var pcBuf [tracev2.MaxFramesPerStack]uintptr
// Figure out gp and mp for the backtrace.
if nstk > 0 && gp.goid == 1 {
nstk-- // skip runtime.main
}
- id := trace.stackTab[gen%2].put(pcBuf[:nstk])
+ id := tab.put(pcBuf[:nstk])
return id
}
--- /dev/null
+// Copyright 2025 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package runtime_test
+
+import (
+ "runtime"
+ "strconv"
+ "testing"
+)
+
+func BenchmarkTraceStack(b *testing.B) {
+ for _, stackDepth := range []int{1, 10, 100} {
+ b.Run("stackDepth="+strconv.Itoa(stackDepth), func(b *testing.B) {
+ benchmarkTraceStack(b, stackDepth)
+ })
+ }
+}
+
+func benchmarkTraceStack(b *testing.B, stackDepth int) {
+ var tab runtime.TraceStackTable
+ defer tab.Reset()
+
+ wait := make(chan struct{})
+ ready := make(chan struct{})
+ done := make(chan struct{})
+ var gp *runtime.G
+ go func() {
+ gp = runtime.Getg()
+ useStackAndCall(stackDepth, func() {
+ ready <- struct{}{}
+ <-wait
+ })
+ done <- struct{}{}
+ }()
+ <-ready
+
+ for b.Loop() {
+ runtime.TraceStack(gp, &tab)
+ }
+
+ // Clean up.
+ wait <- struct{}{}
+ <-done
+}