Skip to content

Instantly share code, notes, and snippets.

@achille-roussel
Last active April 7, 2023 02:40
Show Gist options
  • Save achille-roussel/d99726b26befa4184406eff1cd36def9 to your computer and use it in GitHub Desktop.
Save achille-roussel/d99726b26befa4184406eff1cd36def9 to your computer and use it in GitHub Desktop.
Detect number of goroutines in different state
package main
import (
"fmt"
"runtime"
"strings"
"time"
)
func main() {
ch := make(chan struct{})
for i := 0; i < 10; i++ {
go func() { <-ch }()
}
go time.Sleep(time.Second)
runtime.Gosched()
b := make([]byte, 1024)
t := time.Now()
runtime.Stack(b, true)
d := time.Since(t)
running := 0
receive := 0
sleep := 0
for _, line := range strings.Split(string(b), "\n") {
if strings.HasPrefix(line, "goroutine ") {
switch {
case strings.Contains(line, "running"):
running++
case strings.Contains(line, "chan receive"):
receive++
case strings.Contains(line, "sleep"):
sleep++
}
}
}
fmt.Printf(`=== GOROUTINES ===
chan receive: %d
running: %d
sleep: %d
(%s)
`, receive, running, sleep, d)
}
@achille-roussel
Copy link
Author

$ go run ./test.go
=== GOROUTINES ===
chan receive: 8
running:      1
sleep:        0

(75.5µs)

@achille-roussel
Copy link
Author

Potential states:
https://cs.opensource.google/go/go/+/master:src/runtime/traceback.go;l=1130-1139?q=%5C%22runnable%5C%22&ss=go%2Fgo

var gStatusStrings = [...]string{
	_Gidle:      "idle",
	_Grunnable:  "runnable",
	_Grunning:   "running",
	_Gsyscall:   "syscall",
	_Gwaiting:   "waiting",
	_Gdead:      "dead",
	_Gcopystack: "copystack",
	_Gpreempted: "preempted",
}

https://cs.opensource.google/go/go/+/master:src/runtime/runtime2.go;l=1092-1125?q=%22chan%20receive%22&ss=go%2Fgo

var waitReasonStrings = [...]string{
	waitReasonZero:                  "",
	waitReasonGCAssistMarking:       "GC assist marking",
	waitReasonIOWait:                "IO wait",
	waitReasonChanReceiveNilChan:    "chan receive (nil chan)",
	waitReasonChanSendNilChan:       "chan send (nil chan)",
	waitReasonDumpingHeap:           "dumping heap",
	waitReasonGarbageCollection:     "garbage collection",
	waitReasonGarbageCollectionScan: "garbage collection scan",
	waitReasonPanicWait:             "panicwait",
	waitReasonSelect:                "select",
	waitReasonSelectNoCases:         "select (no cases)",
	waitReasonGCAssistWait:          "GC assist wait",
	waitReasonGCSweepWait:           "GC sweep wait",
	waitReasonGCScavengeWait:        "GC scavenge wait",
	waitReasonChanReceive:           "chan receive",
	waitReasonChanSend:              "chan send",
	waitReasonFinalizerWait:         "finalizer wait",
	waitReasonForceGCIdle:           "force gc (idle)",
	waitReasonSemacquire:            "semacquire",
	waitReasonSleep:                 "sleep",
	waitReasonSyncCondWait:          "sync.Cond.Wait",
	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)",
	waitReasonGCWorkerActive:        "GC worker (active)",
	waitReasonPreempted:             "preempted",
	waitReasonDebugCall:             "debug call",
	waitReasonGCMarkTermination:     "GC mark termination",
	waitReasonStoppingTheWorld:      "stopping the world",
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment