]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: make the wait reason for a g blocked on a mutex more specific
authorMichael Anthony Knyszek <mknyszek@google.com>
Tue, 30 Aug 2022 22:18:01 +0000 (22:18 +0000)
committerGopher Robot <gobot@golang.org>
Fri, 16 Sep 2022 16:32:27 +0000 (16:32 +0000)
This change adds 3 new waitReasons that correspond to sync.Mutex.Lock,
sync.RWMutex.RLock, and sync.RWMutex.Lock that are plumbed down into
semacquire1 by exporting new functions to the sync package from the
runtime.

Currently these three functions show up as "semacquire" in backtraces
which isn't very clear, though the stack trace itself should reveal
what's really going on. This represents a minor improvement to backtrace
readability, though blocking on an RWMutex.w.Lock will still show up as
blocking on a regular mutex (I suppose technically it is).

This is a step toward helping the runtime identify when a goroutine is
blocked on a mutex of some kind.

For #49881.

Change-Id: Ia409b4d27e117fe4bfdc25fa541e9c58d6d587b9
Reviewed-on: https://go-review.googlesource.com/c/go/+/427616
TryBot-Result: Gopher Robot <gobot@golang.org>
Auto-Submit: Michael Knyszek <mknyszek@google.com>
Reviewed-by: Michael Pratt <mpratt@google.com>
Run-TryBot: Michael Knyszek <mknyszek@google.com>

src/runtime/metrics.go
src/runtime/pprof/pprof_test.go
src/runtime/runtime2.go
src/runtime/sema.go
src/sync/runtime.go
src/sync/rwmutex.go

