diff options
| author | Michael Anthony Knyszek <mknyszek@google.com> | 2023-05-11 21:09:10 +0000 |
|---|---|---|
| committer | Michael Knyszek <mknyszek@google.com> | 2023-05-19 17:06:45 +0000 |
| commit | b1aadd034c1feb6ac8409aca5f0efd10ef442950 (patch) | |
| tree | 4872646599671579df0c82627204881bebd087e2 /src/runtime/trace.go | |
| parent | 944911af5630bec413237b9aba010661a353953e (diff) | |
| download | go-b1aadd034c1feb6ac8409aca5f0efd10ef442950.tar.xz | |
runtime: emit STW events for all pauses, not just those for the GC
Currently STW events are only emitted for GC STWs. There's little reason
why the trace can't contain events for every STW: they're rare so don't
take up much space in the trace, yet being able to see when the world
was stopped is often critical to debugging certain latency issues,
especially when they stem from user-level APIs.
This change adds new "kinds" to the EvGCSTWStart event, renames the
GCSTW events to just "STW," and lets the parser deal with unknown STW
kinds for future backwards compatibility.
But, this change must break trace compatibility, so it bumps the trace
version to Go 1.21.
This change also includes a small cleanup in the trace command, which
previously checked for STW events when deciding whether user tasks
overlapped with a GC. Looking at the source, I don't see a way for STW
events to ever enter the stream that that code looks at, so that
condition has been deleted.
Change-Id: I9a5dc144092c53e92eb6950e9a5504a790ac00cf
Reviewed-on: https://go-review.googlesource.com/c/go/+/494495
Reviewed-by: Michael Pratt <mpratt@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Run-TryBot: Michael Knyszek <mknyszek@google.com>
Diffstat (limited to 'src/runtime/trace.go')
| -rw-r--r-- | src/runtime/trace.go | 32 |
1 files changed, 22 insertions, 10 deletions
diff --git a/src/runtime/trace.go b/src/runtime/trace.go index 45a066e7a2..2fe6d2d13f 100644 --- a/src/runtime/trace.go +++ b/src/runtime/trace.go @@ -31,8 +31,8 @@ const ( traceEvProcStop = 6 // stop of P [timestamp] traceEvGCStart = 7 // GC start [timestamp, seq, stack id] traceEvGCDone = 8 // GC done [timestamp] - traceEvGCSTWStart = 9 // GC STW start [timestamp, kind] - traceEvGCSTWDone = 10 // GC STW done [timestamp] + traceEvSTWStart = 9 // STW start [timestamp, kind] + traceEvSTWDone = 10 // STW done [timestamp] traceEvGCSweepStart = 11 // GC sweep start [timestamp, stack id] traceEvGCSweepDone = 12 // GC sweep done [timestamp, swept, reclaimed] traceEvGoCreate = 13 // goroutine creation [timestamp, new goroutine id, new stack id, stack id] @@ -171,7 +171,8 @@ type gTraceState struct { // mTraceState is per-M state for the tracer. type mTraceState struct { - startingTrace bool // this M is in TraceStart, potentially before traceEnabled is true + startingTrace bool // this M is in TraceStart, potentially before traceEnabled is true + tracedSTWStart bool // this M traced a STW start, so it should trace an end } // pTraceState is per-P state for the tracer. @@ -247,7 +248,7 @@ func StartTrace() error { // Do not stop the world during GC so we ensure we always see // a consistent view of GC-related events (e.g. a start is always // paired with an end). - stopTheWorldGC("start tracing") + stopTheWorldGC(stwStartTrace) // Prevent sysmon from running any code that could generate events. lock(&sched.sysmonlock) @@ -377,7 +378,7 @@ func StartTrace() error { func StopTrace() { // Stop the world so that we can collect the trace buffers from all p's below, // and also to avoid races with traceEvent. - stopTheWorldGC("stop tracing") + stopTheWorldGC(stwStopTrace) // See the comment in StartTrace. lock(&sched.sysmonlock) @@ -560,7 +561,7 @@ func readTrace0() (buf []byte, park bool) { trace.headerWritten = true trace.lockOwner = nil unlock(&trace.lock) - return []byte("go 1.19 trace\x00\x00\x00"), false + return []byte("go 1.21 trace\x00\x00\x00"), false } // Optimistically look for CPU profile samples. This may write new stack // records, and may write new tracing buffers. @@ -1485,12 +1486,23 @@ func traceGCDone() { traceEvent(traceEvGCDone, -1) } -func traceGCSTWStart(kind int) { - traceEvent(traceEvGCSTWStart, -1, uint64(kind)) +func traceSTWStart(reason stwReason) { + // Don't trace if this STW is for trace start/stop, since traceEnabled + // switches during a STW. + if reason == stwStartTrace || reason == stwStopTrace { + return + } + getg().m.trace.tracedSTWStart = true + traceEvent(traceEvSTWStart, -1, uint64(reason)) } -func traceGCSTWDone() { - traceEvent(traceEvGCSTWDone, -1) +func traceSTWDone() { + mp := getg().m + if !mp.trace.tracedSTWStart { + return + } + mp.trace.tracedSTWStart = false + traceEvent(traceEvSTWDone, -1) } // traceGCSweepStart prepares to trace a sweep loop. This does not |
