blob: c5e3c94136946b0202340097f0eeb86f3b8f3aa9 [file] [log] [blame]
// Copyright 2023 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package tracev2
// Event types in the trace, args are given in square brackets.
//
// Naming scheme:
// - Time range event pairs have suffixes "Begin" and "End".
// - "Start", "Stop", "Create", "Destroy", "Block", "Unblock"
// are suffixes reserved for scheduling resources.
//
// NOTE: If you add an event type, make sure you also update all
// tables in this file!
const (
EvNone EventType = iota // unused
// Structural events.
EvEventBatch // start of per-M batch of events [generation, M ID, timestamp, batch length]
EvStacks // start of a section of the stack table [...EvStack]
EvStack // stack table entry [ID, ...{PC, func string ID, file string ID, line #}]
EvStrings // start of a section of the string dictionary [...EvString]
EvString // string dictionary entry [ID, length, string]
EvCPUSamples // start of a section of CPU samples [...EvCPUSample]
EvCPUSample // CPU profiling sample [timestamp, M ID, P ID, goroutine ID, stack ID]
EvFrequency // timestamp units per sec [freq]
// Procs.
EvProcsChange // current value of GOMAXPROCS [timestamp, GOMAXPROCS, stack ID]
EvProcStart // start of P [timestamp, P ID, P seq]
EvProcStop // stop of P [timestamp]
EvProcSteal // P was stolen [timestamp, P ID, P seq, M ID]
EvProcStatus // P status at the start of a generation [timestamp, P ID, status]
// Goroutines.
EvGoCreate // goroutine creation [timestamp, new goroutine ID, new stack ID, stack ID]
EvGoCreateSyscall // goroutine appears in syscall (cgo callback) [timestamp, new goroutine ID]
EvGoStart // goroutine starts running [timestamp, goroutine ID, goroutine seq]
EvGoDestroy // goroutine ends [timestamp]
EvGoDestroySyscall // goroutine ends in syscall (cgo callback) [timestamp]
EvGoStop // goroutine yields its time, but is runnable [timestamp, reason, stack ID]
EvGoBlock // goroutine blocks [timestamp, reason, stack ID]
EvGoUnblock // goroutine is unblocked [timestamp, goroutine ID, goroutine seq, stack ID]
EvGoSyscallBegin // syscall enter [timestamp, P seq, stack ID]
EvGoSyscallEnd // syscall exit [timestamp]
EvGoSyscallEndBlocked // syscall exit and it blocked at some point [timestamp]
EvGoStatus // goroutine status at the start of a generation [timestamp, goroutine ID, M ID, status]
// STW.
EvSTWBegin // STW start [timestamp, kind, stack ID]
EvSTWEnd // STW done [timestamp]
// GC events.
EvGCActive // GC active [timestamp, seq]
EvGCBegin // GC start [timestamp, seq, stack ID]
EvGCEnd // GC done [timestamp, seq]
EvGCSweepActive // GC sweep active [timestamp, P ID]
EvGCSweepBegin // GC sweep start [timestamp, stack ID]
EvGCSweepEnd // GC sweep done [timestamp, swept bytes, reclaimed bytes]
EvGCMarkAssistActive // GC mark assist active [timestamp, goroutine ID]
EvGCMarkAssistBegin // GC mark assist start [timestamp, stack ID]
EvGCMarkAssistEnd // GC mark assist done [timestamp]
EvHeapAlloc // gcController.heapLive change [timestamp, heap alloc in bytes]
EvHeapGoal // gcController.heapGoal() change [timestamp, heap goal in bytes]
// Annotations.
EvGoLabel // apply string label to current running goroutine [timestamp, label string ID]
EvUserTaskBegin // trace.NewTask [timestamp, internal task ID, internal parent task ID, name string ID, stack ID]
EvUserTaskEnd // end of a task [timestamp, internal task ID, stack ID]
EvUserRegionBegin // trace.{Start,With}Region [timestamp, internal task ID, name string ID, stack ID]
EvUserRegionEnd // trace.{End,With}Region [timestamp, internal task ID, name string ID, stack ID]
EvUserLog // trace.Log [timestamp, internal task ID, key string ID, value string ID, stack]
// Coroutines. Added in Go 1.23.
EvGoSwitch // goroutine switch (coroswitch) [timestamp, goroutine ID, goroutine seq]
EvGoSwitchDestroy // goroutine switch and destroy [timestamp, goroutine ID, goroutine seq]
EvGoCreateBlocked // goroutine creation (starts blocked) [timestamp, new goroutine ID, new stack ID, stack ID]
// GoStatus with stack. Added in Go 1.23.
EvGoStatusStack // goroutine status at the start of a generation, with a stack [timestamp, goroutine ID, M ID, status, stack ID]
// Batch event for an experimental batch with a custom format. Added in Go 1.23.
EvExperimentalBatch // start of extra data [experiment ID, generation, M ID, timestamp, batch length, batch data...]
// Sync batch. Added in Go 1.25. Previously a lone EvFrequency event.
EvSync // start of a sync batch [...EvFrequency|EvClockSnapshot]
EvClockSnapshot // snapshot of trace, mono and wall clocks [timestamp, mono, sec, nsec]
// In-band end-of-generation signal. Added in Go 1.26.
// Used in Go 1.25 only internally.
EvEndOfGeneration
NumEvents
)
func (ev EventType) Experimental() bool {
return ev > MaxEvent && ev < MaxExperimentalEvent
}
// Experiments.
const (
// AllocFree is the alloc-free events experiment.
AllocFree Experiment = 1 + iota
NumExperiments
)
func Experiments() []string {
return experiments[:]
}
var experiments = [...]string{
NoExperiment: "None",
AllocFree: "AllocFree",
}
// Experimental events.
const (
MaxEvent EventType = 127 + iota
// Experimental events for AllocFree.
// Experimental heap span events. Added in Go 1.23.
EvSpan // heap span exists [timestamp, id, npages, type/class]
EvSpanAlloc // heap span alloc [timestamp, id, npages, type/class]
EvSpanFree // heap span free [timestamp, id]
// Experimental heap object events. Added in Go 1.23.
EvHeapObject // heap object exists [timestamp, id, type]
EvHeapObjectAlloc // heap object alloc [timestamp, id, type]
EvHeapObjectFree // heap object free [timestamp, id]
// Experimental goroutine stack events. Added in Go 1.23.
EvGoroutineStack // stack exists [timestamp, id, order]
EvGoroutineStackAlloc // stack alloc [timestamp, id, order]
EvGoroutineStackFree // stack free [timestamp, id]
MaxExperimentalEvent
)
const NumExperimentalEvents = MaxExperimentalEvent - MaxEvent
// MaxTimedEventArgs is the maximum number of arguments for timed events.
const MaxTimedEventArgs = 5
func Specs() []EventSpec {
return specs[:]
}
var specs = [...]EventSpec{
// "Structural" Events.
EvEventBatch: {
Name: "EventBatch",
Args: []string{"gen", "m", "time", "size"},
},
EvStacks: {
Name: "Stacks",
},
EvStack: {
Name: "Stack",
Args: []string{"id", "nframes"},
IsStack: true,
},
EvStrings: {
Name: "Strings",
},
EvString: {
Name: "String",
Args: []string{"id"},
HasData: true,
},
EvCPUSamples: {
Name: "CPUSamples",
},
EvCPUSample: {
Name: "CPUSample",
Args: []string{"time", "m", "p", "g", "stack"},
// N.B. There's clearly a timestamp here, but these Events
// are special in that they don't appear in the regular
// M streams.
StackIDs: []int{4},
},
EvFrequency: {
Name: "Frequency",
Args: []string{"freq"},
},
EvExperimentalBatch: {
Name: "ExperimentalBatch",
Args: []string{"exp", "gen", "m", "time"},
HasData: true, // Easier to represent for raw readers.
},
EvSync: {
Name: "Sync",
},
EvEndOfGeneration: {
Name: "EndOfGeneration",
},
// "Timed" Events.
EvProcsChange: {
Name: "ProcsChange",
Args: []string{"dt", "procs_value", "stack"},
IsTimedEvent: true,
StackIDs: []int{2},
},
EvProcStart: {
Name: "ProcStart",
Args: []string{"dt", "p", "p_seq"},
IsTimedEvent: true,
},
EvProcStop: {
Name: "ProcStop",
Args: []string{"dt"},
IsTimedEvent: true,
},
EvProcSteal: {
Name: "ProcSteal",
Args: []string{"dt", "p", "p_seq", "m"},
IsTimedEvent: true,
},
EvProcStatus: {
Name: "ProcStatus",
Args: []string{"dt", "p", "pstatus"},
IsTimedEvent: true,
},
EvGoCreate: {
Name: "GoCreate",
Args: []string{"dt", "new_g", "new_stack", "stack"},
IsTimedEvent: true,
StackIDs: []int{3, 2},
},
EvGoCreateSyscall: {
Name: "GoCreateSyscall",
Args: []string{"dt", "new_g"},
IsTimedEvent: true,
},
EvGoStart: {
Name: "GoStart",
Args: []string{"dt", "g", "g_seq"},
IsTimedEvent: true,
},
EvGoDestroy: {
Name: "GoDestroy",
Args: []string{"dt"},
IsTimedEvent: true,
},
EvGoDestroySyscall: {
Name: "GoDestroySyscall",
Args: []string{"dt"},
IsTimedEvent: true,
},
EvGoStop: {
Name: "GoStop",
Args: []string{"dt", "reason_string", "stack"},
IsTimedEvent: true,
StackIDs: []int{2},
StringIDs: []int{1},
},
EvGoBlock: {
Name: "GoBlock",
Args: []string{"dt", "reason_string", "stack"},
IsTimedEvent: true,
StackIDs: []int{2},
StringIDs: []int{1},
},
EvGoUnblock: {
Name: "GoUnblock",
Args: []string{"dt", "g", "g_seq", "stack"},
IsTimedEvent: true,
StackIDs: []int{3},
},
EvGoSyscallBegin: {
Name: "GoSyscallBegin",
Args: []string{"dt", "p_seq", "stack"},
IsTimedEvent: true,
StackIDs: []int{2},
},
EvGoSyscallEnd: {
Name: "GoSyscallEnd",
Args: []string{"dt"},
StartEv: EvGoSyscallBegin,
IsTimedEvent: true,
},
EvGoSyscallEndBlocked: {
Name: "GoSyscallEndBlocked",
Args: []string{"dt"},
StartEv: EvGoSyscallBegin,
IsTimedEvent: true,
},
EvGoStatus: {
Name: "GoStatus",
Args: []string{"dt", "g", "m", "gstatus"},
IsTimedEvent: true,
},
EvSTWBegin: {
Name: "STWBegin",
Args: []string{"dt", "kind_string", "stack"},
IsTimedEvent: true,
StackIDs: []int{2},
StringIDs: []int{1},
},
EvSTWEnd: {
Name: "STWEnd",
Args: []string{"dt"},
StartEv: EvSTWBegin,
IsTimedEvent: true,
},
EvGCActive: {
Name: "GCActive",
Args: []string{"dt", "gc_seq"},
IsTimedEvent: true,
StartEv: EvGCBegin,
},
EvGCBegin: {
Name: "GCBegin",
Args: []string{"dt", "gc_seq", "stack"},
IsTimedEvent: true,
StackIDs: []int{2},
},
EvGCEnd: {
Name: "GCEnd",
Args: []string{"dt", "gc_seq"},
StartEv: EvGCBegin,
IsTimedEvent: true,
},
EvGCSweepActive: {
Name: "GCSweepActive",
Args: []string{"dt", "p"},
StartEv: EvGCSweepBegin,
IsTimedEvent: true,
},
EvGCSweepBegin: {
Name: "GCSweepBegin",
Args: []string{"dt", "stack"},
IsTimedEvent: true,
StackIDs: []int{1},
},
EvGCSweepEnd: {
Name: "GCSweepEnd",
Args: []string{"dt", "swept_value", "reclaimed_value"},
StartEv: EvGCSweepBegin,
IsTimedEvent: true,
},
EvGCMarkAssistActive: {
Name: "GCMarkAssistActive",
Args: []string{"dt", "g"},
StartEv: EvGCMarkAssistBegin,
IsTimedEvent: true,
},
EvGCMarkAssistBegin: {
Name: "GCMarkAssistBegin",
Args: []string{"dt", "stack"},
IsTimedEvent: true,
StackIDs: []int{1},
},
EvGCMarkAssistEnd: {
Name: "GCMarkAssistEnd",
Args: []string{"dt"},
StartEv: EvGCMarkAssistBegin,
IsTimedEvent: true,
},
EvHeapAlloc: {
Name: "HeapAlloc",
Args: []string{"dt", "heapalloc_value"},
IsTimedEvent: true,
},
EvHeapGoal: {
Name: "HeapGoal",
Args: []string{"dt", "heapgoal_value"},
IsTimedEvent: true,
},
EvGoLabel: {
Name: "GoLabel",
Args: []string{"dt", "label_string"},
IsTimedEvent: true,
StringIDs: []int{1},
},
EvUserTaskBegin: {
Name: "UserTaskBegin",
Args: []string{"dt", "task", "parent_task", "name_string", "stack"},
IsTimedEvent: true,
StackIDs: []int{4},
StringIDs: []int{3},
},
EvUserTaskEnd: {
Name: "UserTaskEnd",
Args: []string{"dt", "task", "stack"},
IsTimedEvent: true,
StackIDs: []int{2},
},
EvUserRegionBegin: {
Name: "UserRegionBegin",
Args: []string{"dt", "task", "name_string", "stack"},
IsTimedEvent: true,
StackIDs: []int{3},
StringIDs: []int{2},
},
EvUserRegionEnd: {
Name: "UserRegionEnd",
Args: []string{"dt", "task", "name_string", "stack"},
StartEv: EvUserRegionBegin,
IsTimedEvent: true,
StackIDs: []int{3},
StringIDs: []int{2},
},
EvUserLog: {
Name: "UserLog",
Args: []string{"dt", "task", "key_string", "value_string", "stack"},
IsTimedEvent: true,
StackIDs: []int{4},
StringIDs: []int{2, 3},
},
EvGoSwitch: {
Name: "GoSwitch",
Args: []string{"dt", "g", "g_seq"},
IsTimedEvent: true,
},
EvGoSwitchDestroy: {
Name: "GoSwitchDestroy",
Args: []string{"dt", "g", "g_seq"},
IsTimedEvent: true,
},
EvGoCreateBlocked: {
Name: "GoCreateBlocked",
Args: []string{"dt", "new_g", "new_stack", "stack"},
IsTimedEvent: true,
StackIDs: []int{3, 2},
},
EvGoStatusStack: {
Name: "GoStatusStack",
Args: []string{"dt", "g", "m", "gstatus", "stack"},
IsTimedEvent: true,
StackIDs: []int{4},
},
EvClockSnapshot: {
Name: "ClockSnapshot",
Args: []string{"dt", "mono", "sec", "nsec"},
IsTimedEvent: true,
},
// Experimental events.
EvSpan: {
Name: "Span",
Args: []string{"dt", "id", "npages_value", "kindclass"},
IsTimedEvent: true,
Experiment: AllocFree,
},
EvSpanAlloc: {
Name: "SpanAlloc",
Args: []string{"dt", "id", "npages_value", "kindclass"},
IsTimedEvent: true,
Experiment: AllocFree,
},
EvSpanFree: {
Name: "SpanFree",
Args: []string{"dt", "id"},
IsTimedEvent: true,
Experiment: AllocFree,
},
EvHeapObject: {
Name: "HeapObject",
Args: []string{"dt", "id", "type"},
IsTimedEvent: true,
Experiment: AllocFree,
},
EvHeapObjectAlloc: {
Name: "HeapObjectAlloc",
Args: []string{"dt", "id", "type"},
IsTimedEvent: true,
Experiment: AllocFree,
},
EvHeapObjectFree: {
Name: "HeapObjectFree",
Args: []string{"dt", "id"},
IsTimedEvent: true,
Experiment: AllocFree,
},
EvGoroutineStack: {
Name: "GoroutineStack",
Args: []string{"dt", "id", "order"},
IsTimedEvent: true,
Experiment: AllocFree,
},
EvGoroutineStackAlloc: {
Name: "GoroutineStackAlloc",
Args: []string{"dt", "id", "order"},
IsTimedEvent: true,
Experiment: AllocFree,
},
EvGoroutineStackFree: {
Name: "GoroutineStackFree",
Args: []string{"dt", "id"},
IsTimedEvent: true,
Experiment: AllocFree,
},
}
// GoStatus is the status of a goroutine.
//
// They correspond directly to the various goroutine states.
type GoStatus uint8
const (
GoBad GoStatus = iota
GoRunnable
GoRunning
GoSyscall
GoWaiting
)
func (s GoStatus) String() string {
switch s {
case GoRunnable:
return "Runnable"
case GoRunning:
return "Running"
case GoSyscall:
return "Syscall"
case GoWaiting:
return "Waiting"
}
return "Bad"
}
// ProcStatus is the status of a P.
//
// They mostly correspond to the various P states.
type ProcStatus uint8
const (
ProcBad ProcStatus = iota
ProcRunning
ProcIdle
ProcSyscall
// ProcSyscallAbandoned is a special case of
// ProcSyscall. It's used in the very specific case
// where the first a P is mentioned in a generation is
// part of a ProcSteal event. If that's the first time
// it's mentioned, then there's no GoSyscallBegin to
// connect the P stealing back to at that point. This
// special state indicates this to the parser, so it
// doesn't try to find a GoSyscallEndBlocked that
// corresponds with the ProcSteal.
ProcSyscallAbandoned
)
func (s ProcStatus) String() string {
switch s {
case ProcRunning:
return "Running"
case ProcIdle:
return "Idle"
case ProcSyscall:
return "Syscall"
}
return "Bad"
}
const (
// MaxBatchSize sets the maximum size that a batch can be.
//
// Directly controls the trace batch size in the runtime.
//
// NOTE: If this number decreases, the trace format version must change.
MaxBatchSize = 64 << 10
// Maximum number of PCs in a single stack trace.
//
// Since events contain only stack ID rather than whole stack trace,
// we can allow quite large values here.
//
// Directly controls the maximum number of frames per stack
// in the runtime.
//
// NOTE: If this number decreases, the trace format version must change.
MaxFramesPerStack = 128
// MaxEventTrailerDataSize controls the amount of trailer data that
// an event can have in bytes. Must be smaller than MaxBatchSize.
// Controls the maximum string size in the trace.
//
// Directly controls the maximum such value in the runtime.
//
// NOTE: If this number decreases, the trace format version must change.
MaxEventTrailerDataSize = 1 << 10
)