Source file src/runtime/trace2runtime.go

     1  // Copyright 2023 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  //go:build goexperiment.exectracer2
     6  
     7  // Runtime -> tracer API.
     8  
     9  package runtime
    10  
    11  import (
    12  	"runtime/internal/atomic"
    13  	_ "unsafe" // for go:linkname
    14  )
    15  
    16  // gTraceState is per-G state for the tracer.
    17  type gTraceState struct {
    18  	traceSchedResourceState
    19  }
    20  
    21  // reset resets the gTraceState for a new goroutine.
    22  func (s *gTraceState) reset() {
    23  	s.seq = [2]uint64{}
    24  	// N.B. s.statusTraced is managed and cleared separately.
    25  }
    26  
    27  // mTraceState is per-M state for the tracer.
    28  type mTraceState struct {
    29  	seqlock atomic.Uintptr // seqlock indicating that this M is writing to a trace buffer.
    30  	buf     [2]*traceBuf   // Per-M traceBuf for writing. Indexed by trace.gen%2.
    31  	link    *m             // Snapshot of alllink or freelink.
    32  }
    33  
    34  // pTraceState is per-P state for the tracer.
    35  type pTraceState struct {
    36  	traceSchedResourceState
    37  
    38  	// mSyscallID is the ID of the M this was bound to before entering a syscall.
    39  	mSyscallID int64
    40  
    41  	// maySweep indicates the sweep events should be traced.
    42  	// This is used to defer the sweep start event until a span
    43  	// has actually been swept.
    44  	maySweep bool
    45  
    46  	// inSweep indicates that at least one sweep event has been traced.
    47  	inSweep bool
    48  
    49  	// swept and reclaimed track the number of bytes swept and reclaimed
    50  	// by sweeping in the current sweep loop (while maySweep was true).
    51  	swept, reclaimed uintptr
    52  }
    53  
    54  // traceLockInit initializes global trace locks.
    55  func traceLockInit() {
    56  	// Sharing a lock rank here is fine because they should never be accessed
    57  	// together. If they are, we want to find out immediately.
    58  	lockInit(&trace.stringTab[0].lock, lockRankTraceStrings)
    59  	lockInit(&trace.stringTab[0].tab.lock, lockRankTraceStrings)
    60  	lockInit(&trace.stringTab[1].lock, lockRankTraceStrings)
    61  	lockInit(&trace.stringTab[1].tab.lock, lockRankTraceStrings)
    62  	lockInit(&trace.stackTab[0].tab.lock, lockRankTraceStackTab)
    63  	lockInit(&trace.stackTab[1].tab.lock, lockRankTraceStackTab)
    64  	lockInit(&trace.lock, lockRankTrace)
    65  }
    66  
    67  // lockRankMayTraceFlush records the lock ranking effects of a
    68  // potential call to traceFlush.
    69  //
    70  // nosplit because traceAcquire is nosplit.
    71  //
    72  //go:nosplit
    73  func lockRankMayTraceFlush() {
    74  	lockWithRankMayAcquire(&trace.lock, getLockRank(&trace.lock))
    75  }
    76  
    77  // traceBlockReason is an enumeration of reasons a goroutine might block.
    78  // This is the interface the rest of the runtime uses to tell the
    79  // tracer why a goroutine blocked. The tracer then propagates this information
    80  // into the trace however it sees fit.
    81  //
    82  // Note that traceBlockReasons should not be compared, since reasons that are
    83  // distinct by name may *not* be distinct by value.
    84  type traceBlockReason uint8
    85  
    86  const (
    87  	traceBlockGeneric traceBlockReason = iota
    88  	traceBlockForever
    89  	traceBlockNet
    90  	traceBlockSelect
    91  	traceBlockCondWait
    92  	traceBlockSync
    93  	traceBlockChanSend
    94  	traceBlockChanRecv
    95  	traceBlockGCMarkAssist
    96  	traceBlockGCSweep
    97  	traceBlockSystemGoroutine
    98  	traceBlockPreempted
    99  	traceBlockDebugCall
   100  	traceBlockUntilGCEnds
   101  	traceBlockSleep
   102  )
   103  
   104  var traceBlockReasonStrings = [...]string{
   105  	traceBlockGeneric:         "unspecified",
   106  	traceBlockForever:         "forever",
   107  	traceBlockNet:             "network",
   108  	traceBlockSelect:          "select",
   109  	traceBlockCondWait:        "sync.(*Cond).Wait",
   110  	traceBlockSync:            "sync",
   111  	traceBlockChanSend:        "chan send",
   112  	traceBlockChanRecv:        "chan receive",
   113  	traceBlockGCMarkAssist:    "GC mark assist wait for work",
   114  	traceBlockGCSweep:         "GC background sweeper wait",
   115  	traceBlockSystemGoroutine: "system goroutine wait",
   116  	traceBlockPreempted:       "preempted",
   117  	traceBlockDebugCall:       "wait for debug call",
   118  	traceBlockUntilGCEnds:     "wait until GC ends",
   119  	traceBlockSleep:           "sleep",
   120  }
   121  
   122  // traceGoStopReason is an enumeration of reasons a goroutine might yield.
   123  //
   124  // Note that traceGoStopReasons should not be compared, since reasons that are
   125  // distinct by name may *not* be distinct by value.
   126  type traceGoStopReason uint8
   127  
   128  const (
   129  	traceGoStopGeneric traceGoStopReason = iota
   130  	traceGoStopGoSched
   131  	traceGoStopPreempted
   132  )
   133  
   134  var traceGoStopReasonStrings = [...]string{
   135  	traceGoStopGeneric:   "unspecified",
   136  	traceGoStopGoSched:   "runtime.Gosched",
   137  	traceGoStopPreempted: "preempted",
   138  }
   139  
   140  // traceEnabled returns true if the trace is currently enabled.
   141  //
   142  //go:nosplit
   143  func traceEnabled() bool {
   144  	return trace.gen.Load() != 0
   145  }
   146  
   147  // traceShuttingDown returns true if the trace is currently shutting down.
   148  func traceShuttingDown() bool {
   149  	return trace.shutdown.Load()
   150  }
   151  
   152  // traceLocker represents an M writing trace events. While a traceLocker value
   153  // is valid, the tracer observes all operations on the G/M/P or trace events being
   154  // written as happening atomically.
   155  type traceLocker struct {
   156  	mp  *m
   157  	gen uintptr
   158  }
   159  
   160  // debugTraceReentrancy checks if the trace is reentrant.
   161  //
   162  // This is optional because throwing in a function makes it instantly
   163  // not inlineable, and we want traceAcquire to be inlineable for
   164  // low overhead when the trace is disabled.
   165  const debugTraceReentrancy = false
   166  
   167  // traceAcquire prepares this M for writing one or more trace events.
   168  //
   169  // nosplit because it's called on the syscall path when stack movement is forbidden.
   170  //
   171  //go:nosplit
   172  func traceAcquire() traceLocker {
   173  	if !traceEnabled() {
   174  		return traceLocker{}
   175  	}
   176  	return traceAcquireEnabled()
   177  }
   178  
   179  // traceAcquireEnabled is the traceEnabled path for traceAcquire. It's explicitly
   180  // broken out to make traceAcquire inlineable to keep the overhead of the tracer
   181  // when it's disabled low.
   182  //
   183  // nosplit because it's called by traceAcquire, which is nosplit.
   184  //
   185  //go:nosplit
   186  func traceAcquireEnabled() traceLocker {
   187  	// Any time we acquire a traceLocker, we may flush a trace buffer. But
   188  	// buffer flushes are rare. Record the lock edge even if it doesn't happen
   189  	// this time.
   190  	lockRankMayTraceFlush()
   191  
   192  	// Prevent preemption.
   193  	mp := acquirem()
   194  
   195  	// Acquire the trace seqlock. This prevents traceAdvance from moving forward
   196  	// until all Ms are observed to be outside of their seqlock critical section.
   197  	//
   198  	// Note: The seqlock is mutated here and also in traceCPUSample. If you update
   199  	// usage of the seqlock here, make sure to also look at what traceCPUSample is
   200  	// doing.
   201  	seq := mp.trace.seqlock.Add(1)
   202  	if debugTraceReentrancy && seq%2 != 1 {
   203  		throw("bad use of trace.seqlock or tracer is reentrant")
   204  	}
   205  
   206  	// N.B. This load of gen appears redundant with the one in traceEnabled.
   207  	// However, it's very important that the gen we use for writing to the trace
   208  	// is acquired under a traceLocker so traceAdvance can make sure no stale
   209  	// gen values are being used.
   210  	//
   211  	// Because we're doing this load again, it also means that the trace
   212  	// might end up being disabled when we load it. In that case we need to undo
   213  	// what we did and bail.
   214  	gen := trace.gen.Load()
   215  	if gen == 0 {
   216  		mp.trace.seqlock.Add(1)
   217  		releasem(mp)
   218  		return traceLocker{}
   219  	}
   220  	return traceLocker{mp, gen}
   221  }
   222  
   223  // ok returns true if the traceLocker is valid (i.e. tracing is enabled).
   224  //
   225  // nosplit because it's called on the syscall path when stack movement is forbidden.
   226  //
   227  //go:nosplit
   228  func (tl traceLocker) ok() bool {
   229  	return tl.gen != 0
   230  }
   231  
   232  // traceRelease indicates that this M is done writing trace events.
   233  //
   234  // nosplit because it's called on the syscall path when stack movement is forbidden.
   235  //
   236  //go:nosplit
   237  func traceRelease(tl traceLocker) {
   238  	seq := tl.mp.trace.seqlock.Add(1)
   239  	if debugTraceReentrancy && seq%2 != 0 {
   240  		print("runtime: seq=", seq, "\n")
   241  		throw("bad use of trace.seqlock")
   242  	}
   243  	releasem(tl.mp)
   244  }
   245  
   246  // traceExitingSyscall marks a goroutine as exiting the syscall slow path.
   247  //
   248  // Must be paired with a traceExitedSyscall call.
   249  func traceExitingSyscall() {
   250  	trace.exitingSyscall.Add(1)
   251  }
   252  
   253  // traceExitedSyscall marks a goroutine as having exited the syscall slow path.
   254  func traceExitedSyscall() {
   255  	trace.exitingSyscall.Add(-1)
   256  }
   257  
   258  // Gomaxprocs emits a ProcsChange event.
   259  func (tl traceLocker) Gomaxprocs(procs int32) {
   260  	tl.eventWriter(traceGoRunning, traceProcRunning).commit(traceEvProcsChange, traceArg(procs), tl.stack(1))
   261  }
   262  
   263  // ProcStart traces a ProcStart event.
   264  //
   265  // Must be called with a valid P.
   266  func (tl traceLocker) ProcStart() {
   267  	pp := tl.mp.p.ptr()
   268  	// Procs are typically started within the scheduler when there is no user goroutine. If there is a user goroutine,
   269  	// it must be in _Gsyscall because the only time a goroutine is allowed to have its Proc moved around from under it
   270  	// is during a syscall.
   271  	tl.eventWriter(traceGoSyscall, traceProcIdle).commit(traceEvProcStart, traceArg(pp.id), pp.trace.nextSeq(tl.gen))
   272  }
   273  
   274  // ProcStop traces a ProcStop event.
   275  func (tl traceLocker) ProcStop(pp *p) {
   276  	// The only time a goroutine is allowed to have its Proc moved around
   277  	// from under it is during a syscall.
   278  	tl.eventWriter(traceGoSyscall, traceProcRunning).commit(traceEvProcStop)
   279  }
   280  
   281  // GCActive traces a GCActive event.
   282  //
   283  // Must be emitted by an actively running goroutine on an active P. This restriction can be changed
   284  // easily and only depends on where it's currently called.
   285  func (tl traceLocker) GCActive() {
   286  	tl.eventWriter(traceGoRunning, traceProcRunning).commit(traceEvGCActive, traceArg(trace.seqGC))
   287  	// N.B. Only one GC can be running at a time, so this is naturally
   288  	// serialized by the caller.
   289  	trace.seqGC++
   290  }
   291  
   292  // GCStart traces a GCBegin event.
   293  //
   294  // Must be emitted by an actively running goroutine on an active P. This restriction can be changed
   295  // easily and only depends on where it's currently called.
   296  func (tl traceLocker) GCStart() {
   297  	tl.eventWriter(traceGoRunning, traceProcRunning).commit(traceEvGCBegin, traceArg(trace.seqGC), tl.stack(3))
   298  	// N.B. Only one GC can be running at a time, so this is naturally
   299  	// serialized by the caller.
   300  	trace.seqGC++
   301  }
   302  
   303  // GCDone traces a GCEnd event.
   304  //
   305  // Must be emitted by an actively running goroutine on an active P. This restriction can be changed
   306  // easily and only depends on where it's currently called.
   307  func (tl traceLocker) GCDone() {
   308  	tl.eventWriter(traceGoRunning, traceProcRunning).commit(traceEvGCEnd, traceArg(trace.seqGC))
   309  	// N.B. Only one GC can be running at a time, so this is naturally
   310  	// serialized by the caller.
   311  	trace.seqGC++
   312  }
   313  
   314  // STWStart traces a STWBegin event.
   315  func (tl traceLocker) STWStart(reason stwReason) {
   316  	// Although the current P may be in _Pgcstop here, we model the P as running during the STW. This deviates from the
   317  	// runtime's state tracking, but it's more accurate and doesn't result in any loss of information.
   318  	tl.eventWriter(traceGoRunning, traceProcRunning).commit(traceEvSTWBegin, tl.string(reason.String()), tl.stack(2))
   319  }
   320  
   321  // STWDone traces a STWEnd event.
   322  func (tl traceLocker) STWDone() {
   323  	// Although the current P may be in _Pgcstop here, we model the P as running during the STW. This deviates from the
   324  	// runtime's state tracking, but it's more accurate and doesn't result in any loss of information.
   325  	tl.eventWriter(traceGoRunning, traceProcRunning).commit(traceEvSTWEnd)
   326  }
   327  
   328  // GCSweepStart prepares to trace a sweep loop. This does not
   329  // emit any events until traceGCSweepSpan is called.
   330  //
   331  // GCSweepStart must be paired with traceGCSweepDone and there
   332  // must be no preemption points between these two calls.
   333  //
   334  // Must be called with a valid P.
   335  func (tl traceLocker) GCSweepStart() {
   336  	// Delay the actual GCSweepBegin event until the first span
   337  	// sweep. If we don't sweep anything, don't emit any events.
   338  	pp := tl.mp.p.ptr()
   339  	if pp.trace.maySweep {
   340  		throw("double traceGCSweepStart")
   341  	}
   342  	pp.trace.maySweep, pp.trace.swept, pp.trace.reclaimed = true, 0, 0
   343  }
   344  
   345  // GCSweepSpan traces the sweep of a single span. If this is
   346  // the first span swept since traceGCSweepStart was called, this
   347  // will emit a GCSweepBegin event.
   348  //
   349  // This may be called outside a traceGCSweepStart/traceGCSweepDone
   350  // pair; however, it will not emit any trace events in this case.
   351  //
   352  // Must be called with a valid P.
   353  func (tl traceLocker) GCSweepSpan(bytesSwept uintptr) {
   354  	pp := tl.mp.p.ptr()
   355  	if pp.trace.maySweep {
   356  		if pp.trace.swept == 0 {
   357  			tl.eventWriter(traceGoRunning, traceProcRunning).commit(traceEvGCSweepBegin, tl.stack(1))
   358  			pp.trace.inSweep = true
   359  		}
   360  		pp.trace.swept += bytesSwept
   361  	}
   362  }
   363  
   364  // GCSweepDone finishes tracing a sweep loop. If any memory was
   365  // swept (i.e. traceGCSweepSpan emitted an event) then this will emit
   366  // a GCSweepEnd event.
   367  //
   368  // Must be called with a valid P.
   369  func (tl traceLocker) GCSweepDone() {
   370  	pp := tl.mp.p.ptr()
   371  	if !pp.trace.maySweep {
   372  		throw("missing traceGCSweepStart")
   373  	}
   374  	if pp.trace.inSweep {
   375  		tl.eventWriter(traceGoRunning, traceProcRunning).commit(traceEvGCSweepEnd, traceArg(pp.trace.swept), traceArg(pp.trace.reclaimed))
   376  		pp.trace.inSweep = false
   377  	}
   378  	pp.trace.maySweep = false
   379  }
   380  
   381  // GCMarkAssistStart emits a MarkAssistBegin event.
   382  func (tl traceLocker) GCMarkAssistStart() {
   383  	tl.eventWriter(traceGoRunning, traceProcRunning).commit(traceEvGCMarkAssistBegin, tl.stack(1))
   384  }
   385  
   386  // GCMarkAssistDone emits a MarkAssistEnd event.
   387  func (tl traceLocker) GCMarkAssistDone() {
   388  	tl.eventWriter(traceGoRunning, traceProcRunning).commit(traceEvGCMarkAssistEnd)
   389  }
   390  
   391  // GoCreate emits a GoCreate event.
   392  func (tl traceLocker) GoCreate(newg *g, pc uintptr) {
   393  	newg.trace.setStatusTraced(tl.gen)
   394  	tl.eventWriter(traceGoRunning, traceProcRunning).commit(traceEvGoCreate, traceArg(newg.goid), tl.startPC(pc), tl.stack(2))
   395  }
   396  
   397  // GoStart emits a GoStart event.
   398  //
   399  // Must be called with a valid P.
   400  func (tl traceLocker) GoStart() {
   401  	gp := getg().m.curg
   402  	pp := gp.m.p
   403  	w := tl.eventWriter(traceGoRunnable, traceProcRunning)
   404  	w = w.write(traceEvGoStart, traceArg(gp.goid), gp.trace.nextSeq(tl.gen))
   405  	if pp.ptr().gcMarkWorkerMode != gcMarkWorkerNotWorker {
   406  		w = w.write(traceEvGoLabel, trace.markWorkerLabels[tl.gen%2][pp.ptr().gcMarkWorkerMode])
   407  	}
   408  	w.end()
   409  }
   410  
   411  // GoEnd emits a GoDestroy event.
   412  //
   413  // TODO(mknyszek): Rename this to GoDestroy.
   414  func (tl traceLocker) GoEnd() {
   415  	tl.eventWriter(traceGoRunning, traceProcRunning).commit(traceEvGoDestroy)
   416  }
   417  
   418  // GoSched emits a GoStop event with a GoSched reason.
   419  func (tl traceLocker) GoSched() {
   420  	tl.GoStop(traceGoStopGoSched)
   421  }
   422  
   423  // GoPreempt emits a GoStop event with a GoPreempted reason.
   424  func (tl traceLocker) GoPreempt() {
   425  	tl.GoStop(traceGoStopPreempted)
   426  }
   427  
   428  // GoStop emits a GoStop event with the provided reason.
   429  func (tl traceLocker) GoStop(reason traceGoStopReason) {
   430  	tl.eventWriter(traceGoRunning, traceProcRunning).commit(traceEvGoStop, traceArg(trace.goStopReasons[tl.gen%2][reason]), tl.stack(1))
   431  }
   432  
   433  // GoPark emits a GoBlock event with the provided reason.
   434  //
   435  // TODO(mknyszek): Replace traceBlockReason with waitReason. It's silly
   436  // that we have both, and waitReason is way more descriptive.
   437  func (tl traceLocker) GoPark(reason traceBlockReason, skip int) {
   438  	tl.eventWriter(traceGoRunning, traceProcRunning).commit(traceEvGoBlock, traceArg(trace.goBlockReasons[tl.gen%2][reason]), tl.stack(skip))
   439  }
   440  
   441  // GoUnpark emits a GoUnblock event.
   442  func (tl traceLocker) GoUnpark(gp *g, skip int) {
   443  	// Emit a GoWaiting status if necessary for the unblocked goroutine.
   444  	w := tl.eventWriter(traceGoRunning, traceProcRunning)
   445  	if !gp.trace.statusWasTraced(tl.gen) && gp.trace.acquireStatus(tl.gen) {
   446  		// Careful: don't use the event writer. We never want status or in-progress events
   447  		// to trigger more in-progress events.
   448  		w.w = w.w.writeGoStatus(gp.goid, -1, traceGoWaiting, gp.inMarkAssist)
   449  	}
   450  	w.commit(traceEvGoUnblock, traceArg(gp.goid), gp.trace.nextSeq(tl.gen), tl.stack(skip))
   451  }
   452  
   453  // GoSysCall emits a GoSyscallBegin event.
   454  //
   455  // Must be called with a valid P.
   456  func (tl traceLocker) GoSysCall() {
   457  	var skip int
   458  	switch {
   459  	case tracefpunwindoff():
   460  		// Unwind by skipping 1 frame relative to gp.syscallsp which is captured 3
   461  		// results by hard coding the number of frames in between our caller and the
   462  		// actual syscall, see cases below.
   463  		// TODO(felixge): Implement gp.syscallbp to avoid this workaround?
   464  		skip = 1
   465  	case GOOS == "solaris" || GOOS == "illumos":
   466  		// These platforms don't use a libc_read_trampoline.
   467  		skip = 3
   468  	default:
   469  		// Skip the extra trampoline frame used on most systems.
   470  		skip = 4
   471  	}
   472  	// Scribble down the M that the P is currently attached to.
   473  	pp := tl.mp.p.ptr()
   474  	pp.trace.mSyscallID = int64(tl.mp.procid)
   475  	tl.eventWriter(traceGoRunning, traceProcRunning).commit(traceEvGoSyscallBegin, pp.trace.nextSeq(tl.gen), tl.stack(skip))
   476  }
   477  
   478  // GoSysExit emits a GoSyscallEnd event, possibly along with a GoSyscallBlocked event
   479  // if lostP is true.
   480  //
   481  // lostP must be true in all cases that a goroutine loses its P during a syscall.
   482  // This means it's not sufficient to check if it has no P. In particular, it needs to be
   483  // true in the following cases:
   484  // - The goroutine lost its P, it ran some other code, and then got it back. It's now running with that P.
   485  // - The goroutine lost its P and was unable to reacquire it, and is now running without a P.
   486  // - The goroutine lost its P and acquired a different one, and is now running with that P.
   487  func (tl traceLocker) GoSysExit(lostP bool) {
   488  	ev := traceEvGoSyscallEnd
   489  	procStatus := traceProcSyscall // Procs implicitly enter traceProcSyscall on GoSyscallBegin.
   490  	if lostP {
   491  		ev = traceEvGoSyscallEndBlocked
   492  		procStatus = traceProcRunning // If a G has a P when emitting this event, it reacquired a P and is indeed running.
   493  	} else {
   494  		tl.mp.p.ptr().trace.mSyscallID = -1
   495  	}
   496  	tl.eventWriter(traceGoSyscall, procStatus).commit(ev)
   497  }
   498  
   499  // ProcSteal indicates that our current M stole a P from another M.
   500  //
   501  // inSyscall indicates that we're stealing the P from a syscall context.
   502  //
   503  // The caller must have ownership of pp.
   504  func (tl traceLocker) ProcSteal(pp *p, inSyscall bool) {
   505  	// Grab the M ID we stole from.
   506  	mStolenFrom := pp.trace.mSyscallID
   507  	pp.trace.mSyscallID = -1
   508  
   509  	// The status of the proc and goroutine, if we need to emit one here, is not evident from the
   510  	// context of just emitting this event alone. There are two cases. Either we're trying to steal
   511  	// the P just to get its attention (e.g. STW or sysmon retake) or we're trying to steal a P for
   512  	// ourselves specifically to keep running. The two contexts look different, but can be summarized
   513  	// fairly succinctly. In the former, we're a regular running goroutine and proc, if we have either.
   514  	// In the latter, we're a goroutine in a syscall.
   515  	goStatus := traceGoRunning
   516  	procStatus := traceProcRunning
   517  	if inSyscall {
   518  		goStatus = traceGoSyscall
   519  		procStatus = traceProcSyscallAbandoned
   520  	}
   521  	w := tl.eventWriter(goStatus, procStatus)
   522  
   523  	// Emit the status of the P we're stealing. We may have *just* done this when creating the event
   524  	// writer but it's not guaranteed, even if inSyscall is true. Although it might seem like from a
   525  	// syscall context we're always stealing a P for ourselves, we may have not wired it up yet (so
   526  	// it wouldn't be visible to eventWriter) or we may not even intend to wire it up to ourselves
   527  	// at all (e.g. entersyscall_gcwait).
   528  	if !pp.trace.statusWasTraced(tl.gen) && pp.trace.acquireStatus(tl.gen) {
   529  		// Careful: don't use the event writer. We never want status or in-progress events
   530  		// to trigger more in-progress events.
   531  		w.w = w.w.writeProcStatus(uint64(pp.id), traceProcSyscallAbandoned, pp.trace.inSweep)
   532  	}
   533  	w.commit(traceEvProcSteal, traceArg(pp.id), pp.trace.nextSeq(tl.gen), traceArg(mStolenFrom))
   534  }
   535  
   536  // GoSysBlock is a no-op in the new tracer.
   537  func (tl traceLocker) GoSysBlock(pp *p) {
   538  }
   539  
   540  // HeapAlloc emits a HeapAlloc event.
   541  func (tl traceLocker) HeapAlloc(live uint64) {
   542  	tl.eventWriter(traceGoRunning, traceProcRunning).commit(traceEvHeapAlloc, traceArg(live))
   543  }
   544  
   545  // HeapGoal reads the current heap goal and emits a HeapGoal event.
   546  func (tl traceLocker) HeapGoal() {
   547  	heapGoal := gcController.heapGoal()
   548  	if heapGoal == ^uint64(0) {
   549  		// Heap-based triggering is disabled.
   550  		heapGoal = 0
   551  	}
   552  	tl.eventWriter(traceGoRunning, traceProcRunning).commit(traceEvHeapGoal, traceArg(heapGoal))
   553  }
   554  
   555  // OneNewExtraM is a no-op in the new tracer. This is worth keeping around though because
   556  // it's a good place to insert a thread-level event about the new extra M.
   557  func (tl traceLocker) OneNewExtraM(_ *g) {
   558  }
   559  
   560  // GoCreateSyscall indicates that a goroutine has transitioned from dead to GoSyscall.
   561  //
   562  // Unlike GoCreate, the caller must be running on gp.
   563  //
   564  // This occurs when C code calls into Go. On pthread platforms it occurs only when
   565  // a C thread calls into Go code for the first time.
   566  func (tl traceLocker) GoCreateSyscall(gp *g) {
   567  	// N.B. We should never trace a status for this goroutine (which we're currently running on),
   568  	// since we want this to appear like goroutine creation.
   569  	gp.trace.setStatusTraced(tl.gen)
   570  	tl.eventWriter(traceGoBad, traceProcBad).commit(traceEvGoCreateSyscall, traceArg(gp.goid))
   571  }
   572  
   573  // GoDestroySyscall indicates that a goroutine has transitioned from GoSyscall to dead.
   574  //
   575  // Must not have a P.
   576  //
   577  // This occurs when Go code returns back to C. On pthread platforms it occurs only when
   578  // the C thread is destroyed.
   579  func (tl traceLocker) GoDestroySyscall() {
   580  	// N.B. If we trace a status here, we must never have a P, and we must be on a goroutine
   581  	// that is in the syscall state.
   582  	tl.eventWriter(traceGoSyscall, traceProcBad).commit(traceEvGoDestroySyscall)
   583  }
   584  
   585  // To access runtime functions from runtime/trace.
   586  // See runtime/trace/annotation.go
   587  
   588  // trace_userTaskCreate emits a UserTaskCreate event.
   589  //
   590  //go:linkname trace_userTaskCreate runtime/trace.userTaskCreate
   591  func trace_userTaskCreate(id, parentID uint64, taskType string) {
   592  	tl := traceAcquire()
   593  	if !tl.ok() {
   594  		// Need to do this check because the caller won't have it.
   595  		return
   596  	}
   597  	tl.eventWriter(traceGoRunning, traceProcRunning).commit(traceEvUserTaskBegin, traceArg(id), traceArg(parentID), tl.string(taskType), tl.stack(3))
   598  	traceRelease(tl)
   599  }
   600  
   601  // trace_userTaskEnd emits a UserTaskEnd event.
   602  //
   603  //go:linkname trace_userTaskEnd runtime/trace.userTaskEnd
   604  func trace_userTaskEnd(id uint64) {
   605  	tl := traceAcquire()
   606  	if !tl.ok() {
   607  		// Need to do this check because the caller won't have it.
   608  		return
   609  	}
   610  	tl.eventWriter(traceGoRunning, traceProcRunning).commit(traceEvUserTaskEnd, traceArg(id), tl.stack(2))
   611  	traceRelease(tl)
   612  }
   613  
   614  // trace_userTaskEnd emits a UserRegionBegin or UserRegionEnd event,
   615  // depending on mode (0 == Begin, 1 == End).
   616  //
   617  // TODO(mknyszek): Just make this two functions.
   618  //
   619  //go:linkname trace_userRegion runtime/trace.userRegion
   620  func trace_userRegion(id, mode uint64, name string) {
   621  	tl := traceAcquire()
   622  	if !tl.ok() {
   623  		// Need to do this check because the caller won't have it.
   624  		return
   625  	}
   626  	var ev traceEv
   627  	switch mode {
   628  	case 0:
   629  		ev = traceEvUserRegionBegin
   630  	case 1:
   631  		ev = traceEvUserRegionEnd
   632  	default:
   633  		return
   634  	}
   635  	tl.eventWriter(traceGoRunning, traceProcRunning).commit(ev, traceArg(id), tl.string(name), tl.stack(3))
   636  	traceRelease(tl)
   637  }
   638  
   639  // trace_userTaskEnd emits a UserRegionBegin or UserRegionEnd event.
   640  //
   641  //go:linkname trace_userLog runtime/trace.userLog
   642  func trace_userLog(id uint64, category, message string) {
   643  	tl := traceAcquire()
   644  	if !tl.ok() {
   645  		// Need to do this check because the caller won't have it.
   646  		return
   647  	}
   648  	tl.eventWriter(traceGoRunning, traceProcRunning).commit(traceEvUserLog, traceArg(id), tl.string(category), tl.uniqueString(message), tl.stack(3))
   649  	traceRelease(tl)
   650  }
   651  
   652  // traceProcFree is called when a P is destroyed.
   653  //
   654  // This must run on the system stack to match the old tracer.
   655  //
   656  //go:systemstack
   657  func traceProcFree(_ *p) {
   658  }
   659  
   660  // traceThreadDestroy is called when a thread is removed from
   661  // sched.freem.
   662  //
   663  // mp must not be able to emit trace events anymore.
   664  //
   665  // sched.lock must be held to synchronize with traceAdvance.
   666  func traceThreadDestroy(mp *m) {
   667  	assertLockHeld(&sched.lock)
   668  
   669  	// Flush all outstanding buffers to maintain the invariant
   670  	// that an M only has active buffers while on sched.freem
   671  	// or allm.
   672  	//
   673  	// Perform a traceAcquire/traceRelease on behalf of mp to
   674  	// synchronize with the tracer trying to flush our buffer
   675  	// as well.
   676  	seq := mp.trace.seqlock.Add(1)
   677  	if debugTraceReentrancy && seq%2 != 1 {
   678  		throw("bad use of trace.seqlock or tracer is reentrant")
   679  	}
   680  	systemstack(func() {
   681  		lock(&trace.lock)
   682  		for i := range mp.trace.buf {
   683  			if mp.trace.buf[i] != nil {
   684  				// N.B. traceBufFlush accepts a generation, but it
   685  				// really just cares about gen%2.
   686  				traceBufFlush(mp.trace.buf[i], uintptr(i))
   687  				mp.trace.buf[i] = nil
   688  			}
   689  		}
   690  		unlock(&trace.lock)
   691  	})
   692  	seq1 := mp.trace.seqlock.Add(1)
   693  	if seq1 != seq+1 {
   694  		print("runtime: seq1=", seq1, "\n")
   695  		throw("bad use of trace.seqlock")
   696  	}
   697  }
   698  
   699  // Not used in the new tracer; solely for compatibility with the old tracer.
   700  // nosplit because it's called from exitsyscall without a P.
   701  //
   702  //go:nosplit
   703  func (_ traceLocker) RecordSyscallExitedTime(_ *g, _ *p) {
   704  }
   705  

View as plain text