Source file src/runtime/tracetime.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  // Trace time and clock.
     6  
     7  package runtime
     8  
     9  import (
    10  	"internal/trace/tracev2"
    11  	_ "unsafe"
    12  )
    13  
    14  // Timestamps in trace are produced through nanotime and divided by traceTimeDiv.
    15  // This makes absolute values of timestamp diffs smaller, and so they are
    16  // encoded in fewer bytes.
    17  //
    18  // The target resolution in all cases is 64 nanoseconds.
    19  // This is based on the fact that fundamentally the execution tracer won't emit
    20  // events more frequently than roughly every 200 ns or so, because that's roughly
    21  // how long it takes to call through the scheduler.
    22  // We could be more aggressive and bump this up to 128 ns while still getting
    23  // useful data, but the extra bit doesn't save us that much and the headroom is
    24  // nice to have.
    25  const traceTimeDiv = 64
    26  
    27  // traceTime represents a timestamp for the trace.
    28  type traceTime uint64
    29  
    30  // traceClockNow returns a monotonic timestamp in units of traceTimeDiv nanoseconds.
    31  //
    32  // nosplit because it's called from exitsyscall and various trace writing functions,
    33  // which are nosplit.
    34  //
    35  // traceClockNow is called by runtime/trace and golang.org/x/exp/trace using linkname.
    36  //
    37  //go:linkname traceClockNow
    38  //go:nosplit
    39  func traceClockNow() traceTime {
    40  	return traceTime(nanotime() / traceTimeDiv)
    41  }
    42  
    43  // traceClockUnitsPerSecond returns the number of trace clock units per
    44  // second that elapse.
    45  //
    46  //go:linkname traceClockUnitsPerSecond runtime/trace.runtime_traceClockUnitsPerSecond
    47  func traceClockUnitsPerSecond() uint64 {
    48  	return 1e9 / traceTimeDiv
    49  }
    50  
    51  func traceSyncBatch(gen uintptr, frequency uint64) {
    52  	w := unsafeTraceWriter(gen, nil)
    53  
    54  	// Ensure we have a place to write to.
    55  	w, _ = w.ensure(3 /* EvSync + EvFrequency + EvClockSnapshot */ + 5*traceBytesPerNumber /* frequency, timestamp, mono, sec, nsec */)
    56  
    57  	// Write out the sync batch event.
    58  	w.byte(byte(tracev2.EvSync))
    59  
    60  	// Write out the frequency event.
    61  	w.byte(byte(tracev2.EvFrequency))
    62  	w.varint(frequency)
    63  
    64  	// Write out the clock snapshot event.
    65  	sec, nsec, mono := time_now()
    66  	ts := traceClockNow()
    67  	if ts <= w.traceBuf.lastTime {
    68  		ts = w.traceBuf.lastTime + 1
    69  	}
    70  	tsDiff := uint64(ts - w.traceBuf.lastTime)
    71  	w.traceBuf.lastTime = ts
    72  	w.byte(byte(tracev2.EvClockSnapshot))
    73  	w.varint(tsDiff)
    74  	w.varint(uint64(mono))
    75  	w.varint(uint64(sec))
    76  	w.varint(uint64(nsec))
    77  
    78  	// Immediately flush the buffer.
    79  	systemstack(func() {
    80  		lock(&trace.lock)
    81  		traceBufFlush(w.traceBuf, gen)
    82  		unlock(&trace.lock)
    83  	})
    84  }
    85  

View as plain text