Skip to content

Commit 75b43f9

Browse files
mknyszekgopherbot
authored andcommitted
runtime: make traceStack testable and add a benchmark
Change-Id: Ide4daa5eee3fd4f3007d6ef23aa84b8916562c39 Reviewed-on: https://go-review.googlesource.com/c/go/+/684457 Reviewed-by: Cherry Mui <[email protected]> Auto-Submit: Michael Knyszek <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]>
1 parent 20978f4 commit 75b43f9

File tree

6 files changed

+65
-8
lines changed

6 files changed

+65
-8
lines changed

src/runtime/export_test.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1917,3 +1917,13 @@ const (
19171917
BubbleAssocCurrentBubble = bubbleAssocCurrentBubble
19181918
BubbleAssocOtherBubble = bubbleAssocOtherBubble
19191919
)
1920+
1921+
type TraceStackTable traceStackTable
1922+
1923+
func (t *TraceStackTable) Reset() {
1924+
t.tab.reset()
1925+
}
1926+
1927+
func TraceStack(gp *G, tab *TraceStackTable) {
1928+
traceStack(0, gp, (*traceStackTable)(tab))
1929+
}

src/runtime/symtab.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -981,6 +981,9 @@ func pcvalue(f funcInfo, off uint32, targetpc uintptr, strict bool) (int32, uint
981981
// matches the cached contents.
982982
const debugCheckCache = false
983983

984+
// If true, skip checking the cache entirely.
985+
const skipCache = false
986+
984987
if off == 0 {
985988
return -1, 0
986989
}
@@ -991,7 +994,7 @@ func pcvalue(f funcInfo, off uint32, targetpc uintptr, strict bool) (int32, uint
991994
var checkVal int32
992995
var checkPC uintptr
993996
ck := pcvalueCacheKey(targetpc)
994-
{
997+
if !skipCache {
995998
mp := acquirem()
996999
cache := &mp.pcvalueCache
9971000
// The cache can be used by the signal handler on this M. Avoid

src/runtime/trace.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -396,7 +396,7 @@ func traceAdvance(stopTrace bool) {
396396
ug.status = readgstatus(s.g) &^ _Gscan
397397
ug.waitreason = s.g.waitreason
398398
ug.inMarkAssist = s.g.inMarkAssist
399-
ug.stackID = traceStack(0, gp, gen)
399+
ug.stackID = traceStack(0, gp, &trace.stackTab[gen%2])
400400
}
401401
resumeG(s)
402402
casgstatus(me, _Gwaiting, _Grunning)

src/runtime/traceevent.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ func (e traceEventWriter) event(ev tracev2.EventType, args ...traceArg) {
5656
// It then returns a traceArg representing that stack which may be
5757
// passed to write.
5858
func (tl traceLocker) stack(skip int) traceArg {
59-
return traceArg(traceStack(skip, nil, tl.gen))
59+
return traceArg(traceStack(skip, nil, &trace.stackTab[tl.gen%2]))
6060
}
6161

6262
// startPC takes a start PC for a goroutine and produces a unique

src/runtime/tracestack.go

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,8 @@ const (
2828
// skip controls the number of leaf frames to omit in order to hide tracer internals
2929
// from stack traces, see CL 5523.
3030
//
31-
// Avoid calling this function directly. gen needs to be the current generation
32-
// that this stack trace is being written out for, which needs to be synchronized with
33-
// generations moving forward. Prefer traceEventWriter.stack.
34-
func traceStack(skip int, gp *g, gen uintptr) uint64 {
31+
// Avoid calling this function directly. Prefer traceEventWriter.stack.
32+
func traceStack(skip int, gp *g, tab *traceStackTable) uint64 {
3533
var pcBuf [tracev2.MaxFramesPerStack]uintptr
3634

3735
// Figure out gp and mp for the backtrace.
@@ -134,7 +132,7 @@ func traceStack(skip int, gp *g, gen uintptr) uint64 {
134132
if nstk > 0 && gp.goid == 1 {
135133
nstk-- // skip runtime.main
136134
}
137-
id := trace.stackTab[gen%2].put(pcBuf[:nstk])
135+
id := tab.put(pcBuf[:nstk])
138136
return id
139137
}
140138

src/runtime/tracestack_test.go

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
// Copyright 2025 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package runtime_test
6+
7+
import (
8+
"runtime"
9+
"strconv"
10+
"testing"
11+
)
12+
13+
func BenchmarkTraceStack(b *testing.B) {
14+
for _, stackDepth := range []int{1, 10, 100} {
15+
b.Run("stackDepth="+strconv.Itoa(stackDepth), func(b *testing.B) {
16+
benchmarkTraceStack(b, stackDepth)
17+
})
18+
}
19+
}
20+
21+
func benchmarkTraceStack(b *testing.B, stackDepth int) {
22+
var tab runtime.TraceStackTable
23+
defer tab.Reset()
24+
25+
wait := make(chan struct{})
26+
ready := make(chan struct{})
27+
done := make(chan struct{})
28+
var gp *runtime.G
29+
go func() {
30+
gp = runtime.Getg()
31+
useStackAndCall(stackDepth, func() {
32+
ready <- struct{}{}
33+
<-wait
34+
})
35+
done <- struct{}{}
36+
}()
37+
<-ready
38+
39+
for b.Loop() {
40+
runtime.TraceStack(gp, &tab)
41+
}
42+
43+
// Clean up.
44+
wait <- struct{}{}
45+
<-done
46+
}

0 commit comments

Comments
 (0)