Skip to content

Commit 4d7cf3f

Browse files
committed
runtime: convert g.waitreason from string to uint8
Every time I poke at golang#14921, the g.waitreason string pointer writes show up. They're not particularly important performance-wise, but it'd be nice to clear the noise away. And it does open up a few extra bytes in the g struct for some future use. This is a re-roll of CL 99078, which was rolled back because of failures on s390x. Those failures were apparently due to an old version of gdb. Change-Id: Icc2c12f449b2934063fd61e272e06237625ed589 Reviewed-on: https://go-review.googlesource.com/111256 Run-TryBot: Josh Bleecher Snyder <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Michael Munday <[email protected]>
1 parent 4704149 commit 4d7cf3f

15 files changed

Lines changed: 114 additions & 45 deletions

src/runtime/chan.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ func chansend(c *hchan, ep unsafe.Pointer, block bool, callerpc uintptr) bool {
142142
if !block {
143143
return false
144144
}
145-
gopark(nil, nil, "chan send (nil chan)", traceEvGoStop, 2)
145+
gopark(nil, nil, waitReasonChanSendNilChan, traceEvGoStop, 2)
146146
throw("unreachable")
147147
}
148148

@@ -231,7 +231,7 @@ func chansend(c *hchan, ep unsafe.Pointer, block bool, callerpc uintptr) bool {
231231
gp.waiting = mysg
232232
gp.param = nil
233233
c.sendq.enqueue(mysg)
234-
goparkunlock(&c.lock, "chan send", traceEvGoBlockSend, 3)
234+
goparkunlock(&c.lock, waitReasonChanSend, traceEvGoBlockSend, 3)
235235

236236
// someone woke us up.
237237
if mysg != gp.waiting {
@@ -426,7 +426,7 @@ func chanrecv(c *hchan, ep unsafe.Pointer, block bool) (selected, received bool)
426426
if !block {
427427
return
428428
}
429-
gopark(nil, nil, "chan receive (nil chan)", traceEvGoStop, 2)
429+
gopark(nil, nil, waitReasonChanReceiveNilChan, traceEvGoStop, 2)
430430
throw("unreachable")
431431
}
432432

@@ -517,7 +517,7 @@ func chanrecv(c *hchan, ep unsafe.Pointer, block bool) (selected, received bool)
517517
mysg.c = c
518518
gp.param = nil
519519
c.recvq.enqueue(mysg)
520-
goparkunlock(&c.lock, "chan receive", traceEvGoBlockRecv, 3)
520+
goparkunlock(&c.lock, waitReasonChanReceive, traceEvGoBlockRecv, 3)
521521

522522
// someone woke us up
523523
if mysg != gp.waiting {

src/runtime/heapdump.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -349,7 +349,7 @@ func dumpgoroutine(gp *g) {
349349
dumpbool(isSystemGoroutine(gp))
350350
dumpbool(false) // isbackground
351351
dumpint(uint64(gp.waitsince))
352-
dumpstr(gp.waitreason)
352+
dumpstr(gp.waitreason.String())
353353
dumpint(uint64(uintptr(gp.sched.ctxt)))
354354
dumpint(uint64(uintptr(unsafe.Pointer(gp.m))))
355355
dumpint(uint64(uintptr(unsafe.Pointer(gp._defer))))
@@ -658,7 +658,7 @@ func mdump() {
658658
func writeheapdump_m(fd uintptr) {
659659
_g_ := getg()
660660
casgstatus(_g_.m.curg, _Grunning, _Gwaiting)
661-
_g_.waitreason = "dumping heap"
661+
_g_.waitreason = waitReasonDumpingHeap
662662

663663
// Update stats so we can dump them.
664664
// As a side effect, flushes all the MCaches so the MSpan.freelist

src/runtime/mfinal.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,7 @@ func runfinq() {
172172
gp := getg()
173173
fing = gp
174174
fingwait = true
175-
goparkunlock(&finlock, "finalizer wait", traceEvGoBlock, 1)
175+
goparkunlock(&finlock, waitReasonFinalizerWait, traceEvGoBlock, 1)
176176
continue
177177
}
178178
unlock(&finlock)

src/runtime/mgc.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1149,7 +1149,7 @@ func gcWaitOnMark(n uint32) {
11491149
gp := getg()
11501150
gp.schedlink = work.sweepWaiters.head
11511151
work.sweepWaiters.head.set(gp)
1152-
goparkunlock(&work.sweepWaiters.lock, "wait for GC cycle", traceEvGoBlock, 1)
1152+
goparkunlock(&work.sweepWaiters.lock, waitReasonWaitForGCCycle, traceEvGoBlock, 1)
11531153
}
11541154
}
11551155

@@ -1527,7 +1527,7 @@ func gcMarkTermination(nextTriggerRatio float64) {
15271527
_g_.m.traceback = 2
15281528
gp := _g_.m.curg
15291529
casgstatus(gp, _Grunning, _Gwaiting)
1530-
gp.waitreason = "garbage collection"
1530+
gp.waitreason = waitReasonGarbageCollection
15311531

15321532
// Run gc on the g0 stack. We do this so that the g stack
15331533
// we're currently running on will no longer change. Cuts
@@ -1796,7 +1796,7 @@ func gcBgMarkWorker(_p_ *p) {
17961796
}
17971797
}
17981798
return true
1799-
}, unsafe.Pointer(park), "GC worker (idle)", traceEvGoBlock, 0)
1799+
}, unsafe.Pointer(park), waitReasonGCWorkerIdle, traceEvGoBlock, 0)
18001800

