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