1
2
3
4
5 package trace
6
7 import (
8 "fmt"
9 "iter"
10 "math"
11 "strconv"
12 "strings"
13 "time"
14
15 "internal/trace/tracev2"
16 "internal/trace/version"
17 )
18
19
20
21
22
23 type EventKind uint16
24
25 const (
26 EventBad EventKind = iota
27
28
29
30
31
32 EventSync
33
34
35
36 EventMetric
37
38
39 EventLabel
40
41
42
43
44
45
46
47
48
49 EventStackSample
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65 EventRangeBegin
66 EventRangeActive
67 EventRangeEnd
68
69
70 EventTaskBegin
71 EventTaskEnd
72
73
74 EventRegionBegin
75 EventRegionEnd
76
77
78 EventLog
79
80
81 EventStateTransition
82
83
84
85
86 EventExperimental
87 )
88
89
90 func (e EventKind) String() string {
91 if int(e) >= len(eventKindStrings) {
92 return eventKindStrings[0]
93 }
94 return eventKindStrings[e]
95 }
96
97 var eventKindStrings = [...]string{
98 EventBad: "Bad",
99 EventSync: "Sync",
100 EventMetric: "Metric",
101 EventLabel: "Label",
102 EventStackSample: "StackSample",
103 EventRangeBegin: "RangeBegin",
104 EventRangeActive: "RangeActive",
105 EventRangeEnd: "RangeEnd",
106 EventTaskBegin: "TaskBegin",
107 EventTaskEnd: "TaskEnd",
108 EventRegionBegin: "RegionBegin",
109 EventRegionEnd: "RegionEnd",
110 EventLog: "Log",
111 EventStateTransition: "StateTransition",
112 EventExperimental: "Experimental",
113 }
114
115 const maxTime = Time(math.MaxInt64)
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136 type Time int64
137
138
139 func (t Time) Sub(t0 Time) time.Duration {
140 return time.Duration(int64(t) - int64(t0))
141 }
142
143
144 type Metric struct {
145
146
147
148
149
150
151
152
153 Name string
154
155
156
157
158
159 Value Value
160 }
161
162
163 type Label struct {
164
165 Label string
166
167
168 Resource ResourceID
169 }
170
171
172 type Range struct {
173
174
175
176
177
178
179
180 Name string
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197 Scope ResourceID
198 }
199
200
201 type RangeAttribute struct {
202
203 Name string
204
205
206 Value Value
207 }
208
209
210
211 type TaskID uint64
212
213 const (
214
215 NoTask = TaskID(^uint64(0))
216
217
218
219 BackgroundTask = TaskID(0)
220 )
221
222
223 type Task struct {
224
225
226
227 ID TaskID
228
229
230 Parent TaskID
231
232
233
234
235 Type string
236 }
237
238
239 type Region struct {
240
241 Task TaskID
242
243
244 Type string
245 }
246
247
248 type Log struct {
249
250 Task TaskID
251
252
253 Category string
254
255
256 Message string
257 }
258
259
260
261
262
263 type Stack struct {
264 table *evTable
265 id stackID
266 }
267
268
269 func (s Stack) Frames() iter.Seq[StackFrame] {
270 return func(yield func(StackFrame) bool) {
271 if s.id == 0 {
272 return
273 }
274 stk := s.table.stacks.mustGet(s.id)
275 for _, pc := range stk.pcs {
276 f := s.table.pcs[pc]
277 sf := StackFrame{
278 PC: f.pc,
279 Func: s.table.strings.mustGet(f.funcID),
280 File: s.table.strings.mustGet(f.fileID),
281 Line: f.line,
282 }
283 if !yield(sf) {
284 return
285 }
286 }
287 }
288 }
289
290
291
292 var NoStack = Stack{}
293
294
295 type StackFrame struct {
296
297
298
299 PC uint64
300
301
302 Func string
303
304
305 File string
306
307
308 Line uint64
309 }
310
311
312 type ExperimentalEvent struct {
313
314 Name string
315
316
317 Experiment string
318
319
320 Args []string
321
322
323
324 table *evTable
325 argValues []uint64
326 }
327
328
329 func (e ExperimentalEvent) ArgValue(i int) Value {
330 if i < 0 || i >= len(e.Args) {
331 panic(fmt.Sprintf("experimental event argument index %d out of bounds [0, %d)", i, len(e.Args)))
332 }
333 if strings.HasSuffix(e.Args[i], "string") {
334 s := e.table.strings.mustGet(stringID(e.argValues[i]))
335 return stringValue(s)
336 }
337 return uint64Value(e.argValues[i])
338 }
339
340
341 type ExperimentalBatch struct {
342
343 Thread ThreadID
344
345
346 Data []byte
347 }
348
349
350 type Event struct {
351 table *evTable
352 ctx schedCtx
353 base baseEvent
354 }
355
356
357 func (e Event) Kind() EventKind {
358 return tracev2Type2Kind[e.base.typ]
359 }
360
361
362 func (e Event) Time() Time {
363 return e.base.time
364 }
365
366
367
368
369
370
371
372
373
374
375 func (e Event) Goroutine() GoID {
376 return e.ctx.G
377 }
378
379
380
381
382
383
384 func (e Event) Proc() ProcID {
385 return e.ctx.P
386 }
387
388
389
390
391
392
393
394
395
396
397
398 func (e Event) Thread() ThreadID {
399 return e.ctx.M
400 }
401
402
403
404
405
406 func (e Event) Stack() Stack {
407 if e.base.typ == evSync {
408 return NoStack
409 }
410 if e.base.typ == tracev2.EvCPUSample {
411 return Stack{table: e.table, id: stackID(e.base.args[0])}
412 }
413 spec := tracev2.Specs()[e.base.typ]
414 if len(spec.StackIDs) == 0 {
415 return NoStack
416 }
417
418
419
420 id := stackID(e.base.args[spec.StackIDs[0]-1])
421 if id == 0 {
422 return NoStack
423 }
424 return Stack{table: e.table, id: id}
425 }
426
427
428
429
430 func (e Event) Metric() Metric {
431 if e.Kind() != EventMetric {
432 panic("Metric called on non-Metric event")
433 }
434 var m Metric
435 switch e.base.typ {
436 case tracev2.EvProcsChange:
437 m.Name = "/sched/gomaxprocs:threads"
438 m.Value = uint64Value(e.base.args[0])
439 case tracev2.EvHeapAlloc:
440 m.Name = "/memory/classes/heap/objects:bytes"
441 m.Value = uint64Value(e.base.args[0])
442 case tracev2.EvHeapGoal:
443 m.Name = "/gc/heap/goal:bytes"
444 m.Value = uint64Value(e.base.args[0])
445 default:
446 panic(fmt.Sprintf("internal error: unexpected wire-format event type for Metric kind: %d", e.base.typ))
447 }
448 return m
449 }
450
451
452
453
454 func (e Event) Label() Label {
455 if e.Kind() != EventLabel {
456 panic("Label called on non-Label event")
457 }
458 if e.base.typ != tracev2.EvGoLabel {
459 panic(fmt.Sprintf("internal error: unexpected wire-format event type for Label kind: %d", e.base.typ))
460 }
461 return Label{
462 Label: e.table.strings.mustGet(stringID(e.base.args[0])),
463 Resource: ResourceID{Kind: ResourceGoroutine, id: int64(e.ctx.G)},
464 }
465 }
466
467
468
469
470 func (e Event) Range() Range {
471 if kind := e.Kind(); kind != EventRangeBegin && kind != EventRangeActive && kind != EventRangeEnd {
472 panic("Range called on non-Range event")
473 }
474 var r Range
475 switch e.base.typ {
476 case tracev2.EvSTWBegin, tracev2.EvSTWEnd:
477
478
479 r.Name = "stop-the-world (" + e.table.strings.mustGet(stringID(e.base.args[0])) + ")"
480 r.Scope = ResourceID{Kind: ResourceGoroutine, id: int64(e.Goroutine())}
481 case tracev2.EvGCBegin, tracev2.EvGCActive, tracev2.EvGCEnd:
482 r.Name = "GC concurrent mark phase"
483 r.Scope = ResourceID{Kind: ResourceNone}
484 case tracev2.EvGCSweepBegin, tracev2.EvGCSweepActive, tracev2.EvGCSweepEnd:
485 r.Name = "GC incremental sweep"
486 r.Scope = ResourceID{Kind: ResourceProc}
487 if e.base.typ == tracev2.EvGCSweepActive {
488 r.Scope.id = int64(e.base.args[0])
489 } else {
490 r.Scope.id = int64(e.Proc())
491 }
492 r.Scope.id = int64(e.Proc())
493 case tracev2.EvGCMarkAssistBegin, tracev2.EvGCMarkAssistActive, tracev2.EvGCMarkAssistEnd:
494 r.Name = "GC mark assist"
495 r.Scope = ResourceID{Kind: ResourceGoroutine}
496 if e.base.typ == tracev2.EvGCMarkAssistActive {
497 r.Scope.id = int64(e.base.args[0])
498 } else {
499 r.Scope.id = int64(e.Goroutine())
500 }
501 default:
502 panic(fmt.Sprintf("internal error: unexpected wire-event type for Range kind: %d", e.base.typ))
503 }
504 return r
505 }
506
507
508
509
510 func (e Event) RangeAttributes() []RangeAttribute {
511 if e.Kind() != EventRangeEnd {
512 panic("Range called on non-Range event")
513 }
514 if e.base.typ != tracev2.EvGCSweepEnd {
515 return nil
516 }
517 return []RangeAttribute{
518 {
519 Name: "bytes swept",
520 Value: uint64Value(e.base.args[0]),
521 },
522 {
523 Name: "bytes reclaimed",
524 Value: uint64Value(e.base.args[1]),
525 },
526 }
527 }
528
529
530
531
532 func (e Event) Task() Task {
533 if kind := e.Kind(); kind != EventTaskBegin && kind != EventTaskEnd {
534 panic("Task called on non-Task event")
535 }
536 parentID := NoTask
537 var typ string
538 switch e.base.typ {
539 case tracev2.EvUserTaskBegin:
540 parentID = TaskID(e.base.args[1])
541 typ = e.table.strings.mustGet(stringID(e.base.args[2]))
542 case tracev2.EvUserTaskEnd:
543 parentID = TaskID(e.base.extra(version.Go122)[0])
544 typ = e.table.getExtraString(extraStringID(e.base.extra(version.Go122)[1]))
545 default:
546 panic(fmt.Sprintf("internal error: unexpected wire-format event type for Task kind: %d", e.base.typ))
547 }
548 return Task{
549 ID: TaskID(e.base.args[0]),
550 Parent: parentID,
551 Type: typ,
552 }
553 }
554
555
556
557
558 func (e Event) Region() Region {
559 if kind := e.Kind(); kind != EventRegionBegin && kind != EventRegionEnd {
560 panic("Region called on non-Region event")
561 }
562 if e.base.typ != tracev2.EvUserRegionBegin && e.base.typ != tracev2.EvUserRegionEnd {
563 panic(fmt.Sprintf("internal error: unexpected wire-format event type for Region kind: %d", e.base.typ))
564 }
565 return Region{
566 Task: TaskID(e.base.args[0]),
567 Type: e.table.strings.mustGet(stringID(e.base.args[1])),
568 }
569 }
570
571
572
573
574 func (e Event) Log() Log {
575 if e.Kind() != EventLog {
576 panic("Log called on non-Log event")
577 }
578 if e.base.typ != tracev2.EvUserLog {
579 panic(fmt.Sprintf("internal error: unexpected wire-format event type for Log kind: %d", e.base.typ))
580 }
581 return Log{
582 Task: TaskID(e.base.args[0]),
583 Category: e.table.strings.mustGet(stringID(e.base.args[1])),
584 Message: e.table.strings.mustGet(stringID(e.base.args[2])),
585 }
586 }
587
588
589
590
591 func (e Event) StateTransition() StateTransition {
592 if e.Kind() != EventStateTransition {
593 panic("StateTransition called on non-StateTransition event")
594 }
595 var s StateTransition
596 switch e.base.typ {
597 case tracev2.EvProcStart:
598 s = procStateTransition(ProcID(e.base.args[0]), ProcIdle, ProcRunning)
599 case tracev2.EvProcStop:
600 s = procStateTransition(e.ctx.P, ProcRunning, ProcIdle)
601 case tracev2.EvProcSteal:
602
603 beforeState := ProcRunning
604 if tracev2.ProcStatus(e.base.extra(version.Go122)[0]) == tracev2.ProcSyscallAbandoned {
605
606
607
608
609 beforeState = ProcIdle
610 }
611 s = procStateTransition(ProcID(e.base.args[0]), beforeState, ProcIdle)
612 case tracev2.EvProcStatus:
613
614 s = procStateTransition(ProcID(e.base.args[0]), ProcState(e.base.extra(version.Go122)[0]), tracev2ProcStatus2ProcState[e.base.args[1]])
615 case tracev2.EvGoCreate, tracev2.EvGoCreateBlocked:
616 status := GoRunnable
617 if e.base.typ == tracev2.EvGoCreateBlocked {
618 status = GoWaiting
619 }
620 s = goStateTransition(GoID(e.base.args[0]), GoNotExist, status)
621 s.Stack = Stack{table: e.table, id: stackID(e.base.args[1])}
622 case tracev2.EvGoCreateSyscall:
623 s = goStateTransition(GoID(e.base.args[0]), GoNotExist, GoSyscall)
624 case tracev2.EvGoStart:
625 s = goStateTransition(GoID(e.base.args[0]), GoRunnable, GoRunning)
626 case tracev2.EvGoDestroy:
627 s = goStateTransition(e.ctx.G, GoRunning, GoNotExist)
628 s.Stack = e.Stack()
629 case tracev2.EvGoDestroySyscall:
630 s = goStateTransition(e.ctx.G, GoSyscall, GoNotExist)
631 case tracev2.EvGoStop:
632 s = goStateTransition(e.ctx.G, GoRunning, GoRunnable)
633 s.Reason = e.table.strings.mustGet(stringID(e.base.args[0]))
634 s.Stack = e.Stack()
635 case tracev2.EvGoBlock:
636 s = goStateTransition(e.ctx.G, GoRunning, GoWaiting)
637 s.Reason = e.table.strings.mustGet(stringID(e.base.args[0]))
638 s.Stack = e.Stack()
639 case tracev2.EvGoUnblock, tracev2.EvGoSwitch, tracev2.EvGoSwitchDestroy:
640
641
642
643 s = goStateTransition(GoID(e.base.args[0]), GoWaiting, GoRunnable)
644 case tracev2.EvGoSyscallBegin:
645 s = goStateTransition(e.ctx.G, GoRunning, GoSyscall)
646 s.Stack = e.Stack()
647 case tracev2.EvGoSyscallEnd:
648 s = goStateTransition(e.ctx.G, GoSyscall, GoRunning)
649 s.Stack = e.Stack()
650 case tracev2.EvGoSyscallEndBlocked:
651 s = goStateTransition(e.ctx.G, GoSyscall, GoRunnable)
652 s.Stack = e.Stack()
653 case tracev2.EvGoStatus, tracev2.EvGoStatusStack:
654 packedStatus := e.base.args[2]
655 from, to := packedStatus>>32, packedStatus&((1<<32)-1)
656 s = goStateTransition(GoID(e.base.args[0]), GoState(from), tracev2GoStatus2GoState[to])
657 default:
658 panic(fmt.Sprintf("internal error: unexpected wire-format event type for StateTransition kind: %d", e.base.typ))
659 }
660 return s
661 }
662
663
664
665 func (e Event) Sync() Sync {
666 if e.Kind() != EventSync {
667 panic("Sync called on non-Sync event")
668 }
669 s := Sync{N: int(e.base.args[0])}
670 if e.table != nil {
671 expBatches := make(map[string][]ExperimentalBatch)
672 for exp, batches := range e.table.expBatches {
673 expBatches[tracev2.Experiments()[exp]] = batches
674 }
675 s.ExperimentalBatches = expBatches
676 if e.table.hasClockSnapshot {
677 s.ClockSnapshot = &ClockSnapshot{
678 Trace: e.table.freq.mul(e.table.snapTime),
679 Wall: e.table.snapWall,
680 Mono: e.table.snapMono,
681 }
682 }
683 }
684 return s
685 }
686
687
688
689 type Sync struct {
690
691 N int
692
693
694
695
696 ClockSnapshot *ClockSnapshot
697
698
699 ExperimentalBatches map[string][]ExperimentalBatch
700 }
701
702
703
704
705
706 type ClockSnapshot struct {
707
708 Trace Time
709
710
711 Wall time.Time
712
713
714 Mono uint64
715 }
716
717
718
719
720 func (e Event) Experimental() ExperimentalEvent {
721 if e.Kind() != EventExperimental {
722 panic("Experimental called on non-Experimental event")
723 }
724 spec := tracev2.Specs()[e.base.typ]
725 argNames := spec.Args[1:]
726 return ExperimentalEvent{
727 Name: spec.Name,
728 Experiment: tracev2.Experiments()[spec.Experiment],
729 Args: argNames,
730 table: e.table,
731 argValues: e.base.args[:len(argNames)],
732 }
733 }
734
735 const evSync = ^tracev2.EventType(0)
736
737 var tracev2Type2Kind = [...]EventKind{
738 tracev2.EvCPUSample: EventStackSample,
739 tracev2.EvProcsChange: EventMetric,
740 tracev2.EvProcStart: EventStateTransition,
741 tracev2.EvProcStop: EventStateTransition,
742 tracev2.EvProcSteal: EventStateTransition,
743 tracev2.EvProcStatus: EventStateTransition,
744 tracev2.EvGoCreate: EventStateTransition,
745 tracev2.EvGoCreateSyscall: EventStateTransition,
746 tracev2.EvGoStart: EventStateTransition,
747 tracev2.EvGoDestroy: EventStateTransition,
748 tracev2.EvGoDestroySyscall: EventStateTransition,
749 tracev2.EvGoStop: EventStateTransition,
750 tracev2.EvGoBlock: EventStateTransition,
751 tracev2.EvGoUnblock: EventStateTransition,
752 tracev2.EvGoSyscallBegin: EventStateTransition,
753 tracev2.EvGoSyscallEnd: EventStateTransition,
754 tracev2.EvGoSyscallEndBlocked: EventStateTransition,
755 tracev2.EvGoStatus: EventStateTransition,
756 tracev2.EvSTWBegin: EventRangeBegin,
757 tracev2.EvSTWEnd: EventRangeEnd,
758 tracev2.EvGCActive: EventRangeActive,
759 tracev2.EvGCBegin: EventRangeBegin,
760 tracev2.EvGCEnd: EventRangeEnd,
761 tracev2.EvGCSweepActive: EventRangeActive,
762 tracev2.EvGCSweepBegin: EventRangeBegin,
763 tracev2.EvGCSweepEnd: EventRangeEnd,
764 tracev2.EvGCMarkAssistActive: EventRangeActive,
765 tracev2.EvGCMarkAssistBegin: EventRangeBegin,
766 tracev2.EvGCMarkAssistEnd: EventRangeEnd,
767 tracev2.EvHeapAlloc: EventMetric,
768 tracev2.EvHeapGoal: EventMetric,
769 tracev2.EvGoLabel: EventLabel,
770 tracev2.EvUserTaskBegin: EventTaskBegin,
771 tracev2.EvUserTaskEnd: EventTaskEnd,
772 tracev2.EvUserRegionBegin: EventRegionBegin,
773 tracev2.EvUserRegionEnd: EventRegionEnd,
774 tracev2.EvUserLog: EventLog,
775 tracev2.EvGoSwitch: EventStateTransition,
776 tracev2.EvGoSwitchDestroy: EventStateTransition,
777 tracev2.EvGoCreateBlocked: EventStateTransition,
778 tracev2.EvGoStatusStack: EventStateTransition,
779 tracev2.EvSpan: EventExperimental,
780 tracev2.EvSpanAlloc: EventExperimental,
781 tracev2.EvSpanFree: EventExperimental,
782 tracev2.EvHeapObject: EventExperimental,
783 tracev2.EvHeapObjectAlloc: EventExperimental,
784 tracev2.EvHeapObjectFree: EventExperimental,
785 tracev2.EvGoroutineStack: EventExperimental,
786 tracev2.EvGoroutineStackAlloc: EventExperimental,
787 tracev2.EvGoroutineStackFree: EventExperimental,
788 evSync: EventSync,
789 }
790
791 var tracev2GoStatus2GoState = [...]GoState{
792 tracev2.GoRunnable: GoRunnable,
793 tracev2.GoRunning: GoRunning,
794 tracev2.GoWaiting: GoWaiting,
795 tracev2.GoSyscall: GoSyscall,
796 }
797
798 var tracev2ProcStatus2ProcState = [...]ProcState{
799 tracev2.ProcRunning: ProcRunning,
800 tracev2.ProcIdle: ProcIdle,
801 tracev2.ProcSyscall: ProcRunning,
802 tracev2.ProcSyscallAbandoned: ProcIdle,
803 }
804
805
806
807
808 func (e Event) String() string {
809 var sb strings.Builder
810 fmt.Fprintf(&sb, "M=%d P=%d G=%d", e.Thread(), e.Proc(), e.Goroutine())
811 fmt.Fprintf(&sb, " %s Time=%d", e.Kind(), e.Time())
812
813 switch kind := e.Kind(); kind {
814 case EventMetric:
815 m := e.Metric()
816 v := m.Value.String()
817 if m.Value.Kind() == ValueString {
818 v = strconv.Quote(v)
819 }
820 fmt.Fprintf(&sb, " Name=%q Value=%s", m.Name, m.Value)
821 case EventLabel:
822 l := e.Label()
823 fmt.Fprintf(&sb, " Label=%q Resource=%s", l.Label, l.Resource)
824 case EventRangeBegin, EventRangeActive, EventRangeEnd:
825 r := e.Range()
826 fmt.Fprintf(&sb, " Name=%q Scope=%s", r.Name, r.Scope)
827 if kind == EventRangeEnd {
828 fmt.Fprintf(&sb, " Attributes=[")
829 for i, attr := range e.RangeAttributes() {
830 if i != 0 {
831 fmt.Fprintf(&sb, " ")
832 }
833 fmt.Fprintf(&sb, "%q=%s", attr.Name, attr.Value)
834 }
835 fmt.Fprintf(&sb, "]")
836 }
837 case EventTaskBegin, EventTaskEnd:
838 t := e.Task()
839 fmt.Fprintf(&sb, " ID=%d Parent=%d Type=%q", t.ID, t.Parent, t.Type)
840 case EventRegionBegin, EventRegionEnd:
841 r := e.Region()
842 fmt.Fprintf(&sb, " Task=%d Type=%q", r.Task, r.Type)
843 case EventLog:
844 l := e.Log()
845 fmt.Fprintf(&sb, " Task=%d Category=%q Message=%q", l.Task, l.Category, l.Message)
846 case EventStateTransition:
847 s := e.StateTransition()
848 fmt.Fprintf(&sb, " Resource=%s Reason=%q", s.Resource, s.Reason)
849 switch s.Resource.Kind {
850 case ResourceGoroutine:
851 id := s.Resource.Goroutine()
852 old, new := s.Goroutine()
853 fmt.Fprintf(&sb, " GoID=%d %s->%s", id, old, new)
854 case ResourceProc:
855 id := s.Resource.Proc()
856 old, new := s.Proc()
857 fmt.Fprintf(&sb, " ProcID=%d %s->%s", id, old, new)
858 }
859 if s.Stack != NoStack {
860 fmt.Fprintln(&sb)
861 fmt.Fprintln(&sb, "TransitionStack=")
862 for f := range s.Stack.Frames() {
863 fmt.Fprintf(&sb, "\t%s @ 0x%x\n", f.Func, f.PC)
864 fmt.Fprintf(&sb, "\t\t%s:%d\n", f.File, f.Line)
865 }
866 }
867 case EventExperimental:
868 r := e.Experimental()
869 fmt.Fprintf(&sb, " Name=%s Args=[", r.Name)
870 for i, arg := range r.Args {
871 if i != 0 {
872 fmt.Fprintf(&sb, ", ")
873 }
874 fmt.Fprintf(&sb, "%s=%s", arg, r.ArgValue(i).String())
875 }
876 fmt.Fprintf(&sb, "]")
877 case EventSync:
878 s := e.Sync()
879 fmt.Fprintf(&sb, " N=%d", s.N)
880 if s.ClockSnapshot != nil {
881 fmt.Fprintf(&sb, " Trace=%d Mono=%d Wall=%s",
882 s.ClockSnapshot.Trace,
883 s.ClockSnapshot.Mono,
884 s.ClockSnapshot.Wall.Format(time.RFC3339),
885 )
886 }
887 }
888 if stk := e.Stack(); stk != NoStack {
889 fmt.Fprintln(&sb)
890 fmt.Fprintln(&sb, "Stack=")
891 for f := range stk.Frames() {
892 fmt.Fprintf(&sb, "\t%s @ 0x%x\n", f.Func, f.PC)
893 fmt.Fprintf(&sb, "\t\t%s:%d\n", f.File, f.Line)
894 }
895 }
896 return sb.String()
897 }
898
899
900
901 func (e Event) validateTableIDs() error {
902 if e.base.typ == evSync {
903 return nil
904 }
905 spec := tracev2.Specs()[e.base.typ]
906
907
908 for _, i := range spec.StackIDs {
909 id := stackID(e.base.args[i-1])
910 _, ok := e.table.stacks.get(id)
911 if !ok {
912 return fmt.Errorf("found invalid stack ID %d for event %s", id, spec.Name)
913 }
914 }
915
916
917
918
919 for _, i := range spec.StringIDs {
920 id := stringID(e.base.args[i-1])
921 _, ok := e.table.strings.get(id)
922 if !ok {
923 return fmt.Errorf("found invalid string ID %d for event %s", id, spec.Name)
924 }
925 }
926 return nil
927 }
928
929 func syncEvent(table *evTable, ts Time, n int) Event {
930 ev := Event{
931 table: table,
932 ctx: schedCtx{
933 G: NoGoroutine,
934 P: NoProc,
935 M: NoThread,
936 },
937 base: baseEvent{
938 typ: evSync,
939 time: ts,
940 },
941 }
942 ev.base.args[0] = uint64(n)
943 return ev
944 }
945
View as plain text