mirror of
https://github.com/golang/go.git
synced 2025-10-20 03:23:18 +00:00
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 <cherryyz@google.com> Auto-Submit: Michael Knyszek <mknyszek@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
This commit is contained in:
parent
20978f46fd
commit
75b43f9a97
6 changed files with 65 additions and 8 deletions
|
@ -1917,3 +1917,13 @@ const (
|
||||||
BubbleAssocCurrentBubble = bubbleAssocCurrentBubble
|
BubbleAssocCurrentBubble = bubbleAssocCurrentBubble
|
||||||
BubbleAssocOtherBubble = bubbleAssocOtherBubble
|
BubbleAssocOtherBubble = bubbleAssocOtherBubble
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type TraceStackTable traceStackTable
|
||||||
|
|
||||||
|
func (t *TraceStackTable) Reset() {
|
||||||
|
t.tab.reset()
|
||||||
|
}
|
||||||
|
|
||||||
|
func TraceStack(gp *G, tab *TraceStackTable) {
|
||||||
|
traceStack(0, gp, (*traceStackTable)(tab))
|
||||||
|
}
|
||||||
|
|
|
@ -981,6 +981,9 @@ func pcvalue(f funcInfo, off uint32, targetpc uintptr, strict bool) (int32, uint
|
||||||
// matches the cached contents.
|
// matches the cached contents.
|
||||||
const debugCheckCache = false
|
const debugCheckCache = false
|
||||||
|
|
||||||
|
// If true, skip checking the cache entirely.
|
||||||
|
const skipCache = false
|
||||||
|
|
||||||
if off == 0 {
|
if off == 0 {
|
||||||
return -1, 0
|
return -1, 0
|
||||||
}
|
}
|
||||||
|
@ -991,7 +994,7 @@ func pcvalue(f funcInfo, off uint32, targetpc uintptr, strict bool) (int32, uint
|
||||||
var checkVal int32
|
var checkVal int32
|
||||||
var checkPC uintptr
|
var checkPC uintptr
|
||||||
ck := pcvalueCacheKey(targetpc)
|
ck := pcvalueCacheKey(targetpc)
|
||||||
{
|
if !skipCache {
|
||||||
mp := acquirem()
|
mp := acquirem()
|
||||||
cache := &mp.pcvalueCache
|
cache := &mp.pcvalueCache
|
||||||
// The cache can be used by the signal handler on this M. Avoid
|
// The cache can be used by the signal handler on this M. Avoid
|
||||||
|
|
|
@ -396,7 +396,7 @@ func traceAdvance(stopTrace bool) {
|
||||||
ug.status = readgstatus(s.g) &^ _Gscan
|
ug.status = readgstatus(s.g) &^ _Gscan
|
||||||
ug.waitreason = s.g.waitreason
|
ug.waitreason = s.g.waitreason
|
||||||
ug.inMarkAssist = s.g.inMarkAssist
|
ug.inMarkAssist = s.g.inMarkAssist
|
||||||
ug.stackID = traceStack(0, gp, gen)
|
ug.stackID = traceStack(0, gp, &trace.stackTab[gen%2])
|
||||||
}
|
}
|
||||||
resumeG(s)
|
resumeG(s)
|
||||||
casgstatus(me, _Gwaiting, _Grunning)
|
casgstatus(me, _Gwaiting, _Grunning)
|
||||||
|
|
|
@ -56,7 +56,7 @@ func (e traceEventWriter) event(ev tracev2.EventType, args ...traceArg) {
|
||||||
// It then returns a traceArg representing that stack which may be
|
// It then returns a traceArg representing that stack which may be
|
||||||
// passed to write.
|
// passed to write.
|
||||||
func (tl traceLocker) stack(skip int) traceArg {
|
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
|
// startPC takes a start PC for a goroutine and produces a unique
|
||||||
|
|
|
@ -28,10 +28,8 @@ const (
|
||||||
// skip controls the number of leaf frames to omit in order to hide tracer internals
|
// skip controls the number of leaf frames to omit in order to hide tracer internals
|
||||||
// from stack traces, see CL 5523.
|
// from stack traces, see CL 5523.
|
||||||
//
|
//
|
||||||
// Avoid calling this function directly. gen needs to be the current generation
|
// Avoid calling this function directly. Prefer traceEventWriter.stack.
|
||||||
// that this stack trace is being written out for, which needs to be synchronized with
|
func traceStack(skip int, gp *g, tab *traceStackTable) uint64 {
|
||||||
// generations moving forward. Prefer traceEventWriter.stack.
|
|
||||||
func traceStack(skip int, gp *g, gen uintptr) uint64 {
|
|
||||||
var pcBuf [tracev2.MaxFramesPerStack]uintptr
|
var pcBuf [tracev2.MaxFramesPerStack]uintptr
|
||||||
|
|
||||||
// Figure out gp and mp for the backtrace.
|
// 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 {
|
if nstk > 0 && gp.goid == 1 {
|
||||||
nstk-- // skip runtime.main
|
nstk-- // skip runtime.main
|
||||||
}
|
}
|
||||||
id := trace.stackTab[gen%2].put(pcBuf[:nstk])
|
id := tab.put(pcBuf[:nstk])
|
||||||
return id
|
return id
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
46
src/runtime/tracestack_test.go
Normal file
46
src/runtime/tracestack_test.go
Normal file
|
@ -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
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue