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