resources.mx raw

   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  package trace
   6  
   7  import "fmt"
   8  
   9  // ThreadID is the runtime-internal M structure's ID. This is unique
  10  // for each OS thread.
  11  type ThreadID int64
  12  
  13  // NoThread indicates that the relevant events don't correspond to any
  14  // thread in particular.
  15  const NoThread = ThreadID(-1)
  16  
  17  // ProcID is the runtime-internal G structure's id field. This is unique
  18  // for each P.
  19  type ProcID int64
  20  
  21  // NoProc indicates that the relevant events don't correspond to any
  22  // P in particular.
  23  const NoProc = ProcID(-1)
  24  
  25  // GoID is the runtime-internal G structure's goid field. This is unique
  26  // for each goroutine.
  27  type GoID int64
  28  
  29  // NoGoroutine indicates that the relevant events don't correspond to any
  30  // goroutine in particular.
  31  const NoGoroutine = GoID(-1)
  32  
  33  // GoState represents the state of a goroutine.
  34  //
  35  // New GoStates may be added in the future. Users of this type must be robust
  36  // to that possibility.
  37  type GoState uint8
  38  
  39  const (
  40  	GoUndetermined GoState = iota // No information is known about the goroutine.
  41  	GoNotExist                    // Goroutine does not exist.
  42  	GoRunnable                    // Goroutine is runnable but not running.
  43  	GoRunning                     // Goroutine is running.
  44  	GoWaiting                     // Goroutine is waiting on something to happen.
  45  	GoSyscall                     // Goroutine is in a system call.
  46  )
  47  
  48  // Executing returns true if the state indicates that the goroutine is executing
  49  // and bound to its thread.
  50  func (s GoState) Executing() bool {
  51  	return s == GoRunning || s == GoSyscall
  52  }
  53  
  54  // String returns a human-readable representation of a GoState.
  55  //
  56  // The format of the returned string is for debugging purposes and is subject to change.
  57  func (s GoState) String() string {
  58  	switch s {
  59  	case GoUndetermined:
  60  		return "Undetermined"
  61  	case GoNotExist:
  62  		return "NotExist"
  63  	case GoRunnable:
  64  		return "Runnable"
  65  	case GoRunning:
  66  		return "Running"
  67  	case GoWaiting:
  68  		return "Waiting"
  69  	case GoSyscall:
  70  		return "Syscall"
  71  	}
  72  	return "Bad"
  73  }
  74  
  75  // ProcState represents the state of a proc.
  76  //
  77  // New ProcStates may be added in the future. Users of this type must be robust
  78  // to that possibility.
  79  type ProcState uint8
  80  
  81  const (
  82  	ProcUndetermined ProcState = iota // No information is known about the proc.
  83  	ProcNotExist                      // Proc does not exist.
  84  	ProcRunning                       // Proc is running.
  85  	ProcIdle                          // Proc is idle.
  86  )
  87  
  88  // Executing returns true if the state indicates that the proc is executing
  89  // and bound to its thread.
  90  func (s ProcState) Executing() bool {
  91  	return s == ProcRunning
  92  }
  93  
  94  // String returns a human-readable representation of a ProcState.
  95  //
  96  // The format of the returned string is for debugging purposes and is subject to change.
  97  func (s ProcState) String() string {
  98  	switch s {
  99  	case ProcUndetermined:
 100  		return "Undetermined"
 101  	case ProcNotExist:
 102  		return "NotExist"
 103  	case ProcRunning:
 104  		return "Running"
 105  	case ProcIdle:
 106  		return "Idle"
 107  	}
 108  	return "Bad"
 109  }
 110  
 111  // ResourceKind indicates a kind of resource that has a state machine.
 112  //
 113  // New ResourceKinds may be added in the future. Users of this type must be robust
 114  // to that possibility.
 115  type ResourceKind uint8
 116  
 117  const (
 118  	ResourceNone      ResourceKind = iota // No resource.
 119  	ResourceGoroutine                     // Goroutine.
 120  	ResourceProc                          // Proc.
 121  	ResourceThread                        // Thread.
 122  )
 123  
 124  // String returns a human-readable representation of a ResourceKind.
 125  //
 126  // The format of the returned string is for debugging purposes and is subject to change.
 127  func (r ResourceKind) String() string {
 128  	switch r {
 129  	case ResourceNone:
 130  		return "None"
 131  	case ResourceGoroutine:
 132  		return "Goroutine"
 133  	case ResourceProc:
 134  		return "Proc"
 135  	case ResourceThread:
 136  		return "Thread"
 137  	}
 138  	return "Bad"
 139  }
 140  
 141  // ResourceID represents a generic resource ID.
 142  type ResourceID struct {
 143  	// Kind is the kind of resource this ID is for.
 144  	Kind ResourceKind
 145  	id   int64
 146  }
 147  
 148  // MakeResourceID creates a general resource ID from a specific resource's ID.
 149  func MakeResourceID[T interface{ GoID | ProcID | ThreadID }](id T) ResourceID {
 150  	var rd ResourceID
 151  	var a any = id
 152  	switch a.(type) {
 153  	case GoID:
 154  		rd.Kind = ResourceGoroutine
 155  	case ProcID:
 156  		rd.Kind = ResourceProc
 157  	case ThreadID:
 158  		rd.Kind = ResourceThread
 159  	}
 160  	rd.id = int64(id)
 161  	return rd
 162  }
 163  
 164  // Goroutine obtains a GoID from the resource ID.
 165  //
 166  // r.Kind must be ResourceGoroutine or this function will panic.
 167  func (r ResourceID) Goroutine() GoID {
 168  	if r.Kind != ResourceGoroutine {
 169  		panic(fmt.Sprintf("attempted to get GoID from %s resource ID", r.Kind))
 170  	}
 171  	return GoID(r.id)
 172  }
 173  
 174  // Proc obtains a ProcID from the resource ID.
 175  //
 176  // r.Kind must be ResourceProc or this function will panic.
 177  func (r ResourceID) Proc() ProcID {
 178  	if r.Kind != ResourceProc {
 179  		panic(fmt.Sprintf("attempted to get ProcID from %s resource ID", r.Kind))
 180  	}
 181  	return ProcID(r.id)
 182  }
 183  
 184  // Thread obtains a ThreadID from the resource ID.
 185  //
 186  // r.Kind must be ResourceThread or this function will panic.
 187  func (r ResourceID) Thread() ThreadID {
 188  	if r.Kind != ResourceThread {
 189  		panic(fmt.Sprintf("attempted to get ThreadID from %s resource ID", r.Kind))
 190  	}
 191  	return ThreadID(r.id)
 192  }
 193  
 194  // String returns a human-readable string representation of the ResourceID.
 195  //
 196  // This representation is subject to change and is intended primarily for debugging.
 197  func (r ResourceID) String() string {
 198  	if r.Kind == ResourceNone {
 199  		return r.Kind.String()
 200  	}
 201  	return fmt.Sprintf("%s(%d)", r.Kind, r.id)
 202  }
 203  
 204  // StateTransition provides details about a StateTransition event.
 205  type StateTransition struct {
 206  	// Resource is the resource this state transition is for.
 207  	Resource ResourceID
 208  
 209  	// Reason is a human-readable reason for the state transition.
 210  	Reason []byte
 211  
 212  	// Stack is the stack trace of the resource making the state transition.
 213  	//
 214  	// This is distinct from the result (Event).Stack because it pertains to
 215  	// the transitioning resource, not any of the ones executing the event
 216  	// this StateTransition came from.
 217  	//
 218  	// An example of this difference is the NotExist -> Runnable transition for
 219  	// goroutines, which indicates goroutine creation. In this particular case,
 220  	// a Stack here would refer to the starting stack of the new goroutine, and
 221  	// an (Event).Stack would refer to the stack trace of whoever created the
 222  	// goroutine.
 223  	Stack Stack
 224  
 225  	// The actual transition data. Stored in a neutral form so that
 226  	// we don't need fields for every kind of resource.
 227  	id       int64
 228  	oldState uint8
 229  	newState uint8
 230  }
 231  
 232  func goStateTransition(id GoID, from, to GoState) StateTransition {
 233  	return StateTransition{
 234  		Resource: ResourceID{Kind: ResourceGoroutine, id: int64(id)},
 235  		oldState: uint8(from),
 236  		newState: uint8(to),
 237  	}
 238  }
 239  
 240  func procStateTransition(id ProcID, from, to ProcState) StateTransition {
 241  	return StateTransition{
 242  		Resource: ResourceID{Kind: ResourceProc, id: int64(id)},
 243  		oldState: uint8(from),
 244  		newState: uint8(to),
 245  	}
 246  }
 247  
 248  // Goroutine returns the state transition for a goroutine.
 249  //
 250  // Transitions to and from states that are Executing are special in that
 251  // they change the future execution context. In other words, future events
 252  // on the same thread will feature the same goroutine until it stops running.
 253  //
 254  // Panics if d.Resource.Kind is not ResourceGoroutine.
 255  func (d StateTransition) Goroutine() (from, to GoState) {
 256  	if d.Resource.Kind != ResourceGoroutine {
 257  		panic("Goroutine called on non-Goroutine state transition")
 258  	}
 259  	return GoState(d.oldState), GoState(d.newState)
 260  }
 261  
 262  // Proc returns the state transition for a proc.
 263  //
 264  // Transitions to and from states that are Executing are special in that
 265  // they change the future execution context. In other words, future events
 266  // on the same thread will feature the same goroutine until it stops running.
 267  //
 268  // Panics if d.Resource.Kind is not ResourceProc.
 269  func (d StateTransition) Proc() (from, to ProcState) {
 270  	if d.Resource.Kind != ResourceProc {
 271  		panic("Proc called on non-Proc state transition")
 272  	}
 273  	return ProcState(d.oldState), ProcState(d.newState)
 274  }
 275