]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: clarify stack traces for bubbled goroutines
authorDamien Neil <dneil@google.com>
Thu, 5 Jun 2025 21:21:47 +0000 (14:21 -0700)
committerGopher Robot <gobot@golang.org>
Mon, 9 Jun 2025 17:58:51 +0000 (10:58 -0700)
Use the synctest bubble ID to identify bubbles in traces,
rather than the goroutine ID of the bubble's root goroutine.

Some waitReasons include a "(synctest)" suffix to distinguish
a durably blocking state from a non-durable one. For example,
"chan send" vs. "chan send (synctest)". Change this suffix
to "(durable)".

Always print a "(durable)" sufix for the state of durably
blocked bubbled goroutines. For example, print "sleep (durable)".

Drop the "[not] durably blocked" text from goroutine states,
since this is now entirely redundant with the waitReason.

Old:
  goroutine 8 [chan receive (synctest), synctest bubble 7, durably blocked]:
  goroutine 9 [select (no cases), synctest bubble 7, durably blocked]:

New:
  goroutine 8 [chan receive (durable), synctest bubble 1]:
  goroutine 9 [select (no cases) (durable), synctest bubble 1]:

Change-Id: I89112efb25150a98a2954f54d1910ccec52a5824
Reviewed-on: https://go-review.googlesource.com/c/go/+/679376
Auto-Submit: Damien Neil <dneil@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Michael Pratt <mpratt@google.com>
src/runtime/runtime2.go
src/runtime/traceback.go

index 589642efc66309e83d740c9e8203740aaa4673a0..d1b31be172e65f586fdf4995fbd3a9bbbb915522 100644 (file)
@@ -1093,10 +1093,10 @@ const (
        waitReasonGCWeakToStrongWait                      // "GC weak to strong wait"
        waitReasonSynctestRun                             // "synctest.Run"
        waitReasonSynctestWait                            // "synctest.Wait"
-       waitReasonSynctestChanReceive                     // "chan receive (synctest)"
-       waitReasonSynctestChanSend                        // "chan send (synctest)"
-       waitReasonSynctestSelect                          // "select (synctest)"
-       waitReasonSynctestWaitGroupWait                   // "sync.WaitGroup.Wait (synctest)"
+       waitReasonSynctestChanReceive                     // "chan receive (durable)"
+       waitReasonSynctestChanSend                        // "chan send (durable)"
+       waitReasonSynctestSelect                          // "select (durable)"
+       waitReasonSynctestWaitGroupWait                   // "sync.WaitGroup.Wait (durable)"
        waitReasonCleanupWait                             // "cleanup wait"
 )
 
@@ -1143,10 +1143,10 @@ var waitReasonStrings = [...]string{
        waitReasonGCWeakToStrongWait:    "GC weak to strong wait",
        waitReasonSynctestRun:           "synctest.Run",
        waitReasonSynctestWait:          "synctest.Wait",
-       waitReasonSynctestChanReceive:   "chan receive (synctest)",
-       waitReasonSynctestChanSend:      "chan send (synctest)",
-       waitReasonSynctestSelect:        "select (synctest)",
-       waitReasonSynctestWaitGroupWait: "sync.WaitGroup.Wait (synctest)",
+       waitReasonSynctestChanReceive:   "chan receive (durable)",
+       waitReasonSynctestChanSend:      "chan send (durable)",
+       waitReasonSynctestSelect:        "select (durable)",
+       waitReasonSynctestWaitGroupWait: "sync.WaitGroup.Wait (durable)",
        waitReasonCleanupWait:           "cleanup wait",
 }
 
@@ -1207,12 +1207,12 @@ var isIdleInSynctest = [len(waitReasonStrings)]bool{
 }
 
 var (
-       allm           *m
-       gomaxprocs     int32
-       numCPUStartup  int32
-       forcegc        forcegcstate
-       sched          schedt
-       newprocs       int32
+       allm          *m
+       gomaxprocs    int32
+       numCPUStartup int32
+       forcegc       forcegcstate
+       sched         schedt
+       newprocs      int32
 )
 
 var (
index b3baa3b4eded137f9617640d77bae1920736aa40..00c0f08e5593c813f78e4c626fe06d66c03aed0e 100644 (file)
@@ -1248,6 +1248,13 @@ func goroutineheader(gp *g) {
        if isScan {
                print(" (scan)")
        }
+       if bubble := gp.bubble; bubble != nil &&
+               gp.waitreason.isIdleInSynctest() &&
+               !stringslite.HasSuffix(status, "(durable)") {
+               // If this isn't a status where the name includes a (durable)
+               // suffix to distinguish it from the non-durable form, add it here.
+               print(" (durable)")
+       }
        if waitfor >= 1 {
                print(", ", waitfor, " minutes")
        }
@@ -1255,11 +1262,7 @@ func goroutineheader(gp *g) {
                print(", locked to thread")
        }
        if bubble := gp.bubble; bubble != nil {
-               print(", synctest bubble ", bubble.root.goid, ", ")
-               if !gp.waitreason.isIdleInSynctest() {
-                       print("not ")
-               }
-               print("durably blocked")
+               print(", synctest bubble ", bubble.id)
        }
        print("]:\n")
 }