aboutsummaryrefslogtreecommitdiff
path: root/src/runtime
diff options
context:
space:
mode:
Diffstat (limited to 'src/runtime')
-rw-r--r--src/runtime/export_test.go10
-rw-r--r--src/runtime/symtab.go5
-rw-r--r--src/runtime/trace.go2
-rw-r--r--src/runtime/traceevent.go2
-rw-r--r--src/runtime/tracestack.go8
-rw-r--r--src/runtime/tracestack_test.go46
6 files changed, 65 insertions, 8 deletions
diff --git a/src/runtime/export_test.go b/src/runtime/export_test.go
index 83cf301be4..9a4611e26e 100644
--- a/src/runtime/export_test.go
+++ b/src/runtime/export_test.go
@@ -1917,3 +1917,13 @@ const (
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))
+}
diff --git a/src/runtime/symtab.go b/src/runtime/symtab.go
index 8c6ef2b4fc..866c46a83d 100644
--- a/src/runtime/symtab.go
+++ b/src/runtime/symtab.go
@@ -981,6 +981,9 @@ func pcvalue(f funcInfo, off uint32, targetpc uintptr, strict bool) (int32, uint
// matches the cached contents.
const debugCheckCache = false
+ // If true, skip checking the cache entirely.
+ const skipCache = false
+
if off == 0 {
return -1, 0
}
@@ -991,7 +994,7 @@ func pcvalue(f funcInfo, off uint32, targetpc uintptr, strict bool) (int32, uint
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
diff --git a/src/runtime/trace.go b/src/runtime/trace.go
index b92e7b4e8e..0d71ad445c 100644
--- a/src/runtime/trace.go
+++ b/src/runtime/trace.go
@@ -396,7 +396,7 @@ func traceAdvance(stopTrace bool) {
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)
diff --git a/src/runtime/traceevent.go b/src/runtime/traceevent.go
index 9d1a93d3f9..263847be2e 100644
--- a/src/runtime/traceevent.go
+++ b/src/runtime/traceevent.go
@@ -56,7 +56,7 @@ func (e traceEventWriter) event(ev tracev2.EventType, args ...traceArg) {
// 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
diff --git a/src/runtime/tracestack.go b/src/runtime/tracestack.go
index 2ee68c85f0..76d6b05048 100644
--- a/src/runtime/tracestack.go
+++ b/src/runtime/tracestack.go
@@ -28,10 +28,8 @@ const (
// 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.
@@ -134,7 +132,7 @@ func traceStack(skip int, gp *g, gen uintptr) uint64 {
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
}
diff --git a/src/runtime/tracestack_test.go b/src/runtime/tracestack_test.go
new file mode 100644
index 0000000000..eaf4d906e3
--- /dev/null
+++ b/src/runtime/tracestack_test.go
@@ -0,0 +1,46 @@
+// 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
+}