| // 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" | |
| case ProcSyscallAbandoned: | |
| return "SyscallAbandoned" | |
| } | |
| 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 | |
| ) |