]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: make traceStack testable and add a benchmark
authorMichael Anthony Knyszek <mknyszek@google.com>
Fri, 27 Jun 2025 16:40:43 +0000 (16:40 +0000)
committerGopher Robot <gobot@golang.org>
Mon, 7 Jul 2025 17:31:37 +0000 (10:31 -0700)
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>

src/runtime/export_test.go
src/runtime/symtab.go
src/runtime/trace.go
src/runtime/traceevent.go
src/runtime/tracestack.go
src/runtime/tracestack_test.go [new file with mode: 0644]

index 83cf301be49cc80078b1e6167ab823e5891b0215..9a4611e26e52a254ffe134e0548c25a0f71de02d 100644 (file)
@@ -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))
+}
index 8c6ef2b4fc60816c2e3d428cde3541e04512dd94..866c46a83d7fdf43657f8f6194c21d17b839d486 100644 (file)
@@ -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
index b92e7b4e8e36569b89deae70c77b004da6853733..0d71ad445c2a4fcd03aff67b7c18036c3cc016bb 100644 (file)
@@ -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)
index 9d1a93d3f9f255f1dfbabb0d7db7731c627305b1..263847be2e12cd44817bd808aba9143d825bb9df 100644 (file)
@@ -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
index 2ee68c85f0e80c2a19e9afca3eb34f3a5c586769..76d6b05048f83a96f4188636292b155ff4cac1ef 100644 (file)
@@ -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 (file)
index 0000000..eaf4d90
--- /dev/null
@@ -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
+}