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 case tracev2.EvGCMarkAssistBegin, tracev2.EvGCMarkAssistActive, tracev2.EvGCMarkAssistEnd:
493 r.Name = "GC mark assist"
494 r.Scope = ResourceID{Kind: ResourceGoroutine}
495 if e.base.typ == tracev2.EvGCMarkAssistActive {
496 r.Scope.id = int64(e.base.args[0])
497 } else {
498 r.Scope.id = int64(e.Goroutine())
499 }
500 default:
501 panic(fmt.Sprintf("internal error: unexpected wire-event type for Range kind: %d", e.base.typ))
502 }
503 return r
504 }
505
506
507
508
509 func (e Event) RangeAttributes() []RangeAttribute {
510 if e.Kind() != EventRangeEnd {
511 panic("Range called on non-Range event")
512 }
513 if e.base.typ != tracev2.EvGCSweepEnd {
514 return nil
515 }
516 return []RangeAttribute{
517 {
518 Name: "bytes swept",
519 Value: uint64Value(e.base.args[0]),
520 },
521 {
522 Name: "bytes reclaimed",
523 Value: uint64Value(e.base.args[1]),
524 },
525 }
526 }
527
528
529
530
531 func (e Event) Task() Task {
532 if kind := e.Kind(); kind != EventTaskBegin && kind != EventTaskEnd {
533 panic("Task called on non-Task event")
534 }
535 parentID := NoTask
536 var typ string
537 switch e.base.typ {
538 case tracev2.EvUserTaskBegin:
539 parentID = TaskID(e.base.args[1])
540 typ = e.table.strings.mustGet(stringID(e.base.args[2]))
541 case tracev2.EvUserTaskEnd:
542 parentID = TaskID(e.base.extra(version.Go122)[0])
543 typ = e.table.getExtraString(extraStringID(e.base.extra(version.Go122)[1]))
544 default:
545 panic(fmt.Sprintf("internal error: unexpected wire-format event type for Task kind: %d", e.base.typ))
546 }
547 return Task{
548 ID: TaskID(e.base.args[0]),
549 Parent: parentID,
550 Type: typ,
551 }
552 }
553
554
555
556
557 func (e Event) Region() Region {
558 if kind := e.Kind(); kind != EventRegionBegin && kind != EventRegionEnd {
559 panic("Region called on non-Region event")
560 }
561 if e.base.typ != tracev2.EvUserRegionBegin && e.base.typ != tracev2.EvUserRegionEnd {
562 panic(fmt.Sprintf("internal error: unexpected wire-format event type for Region kind: %d", e.base.typ))
563 }
564 return Region{
565 Task: TaskID(e.base.args[0]),
566 Type: e.table.strings.mustGet(stringID(e.base.args[1])),
567 }
568 }
569
570
571
572
573 func (e Event) Log() Log {
574 if e.Kind() != EventLog {
575 panic("Log called on non-Log event")
576 }
577 if e.base.typ != tracev2.EvUserLog {
578 panic(fmt.Sprintf("internal error: unexpected wire-format event type for Log kind: %d", e.base.typ))
579 }
580 return Log{
581 Task: TaskID(e.base.args[0]),
582 Category: e.table.strings.mustGet(stringID(e.base.args[1])),
583 Message: e.table.strings.mustGet(stringID(e.base.args[2])),
584 }
585 }
586
587
588
589
590 func (e Event) StateTransition() StateTransition {
591 if e.Kind() != EventStateTransition {
592 panic("StateTransition called on non-StateTransition event")
593 }
594 var s StateTransition
595 switch e.base.typ {
596 case tracev2.EvProcStart:
597 s = procStateTransition(ProcID(e.base.args[0]), ProcIdle, ProcRunning)
598 case tracev2.EvProcStop:
599 s = procStateTransition(e.ctx.P, ProcRunning, ProcIdle)
600 case tracev2.EvProcSteal:
601
602 beforeState := ProcRunning
603 if tracev2.ProcStatus(e.base.extra(version.Go122)[0]) == tracev2.ProcSyscallAbandoned {
604
605
606
607
608 beforeState = ProcIdle
609 }
610 s = procStateTransition(ProcID(e.base.args[0]), beforeState, ProcIdle)
611 case tracev2.EvProcStatus:
612
613 s = procStateTransition(ProcID(e.base.args[0]), ProcState(e.base.extra(version.Go122)[0]), tracev2ProcStatus2ProcState[e.base.args[1]])
614 case tracev2.EvGoCreate, tracev2.EvGoCreateBlocked:
615 status := GoRunnable
616 if e.base.typ == tracev2.EvGoCreateBlocked {
617 status = GoWaiting
618 }
619 s = goStateTransition(GoID(e.base.args[0]), GoNotExist, status)
620 s.Stack = Stack{table: e.table, id: stackID(e.base.args[1])}
621 case tracev2.EvGoCreateSyscall:
622 s = goStateTransition(GoID(e.base.args[0]), GoNotExist, GoSyscall)
623 case tracev2.EvGoStart:
624 s = goStateTransition(GoID(e.base.args[0]), GoRunnable, GoRunning)
625 case tracev2.EvGoDestroy:
626 s = goStateTransition(e.ctx.G, GoRunning, GoNotExist)
627 case tracev2.EvGoDestroySyscall:
628 s = goStateTransition(e.ctx.G, GoSyscall, GoNotExist)
629 case tracev2.EvGoStop:
630 s = goStateTransition(e.ctx.G, GoRunning, GoRunnable)
631 s.Reason = e.table.strings.mustGet(stringID(e.base.args[0]))
632 s.Stack = e.Stack()
633 case tracev2.EvGoBlock:
634 s = goStateTransition(e.ctx.G, GoRunning, GoWaiting)
635 s.Reason = e.table.strings.mustGet(stringID(e.base.args[0]))
636 s.Stack = e.Stack()
637 case tracev2.EvGoUnblock, tracev2.EvGoSwitch, tracev2.EvGoSwitchDestroy:
638
639
640
641 s = goStateTransition(GoID(e.base.args[0]), GoWaiting, GoRunnable)
642 case tracev2.EvGoSyscallBegin:
643 s = goStateTransition(e.ctx.G, GoRunning, GoSyscall)
644 s.Stack = e.Stack()
645 case tracev2.EvGoSyscallEnd:
646 s = goStateTransition(e.ctx.G, GoSyscall, GoRunning)
647 case tracev2.EvGoSyscallEndBlocked:
648 s = goStateTransition(e.ctx.G, GoSyscall, GoRunnable)
649 case tracev2.EvGoStatus, tracev2.EvGoStatusStack:
650 packedStatus := e.base.args[2]
651 from, to := packedStatus>>32, packedStatus&((1<<32)-1)
652 s = goStateTransition(GoID(e.base.args[0]), GoState(from), tracev2GoStatus2GoState[to])
653 default:
654 panic(fmt.Sprintf("internal error: unexpected wire-format event type for StateTransition kind: %d", e.base.typ))
655 }
656 return s
657 }
658
659
660
661 func (e Event) Sync() Sync {
662 if e.Kind() != EventSync {
663 panic("Sync called on non-Sync event")
664 }
665 s := Sync{N: int(e.base.args[0])}
666 if e.table != nil {
667 expBatches := make(map[string][]ExperimentalBatch)
668 for exp, batches := range e.table.expBatches {
669 expBatches[tracev2.Experiments()[exp]] = batches
670 }
671 s.ExperimentalBatches = expBatches
672 if e.table.hasClockSnapshot {
673 s.ClockSnapshot = &ClockSnapshot{
674 Trace: e.table.freq.mul(e.table.snapTime),
675 Wall: e.table.snapWall,
676 Mono: e.table.snapMono,
677 }
678 }
679 }
680 return s
681 }
682
683
684
685 type Sync struct {
686
687 N int
688
689
690
691
692
693
694 ClockSnapshot *ClockSnapshot
695
696
697 ExperimentalBatches map[string][]ExperimentalBatch
698 }
699
700
701
702
703
704 type ClockSnapshot struct {
705
706 Trace Time
707
708
709 Wall time.Time
710
711
712 Mono uint64
713 }
714
715
716
717
718 func (e Event) Experimental() ExperimentalEvent {
719 if e.Kind() != EventExperimental {
720 panic("Experimental called on non-Experimental event")
721 }
722 spec := tracev2.Specs()[e.base.typ]
723 argNames := spec.Args[1:]
724 return ExperimentalEvent{
725 Name: spec.Name,
726 Experiment: tracev2.Experiments()[spec.Experiment],
727 Args: argNames,
728 table: e.table,
729 argValues: e.base.args[:len(argNames)],
730 }
731 }
732
733 const evSync = ^tracev2.EventType(0)
734
735 var tracev2Type2Kind = [...]EventKind{
736 tracev2.EvCPUSample: EventStackSample,
737 tracev2.EvProcsChange: EventMetric,
738 tracev2.EvProcStart: EventStateTransition,
739 tracev2.EvProcStop: EventStateTransition,
740 tracev2.EvProcSteal: EventStateTransition,
741 tracev2.EvProcStatus: EventStateTransition,
742 tracev2.EvGoCreate: EventStateTransition,
743 tracev2.EvGoCreateSyscall: EventStateTransition,
744 tracev2.EvGoStart: EventStateTransition,
745 tracev2.EvGoDestroy: EventStateTransition,
746 tracev2.EvGoDestroySyscall: EventStateTransition,
747 tracev2.EvGoStop: EventStateTransition,
748 tracev2.EvGoBlock: EventStateTransition,
749 tracev2.EvGoUnblock: EventStateTransition,
750 tracev2.EvGoSyscallBegin: EventStateTransition,
751 tracev2.EvGoSyscallEnd: EventStateTransition,
752 tracev2.EvGoSyscallEndBlocked: EventStateTransition,
753 tracev2.EvGoStatus: EventStateTransition,
754 tracev2.EvSTWBegin: EventRangeBegin,
755 tracev2.EvSTWEnd: EventRangeEnd,
756 tracev2.EvGCActive: EventRangeActive,
757 tracev2.EvGCBegin: EventRangeBegin,
758 tracev2.EvGCEnd: EventRangeEnd,
759 tracev2.EvGCSweepActive: EventRangeActive,
760 tracev2.EvGCSweepBegin: EventRangeBegin,
761 tracev2.EvGCSweepEnd: EventRangeEnd,
762 tracev2.EvGCMarkAssistActive: EventRangeActive,
763 tracev2.EvGCMarkAssistBegin: EventRangeBegin,
764 tracev2.EvGCMarkAssistEnd: EventRangeEnd,
765 tracev2.EvHeapAlloc: EventMetric,
766 tracev2.EvHeapGoal: EventMetric,
767 tracev2.EvGoLabel: EventLabel,
768 tracev2.EvUserTaskBegin: EventTaskBegin,
769 tracev2.EvUserTaskEnd: EventTaskEnd,
770 tracev2.EvUserRegionBegin: EventRegionBegin,
771 tracev2.EvUserRegionEnd: EventRegionEnd,
772 tracev2.EvUserLog: EventLog,
773 tracev2.EvGoSwitch: EventStateTransition,
774 tracev2.EvGoSwitchDestroy: EventStateTransition,
775 tracev2.EvGoCreateBlocked: EventStateTransition,
776 tracev2.EvGoStatusStack: EventStateTransition,
777 tracev2.EvSpan: EventExperimental,
778 tracev2.EvSpanAlloc: EventExperimental,
779 tracev2.EvSpanFree: EventExperimental,
780 tracev2.EvHeapObject: EventExperimental,
781 tracev2.EvHeapObjectAlloc: EventExperimental,
782 tracev2.EvHeapObjectFree: EventExperimental,
783 tracev2.EvGoroutineStack: EventExperimental,
784 tracev2.EvGoroutineStackAlloc: EventExperimental,
785 tracev2.EvGoroutineStackFree: EventExperimental,
786 evSync: EventSync,
787 }
788
789 var tracev2GoStatus2GoState = [...]GoState{
790 tracev2.GoRunnable: GoRunnable,
791 tracev2.GoRunning: GoRunning,
792 tracev2.GoWaiting: GoWaiting,
793 tracev2.GoSyscall: GoSyscall,
794 }
795
796 var tracev2ProcStatus2ProcState = [...]ProcState{
797 tracev2.ProcRunning: ProcRunning,
798 tracev2.ProcIdle: ProcIdle,
799 tracev2.ProcSyscall: ProcRunning,
800 tracev2.ProcSyscallAbandoned: ProcIdle,
801 }
802
803
804
805
806 func (e Event) String() string {
807 var sb strings.Builder
808 fmt.Fprintf(&sb, "M=%d P=%d G=%d", e.Thread(), e.Proc(), e.Goroutine())
809 fmt.Fprintf(&sb, " %s Time=%d", e.Kind(), e.Time())
810
811 switch kind := e.Kind(); kind {
812 case EventMetric:
813 m := e.Metric()
814 v := m.Value.String()
815 if m.Value.Kind() == ValueString {
816 v = strconv.Quote(v)
817 }
818 fmt.Fprintf(&sb, " Name=%q Value=%s", m.Name, m.Value)
819 case EventLabel:
820 l := e.Label()
821 fmt.Fprintf(&sb, " Label=%q Resource=%s", l.Label, l.Resource)
822 case EventRangeBegin, EventRangeActive, EventRangeEnd:
823 r := e.Range()
824 fmt.Fprintf(&sb, " Name=%q Scope=%s", r.Name, r.Scope)
825 if kind == EventRangeEnd {
826 fmt.Fprintf(&sb, " Attributes=[")
827 for i, attr := range e.RangeAttributes() {
828 if i != 0 {
829 fmt.Fprintf(&sb, " ")
830 }
831 fmt.Fprintf(&sb, "%q=%s", attr.Name, attr.Value)
832 }
833 fmt.Fprintf(&sb, "]")
834 }
835 case EventTaskBegin, EventTaskEnd:
836 t := e.Task()
837 fmt.Fprintf(&sb, " ID=%d Parent=%d Type=%q", t.ID, t.Parent, t.Type)
838 case EventRegionBegin, EventRegionEnd:
839 r := e.Region()
840 fmt.Fprintf(&sb, " Task=%d Type=%q", r.Task, r.Type)
841 case EventLog:
842 l := e.Log()
843 fmt.Fprintf(&sb, " Task=%d Category=%q Message=%q", l.Task, l.Category, l.Message)
844 case EventStateTransition:
845 s := e.StateTransition()
846 switch s.Resource.Kind {
847 case ResourceGoroutine:
848 id := s.Resource.Goroutine()
849 old, new := s.Goroutine()
850 fmt.Fprintf(&sb, " GoID=%d %s->%s", id, old, new)
851 case ResourceProc:
852 id := s.Resource.Proc()
853 old, new := s.Proc()
854 fmt.Fprintf(&sb, " ProcID=%d %s->%s", id, old, new)
855 }
856 fmt.Fprintf(&sb, " Reason=%q", s.Reason)
857 if s.Stack != NoStack {
858 fmt.Fprintln(&sb)
859 fmt.Fprintln(&sb, "TransitionStack=")
860 for f := range s.Stack.Frames() {
861 fmt.Fprintf(&sb, "\t%s @ 0x%x\n", f.Func, f.PC)
862 fmt.Fprintf(&sb, "\t\t%s:%d\n", f.File, f.Line)
863 }
864 }
865 case EventExperimental:
866 r := e.Experimental()
867 fmt.Fprintf(&sb, " Name=%s Args=[", r.Name)
868 for i, arg := range r.Args {
869 if i != 0 {
870 fmt.Fprintf(&sb, ", ")
871 }
872 fmt.Fprintf(&sb, "%s=%s", arg, r.ArgValue(i).String())
873 }
874 fmt.Fprintf(&sb, "]")
875 case EventSync:
876 s := e.Sync()
877 fmt.Fprintf(&sb, " N=%d", s.N)
878 if s.ClockSnapshot != nil {
879 fmt.Fprintf(&sb, " Trace=%d Mono=%d Wall=%s",
880 s.ClockSnapshot.Trace,
881 s.ClockSnapshot.Mono,
882 s.ClockSnapshot.Wall.Format(time.RFC3339Nano),
883 )
884 }
885 }
886 if stk := e.Stack(); stk != NoStack {
887 fmt.Fprintln(&sb)
888 fmt.Fprintln(&sb, "Stack=")
889 for f := range stk.Frames() {
890 fmt.Fprintf(&sb, "\t%s @ 0x%x\n", f.Func, f.PC)
891 fmt.Fprintf(&sb, "\t\t%s:%d\n", f.File, f.Line)
892 }
893 }
894 return sb.String()
895 }
896
897
898
899 func (e Event) validateTableIDs() error {
900 if e.base.typ == evSync {
901 return nil
902 }
903 spec := tracev2.Specs()[e.base.typ]
904
905
906 for _, i := range spec.StackIDs {
907 id := stackID(e.base.args[i-1])
908 _, ok := e.table.stacks.get(id)
909 if !ok {
910 return fmt.Errorf("found invalid stack ID %d for event %s", id, spec.Name)
911 }
912 }
913
914
915
916
917 for _, i := range spec.StringIDs {
918 id := stringID(e.base.args[i-1])
919 _, ok := e.table.strings.get(id)
920 if !ok {
921 return fmt.Errorf("found invalid string ID %d for event %s", id, spec.Name)
922 }
923 }
924 return nil
925 }
926
927 func syncEvent(table *evTable, ts Time, n int) Event {
928 ev := Event{
929 table: table,
930 ctx: schedCtx{
931 G: NoGoroutine,
932 P: NoProc,
933 M: NoThread,
934 },
935 base: baseEvent{
936 typ: evSync,
937 time: ts,
938 },
939 }
940 ev.base.args[0] = uint64(n)
941 return ev
942 }
943
View as plain text