Skip to content

Commit a2c396c

Browse files
mknyszekgopherbot
authored andcommitted
runtime: make the wait reason for a g blocked on a mutex more specific
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 <[email protected]> Auto-Submit: Michael Knyszek <[email protected]> Reviewed-by: Michael Pratt <[email protected]> Run-TryBot: Michael Knyszek <[email protected]>
1 parent b7c28f4 commit a2c396c

File tree

6 files changed

+33
-13
lines changed

6 files changed

+33
-13
lines changed

Diff for: src/runtime/metrics.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ func metricsLock() {
4040
// Acquire the metricsSema but with handoff. Operations are typically
4141
// expensive enough that queueing up goroutines and handing off between
4242
// them will be noticeably better-behaved.
43-
semacquire1(&metricsSema, true, 0, 0)
43+
semacquire1(&metricsSema, true, 0, 0, waitReasonSemacquire)
4444
if raceenabled {
4545
raceacquire(unsafe.Pointer(&metricsSema))
4646
}

Diff for: src/runtime/pprof/pprof_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -1089,7 +1089,7 @@ func blockMutex(t *testing.T) {
10891089
var mu sync.Mutex
10901090
mu.Lock()
10911091
go func() {
1092-
awaitBlockedGoroutine(t, "semacquire", "blockMutex")
1092+
awaitBlockedGoroutine(t, "sync.Mutex.Lock", "blockMutex")
10931093
mu.Unlock()
10941094
}()
10951095
// Note: Unlock releases mu before recording the mutex event,

Diff for: src/runtime/runtime2.go

+6-2
Original file line numberDiff line numberDiff line change
@@ -1054,7 +1054,9 @@ const (
10541054
waitReasonSemacquire // "semacquire"
10551055
waitReasonSleep // "sleep"
10561056
waitReasonSyncCondWait // "sync.Cond.Wait"
1057-
waitReasonTimerGoroutineIdle // "timer goroutine (idle)"
1057+
waitReasonSyncMutexLock // "sync.Mutex.Lock"
1058+
waitReasonSyncRWMutexRLock // "sync.RWMutex.RLock"
1059+
waitReasonSyncRWMutexLock // "sync.RWMutex.Lock"
10581060
waitReasonTraceReaderBlocked // "trace reader (blocked)"
10591061
waitReasonWaitForGCCycle // "wait for GC cycle"
10601062
waitReasonGCWorkerIdle // "GC worker (idle)"
@@ -1084,7 +1086,9 @@ var waitReasonStrings = [...]string{
10841086
waitReasonSemacquire: "semacquire",
10851087
waitReasonSleep: "sleep",
10861088
waitReasonSyncCondWait: "sync.Cond.Wait",
1087-
waitReasonTimerGoroutineIdle: "timer goroutine (idle)",
1089+
waitReasonSyncMutexLock: "sync.Mutex.Lock",
1090+
waitReasonSyncRWMutexRLock: "sync.RWMutex.RLock",
1091+
waitReasonSyncRWMutexLock: "sync.RWMutex.Lock",
10881092
waitReasonTraceReaderBlocked: "trace reader (blocked)",
10891093
waitReasonWaitForGCCycle: "wait for GC cycle",
10901094
waitReasonGCWorkerIdle: "GC worker (idle)",

Diff for: src/runtime/sema.go

+16-6
Original file line numberDiff line numberDiff line change
@@ -59,12 +59,12 @@ func (t *semTable) rootFor(addr *uint32) *semaRoot {
5959

6060
//go:linkname sync_runtime_Semacquire sync.runtime_Semacquire
6161
func sync_runtime_Semacquire(addr *uint32) {
62-
semacquire1(addr, false, semaBlockProfile, 0)
62+
semacquire1(addr, false, semaBlockProfile, 0, waitReasonSemacquire)
6363
}
6464

6565
//go:linkname poll_runtime_Semacquire internal/poll.runtime_Semacquire
6666
func poll_runtime_Semacquire(addr *uint32) {
67-
semacquire1(addr, false, semaBlockProfile, 0)
67+
semacquire1(addr, false, semaBlockProfile, 0, waitReasonSemacquire)
6868
}
6969

7070
//go:linkname sync_runtime_Semrelease sync.runtime_Semrelease
@@ -74,7 +74,17 @@ func sync_runtime_Semrelease(addr *uint32, handoff bool, skipframes int) {
7474

7575
//go:linkname sync_runtime_SemacquireMutex sync.runtime_SemacquireMutex
7676
func sync_runtime_SemacquireMutex(addr *uint32, lifo bool, skipframes int) {
77-
semacquire1(addr, lifo, semaBlockProfile|semaMutexProfile, skipframes)
77+
semacquire1(addr, lifo, semaBlockProfile|semaMutexProfile, skipframes, waitReasonSyncMutexLock)
78+
}
79+
80+
//go:linkname sync_runtime_SemacquireRWMutexR sync.runtime_SemacquireRWMutexR
81+
func sync_runtime_SemacquireRWMutexR(addr *uint32, lifo bool, skipframes int) {
82+
semacquire1(addr, lifo, semaBlockProfile|semaMutexProfile, skipframes, waitReasonSyncRWMutexRLock)
83+
}
84+
85+
//go:linkname sync_runtime_SemacquireRWMutex sync.runtime_SemacquireRWMutex
86+
func sync_runtime_SemacquireRWMutex(addr *uint32, lifo bool, skipframes int) {
87+
semacquire1(addr, lifo, semaBlockProfile|semaMutexProfile, skipframes, waitReasonSyncRWMutexLock)
7888
}
7989

8090
//go:linkname poll_runtime_Semrelease internal/poll.runtime_Semrelease
@@ -98,10 +108,10 @@ const (
98108

99109
// Called from runtime.
100110
func semacquire(addr *uint32) {
101-
semacquire1(addr, false, 0, 0)
111+
semacquire1(addr, false, 0, 0, waitReasonSemacquire)
102112
}
103113

104-
func semacquire1(addr *uint32, lifo bool, profile semaProfileFlags, skipframes int) {
114+
func semacquire1(addr *uint32, lifo bool, profile semaProfileFlags, skipframes int, reason waitReason) {
105115
gp := getg()
106116
if gp != gp.m.curg {
107117
throw("semacquire not on the G stack")
@@ -147,7 +157,7 @@ func semacquire1(addr *uint32, lifo bool, profile semaProfileFlags, skipframes i
147157
// Any semrelease after the cansemacquire knows we're waiting
148158
// (we set nwait above), so go to sleep.
149159
root.queue(addr, s, lifo)
150-
goparkunlock(&root.lock, waitReasonSemacquire, traceEvGoBlockSync, 4+skipframes)
160+
goparkunlock(&root.lock, reason, traceEvGoBlockSync, 4+skipframes)
151161
if s.ticket != 0 || cansemacquire(addr) {
152162
break
153163
}

Diff for: src/sync/runtime.go

+7-1
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,17 @@ import "unsafe"
1313
// library and should not be used directly.
1414
func runtime_Semacquire(s *uint32)
1515

16-
// SemacquireMutex is like Semacquire, but for profiling contended Mutexes.
16+
// Semacquire(RW)Mutex(R) is like Semacquire, but for profiling contended
17+
// Mutexes and RWMutexes.
1718
// If lifo is true, queue waiter at the head of wait queue.
1819
// skipframes is the number of frames to omit during tracing, counting from
1920
// runtime_SemacquireMutex's caller.
21+
// The different forms of this function just tell the runtime how to present
22+
// the reason for waiting in a backtrace, and is used to compute some metrics.
23+
// Otherwise they're functionally identical.
2024
func runtime_SemacquireMutex(s *uint32, lifo bool, skipframes int)
25+
func runtime_SemacquireRWMutexR(s *uint32, lifo bool, skipframes int)
26+
func runtime_SemacquireRWMutex(s *uint32, lifo bool, skipframes int)
2127

2228
// Semrelease atomically increments *s and notifies a waiting goroutine
2329
// if one is blocked in Semacquire.

Diff for: src/sync/rwmutex.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ func (rw *RWMutex) RLock() {
6868
}
6969
if rw.readerCount.Add(1) < 0 {
7070
// A writer is pending, wait for it.
71-
runtime_SemacquireMutex(&rw.readerSem, false, 0)
71+
runtime_SemacquireRWMutexR(&rw.readerSem, false, 0)
7272
}
7373
if race.Enabled {
7474
race.Enable()
@@ -149,7 +149,7 @@ func (rw *RWMutex) Lock() {
149149
r := rw.readerCount.Add(-rwmutexMaxReaders) + rwmutexMaxReaders
150150
// Wait for active readers.
151151
if r != 0 && rw.readerWait.Add(r) != 0 {
152-
runtime_SemacquireMutex(&rw.writerSem, false, 0)
152+
runtime_SemacquireRWMutex(&rw.writerSem, false, 0)
153153
}
154154
if race.Enabled {
155155
race.Enable()

0 commit comments

Comments
 (0)