golang.org/x/exp@v0.0.0-20240506185415-9bf2ced13842/trace/event.go (about) 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 // Code generated by "gen.bash" from internal/trace/v2; DO NOT EDIT. 6 7 //go:build go1.21 8 9 package trace 10 11 import ( 12 "fmt" 13 "math" 14 "strings" 15 "time" 16 17 "golang.org/x/exp/trace/internal/event" 18 "golang.org/x/exp/trace/internal/event/go122" 19 "golang.org/x/exp/trace/internal/version" 20 ) 21 22 // EventKind indicates the kind of event this is. 23 // 24 // Use this information to obtain a more specific event that 25 // allows access to more detailed information. 26 type EventKind uint16 27 28 const ( 29 EventBad EventKind = iota 30 31 // EventKindSync is an event that indicates a global synchronization 32 // point in the trace. At the point of a sync event, the 33 // trace reader can be certain that all resources (e.g. threads, 34 // goroutines) that have existed until that point have been enumerated. 35 EventSync 36 37 // EventMetric is an event that represents the value of a metric at 38 // a particular point in time. 39 EventMetric 40 41 // EventLabel attaches a label to a resource. 42 EventLabel 43 44 // EventStackSample represents an execution sample, indicating what a 45 // thread/proc/goroutine was doing at a particular point in time via 46 // its backtrace. 47 // 48 // Note: Samples should be considered a close approximation of 49 // what a thread/proc/goroutine was executing at a given point in time. 50 // These events may slightly contradict the situation StateTransitions 51 // describe, so they should only be treated as a best-effort annotation. 52 EventStackSample 53 54 // EventRangeBegin and EventRangeEnd are a pair of generic events representing 55 // a special range of time. Ranges are named and scoped to some resource 56 // (identified via ResourceKind). A range that has begun but has not ended 57 // is considered active. 58 // 59 // EvRangeBegin and EvRangeEnd will share the same name, and an End will always 60 // follow a Begin on the same instance of the resource. The associated 61 // resource ID can be obtained from the Event. ResourceNone indicates the 62 // range is globally scoped. That is, any goroutine/proc/thread can start or 63 // stop, but only one such range may be active at any given time. 64 // 65 // EventRangeActive is like EventRangeBegin, but indicates that the range was 66 // already active. In this case, the resource referenced may not be in the current 67 // context. 68 EventRangeBegin 69 EventRangeActive 70 EventRangeEnd 71 72 // EvTaskBegin and EvTaskEnd are a pair of events representing a runtime/trace.Task. 73 EventTaskBegin 74 EventTaskEnd 75 76 // EventRegionBegin and EventRegionEnd are a pair of events represent a runtime/trace.Region. 77 EventRegionBegin 78 EventRegionEnd 79 80 // EventLog represents a runtime/trace.Log call. 81 EventLog 82 83 // Transitions in state for some resource. 84 EventStateTransition 85 ) 86 87 // String returns a string form of the EventKind. 88 func (e EventKind) String() string { 89 if int(e) >= len(eventKindStrings) { 90 return eventKindStrings[0] 91 } 92 return eventKindStrings[e] 93 } 94 95 var eventKindStrings = [...]string{ 96 EventBad: "Bad", 97 EventSync: "Sync", 98 EventMetric: "Metric", 99 EventLabel: "Label", 100 EventStackSample: "StackSample", 101 EventRangeBegin: "RangeBegin", 102 EventRangeActive: "RangeActive", 103 EventRangeEnd: "RangeEnd", 104 EventTaskBegin: "TaskBegin", 105 EventTaskEnd: "TaskEnd", 106 EventRegionBegin: "RegionBegin", 107 EventRegionEnd: "RegionEnd", 108 EventLog: "Log", 109 EventStateTransition: "StateTransition", 110 } 111 112 const maxTime = Time(math.MaxInt64) 113 114 // Time is a timestamp in nanoseconds. 115 // 116 // It corresponds to the monotonic clock on the platform that the 117 // trace was taken, and so is possible to correlate with timestamps 118 // for other traces taken on the same machine using the same clock 119 // (i.e. no reboots in between). 120 // 121 // The actual absolute value of the timestamp is only meaningful in 122 // relation to other timestamps from the same clock. 123 // 124 // BUG: Timestamps coming from traces on Windows platforms are 125 // only comparable with timestamps from the same trace. Timestamps 126 // across traces cannot be compared, because the system clock is 127 // not used as of Go 1.22. 128 // 129 // BUG: Traces produced by Go versions 1.21 and earlier cannot be 130 // compared with timestamps from other traces taken on the same 131 // machine. This is because the system clock was not used at all 132 // to collect those timestamps. 133 type Time int64 134 135 // Sub subtracts t0 from t, returning the duration in nanoseconds. 136 func (t Time) Sub(t0 Time) time.Duration { 137 return time.Duration(int64(t) - int64(t0)) 138 } 139 140 // Metric provides details about a Metric event. 141 type Metric struct { 142 // Name is the name of the sampled metric. 143 // 144 // Names follow the same convention as metric names in the 145 // runtime/metrics package, meaning they include the unit. 146 // Names that match with the runtime/metrics package represent 147 // the same quantity. Note that this corresponds to the 148 // runtime/metrics package for the Go version this trace was 149 // collected for. 150 Name string 151 152 // Value is the sampled value of the metric. 153 // 154 // The Value's Kind is tied to the name of the metric, and so is 155 // guaranteed to be the same for metric samples for the same metric. 156 Value Value 157 } 158 159 // Label provides details about a Label event. 160 type Label struct { 161 // Label is the label applied to some resource. 162 Label string 163 164 // Resource is the resource to which this label should be applied. 165 Resource ResourceID 166 } 167 168 // Range provides details about a Range event. 169 type Range struct { 170 // Name is a human-readable name for the range. 171 // 172 // This name can be used to identify the end of the range for the resource 173 // its scoped to, because only one of each type of range may be active on 174 // a particular resource. The relevant resource should be obtained from the 175 // Event that produced these details. The corresponding RangeEnd will have 176 // an identical name. 177 Name string 178 179 // Scope is the resource that the range is scoped to. 180 // 181 // For example, a ResourceGoroutine scope means that the same goroutine 182 // must have a start and end for the range, and that goroutine can only 183 // have one range of a particular name active at any given time. The 184 // ID that this range is scoped to may be obtained via Event.Goroutine. 185 // 186 // The ResourceNone scope means that the range is globally scoped. As a 187 // result, any goroutine/proc/thread may start or end the range, and only 188 // one such named range may be active globally at any given time. 189 // 190 // For RangeBegin and RangeEnd events, this will always reference some 191 // resource ID in the current execution context. For RangeActive events, 192 // this may reference a resource not in the current context. Prefer Scope 193 // over the current execution context. 194 Scope ResourceID 195 } 196 197 // RangeAttributes provides attributes about a completed Range. 198 type RangeAttribute struct { 199 // Name is the human-readable name for the range. 200 Name string 201 202 // Value is the value of the attribute. 203 Value Value 204 } 205 206 // TaskID is the internal ID of a task used to disambiguate tasks (even if they 207 // are of the same type). 208 type TaskID uint64 209 210 const ( 211 // NoTask indicates the lack of a task. 212 NoTask = TaskID(^uint64(0)) 213 214 // BackgroundTask is the global task that events are attached to if there was 215 // no other task in the context at the point the event was emitted. 216 BackgroundTask = TaskID(0) 217 ) 218 219 // Task provides details about a Task event. 220 type Task struct { 221 // ID is a unique identifier for the task. 222 // 223 // This can be used to associate the beginning of a task with its end. 224 ID TaskID 225 226 // ParentID is the ID of the parent task. 227 Parent TaskID 228 229 // Type is the taskType that was passed to runtime/trace.NewTask. 230 // 231 // May be "" if a task's TaskBegin event isn't present in the trace. 232 Type string 233 } 234 235 // Region provides details about a Region event. 236 type Region struct { 237 // Task is the ID of the task this region is associated with. 238 Task TaskID 239 240 // Type is the regionType that was passed to runtime/trace.StartRegion or runtime/trace.WithRegion. 241 Type string 242 } 243 244 // Log provides details about a Log event. 245 type Log struct { 246 // Task is the ID of the task this region is associated with. 247 Task TaskID 248 249 // Category is the category that was passed to runtime/trace.Log or runtime/trace.Logf. 250 Category string 251 252 // Message is the message that was passed to runtime/trace.Log or runtime/trace.Logf. 253 Message string 254 } 255 256 // Stack represents a stack. It's really a handle to a stack and it's trivially comparable. 257 // 258 // If two Stacks are equal then their Frames are guaranteed to be identical. If they are not 259 // equal, however, their Frames may still be equal. 260 type Stack struct { 261 table *evTable 262 id stackID 263 } 264 265 // Frames is an iterator over the frames in a Stack. 266 func (s Stack) Frames(yield func(f StackFrame) bool) bool { 267 if s.id == 0 { 268 return true 269 } 270 stk := s.table.stacks.mustGet(s.id) 271 for _, pc := range stk.pcs { 272 f := s.table.pcs[pc] 273 sf := StackFrame{ 274 PC: f.pc, 275 Func: s.table.strings.mustGet(f.funcID), 276 File: s.table.strings.mustGet(f.fileID), 277 Line: f.line, 278 } 279 if !yield(sf) { 280 return false 281 } 282 } 283 return true 284 } 285 286 // NoStack is a sentinel value that can be compared against any Stack value, indicating 287 // a lack of a stack trace. 288 var NoStack = Stack{} 289 290 // StackFrame represents a single frame of a stack. 291 type StackFrame struct { 292 // PC is the program counter of the function call if this 293 // is not a leaf frame. If it's a leaf frame, it's the point 294 // at which the stack trace was taken. 295 PC uint64 296 297 // Func is the name of the function this frame maps to. 298 Func string 299 300 // File is the file which contains the source code of Func. 301 File string 302 303 // Line is the line number within File which maps to PC. 304 Line uint64 305 } 306 307 // Event represents a single event in the trace. 308 type Event struct { 309 table *evTable 310 ctx schedCtx 311 base baseEvent 312 } 313 314 // Kind returns the kind of event that this is. 315 func (e Event) Kind() EventKind { 316 return go122Type2Kind[e.base.typ] 317 } 318 319 // Time returns the timestamp of the event. 320 func (e Event) Time() Time { 321 return e.base.time 322 } 323 324 // Goroutine returns the ID of the goroutine that was executing when 325 // this event happened. It describes part of the execution context 326 // for this event. 327 // 328 // Note that for goroutine state transitions this always refers to the 329 // state before the transition. For example, if a goroutine is just 330 // starting to run on this thread and/or proc, then this will return 331 // NoGoroutine. In this case, the goroutine starting to run will be 332 // can be found at Event.StateTransition().Resource. 333 func (e Event) Goroutine() GoID { 334 return e.ctx.G 335 } 336 337 // Proc returns the ID of the proc this event event pertains to. 338 // 339 // Note that for proc state transitions this always refers to the 340 // state before the transition. For example, if a proc is just 341 // starting to run on this thread, then this will return NoProc. 342 func (e Event) Proc() ProcID { 343 return e.ctx.P 344 } 345 346 // Thread returns the ID of the thread this event pertains to. 347 // 348 // Note that for thread state transitions this always refers to the 349 // state before the transition. For example, if a thread is just 350 // starting to run, then this will return NoThread. 351 // 352 // Note: tracking thread state is not currently supported, so this 353 // will always return a valid thread ID. However thread state transitions 354 // may be tracked in the future, and callers must be robust to this 355 // possibility. 356 func (e Event) Thread() ThreadID { 357 return e.ctx.M 358 } 359 360 // Stack returns a handle to a stack associated with the event. 361 // 362 // This represents a stack trace at the current moment in time for 363 // the current execution context. 364 func (e Event) Stack() Stack { 365 if e.base.typ == evSync { 366 return NoStack 367 } 368 if e.base.typ == go122.EvCPUSample { 369 return Stack{table: e.table, id: stackID(e.base.args[0])} 370 } 371 spec := go122.Specs()[e.base.typ] 372 if len(spec.StackIDs) == 0 { 373 return NoStack 374 } 375 // The stack for the main execution context is always the 376 // first stack listed in StackIDs. Subtract one from this 377 // because we've peeled away the timestamp argument. 378 id := stackID(e.base.args[spec.StackIDs[0]-1]) 379 if id == 0 { 380 return NoStack 381 } 382 return Stack{table: e.table, id: id} 383 } 384 385 // Metric returns details about a Metric event. 386 // 387 // Panics if Kind != EventMetric. 388 func (e Event) Metric() Metric { 389 if e.Kind() != EventMetric { 390 panic("Metric called on non-Metric event") 391 } 392 var m Metric 393 switch e.base.typ { 394 case go122.EvProcsChange: 395 m.Name = "/sched/gomaxprocs:threads" 396 m.Value = Value{kind: ValueUint64, scalar: e.base.args[0]} 397 case go122.EvHeapAlloc: 398 m.Name = "/memory/classes/heap/objects:bytes" 399 m.Value = Value{kind: ValueUint64, scalar: e.base.args[0]} 400 case go122.EvHeapGoal: 401 m.Name = "/gc/heap/goal:bytes" 402 m.Value = Value{kind: ValueUint64, scalar: e.base.args[0]} 403 default: 404 panic(fmt.Sprintf("internal error: unexpected event type for Metric kind: %s", go122.EventString(e.base.typ))) 405 } 406 return m 407 } 408 409 // Label returns details about a Label event. 410 // 411 // Panics if Kind != EventLabel. 412 func (e Event) Label() Label { 413 if e.Kind() != EventLabel { 414 panic("Label called on non-Label event") 415 } 416 if e.base.typ != go122.EvGoLabel { 417 panic(fmt.Sprintf("internal error: unexpected event type for Label kind: %s", go122.EventString(e.base.typ))) 418 } 419 return Label{ 420 Label: e.table.strings.mustGet(stringID(e.base.args[0])), 421 Resource: ResourceID{Kind: ResourceGoroutine, id: int64(e.ctx.G)}, 422 } 423 } 424 425 // Range returns details about an EventRangeBegin, EventRangeActive, or EventRangeEnd event. 426 // 427 // Panics if Kind != EventRangeBegin, Kind != EventRangeActive, and Kind != EventRangeEnd. 428 func (e Event) Range() Range { 429 if kind := e.Kind(); kind != EventRangeBegin && kind != EventRangeActive && kind != EventRangeEnd { 430 panic("Range called on non-Range event") 431 } 432 var r Range 433 switch e.base.typ { 434 case go122.EvSTWBegin, go122.EvSTWEnd: 435 // N.B. ordering.advance smuggles in the STW reason as e.base.args[0] 436 // for go122.EvSTWEnd (it's already there for Begin). 437 r.Name = "stop-the-world (" + e.table.strings.mustGet(stringID(e.base.args[0])) + ")" 438 r.Scope = ResourceID{Kind: ResourceGoroutine, id: int64(e.Goroutine())} 439 case go122.EvGCBegin, go122.EvGCActive, go122.EvGCEnd: 440 r.Name = "GC concurrent mark phase" 441 r.Scope = ResourceID{Kind: ResourceNone} 442 case go122.EvGCSweepBegin, go122.EvGCSweepActive, go122.EvGCSweepEnd: 443 r.Name = "GC incremental sweep" 444 r.Scope = ResourceID{Kind: ResourceProc} 445 if e.base.typ == go122.EvGCSweepActive { 446 r.Scope.id = int64(e.base.args[0]) 447 } else { 448 r.Scope.id = int64(e.Proc()) 449 } 450 r.Scope.id = int64(e.Proc()) 451 case go122.EvGCMarkAssistBegin, go122.EvGCMarkAssistActive, go122.EvGCMarkAssistEnd: 452 r.Name = "GC mark assist" 453 r.Scope = ResourceID{Kind: ResourceGoroutine} 454 if e.base.typ == go122.EvGCMarkAssistActive { 455 r.Scope.id = int64(e.base.args[0]) 456 } else { 457 r.Scope.id = int64(e.Goroutine()) 458 } 459 default: 460 panic(fmt.Sprintf("internal error: unexpected event type for Range kind: %s", go122.EventString(e.base.typ))) 461 } 462 return r 463 } 464 465 // RangeAttributes returns attributes for a completed range. 466 // 467 // Panics if Kind != EventRangeEnd. 468 func (e Event) RangeAttributes() []RangeAttribute { 469 if e.Kind() != EventRangeEnd { 470 panic("Range called on non-Range event") 471 } 472 if e.base.typ != go122.EvGCSweepEnd { 473 return nil 474 } 475 return []RangeAttribute{ 476 { 477 Name: "bytes swept", 478 Value: Value{kind: ValueUint64, scalar: e.base.args[0]}, 479 }, 480 { 481 Name: "bytes reclaimed", 482 Value: Value{kind: ValueUint64, scalar: e.base.args[1]}, 483 }, 484 } 485 } 486 487 // Task returns details about a TaskBegin or TaskEnd event. 488 // 489 // Panics if Kind != EventTaskBegin and Kind != EventTaskEnd. 490 func (e Event) Task() Task { 491 if kind := e.Kind(); kind != EventTaskBegin && kind != EventTaskEnd { 492 panic("Task called on non-Task event") 493 } 494 parentID := NoTask 495 var typ string 496 switch e.base.typ { 497 case go122.EvUserTaskBegin: 498 parentID = TaskID(e.base.args[1]) 499 typ = e.table.strings.mustGet(stringID(e.base.args[2])) 500 case go122.EvUserTaskEnd: 501 parentID = TaskID(e.base.extra(version.Go122)[0]) 502 typ = e.table.getExtraString(extraStringID(e.base.extra(version.Go122)[1])) 503 default: 504 panic(fmt.Sprintf("internal error: unexpected event type for Task kind: %s", go122.EventString(e.base.typ))) 505 } 506 return Task{ 507 ID: TaskID(e.base.args[0]), 508 Parent: parentID, 509 Type: typ, 510 } 511 } 512 513 // Region returns details about a RegionBegin or RegionEnd event. 514 // 515 // Panics if Kind != EventRegionBegin and Kind != EventRegionEnd. 516 func (e Event) Region() Region { 517 if kind := e.Kind(); kind != EventRegionBegin && kind != EventRegionEnd { 518 panic("Region called on non-Region event") 519 } 520 if e.base.typ != go122.EvUserRegionBegin && e.base.typ != go122.EvUserRegionEnd { 521 panic(fmt.Sprintf("internal error: unexpected event type for Region kind: %s", go122.EventString(e.base.typ))) 522 } 523 return Region{ 524 Task: TaskID(e.base.args[0]), 525 Type: e.table.strings.mustGet(stringID(e.base.args[1])), 526 } 527 } 528 529 // Log returns details about a Log event. 530 // 531 // Panics if Kind != EventLog. 532 func (e Event) Log() Log { 533 if e.Kind() != EventLog { 534 panic("Log called on non-Log event") 535 } 536 if e.base.typ != go122.EvUserLog { 537 panic(fmt.Sprintf("internal error: unexpected event type for Log kind: %s", go122.EventString(e.base.typ))) 538 } 539 return Log{ 540 Task: TaskID(e.base.args[0]), 541 Category: e.table.strings.mustGet(stringID(e.base.args[1])), 542 Message: e.table.strings.mustGet(stringID(e.base.args[2])), 543 } 544 } 545 546 // StateTransition returns details about a StateTransition event. 547 // 548 // Panics if Kind != EventStateTransition. 549 func (e Event) StateTransition() StateTransition { 550 if e.Kind() != EventStateTransition { 551 panic("StateTransition called on non-StateTransition event") 552 } 553 var s StateTransition 554 switch e.base.typ { 555 case go122.EvProcStart: 556 s = procStateTransition(ProcID(e.base.args[0]), ProcIdle, ProcRunning) 557 case go122.EvProcStop: 558 s = procStateTransition(e.ctx.P, ProcRunning, ProcIdle) 559 case go122.EvProcSteal: 560 // N.B. ordering.advance populates e.base.extra. 561 beforeState := ProcRunning 562 if go122.ProcStatus(e.base.extra(version.Go122)[0]) == go122.ProcSyscallAbandoned { 563 // We've lost information because this ProcSteal advanced on a 564 // SyscallAbandoned state. Treat the P as idle because ProcStatus 565 // treats SyscallAbandoned as Idle. Otherwise we'll have an invalid 566 // transition. 567 beforeState = ProcIdle 568 } 569 s = procStateTransition(ProcID(e.base.args[0]), beforeState, ProcIdle) 570 case go122.EvProcStatus: 571 // N.B. ordering.advance populates e.base.extra. 572 s = procStateTransition(ProcID(e.base.args[0]), ProcState(e.base.extra(version.Go122)[0]), go122ProcStatus2ProcState[e.base.args[1]]) 573 case go122.EvGoCreate, go122.EvGoCreateBlocked: 574 status := GoRunnable 575 if e.base.typ == go122.EvGoCreateBlocked { 576 status = GoWaiting 577 } 578 s = goStateTransition(GoID(e.base.args[0]), GoNotExist, status) 579 s.Stack = Stack{table: e.table, id: stackID(e.base.args[1])} 580 case go122.EvGoCreateSyscall: 581 s = goStateTransition(GoID(e.base.args[0]), GoNotExist, GoSyscall) 582 case go122.EvGoStart: 583 s = goStateTransition(GoID(e.base.args[0]), GoRunnable, GoRunning) 584 case go122.EvGoDestroy: 585 s = goStateTransition(e.ctx.G, GoRunning, GoNotExist) 586 s.Stack = e.Stack() // This event references the resource the event happened on. 587 case go122.EvGoDestroySyscall: 588 s = goStateTransition(e.ctx.G, GoSyscall, GoNotExist) 589 case go122.EvGoStop: 590 s = goStateTransition(e.ctx.G, GoRunning, GoRunnable) 591 s.Reason = e.table.strings.mustGet(stringID(e.base.args[0])) 592 s.Stack = e.Stack() // This event references the resource the event happened on. 593 case go122.EvGoBlock: 594 s = goStateTransition(e.ctx.G, GoRunning, GoWaiting) 595 s.Reason = e.table.strings.mustGet(stringID(e.base.args[0])) 596 s.Stack = e.Stack() // This event references the resource the event happened on. 597 case go122.EvGoUnblock, go122.EvGoSwitch, go122.EvGoSwitchDestroy: 598 // N.B. GoSwitch and GoSwitchDestroy both emit additional events, but 599 // the first thing they both do is unblock the goroutine they name, 600 // identically to an unblock event (even their arguments match). 601 s = goStateTransition(GoID(e.base.args[0]), GoWaiting, GoRunnable) 602 case go122.EvGoSyscallBegin: 603 s = goStateTransition(e.ctx.G, GoRunning, GoSyscall) 604 s.Stack = e.Stack() // This event references the resource the event happened on. 605 case go122.EvGoSyscallEnd: 606 s = goStateTransition(e.ctx.G, GoSyscall, GoRunning) 607 s.Stack = e.Stack() // This event references the resource the event happened on. 608 case go122.EvGoSyscallEndBlocked: 609 s = goStateTransition(e.ctx.G, GoSyscall, GoRunnable) 610 s.Stack = e.Stack() // This event references the resource the event happened on. 611 case go122.EvGoStatus, go122.EvGoStatusStack: 612 // N.B. ordering.advance populates e.base.extra. 613 s = goStateTransition(GoID(e.base.args[0]), GoState(e.base.extra(version.Go122)[0]), go122GoStatus2GoState[e.base.args[2]]) 614 default: 615 panic(fmt.Sprintf("internal error: unexpected event type for StateTransition kind: %s", go122.EventString(e.base.typ))) 616 } 617 return s 618 } 619 620 const evSync = ^event.Type(0) 621 622 var go122Type2Kind = [...]EventKind{ 623 go122.EvCPUSample: EventStackSample, 624 go122.EvProcsChange: EventMetric, 625 go122.EvProcStart: EventStateTransition, 626 go122.EvProcStop: EventStateTransition, 627 go122.EvProcSteal: EventStateTransition, 628 go122.EvProcStatus: EventStateTransition, 629 go122.EvGoCreate: EventStateTransition, 630 go122.EvGoCreateSyscall: EventStateTransition, 631 go122.EvGoStart: EventStateTransition, 632 go122.EvGoDestroy: EventStateTransition, 633 go122.EvGoDestroySyscall: EventStateTransition, 634 go122.EvGoStop: EventStateTransition, 635 go122.EvGoBlock: EventStateTransition, 636 go122.EvGoUnblock: EventStateTransition, 637 go122.EvGoSyscallBegin: EventStateTransition, 638 go122.EvGoSyscallEnd: EventStateTransition, 639 go122.EvGoSyscallEndBlocked: EventStateTransition, 640 go122.EvGoStatus: EventStateTransition, 641 go122.EvSTWBegin: EventRangeBegin, 642 go122.EvSTWEnd: EventRangeEnd, 643 go122.EvGCActive: EventRangeActive, 644 go122.EvGCBegin: EventRangeBegin, 645 go122.EvGCEnd: EventRangeEnd, 646 go122.EvGCSweepActive: EventRangeActive, 647 go122.EvGCSweepBegin: EventRangeBegin, 648 go122.EvGCSweepEnd: EventRangeEnd, 649 go122.EvGCMarkAssistActive: EventRangeActive, 650 go122.EvGCMarkAssistBegin: EventRangeBegin, 651 go122.EvGCMarkAssistEnd: EventRangeEnd, 652 go122.EvHeapAlloc: EventMetric, 653 go122.EvHeapGoal: EventMetric, 654 go122.EvGoLabel: EventLabel, 655 go122.EvUserTaskBegin: EventTaskBegin, 656 go122.EvUserTaskEnd: EventTaskEnd, 657 go122.EvUserRegionBegin: EventRegionBegin, 658 go122.EvUserRegionEnd: EventRegionEnd, 659 go122.EvUserLog: EventLog, 660 go122.EvGoSwitch: EventStateTransition, 661 go122.EvGoSwitchDestroy: EventStateTransition, 662 go122.EvGoCreateBlocked: EventStateTransition, 663 go122.EvGoStatusStack: EventStateTransition, 664 evSync: EventSync, 665 } 666 667 var go122GoStatus2GoState = [...]GoState{ 668 go122.GoRunnable: GoRunnable, 669 go122.GoRunning: GoRunning, 670 go122.GoWaiting: GoWaiting, 671 go122.GoSyscall: GoSyscall, 672 } 673 674 var go122ProcStatus2ProcState = [...]ProcState{ 675 go122.ProcRunning: ProcRunning, 676 go122.ProcIdle: ProcIdle, 677 go122.ProcSyscall: ProcRunning, 678 go122.ProcSyscallAbandoned: ProcIdle, 679 } 680 681 // String returns the event as a human-readable string. 682 // 683 // The format of the string is intended for debugging and is subject to change. 684 func (e Event) String() string { 685 var sb strings.Builder 686 fmt.Fprintf(&sb, "M=%d P=%d G=%d", e.Thread(), e.Proc(), e.Goroutine()) 687 fmt.Fprintf(&sb, " %s Time=%d", e.Kind(), e.Time()) 688 // Kind-specific fields. 689 switch kind := e.Kind(); kind { 690 case EventMetric: 691 m := e.Metric() 692 fmt.Fprintf(&sb, " Name=%q Value=%s", m.Name, valueAsString(m.Value)) 693 case EventLabel: 694 l := e.Label() 695 fmt.Fprintf(&sb, " Label=%q Resource=%s", l.Label, l.Resource) 696 case EventRangeBegin, EventRangeActive, EventRangeEnd: 697 r := e.Range() 698 fmt.Fprintf(&sb, " Name=%q Scope=%s", r.Name, r.Scope) 699 if kind == EventRangeEnd { 700 fmt.Fprintf(&sb, " Attributes=[") 701 for i, attr := range e.RangeAttributes() { 702 if i != 0 { 703 fmt.Fprintf(&sb, " ") 704 } 705 fmt.Fprintf(&sb, "%q=%s", attr.Name, valueAsString(attr.Value)) 706 } 707 fmt.Fprintf(&sb, "]") 708 } 709 case EventTaskBegin, EventTaskEnd: 710 t := e.Task() 711 fmt.Fprintf(&sb, " ID=%d Parent=%d Type=%q", t.ID, t.Parent, t.Type) 712 case EventRegionBegin, EventRegionEnd: 713 r := e.Region() 714 fmt.Fprintf(&sb, " Task=%d Type=%q", r.Task, r.Type) 715 case EventLog: 716 l := e.Log() 717 fmt.Fprintf(&sb, " Task=%d Category=%q Message=%q", l.Task, l.Category, l.Message) 718 case EventStateTransition: 719 s := e.StateTransition() 720 fmt.Fprintf(&sb, " Resource=%s Reason=%q", s.Resource, s.Reason) 721 switch s.Resource.Kind { 722 case ResourceGoroutine: 723 id := s.Resource.Goroutine() 724 old, new := s.Goroutine() 725 fmt.Fprintf(&sb, " GoID=%d %s->%s", id, old, new) 726 case ResourceProc: 727 id := s.Resource.Proc() 728 old, new := s.Proc() 729 fmt.Fprintf(&sb, " ProcID=%d %s->%s", id, old, new) 730 } 731 if s.Stack != NoStack { 732 fmt.Fprintln(&sb) 733 fmt.Fprintln(&sb, "TransitionStack=") 734 s.Stack.Frames(func(f StackFrame) bool { 735 fmt.Fprintf(&sb, "\t%s @ 0x%x\n", f.Func, f.PC) 736 fmt.Fprintf(&sb, "\t\t%s:%d\n", f.File, f.Line) 737 return true 738 }) 739 } 740 } 741 if stk := e.Stack(); stk != NoStack { 742 fmt.Fprintln(&sb) 743 fmt.Fprintln(&sb, "Stack=") 744 stk.Frames(func(f StackFrame) bool { 745 fmt.Fprintf(&sb, "\t%s @ 0x%x\n", f.Func, f.PC) 746 fmt.Fprintf(&sb, "\t\t%s:%d\n", f.File, f.Line) 747 return true 748 }) 749 } 750 return sb.String() 751 } 752 753 // validateTableIDs checks to make sure lookups in e.table 754 // will work. 755 func (e Event) validateTableIDs() error { 756 if e.base.typ == evSync { 757 return nil 758 } 759 spec := go122.Specs()[e.base.typ] 760 761 // Check stacks. 762 for _, i := range spec.StackIDs { 763 id := stackID(e.base.args[i-1]) 764 _, ok := e.table.stacks.get(id) 765 if !ok { 766 return fmt.Errorf("found invalid stack ID %d for event %s", id, spec.Name) 767 } 768 } 769 // N.B. Strings referenced by stack frames are validated 770 // early on, when reading the stacks in to begin with. 771 772 // Check strings. 773 for _, i := range spec.StringIDs { 774 id := stringID(e.base.args[i-1]) 775 _, ok := e.table.strings.get(id) 776 if !ok { 777 return fmt.Errorf("found invalid string ID %d for event %s", id, spec.Name) 778 } 779 } 780 return nil 781 } 782 783 func syncEvent(table *evTable, ts Time) Event { 784 return Event{ 785 table: table, 786 ctx: schedCtx{ 787 G: NoGoroutine, 788 P: NoProc, 789 M: NoThread, 790 }, 791 base: baseEvent{ 792 typ: evSync, 793 time: ts, 794 }, 795 } 796 }