diff options
Diffstat (limited to 'src/internal/trace/v2/resources.go')
-rw-r--r-- | src/internal/trace/v2/resources.go | 274 |
1 files changed, 274 insertions, 0 deletions
diff --git a/src/internal/trace/v2/resources.go b/src/internal/trace/v2/resources.go new file mode 100644 index 0000000..f49696f --- /dev/null +++ b/src/internal/trace/v2/resources.go @@ -0,0 +1,274 @@ +// 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 trace + +import "fmt" + +// ThreadID is the runtime-internal M structure's ID. This is unique +// for each OS thread. +type ThreadID int64 + +// NoThread indicates that the relevant events don't correspond to any +// thread in particular. +const NoThread = ThreadID(-1) + +// ProcID is the runtime-internal G structure's id field. This is unique +// for each P. +type ProcID int64 + +// NoProc indicates that the relevant events don't correspond to any +// P in particular. +const NoProc = ProcID(-1) + +// GoID is the runtime-internal G structure's goid field. This is unique +// for each goroutine. +type GoID int64 + +// NoGoroutine indicates that the relevant events don't correspond to any +// goroutine in particular. +const NoGoroutine = GoID(-1) + +// GoState represents the state of a goroutine. +// +// New GoStates may be added in the future. Users of this type must be robust +// to that possibility. +type GoState uint8 + +const ( + GoUndetermined GoState = iota // No information is known about the goroutine. + GoNotExist // Goroutine does not exist. + GoRunnable // Goroutine is runnable but not running. + GoRunning // Goroutine is running. + GoWaiting // Goroutine is waiting on something to happen. + GoSyscall // Goroutine is in a system call. +) + +// Executing returns true if the state indicates that the goroutine is executing +// and bound to its thread. +func (s GoState) Executing() bool { + return s == GoRunning || s == GoSyscall +} + +// String returns a human-readable representation of a GoState. +// +// The format of the returned string is for debugging purposes and is subject to change. +func (s GoState) String() string { + switch s { + case GoUndetermined: + return "Undetermined" + case GoNotExist: + return "NotExist" + case GoRunnable: + return "Runnable" + case GoRunning: + return "Running" + case GoWaiting: + return "Waiting" + case GoSyscall: + return "Syscall" + } + return "Bad" +} + +// ProcState represents the state of a proc. +// +// New ProcStates may be added in the future. Users of this type must be robust +// to that possibility. +type ProcState uint8 + +const ( + ProcUndetermined ProcState = iota // No information is known about the proc. + ProcNotExist // Proc does not exist. + ProcRunning // Proc is running. + ProcIdle // Proc is idle. +) + +// Executing returns true if the state indicates that the proc is executing +// and bound to its thread. +func (s ProcState) Executing() bool { + return s == ProcRunning +} + +// String returns a human-readable representation of a ProcState. +// +// The format of the returned string is for debugging purposes and is subject to change. +func (s ProcState) String() string { + switch s { + case ProcUndetermined: + return "Undetermined" + case ProcNotExist: + return "NotExist" + case ProcRunning: + return "Running" + case ProcIdle: + return "Idle" + } + return "Bad" +} + +// ResourceKind indicates a kind of resource that has a state machine. +// +// New ResourceKinds may be added in the future. Users of this type must be robust +// to that possibility. +type ResourceKind uint8 + +const ( + ResourceNone ResourceKind = iota // No resource. + ResourceGoroutine // Goroutine. + ResourceProc // Proc. + ResourceThread // Thread. +) + +// String returns a human-readable representation of a ResourceKind. +// +// The format of the returned string is for debugging purposes and is subject to change. +func (r ResourceKind) String() string { + switch r { + case ResourceNone: + return "None" + case ResourceGoroutine: + return "Goroutine" + case ResourceProc: + return "Proc" + case ResourceThread: + return "Thread" + } + return "Bad" +} + +// ResourceID represents a generic resource ID. +type ResourceID struct { + // Kind is the kind of resource this ID is for. + Kind ResourceKind + id int64 +} + +// MakeResourceID creates a general resource ID from a specific resource's ID. +func MakeResourceID[T interface{ GoID | ProcID | ThreadID }](id T) ResourceID { + var rd ResourceID + var a any = id + switch a.(type) { + case GoID: + rd.Kind = ResourceGoroutine + case ProcID: + rd.Kind = ResourceProc + case ThreadID: + rd.Kind = ResourceThread + } + rd.id = int64(id) + return rd +} + +// Goroutine obtains a GoID from the resource ID. +// +// r.Kind must be ResourceGoroutine or this function will panic. +func (r ResourceID) Goroutine() GoID { + if r.Kind != ResourceGoroutine { + panic(fmt.Sprintf("attempted to get GoID from %s resource ID", r.Kind)) + } + return GoID(r.id) +} + +// Proc obtains a ProcID from the resource ID. +// +// r.Kind must be ResourceProc or this function will panic. +func (r ResourceID) Proc() ProcID { + if r.Kind != ResourceProc { + panic(fmt.Sprintf("attempted to get ProcID from %s resource ID", r.Kind)) + } + return ProcID(r.id) +} + +// Thread obtains a ThreadID from the resource ID. +// +// r.Kind must be ResourceThread or this function will panic. +func (r ResourceID) Thread() ThreadID { + if r.Kind != ResourceThread { + panic(fmt.Sprintf("attempted to get ThreadID from %s resource ID", r.Kind)) + } + return ThreadID(r.id) +} + +// String returns a human-readable string representation of the ResourceID. +// +// This representation is subject to change and is intended primarily for debugging. +func (r ResourceID) String() string { + if r.Kind == ResourceNone { + return r.Kind.String() + } + return fmt.Sprintf("%s(%d)", r.Kind, r.id) +} + +// StateTransition provides details about a StateTransition event. +type StateTransition struct { + // Resource is the resource this state transition is for. + Resource ResourceID + + // Reason is a human-readable reason for the state transition. + Reason string + + // Stack is the stack trace of the resource making the state transition. + // + // This is distinct from the result (Event).Stack because it pertains to + // the transitioning resource, not any of the ones executing the event + // this StateTransition came from. + // + // An example of this difference is the NotExist -> Runnable transition for + // goroutines, which indicates goroutine creation. In this particular case, + // a Stack here would refer to the starting stack of the new goroutine, and + // an (Event).Stack would refer to the stack trace of whoever created the + // goroutine. + Stack Stack + + // The actual transition data. Stored in a neutral form so that + // we don't need fields for every kind of resource. + id int64 + oldState uint8 + newState uint8 +} + +func goStateTransition(id GoID, from, to GoState) StateTransition { + return StateTransition{ + Resource: ResourceID{Kind: ResourceGoroutine, id: int64(id)}, + oldState: uint8(from), + newState: uint8(to), + } +} + +func procStateTransition(id ProcID, from, to ProcState) StateTransition { + return StateTransition{ + Resource: ResourceID{Kind: ResourceProc, id: int64(id)}, + oldState: uint8(from), + newState: uint8(to), + } +} + +// Goroutine returns the state transition for a goroutine. +// +// Transitions to and from states that are Executing are special in that +// they change the future execution context. In other words, future events +// on the same thread will feature the same goroutine until it stops running. +// +// Panics if d.Resource.Kind is not ResourceGoroutine. +func (d StateTransition) Goroutine() (from, to GoState) { + if d.Resource.Kind != ResourceGoroutine { + panic("Goroutine called on non-Goroutine state transition") + } + return GoState(d.oldState), GoState(d.newState) +} + +// Proc returns the state transition for a proc. +// +// Transitions to and from states that are Executing are special in that +// they change the future execution context. In other words, future events +// on the same thread will feature the same goroutine until it stops running. +// +// Panics if d.Resource.Kind is not ResourceProc. +func (d StateTransition) Proc() (from, to ProcState) { + if d.Resource.Kind != ResourceProc { + panic("Proc called on non-Proc state transition") + } + return ProcState(d.oldState), ProcState(d.newState) +} |