index 44fb4878ac8b0c5c8eec458ab758d7a91dd0e539..8e1c5968527d95fc895e9ee02a13779fc13aabc9 100644 (file)
@@ -40,7 +40,7 @@ func metricsLock() {
        // Acquire the metricsSema but with handoff. Operations are typically
        // expensive enough that queueing up goroutines and handing off between
        // them will be noticeably better-behaved.
-       semacquire1(&metricsSema, true, 0, 0)
+       semacquire1(&metricsSema, true, 0, 0, waitReasonSemacquire)
        if raceenabled {
                raceacquire(unsafe.Pointer(&metricsSema))
        }
index 79febc4285cb2723e6a15b977112bf78431a2f82..434d106f4a398a1d93f7fc7f34bd26eb37c5babf 100644 (file)
@@ -1089,7 +1089,7 @@ func blockMutex(t *testing.T) {
        var mu sync.Mutex
        mu.Lock()
        go func() {
-               awaitBlockedGoroutine(t, "semacquire", "blockMutex")
+               awaitBlockedGoroutine(t, "sync.Mutex.Lock", "blockMutex")
                mu.Unlock()
        }()
        // Note: Unlock releases mu before recording the mutex event,
index 5e0d61c058903410a85dde485c0844120bc3cf70..a5b0135470f565175f7977a00919e884852ca3ac 100644 (file)
@@ -1054,7 +1054,9 @@ const (
        waitReasonSemacquire                              // "semacquire"
        waitReasonSleep                                   // "sleep"
        waitReasonSyncCondWait                            // "sync.Cond.Wait"
-       waitReasonTimerGoroutineIdle                      // "timer goroutine (idle)"
+       waitReasonSyncMutexLock                           // "sync.Mutex.Lock"
+       waitReasonSyncRWMutexRLock                        // "sync.RWMutex.RLock"
+       waitReasonSyncRWMutexLock                         // "sync.RWMutex.Lock"
        waitReasonTraceReaderBlocked                      // "trace reader (blocked)"
        waitReasonWaitForGCCycle                          // "wait for GC cycle"
        waitReasonGCWorkerIdle                            // "GC worker (idle)"
@@ -1084,7 +1086,9 @@ var waitReasonStrings = [...]string{
        waitReasonSemacquire:            "semacquire",
        waitReasonSleep:                 "sleep",
        waitReasonSyncCondWait:          "sync.Cond.Wait",
-       waitReasonTimerGoroutineIdle:    "timer goroutine (idle)",
+       waitReasonSyncMutexLock:         "sync.Mutex.Lock",
+       waitReasonSyncRWMutexRLock:      "sync.RWMutex.RLock",
+       waitReasonSyncRWMutexLock:       "sync.RWMutex.Lock",
        waitReasonTraceReaderBlocked:    "trace reader (blocked)",
        waitReasonWaitForGCCycle:        "wait for GC cycle",
        waitReasonGCWorkerIdle:          "GC worker (idle)",
index c654889caca9d0ac2f4257b13a677acef630c4c4..bc23a85e348948e4b4c271e318c1391f52e321a6 100644 (file)
@@ -59,12 +59,12 @@ func (t *semTable) rootFor(addr *uint32) *semaRoot {
 
 //go:linkname sync_runtime_Semacquire sync.runtime_Semacquire
 func sync_runtime_Semacquire(addr *uint32) {
-       semacquire1(addr, false, semaBlockProfile, 0)
+       semacquire1(addr, false, semaBlockProfile, 0, waitReasonSemacquire)
 }
 
 //go:linkname poll_runtime_Semacquire internal/poll.runtime_Semacquire
 func poll_runtime_Semacquire(addr *uint32) {
-       semacquire1(addr, false, semaBlockProfile, 0)
+       semacquire1(addr, false, semaBlockProfile, 0, waitReasonSemacquire)
 }
 
 //go:linkname sync_runtime_Semrelease sync.runtime_Semrelease
@@ -74,7 +74,17 @@ func sync_runtime_Semrelease(addr *uint32, handoff bool, skipframes int) {
 
 //go:linkname sync_runtime_SemacquireMutex sync.runtime_SemacquireMutex
 func sync_runtime_SemacquireMutex(addr *uint32, lifo bool, skipframes int) {
-       semacquire1(addr, lifo, semaBlockProfile|semaMutexProfile, skipframes)
+       semacquire1(addr, lifo, semaBlockProfile|semaMutexProfile, skipframes, waitReasonSyncMutexLock)
+}
+
+//go:linkname sync_runtime_SemacquireRWMutexR sync.runtime_SemacquireRWMutexR
+func sync_runtime_SemacquireRWMutexR(addr *uint32, lifo bool, skipframes int) {
+       semacquire1(addr, lifo, semaBlockProfile|semaMutexProfile, skipframes, waitReasonSyncRWMutexRLock)
+}
+
+//go:linkname sync_runtime_SemacquireRWMutex sync.runtime_SemacquireRWMutex
+func sync_runtime_SemacquireRWMutex(addr *uint32, lifo bool, skipframes int) {
+       semacquire1(addr, lifo, semaBlockProfile|semaMutexProfile, skipframes, waitReasonSyncRWMutexLock)
 }
 
 //go:linkname poll_runtime_Semrelease internal/poll.runtime_Semrelease
@@ -98,10 +108,10 @@ const (
 
 // Called from runtime.
 func semacquire(addr *uint32) {
-       semacquire1(addr, false, 0, 0)
+       semacquire1(addr, false, 0, 0, waitReasonSemacquire)
 }
 
-func semacquire1(addr *uint32, lifo bool, profile semaProfileFlags, skipframes int) {
+func semacquire1(addr *uint32, lifo bool, profile semaProfileFlags, skipframes int, reason waitReason) {
        gp := getg()
        if gp != gp.m.curg {
                throw("semacquire not on the G stack")
@@ -147,7 +157,7 @@ func semacquire1(addr *uint32, lifo bool, profile semaProfileFlags, skipframes i
                // Any semrelease after the cansemacquire knows we're waiting
                // (we set nwait above), so go to sleep.
                root.queue(addr, s, lifo)
-               goparkunlock(&root.lock, waitReasonSemacquire, traceEvGoBlockSync, 4+skipframes)
+               goparkunlock(&root.lock, reason, traceEvGoBlockSync, 4+skipframes)
                if s.ticket != 0 || cansemacquire(addr) {
                        break
                }
index de2b0a3ccd2af523429aa8abdcd8db65ecd21d33..5a9081358545d585dd0949101fd32fd180ef69e7 100644 (file)
@@ -13,11 +13,17 @@ import "unsafe"
 // library and should not be used directly.
 func runtime_Semacquire(s *uint32)
 
-// SemacquireMutex is like Semacquire, but for profiling contended Mutexes.
+// Semacquire(RW)Mutex(R) is like Semacquire, but for profiling contended
+// Mutexes and RWMutexes.
 // If lifo is true, queue waiter at the head of wait queue.
 // skipframes is the number of frames to omit during tracing, counting from
 // runtime_SemacquireMutex's caller.
+// The different forms of this function just tell the runtime how to present
+// the reason for waiting in a backtrace, and is used to compute some metrics.
+// Otherwise they're functionally identical.
 func runtime_SemacquireMutex(s *uint32, lifo bool, skipframes int)
+func runtime_SemacquireRWMutexR(s *uint32, lifo bool, skipframes int)
+func runtime_SemacquireRWMutex(s *uint32, lifo bool, skipframes int)
 
 // Semrelease atomically increments *s and notifies a waiting goroutine
 // if one is blocked in Semacquire.
index e7d95181d58f1e7999f7e1f31f067fa35156f401..ad52951311e6641c91382461cdacf9d9ce930b58 100644 (file)
@@ -68,7 +68,7 @@ func (rw *RWMutex) RLock() {
        }
        if rw.readerCount.Add(1) < 0 {
                // A writer is pending, wait for it.
-               runtime_SemacquireMutex(&rw.readerSem, false, 0)
+               runtime_SemacquireRWMutexR(&rw.readerSem, false, 0)
        }
        if race.Enabled {
                race.Enable()
@@ -149,7 +149,7 @@ func (rw *RWMutex) Lock() {
        r := rw.readerCount.Add(-rwmutexMaxReaders) + rwmutexMaxReaders
        // Wait for active readers.
        if r != 0 && rw.readerWait.Add(r) != 0 {
-               runtime_SemacquireMutex(&rw.writerSem, false, 0)
+               runtime_SemacquireRWMutex(&rw.writerSem, false, 0)
        }
        if race.Enabled {
                race.Enable()