summaryrefslogtreecommitdiffstats
path: root/src/internal/trace/v2/resources.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/internal/trace/v2/resources.go')
-rw-r--r--src/internal/trace/v2/resources.go274
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)
+}