]> Cypherpunks.ru repositories - gostls13.git/blobdiff - src/runtime/mgcmark.go
runtime: add execution tracer v2 behind GOEXPERIMENT=exectracer2
[gostls13.git] / src / runtime / mgcmark.go
index 004dc88828a0a4efe7fc3b122583631bcad39a73..95ec069bcfd76628d31e88604bf22a71e3efca4f 100644 (file)
@@ -414,16 +414,47 @@ func gcAssistAlloc(gp *g) {
                return
        }
 
-       traced := false
+       // This extremely verbose boolean indicates whether we've
+       // entered mark assist from the perspective of the tracer.
+       //
+       // In the old tracer, this is just before we call gcAssistAlloc1
+       // *and* tracing is enabled. Because the old tracer doesn't
+       // do any extra tracking, we need to be careful to not emit an
+       // "end" event if there was no corresponding "begin" for the
+       // mark assist.
+       //
+       // In the new tracer, this is just before we call gcAssistAlloc1
+       // *regardless* of whether tracing is enabled. This is because
+       // the new tracer allows for tracing to begin (and advance
+       // generations) in the middle of a GC mark phase, so we need to
+       // record some state so that the tracer can pick it up to ensure
+       // a consistent trace result.
+       //
+       // TODO(mknyszek): Hide the details of inMarkAssist in tracer
+       // functions and simplify all the state tracking. This is a lot.
+       enteredMarkAssistForTracing := false
 retry:
        if gcCPULimiter.limiting() {
                // If the CPU limiter is enabled, intentionally don't
                // assist to reduce the amount of CPU time spent in the GC.
-               if traced {
+               if enteredMarkAssistForTracing {
                        trace := traceAcquire()
                        if trace.ok() {
                                trace.GCMarkAssistDone()
+                               // Set this *after* we trace the end to make sure
+                               // that we emit an in-progress event if this is
+                               // the first event for the goroutine in the trace
+                               // or trace generation. Also, do this between
+                               // acquire/release because this is part of the
+                               // goroutine's trace state, and it must be atomic
+                               // with respect to the tracer.
+                               gp.inMarkAssist = false
                                traceRelease(trace)
+                       } else {
+                               // This state is tracked even if tracing isn't enabled.
+                               // It's only used by the new tracer.
+                               // See the comment on enteredMarkAssistForTracing.
+                               gp.inMarkAssist = false
                        }
                }
                return
@@ -464,22 +495,59 @@ retry:
                if scanWork == 0 {
                        // We were able to steal all of the credit we
                        // needed.
-                       if traced {
+                       if enteredMarkAssistForTracing {
                                trace := traceAcquire()
                                if trace.ok() {
                                        trace.GCMarkAssistDone()
+                                       // Set this *after* we trace the end to make sure
+                                       // that we emit an in-progress event if this is
+                                       // the first event for the goroutine in the trace
+                                       // or trace generation. Also, do this between
+                                       // acquire/release because this is part of the
+                                       // goroutine's trace state, and it must be atomic
+                                       // with respect to the tracer.
+                                       gp.inMarkAssist = false
                                        traceRelease(trace)
+                               } else {
+                                       // This state is tracked even if tracing isn't enabled.
+                                       // It's only used by the new tracer.
+                                       // See the comment on enteredMarkAssistForTracing.
+                                       gp.inMarkAssist = false
                                }
                        }
                        return
                }
        }
-       if traceEnabled() && !traced {
+       if !enteredMarkAssistForTracing {
                trace := traceAcquire()
                if trace.ok() {
-                       traced = true
+                       if !goexperiment.ExecTracer2 {
+                               // In the old tracer, enter mark assist tracing only
+                               // if we actually traced an event. Otherwise a goroutine
+                               // waking up from mark assist post-GC might end up
+                               // writing a stray "end" event.
+                               //
+                               // This means inMarkAssist will not be meaningful
+                               // in the old tracer; that's OK, it's unused.
+                               //
+                               // See the comment on enteredMarkAssistForTracing.
+                               enteredMarkAssistForTracing = true
+                       }
                        trace.GCMarkAssistStart()
+                       // Set this *after* we trace the start, otherwise we may
+                       // emit an in-progress event for an assist we're about to start.
+                       gp.inMarkAssist = true
                        traceRelease(trace)
+               } else {
+                       gp.inMarkAssist = true
+               }
+               if goexperiment.ExecTracer2 {
+                       // In the new tracer, set enter mark assist tracing if we
+                       // ever pass this point, because we must manage inMarkAssist
+                       // correctly.
+                       //
+                       // See the comment on enteredMarkAssistForTracing.
+                       enteredMarkAssistForTracing = true
                }
        }
 
@@ -525,11 +593,24 @@ retry:
                // At this point either background GC has satisfied
                // this G's assist debt, or the GC cycle is over.
        }
-       if traced {
+       if enteredMarkAssistForTracing {
                trace := traceAcquire()
                if trace.ok() {
                        trace.GCMarkAssistDone()
+                       // Set this *after* we trace the end to make sure
+                       // that we emit an in-progress event if this is
+                       // the first event for the goroutine in the trace
+                       // or trace generation. Also, do this between
+                       // acquire/release because this is part of the
+                       // goroutine's trace state, and it must be atomic
+                       // with respect to the tracer.
+                       gp.inMarkAssist = false
                        traceRelease(trace)
+               } else {
+                       // This state is tracked even if tracing isn't enabled.
+                       // It's only used by the new tracer.
+                       // See the comment on enteredMarkAssistForTracing.
+                       gp.inMarkAssist = false
                }
        }
 }