18011801
// Loop until the P dies and disassociates this
18021802
// worker (the P may later be reused, in which case

src/runtime/mgcmark.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,7 @@ func markroot(gcw *gcWork, i uint32) {
251251
selfScan := gp == userG && readgstatus(userG) == _Grunning
252252
if selfScan {
253253
casgstatus(userG, _Grunning, _Gwaiting)
254-
userG.waitreason = "garbage collection scan"
254+
userG.waitreason = waitReasonGarbageCollectionScan
255255
}
256256

257257
// TODO: scang blocks until gp's stack has
@@ -549,7 +549,7 @@ func gcAssistAlloc1(gp *g, scanWork int64) {
549549

550550
// gcDrainN requires the caller to be preemptible.
551551
casgstatus(gp, _Grunning, _Gwaiting)
552-
gp.waitreason = "GC assist marking"
552+
gp.waitreason = waitReasonGCAssistMarking
553553

554554
// drain own cached work first in the hopes that it
555555
// will be more cache friendly.
@@ -648,7 +648,7 @@ func gcParkAssist() bool {
648648
return false
649649
}
650650
// Park.
651-
goparkunlock(&work.assistQueue.lock, "GC assist wait", traceEvGoBlockGC, 2)
651+
goparkunlock(&work.assistQueue.lock, waitReasonGCAssistWait, traceEvGoBlockGC, 2)
652652
return true
653653
}
654654

src/runtime/mgcsweep.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ func bgsweep(c chan int) {
4949
lock(&sweep.lock)
5050
sweep.parked = true
5151
c <- 1
52-
goparkunlock(&sweep.lock, "GC sweep wait", traceEvGoBlock, 1)
52+
goparkunlock(&sweep.lock, waitReasonGCSweepWait, traceEvGoBlock, 1)
5353

5454
for {
5555
for gosweepone() != ^uintptr(0) {
@@ -68,7 +68,7 @@ func bgsweep(c chan int) {
6868
continue
6969
}
7070
sweep.parked = true
71-
goparkunlock(&sweep.lock, "GC sweep wait", traceEvGoBlock, 1)
71+
goparkunlock(&sweep.lock, waitReasonGCSweepWait, traceEvGoBlock, 1)
7272
}
7373
}
7474

src/runtime/netpoll.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -363,7 +363,7 @@ func netpollblock(pd *pollDesc, mode int32, waitio bool) bool {
363363
// this is necessary because runtime_pollUnblock/runtime_pollSetDeadline/deadlineimpl
364364
// do the opposite: store to closing/rd/wd, membarrier, load of rg/wg
365365
if waitio || netpollcheckerr(pd, mode) == 0 {
366-
gopark(netpollblockcommit, unsafe.Pointer(gpp), "IO wait", traceEvGoBlockNet, 5)
366+
gopark(netpollblockcommit, unsafe.Pointer(gpp), waitReasonIOWait, traceEvGoBlockNet, 5)
367367
}
368368
// be careful to not lose concurrent READY notification
369369
old := atomic.Xchguintptr(gpp, 0)

src/runtime/proc.go

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,7 @@ func main() {
214214
}
215215
}
216216
if atomic.Load(&panicking) != 0 {
217-
gopark(nil, nil, "panicwait", traceEvGoStop, 1)
217+
gopark(nil, nil, waitReasonPanicWait, traceEvGoStop, 1)
218218
}
219219

220220
exit(0)
@@ -245,7 +245,7 @@ func forcegchelper() {
245245
throw("forcegc: phase error")
246246
}
247247
atomic.Store(&forcegc.idle, 1)
248-
goparkunlock(&forcegc.lock, "force gc (idle)", traceEvGoBlock, 1)
248+
goparkunlock(&forcegc.lock, waitReasonForceGGIdle, traceEvGoBlock, 1)
249249
// this goroutine is explicitly resumed by sysmon
250250
if debug.gctrace > 0 {
251251
println("GC forced")
@@ -274,7 +274,11 @@ func goschedguarded() {
274274
// If unlockf returns false, the goroutine is resumed.
275275
// unlockf must not access this G's stack, as it may be moved between
276276
// the call to gopark and the call to unlockf.
277-
func gopark(unlockf func(*g, unsafe.Pointer) bool, lock unsafe.Pointer, reason string, traceEv byte, traceskip int) {
277+
// Reason explains why the goroutine has been parked.
278+
// It is displayed in stack traces and heap dumps.
279+
// Reasons should be unique and descriptive.
280+
// Do not re-use reasons, add new ones.
281+
func gopark(unlockf func(*g, unsafe.Pointer) bool, lock unsafe.Pointer, reason waitReason, traceEv byte, traceskip int) {
278282
mp := acquirem()
279283
gp := mp.curg
280284
status := readgstatus(gp)
@@ -293,7 +297,7 @@ func gopark(unlockf func(*g, unsafe.Pointer) bool, lock unsafe.Pointer, reason s
293297

294298
// Puts the current goroutine into a waiting state and unlocks the lock.
295299
// The goroutine can be made runnable again by calling goready(gp).
296-
func goparkunlock(lock *mutex, reason string, traceEv byte, traceskip int) {
300+
func goparkunlock(lock *mutex, reason waitReason, traceEv byte, traceskip int) {
297301
gopark(parkunlock_c, unsafe.Pointer(lock), reason, traceEv, traceskip)
298302
}
299303

@@ -2676,7 +2680,7 @@ func goexit0(gp *g) {
26762680
gp._defer = nil // should be true already but just in case.
26772681
gp._panic = nil // non-nil for Goexit during panic. points at stack-allocated data.
26782682
gp.writebuf = nil
2679-
gp.waitreason = ""
2683+
gp.waitreason = 0
26802684
gp.param = nil
26812685
gp.labels = nil
26822686
gp.timer = nil
@@ -4542,7 +4546,7 @@ func schedtrace(detailed bool) {
45424546
if lockedm != nil {
45434547
id2 = lockedm.id
45444548
}
4545-
print(" G", gp.goid, ": status=", readgstatus(gp), "(", gp.waitreason, ") m=", id1, " lockedm=", id2, "\n")
4549+
print(" G", gp.goid, ": status=", readgstatus(gp), "(", gp.waitreason.String(), ") m=", id1, " lockedm=", id2, "\n")
45464550
}
45474551
unlock(&allglock)
45484552
unlock(&sched.lock)

src/runtime/runtime2.go

Lines changed: 78 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -358,20 +358,20 @@ type g struct {
358358
atomicstatus uint32
359359
stackLock uint32 // sigprof/scang lock; TODO: fold in to atomicstatus
360360
goid int64
361-
waitsince int64 // approx time when the g become blocked
362-
waitreason string // if status==Gwaiting
363361
schedlink guintptr
364-
preempt bool // preemption signal, duplicates stackguard0 = stackpreempt
365-
paniconfault bool // panic (instead of crash) on unexpected fault address
366-
preemptscan bool // preempted g does scan for gc
367-
gcscandone bool // g has scanned stack; protected by _Gscan bit in status
368-
gcscanvalid bool // false at start of gc cycle, true if G has not run since last scan; TODO: remove?
369-
throwsplit bool // must not split stack
370-
raceignore int8 // ignore race detection events
371-
sysblocktraced bool // StartTrace has emitted EvGoInSyscall about this goroutine
372-
sysexitticks int64 // cputicks when syscall has returned (for tracing)
373-
traceseq uint64 // trace event sequencer
374-
tracelastp puintptr // last P emitted an event for this goroutine
362+
waitsince int64 // approx time when the g become blocked
363+
waitreason waitReason // if status==Gwaiting
364+
preempt bool // preemption signal, duplicates stackguard0 = stackpreempt
365+
paniconfault bool // panic (instead of crash) on unexpected fault address
366+
preemptscan bool // preempted g does scan for gc
367+
gcscandone bool // g has scanned stack; protected by _Gscan bit in status
368+
gcscanvalid bool // false at start of gc cycle, true if G has not run since last scan; TODO: remove?
369+
throwsplit bool // must not split stack
370+
raceignore int8 // ignore race detection events
371+
sysblocktraced bool // StartTrace has emitted EvGoInSyscall about this goroutine
372+
sysexitticks int64 // cputicks when syscall has returned (for tracing)
373+
traceseq uint64 // trace event sequencer
374+
tracelastp puintptr // last P emitted an event for this goroutine
375375
lockedm muintptr
376376
sig uint32
377377
writebuf []byte
@@ -756,6 +756,71 @@ const (
756756
// The maximum number of frames we print for a traceback
757757
const _TracebackMaxFrames = 100
758758

759+
// A waitReason explains why a goroutine has been stopped.
760+
// See gopark. Do not re-use waitReasons, add new ones.
761+
type waitReason uint8
762+
763+
const (
764+
waitReasonZero waitReason = iota // ""
765+
waitReasonGCAssistMarking // "GC assist marking"
766+
waitReasonIOWait // "IO wait"
767+
waitReasonChanReceiveNilChan // "chan receive (nil chan)"
768+
waitReasonChanSendNilChan // "chan send (nil chan)"
769+
waitReasonDumpingHeap // "dumping heap"
770+
waitReasonGarbageCollection // "garbage collection"
771+
waitReasonGarbageCollectionScan // "garbage collection scan"
772+
waitReasonPanicWait // "panicwait"
773+
waitReasonSelect // "select"
774+
waitReasonSelectNoCases // "select (no cases)"
775+
waitReasonGCAssistWait // "GC assist wait"
776+
waitReasonGCSweepWait // "GC sweep wait"
777+
waitReasonChanReceive // "chan receive"
778+
waitReasonChanSend // "chan send"
779+
waitReasonFinalizerWait // "finalizer wait"
780+
waitReasonForceGGIdle // "force gc (idle)"
781+
waitReasonSemacquire // "semacquire"
782+
waitReasonSleep // "sleep"
783+
waitReasonSyncCondWait // "sync.Cond.Wait"
784+
waitReasonTimerGoroutineIdle // "timer goroutine (idle)"
785+
waitReasonTraceReaderBlocked // "trace reader (blocked)"
786+
waitReasonWaitForGCCycle // "wait for GC cycle"
787+
waitReasonGCWorkerIdle // "GC worker (idle)"
788+
)
789+
790+
var waitReasonStrings = [...]string{
791+
waitReasonZero: "",
792+
waitReasonGCAssistMarking: "GC assist marking",
793+
waitReasonIOWait: "IO wait",
794+
waitReasonChanReceiveNilChan: "chan receive (nil chan)",
795+
waitReasonChanSendNilChan: "chan send (nil chan)",
796+
waitReasonDumpingHeap: "dumping heap",
797+
waitReasonGarbageCollection: "garbage collection",
798+
waitReasonGarbageCollectionScan: "garbage collection scan",
799+
waitReasonPanicWait: "panicwait",
800+
waitReasonSelect: "select",
801+
waitReasonSelectNoCases: "select (no cases)",
802+
waitReasonGCAssistWait: "GC assist wait",
803+
waitReasonGCSweepWait: "GC sweep wait",
804+
waitReasonChanReceive: "chan receive",
805+
waitReasonChanSend: "chan send",
806+
waitReasonFinalizerWait: "finalizer wait",
807+
waitReasonForceGGIdle: "force gc (idle)",
808+
waitReasonSemacquire: "semacquire",
809+
waitReasonSleep: "sleep",
810+
waitReasonSyncCondWait: "sync.Cond.Wait",
811+
waitReasonTimerGoroutineIdle: "timer goroutine (idle)",
812+
waitReasonTraceReaderBlocked: "trace reader (blocked)",
813+
waitReasonWaitForGCCycle: "wait for GC cycle",
814+
waitReasonGCWorkerIdle: "GC worker (idle)",
815+
}
816+
817+
func (w waitReason) String() string {
818+
if w < 0 || w >= waitReason(len(waitReasonStrings)) {
819+
return "unknown wait reason"
820+
}
821+
return waitReasonStrings[w]
822+
}
823+
759824
var (
760825
allglen uintptr
761826
allm *m

src/runtime/select.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ func selparkcommit(gp *g, _ unsafe.Pointer) bool {
9999
}
100100

101101
func block() {
102-
gopark(nil, nil, "select (no cases)", traceEvGoStop, 1) // forever
102+
gopark(nil, nil, waitReasonSelectNoCases, traceEvGoStop, 1) // forever
103103
}
104104

105105
// selectgo implements the select statement.
@@ -309,7 +309,7 @@ loop:
309309

310310
// wait for someone to wake us up
311311
gp.param = nil
312-
gopark(selparkcommit, nil, "select", traceEvGoBlockSelect, 1)
312+
gopark(selparkcommit, nil, waitReasonSelect, traceEvGoBlockSelect, 1)
313313

314314
sellock(scases, lockorder)
315315

0 commit comments

Comments
 (0)