1
2
3
4
5 package trace
6
7 import (
8 "fmt"
9 "strings"
10
11 "internal/trace/v2/event"
12 "internal/trace/v2/event/go122"
13 "internal/trace/v2/version"
14 )
15
16
17
18 type ordering struct {
19 gStates map[GoID]*gState
20 pStates map[ProcID]*pState
21 mStates map[ThreadID]*mState
22 activeTasks map[TaskID]taskState
23 gcSeq uint64
24 gcState gcState
25 initialGen uint64
26
27
28
29
30
31
32 extraEvent Event
33 }
34
35
36 func (o *ordering) consumeExtraEvent() Event {
37 if o.extraEvent.Kind() == EventBad {
38 return Event{}
39 }
40 r := o.extraEvent
41 o.extraEvent = Event{}
42 return r
43 }
44
45
46
47
48
49
50
51
52
53
54
55
56 func (o *ordering) advance(ev *baseEvent, evt *evTable, m ThreadID, gen uint64) (schedCtx, bool, error) {
57 if o.initialGen == 0 {
58
59 o.initialGen = gen
60 }
61
62 var curCtx, newCtx schedCtx
63 curCtx.M = m
64 newCtx.M = m
65
66 if m == NoThread {
67 curCtx.P = NoProc
68 curCtx.G = NoGoroutine
69 newCtx = curCtx
70 } else {
71
72 ms, ok := o.mStates[m]
73 if !ok {
74 ms = &mState{
75 g: NoGoroutine,
76 p: NoProc,
77 }
78 o.mStates[m] = ms
79 }
80 curCtx.P = ms.p
81 curCtx.G = ms.g
82 newCtx = curCtx
83 defer func() {
84
85 ms.p = newCtx.P
86 ms.g = newCtx.G
87 }()
88 }
89
90 switch typ := ev.typ; typ {
91
92 case go122.EvProcStatus:
93 pid := ProcID(ev.args[0])
94 status := go122.ProcStatus(ev.args[1])
95 if int(status) >= len(go122ProcStatus2ProcState) {
96 return curCtx, false, fmt.Errorf("invalid status for proc %d: %d", pid, status)
97 }
98 oldState := go122ProcStatus2ProcState[status]
99 if s, ok := o.pStates[pid]; ok {
100 if status == go122.ProcSyscallAbandoned && s.status == go122.ProcSyscall {
101
102
103
104 oldState = ProcRunning
105 ev.args[1] = uint64(go122.ProcSyscall)
106 } else if status == go122.ProcSyscallAbandoned && s.status == go122.ProcSyscallAbandoned {
107
108
109
110 oldState = ProcIdle
111 ev.args[1] = uint64(go122.ProcSyscallAbandoned)
112 } else if s.status != status {
113 return curCtx, false, fmt.Errorf("inconsistent status for proc %d: old %v vs. new %v", pid, s.status, status)
114 }
115 s.seq = makeSeq(gen, 0)
116 } else {
117 o.pStates[pid] = &pState{id: pid, status: status, seq: makeSeq(gen, 0)}
118 if gen == o.initialGen {
119 oldState = ProcUndetermined
120 } else {
121 oldState = ProcNotExist
122 }
123 }
124 ev.extra(version.Go122)[0] = uint64(oldState)
125
126
127 if status == go122.ProcRunning || status == go122.ProcSyscall {
128 newCtx.P = pid
129 }
130
131
132
133
134
135
136 if status == go122.ProcSyscallAbandoned && oldState == ProcRunning {
137
138 found := false
139 for mid, ms := range o.mStates {
140 if ms.p == pid {
141 curCtx.M = mid
142 curCtx.P = pid
143 curCtx.G = ms.g
144 found = true
145 }
146 }
147 if !found {
148 return curCtx, false, fmt.Errorf("failed to find sched context for proc %d that's about to be stolen", pid)
149 }
150 }
151 return curCtx, true, nil
152 case go122.EvProcStart:
153 pid := ProcID(ev.args[0])
154 seq := makeSeq(gen, ev.args[1])
155
156
157
158
159 state, ok := o.pStates[pid]
160 if !ok || state.status != go122.ProcIdle || !seq.succeeds(state.seq) || curCtx.P != NoProc {
161
162
163
164
165
166 return curCtx, false, nil
167 }
168
169
170
171 reqs := event.SchedReqs{Thread: event.MustHave, Proc: event.MustNotHave, Goroutine: event.MayHave}
172 if err := validateCtx(curCtx, reqs); err != nil {
173 return curCtx, false, err
174 }
175 state.status = go122.ProcRunning
176 state.seq = seq
177 newCtx.P = pid
178 return curCtx, true, nil
179 case go122.EvProcStop:
180
181
182
183
184
185
186
187
188
189 state, ok := o.pStates[curCtx.P]
190 if !ok {
191 return curCtx, false, fmt.Errorf("event %s for proc (%v) that doesn't exist", go122.EventString(typ), curCtx.P)
192 }
193 if state.status != go122.ProcRunning && state.status != go122.ProcSyscall {
194 return curCtx, false, fmt.Errorf("%s event for proc that's not %s or %s", go122.EventString(typ), go122.ProcRunning, go122.ProcSyscall)
195 }
196 reqs := event.SchedReqs{Thread: event.MustHave, Proc: event.MustHave, Goroutine: event.MayHave}
197 if err := validateCtx(curCtx, reqs); err != nil {
198 return curCtx, false, err
199 }
200 state.status = go122.ProcIdle
201 newCtx.P = NoProc
202 return curCtx, true, nil
203 case go122.EvProcSteal:
204 pid := ProcID(ev.args[0])
205 seq := makeSeq(gen, ev.args[1])
206 state, ok := o.pStates[pid]
207 if !ok || (state.status != go122.ProcSyscall && state.status != go122.ProcSyscallAbandoned) || !seq.succeeds(state.seq) {
208
209
210
211 return curCtx, false, nil
212 }
213
214 reqs := event.SchedReqs{Thread: event.MustHave, Proc: event.MayHave, Goroutine: event.MayHave}
215 if err := validateCtx(curCtx, reqs); err != nil {
216 return curCtx, false, err
217 }
218
219
220
221
222
223
224 oldStatus := state.status
225 ev.extra(version.Go122)[0] = uint64(oldStatus)
226
227
228 state.status = go122.ProcIdle
229 state.seq = seq
230
231
232
233 if oldStatus == go122.ProcSyscallAbandoned {
234 return curCtx, true, nil
235 }
236
237
238 mid := ThreadID(ev.args[2])
239
240 if mid == curCtx.M {
241
242 if curCtx.P != pid {
243 return curCtx, false, fmt.Errorf("tried to self-steal proc %d (thread %d), but got proc %d instead", pid, mid, curCtx.P)
244 }
245 newCtx.P = NoProc
246 return curCtx, true, nil
247 }
248
249
250 mState, ok := o.mStates[mid]
251 if !ok {
252 return curCtx, false, fmt.Errorf("stole proc from non-existent thread %d", mid)
253 }
254
255
256 if mState.p != pid {
257 return curCtx, false, fmt.Errorf("tried to steal proc %d from thread %d, but got proc %d instead", pid, mid, mState.p)
258 }
259
260
261
262
263
264
265
266 mState.p = NoProc
267 return curCtx, true, nil
268
269
270 case go122.EvGoStatus:
271 gid := GoID(ev.args[0])
272 mid := ThreadID(ev.args[1])
273 status := go122.GoStatus(ev.args[2])
274
275 if int(status) >= len(go122GoStatus2GoState) {
276 return curCtx, false, fmt.Errorf("invalid status for goroutine %d: %d", gid, status)
277 }
278 oldState := go122GoStatus2GoState[status]
279 if s, ok := o.gStates[gid]; ok {
280 if s.status != status {
281 return curCtx, false, fmt.Errorf("inconsistent status for goroutine %d: old %v vs. new %v", gid, s.status, status)
282 }
283 s.seq = makeSeq(gen, 0)
284 } else if gen == o.initialGen {
285
286 o.gStates[gid] = &gState{id: gid, status: status, seq: makeSeq(gen, 0)}
287 oldState = GoUndetermined
288 } else {
289 return curCtx, false, fmt.Errorf("found goroutine status for new goroutine after the first generation: id=%v status=%v", gid, status)
290 }
291 ev.extra(version.Go122)[0] = uint64(oldState)
292
293 switch status {
294 case go122.GoRunning:
295
296 newCtx.G = gid
297 case go122.GoSyscall:
298 if mid == NoThread {
299 return curCtx, false, fmt.Errorf("found goroutine %d in syscall without a thread", gid)
300 }
301
302
303
304 if mid == curCtx.M {
305 if gen != o.initialGen && curCtx.G != gid {
306
307
308
309
310 return curCtx, false, fmt.Errorf("inconsistent thread for syscalling goroutine %d: thread has goroutine %d", gid, curCtx.G)
311 }
312 newCtx.G = gid
313 break
314 }
315
316
317
318
319
320 ms, ok := o.mStates[mid]
321 if ok {
322
323
324 if ms.g != gid {
325
326 return curCtx, false, fmt.Errorf("inconsistent thread for syscalling goroutine %d: thread has goroutine %d", gid, ms.g)
327 }
328
329
330 curCtx.G = ms.g
331 } else if !ok {
332
333
334
335 o.mStates[mid] = &mState{g: gid, p: NoProc}
336
337
338 }
339
340 curCtx.M = mid
341 }
342 return curCtx, true, nil
343 case go122.EvGoCreate:
344
345
346 reqs := event.SchedReqs{Thread: event.MustHave, Proc: event.MustHave, Goroutine: event.MayHave}
347 if err := validateCtx(curCtx, reqs); err != nil {
348 return curCtx, false, err
349 }
350
351 if state, ok := o.gStates[curCtx.G]; ok && state.status != go122.GoRunning {
352 return curCtx, false, fmt.Errorf("%s event for goroutine that's not %s", go122.EventString(typ), GoRunning)
353 }
354
355 newgid := GoID(ev.args[0])
356 if _, ok := o.gStates[newgid]; ok {
357 return curCtx, false, fmt.Errorf("tried to create goroutine (%v) that already exists", newgid)
358 }
359 o.gStates[newgid] = &gState{id: newgid, status: go122.GoRunnable, seq: makeSeq(gen, 0)}
360 return curCtx, true, nil
361 case go122.EvGoDestroy, go122.EvGoStop, go122.EvGoBlock:
362
363
364
365 if err := validateCtx(curCtx, event.UserGoReqs); err != nil {
366 return curCtx, false, err
367 }
368 state, ok := o.gStates[curCtx.G]
369 if !ok {
370 return curCtx, false, fmt.Errorf("event %s for goroutine (%v) that doesn't exist", go122.EventString(typ), curCtx.G)
371 }
372 if state.status != go122.GoRunning {
373 return curCtx, false, fmt.Errorf("%s event for goroutine that's not %s", go122.EventString(typ), GoRunning)
374 }
375
376
377 switch typ {
378 case go122.EvGoDestroy:
379
380 delete(o.gStates, curCtx.G)
381 newCtx.G = NoGoroutine
382 case go122.EvGoStop:
383
384 state.status = go122.GoRunnable
385 newCtx.G = NoGoroutine
386 case go122.EvGoBlock:
387
388 state.status = go122.GoWaiting
389 newCtx.G = NoGoroutine
390 }
391 return curCtx, true, nil
392 case go122.EvGoStart:
393 gid := GoID(ev.args[0])
394 seq := makeSeq(gen, ev.args[1])
395 state, ok := o.gStates[gid]
396 if !ok || state.status != go122.GoRunnable || !seq.succeeds(state.seq) {
397
398
399
400 return curCtx, false, nil
401 }
402
403 reqs := event.SchedReqs{Thread: event.MustHave, Proc: event.MustHave, Goroutine: event.MustNotHave}
404 if err := validateCtx(curCtx, reqs); err != nil {
405 return curCtx, false, err
406 }
407 state.status = go122.GoRunning
408 state.seq = seq
409 newCtx.G = gid
410 return curCtx, true, nil
411 case go122.EvGoUnblock:
412
413 gid := GoID(ev.args[0])
414 seq := makeSeq(gen, ev.args[1])
415 state, ok := o.gStates[gid]
416 if !ok || state.status != go122.GoWaiting || !seq.succeeds(state.seq) {
417
418
419
420 return curCtx, false, nil
421 }
422 state.status = go122.GoRunnable
423 state.seq = seq
424
425
426 return curCtx, true, nil
427 case go122.EvGoSyscallBegin:
428
429
430 if err := validateCtx(curCtx, event.UserGoReqs); err != nil {
431 return curCtx, false, err
432 }
433 state, ok := o.gStates[curCtx.G]
434 if !ok {
435 return curCtx, false, fmt.Errorf("event %s for goroutine (%v) that doesn't exist", go122.EventString(typ), curCtx.G)
436 }
437 if state.status != go122.GoRunning {
438 return curCtx, false, fmt.Errorf("%s event for goroutine that's not %s", go122.EventString(typ), GoRunning)
439 }
440
441 state.status = go122.GoSyscall
442 pState, ok := o.pStates[curCtx.P]
443 if !ok {
444 return curCtx, false, fmt.Errorf("uninitialized proc %d found during %s", curCtx.P, go122.EventString(typ))
445 }
446 pState.status = go122.ProcSyscall
447
448
449
450
451
452
453
454
455
456
457
458 pSeq := makeSeq(gen, ev.args[0])
459 if !pSeq.succeeds(pState.seq) {
460 return curCtx, false, fmt.Errorf("failed to advance %s: can't make sequence: %s -> %s", go122.EventString(typ), pState.seq, pSeq)
461 }
462 pState.seq = pSeq
463 return curCtx, true, nil
464 case go122.EvGoSyscallEnd:
465
466
467
468 if err := validateCtx(curCtx, event.UserGoReqs); err != nil {
469 return curCtx, false, err
470 }
471 state, ok := o.gStates[curCtx.G]
472 if !ok {
473 return curCtx, false, fmt.Errorf("event %s for goroutine (%v) that doesn't exist", go122.EventString(typ), curCtx.G)
474 }
475 if state.status != go122.GoSyscall {
476 return curCtx, false, fmt.Errorf("%s event for goroutine that's not %s", go122.EventString(typ), GoRunning)
477 }
478 state.status = go122.GoRunning
479
480
481 pState, ok := o.pStates[curCtx.P]
482 if !ok {
483 return curCtx, false, fmt.Errorf("uninitialized proc %d found during %s", curCtx.P, go122.EventString(typ))
484 }
485 if pState.status != go122.ProcSyscall {
486 return curCtx, false, fmt.Errorf("expected proc %d in state %v, but got %v instead", curCtx.P, go122.ProcSyscall, pState.status)
487 }
488 pState.status = go122.ProcRunning
489 return curCtx, true, nil
490 case go122.EvGoSyscallEndBlocked:
491
492
493
494
495
496
497
498
499
500
501 if curCtx.P != NoProc {
502 pState, ok := o.pStates[curCtx.P]
503 if !ok {
504 return curCtx, false, fmt.Errorf("uninitialized proc %d found during %s", curCtx.P, go122.EventString(typ))
505 }
506 if pState.status == go122.ProcSyscall {
507 return curCtx, false, nil
508 }
509 }
510
511
512 if err := validateCtx(curCtx, event.SchedReqs{Thread: event.MustHave, Proc: event.MayHave, Goroutine: event.MustHave}); err != nil {
513 return curCtx, false, err
514 }
515 state, ok := o.gStates[curCtx.G]
516 if !ok {
517 return curCtx, false, fmt.Errorf("event %s for goroutine (%v) that doesn't exist", go122.EventString(typ), curCtx.G)
518 }
519 if state.status != go122.GoSyscall {
520 return curCtx, false, fmt.Errorf("%s event for goroutine that's not %s", go122.EventString(typ), GoRunning)
521 }
522 newCtx.G = NoGoroutine
523 state.status = go122.GoRunnable
524 return curCtx, true, nil
525 case go122.EvGoCreateSyscall:
526
527
528
529 if err := validateCtx(curCtx, event.SchedReqs{Thread: event.MustHave, Proc: event.MayHave, Goroutine: event.MustNotHave}); err != nil {
530 return curCtx, false, err
531 }
532
533 newgid := GoID(ev.args[0])
534 if _, ok := o.gStates[newgid]; ok {
535 return curCtx, false, fmt.Errorf("tried to create goroutine (%v) in syscall that already exists", newgid)
536 }
537 o.gStates[newgid] = &gState{id: newgid, status: go122.GoSyscall, seq: makeSeq(gen, 0)}
538
539 newCtx.G = newgid
540 return curCtx, true, nil
541 case go122.EvGoDestroySyscall:
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558 if err := validateCtx(curCtx, event.SchedReqs{Thread: event.MustHave, Proc: event.MayHave, Goroutine: event.MustHave}); err != nil {
559 return curCtx, false, err
560 }
561
562 state, ok := o.gStates[curCtx.G]
563 if !ok {
564 return curCtx, false, fmt.Errorf("event %s for goroutine (%v) that doesn't exist", go122.EventString(typ), curCtx.G)
565 }
566 if state.status != go122.GoSyscall {
567 return curCtx, false, fmt.Errorf("%s event for goroutine that's not %v", go122.EventString(typ), GoSyscall)
568 }
569
570 delete(o.gStates, curCtx.G)
571 newCtx.G = NoGoroutine
572
573
574 if curCtx.P != NoProc {
575 pState, ok := o.pStates[curCtx.P]
576 if !ok {
577 return curCtx, false, fmt.Errorf("found invalid proc %d during %s", curCtx.P, go122.EventString(typ))
578 }
579 if pState.status != go122.ProcSyscall {
580 return curCtx, false, fmt.Errorf("proc %d in unexpected state %s during %s", curCtx.P, pState.status, go122.EventString(typ))
581 }
582
583 pState.status = go122.ProcSyscallAbandoned
584 newCtx.P = NoProc
585
586
587 o.extraEvent = Event{
588 table: evt,
589 ctx: curCtx,
590 base: baseEvent{
591 typ: go122.EvProcSteal,
592 time: ev.time,
593 },
594 }
595 o.extraEvent.base.args[0] = uint64(curCtx.P)
596 o.extraEvent.base.extra(version.Go122)[0] = uint64(go122.ProcSyscall)
597 }
598 return curCtx, true, nil
599
600
601
602
603
604
605
606
607 case go122.EvUserTaskBegin:
608 id := TaskID(ev.args[0])
609 if _, ok := o.activeTasks[id]; ok {
610 return curCtx, false, fmt.Errorf("task ID conflict: %d", id)
611 }
612
613
614 parentID := TaskID(ev.args[1])
615 if parentID == BackgroundTask {
616
617
618
619 parentID = NoTask
620 ev.args[1] = uint64(NoTask)
621 }
622
623
624
625 nameID := stringID(ev.args[2])
626 name, ok := evt.strings.get(nameID)
627 if !ok {
628 return curCtx, false, fmt.Errorf("invalid string ID %v for %v event", nameID, typ)
629 }
630 o.activeTasks[id] = taskState{name: name, parentID: parentID}
631 return curCtx, true, validateCtx(curCtx, event.UserGoReqs)
632 case go122.EvUserTaskEnd:
633 id := TaskID(ev.args[0])
634 if ts, ok := o.activeTasks[id]; ok {
635
636
637
638 ev.extra(version.Go122)[0] = uint64(ts.parentID)
639 ev.extra(version.Go122)[1] = uint64(evt.addExtraString(ts.name))
640 delete(o.activeTasks, id)
641 } else {
642
643 ev.extra(version.Go122)[0] = uint64(NoTask)
644 ev.extra(version.Go122)[1] = uint64(evt.addExtraString(""))
645 }
646 return curCtx, true, validateCtx(curCtx, event.UserGoReqs)
647
648
649 case go122.EvUserRegionBegin:
650 if err := validateCtx(curCtx, event.UserGoReqs); err != nil {
651 return curCtx, false, err
652 }
653 tid := TaskID(ev.args[0])
654 nameID := stringID(ev.args[1])
655 name, ok := evt.strings.get(nameID)
656 if !ok {
657 return curCtx, false, fmt.Errorf("invalid string ID %v for %v event", nameID, typ)
658 }
659 gState, ok := o.gStates[curCtx.G]
660 if !ok {
661 return curCtx, false, fmt.Errorf("encountered EvUserRegionBegin without known state for current goroutine %d", curCtx.G)
662 }
663 if err := gState.beginRegion(userRegion{tid, name}); err != nil {
664 return curCtx, false, err
665 }
666 return curCtx, true, nil
667 case go122.EvUserRegionEnd:
668 if err := validateCtx(curCtx, event.UserGoReqs); err != nil {
669 return curCtx, false, err
670 }
671 tid := TaskID(ev.args[0])
672 nameID := stringID(ev.args[1])
673 name, ok := evt.strings.get(nameID)
674 if !ok {
675 return curCtx, false, fmt.Errorf("invalid string ID %v for %v event", nameID, typ)
676 }
677 gState, ok := o.gStates[curCtx.G]
678 if !ok {
679 return curCtx, false, fmt.Errorf("encountered EvUserRegionEnd without known state for current goroutine %d", curCtx.G)
680 }
681 if err := gState.endRegion(userRegion{tid, name}); err != nil {
682 return curCtx, false, err
683 }
684 return curCtx, true, nil
685
686
687
688
689
690
691
692
693 case go122.EvGCActive:
694 seq := ev.args[0]
695 if gen == o.initialGen {
696 if o.gcState != gcUndetermined {
697 return curCtx, false, fmt.Errorf("GCActive in the first generation isn't first GC event")
698 }
699 o.gcSeq = seq
700 o.gcState = gcRunning
701 return curCtx, true, nil
702 }
703 if seq != o.gcSeq+1 {
704
705 return curCtx, false, nil
706 }
707 if o.gcState != gcRunning {
708 return curCtx, false, fmt.Errorf("encountered GCActive while GC was not in progress")
709 }
710 o.gcSeq = seq
711 if err := validateCtx(curCtx, event.UserGoReqs); err != nil {
712 return curCtx, false, err
713 }
714 return curCtx, true, nil
715 case go122.EvGCBegin:
716 seq := ev.args[0]
717 if o.gcState == gcUndetermined {
718 o.gcSeq = seq
719 o.gcState = gcRunning
720 return curCtx, true, nil
721 }
722 if seq != o.gcSeq+1 {
723
724 return curCtx, false, nil
725 }
726 if o.gcState == gcRunning {
727 return curCtx, false, fmt.Errorf("encountered GCBegin while GC was already in progress")
728 }
729 o.gcSeq = seq
730 o.gcState = gcRunning
731 if err := validateCtx(curCtx, event.UserGoReqs); err != nil {
732 return curCtx, false, err
733 }
734 return curCtx, true, nil
735 case go122.EvGCEnd:
736 seq := ev.args[0]
737 if seq != o.gcSeq+1 {
738
739 return curCtx, false, nil
740 }
741 if o.gcState == gcNotRunning {
742 return curCtx, false, fmt.Errorf("encountered GCEnd when GC was not in progress")
743 }
744 if o.gcState == gcUndetermined {
745 return curCtx, false, fmt.Errorf("encountered GCEnd when GC was in an undetermined state")
746 }
747 o.gcSeq = seq
748 o.gcState = gcNotRunning
749 if err := validateCtx(curCtx, event.UserGoReqs); err != nil {
750 return curCtx, false, err
751 }
752 return curCtx, true, nil
753
754
755 case go122.EvGoLabel, go122.EvProcsChange, go122.EvUserLog:
756 if err := validateCtx(curCtx, event.UserGoReqs); err != nil {
757 return curCtx, false, err
758 }
759 return curCtx, true, nil
760
761
762 case go122.EvHeapAlloc, go122.EvHeapGoal:
763 if err := validateCtx(curCtx, event.SchedReqs{Thread: event.MustHave, Proc: event.MustHave, Goroutine: event.MayHave}); err != nil {
764 return curCtx, false, err
765 }
766 return curCtx, true, nil
767
768
769 case go122.EvGCSweepBegin:
770 if err := validateCtx(curCtx, event.SchedReqs{Thread: event.MustHave, Proc: event.MustHave, Goroutine: event.MayHave}); err != nil {
771 return curCtx, false, err
772 }
773 if err := o.pStates[curCtx.P].beginRange(makeRangeType(typ, 0)); err != nil {
774 return curCtx, false, err
775 }
776 return curCtx, true, nil
777 case go122.EvGCSweepActive:
778 pid := ProcID(ev.args[0])
779
780
781
782
783 pState, ok := o.pStates[pid]
784 if !ok {
785 return curCtx, false, fmt.Errorf("encountered GCSweepActive for unknown proc %d", pid)
786 }
787 if err := pState.activeRange(makeRangeType(typ, 0), gen == o.initialGen); err != nil {
788 return curCtx, false, err
789 }
790 return curCtx, true, nil
791 case go122.EvGCSweepEnd:
792 if err := validateCtx(curCtx, event.SchedReqs{Thread: event.MustHave, Proc: event.MustHave, Goroutine: event.MayHave}); err != nil {
793 return curCtx, false, err
794 }
795 _, err := o.pStates[curCtx.P].endRange(typ)
796 if err != nil {
797 return curCtx, false, err
798 }
799 return curCtx, true, nil
800
801
802 case go122.EvSTWBegin, go122.EvGCMarkAssistBegin:
803 if err := validateCtx(curCtx, event.UserGoReqs); err != nil {
804 return curCtx, false, err
805 }
806 desc := stringID(0)
807 if typ == go122.EvSTWBegin {
808 desc = stringID(ev.args[0])
809 }
810 gState, ok := o.gStates[curCtx.G]
811 if !ok {
812 return curCtx, false, fmt.Errorf("encountered event of type %d without known state for current goroutine %d", typ, curCtx.G)
813 }
814 if err := gState.beginRange(makeRangeType(typ, desc)); err != nil {
815 return curCtx, false, err
816 }
817 return curCtx, true, nil
818 case go122.EvGCMarkAssistActive:
819 gid := GoID(ev.args[0])
820
821
822
823 gState, ok := o.gStates[gid]
824 if !ok {
825 return curCtx, false, fmt.Errorf("uninitialized goroutine %d found during %s", gid, go122.EventString(typ))
826 }
827 if err := gState.activeRange(makeRangeType(typ, 0), gen == o.initialGen); err != nil {
828 return curCtx, false, err
829 }
830 return curCtx, true, nil
831 case go122.EvSTWEnd, go122.EvGCMarkAssistEnd:
832 if err := validateCtx(curCtx, event.UserGoReqs); err != nil {
833 return curCtx, false, err
834 }
835 gState, ok := o.gStates[curCtx.G]
836 if !ok {
837 return curCtx, false, fmt.Errorf("encountered event of type %d without known state for current goroutine %d", typ, curCtx.G)
838 }
839 desc, err := gState.endRange(typ)
840 if err != nil {
841 return curCtx, false, err
842 }
843 if typ == go122.EvSTWEnd {
844
845
846 ev.args[0] = uint64(desc)
847 }
848 return curCtx, true, nil
849 }
850 return curCtx, false, fmt.Errorf("bad event type found while ordering: %v", ev.typ)
851 }
852
853
854 type schedCtx struct {
855 G GoID
856 P ProcID
857 M ThreadID
858 }
859
860
861
862 func validateCtx(ctx schedCtx, reqs event.SchedReqs) error {
863
864 if reqs.Thread == event.MustHave && ctx.M == NoThread {
865 return fmt.Errorf("expected a thread but didn't have one")
866 } else if reqs.Thread == event.MustNotHave && ctx.M != NoThread {
867 return fmt.Errorf("expected no thread but had one")
868 }
869
870
871 if reqs.Proc == event.MustHave && ctx.P == NoProc {
872 return fmt.Errorf("expected a proc but didn't have one")
873 } else if reqs.Proc == event.MustNotHave && ctx.P != NoProc {
874 return fmt.Errorf("expected no proc but had one")
875 }
876
877
878 if reqs.Goroutine == event.MustHave && ctx.G == NoGoroutine {
879 return fmt.Errorf("expected a goroutine but didn't have one")
880 } else if reqs.Goroutine == event.MustNotHave && ctx.G != NoGoroutine {
881 return fmt.Errorf("expected no goroutine but had one")
882 }
883 return nil
884 }
885
886
887
888
889 type gcState uint8
890
891 const (
892 gcUndetermined gcState = iota
893 gcNotRunning
894 gcRunning
895 )
896
897
898 func (s gcState) String() string {
899 switch s {
900 case gcUndetermined:
901 return "Undetermined"
902 case gcNotRunning:
903 return "NotRunning"
904 case gcRunning:
905 return "Running"
906 }
907 return "Bad"
908 }
909
910
911 type userRegion struct {
912
913
914
915 taskID TaskID
916 name string
917 }
918
919
920
921
922
923
924 type rangeType struct {
925 typ event.Type
926 desc stringID
927 }
928
929
930 func makeRangeType(typ event.Type, desc stringID) rangeType {
931 if styp := go122.Specs()[typ].StartEv; styp != go122.EvNone {
932 typ = styp
933 }
934 return rangeType{typ, desc}
935 }
936
937
938 type gState struct {
939 id GoID
940 status go122.GoStatus
941 seq seqCounter
942
943
944 regions []userRegion
945
946
947 rangeState
948 }
949
950
951 func (s *gState) beginRegion(r userRegion) error {
952 s.regions = append(s.regions, r)
953 return nil
954 }
955
956
957 func (s *gState) endRegion(r userRegion) error {
958 if len(s.regions) == 0 {
959
960 return nil
961 }
962 if next := s.regions[len(s.regions)-1]; next != r {
963 return fmt.Errorf("misuse of region in goroutine %v: region end %v when the inner-most active region start event is %v", s.id, r, next)
964 }
965 s.regions = s.regions[:len(s.regions)-1]
966 return nil
967 }
968
969
970 type pState struct {
971 id ProcID
972 status go122.ProcStatus
973 seq seqCounter
974
975
976 rangeState
977 }
978
979
980 type mState struct {
981 g GoID
982 p ProcID
983 }
984
985
986 type rangeState struct {
987
988 inFlight []rangeType
989 }
990
991
992
993
994 func (s *rangeState) beginRange(typ rangeType) error {
995 if s.hasRange(typ) {
996 return fmt.Errorf("discovered event already in-flight for when starting event %v", go122.Specs()[typ.typ].Name)
997 }
998 s.inFlight = append(s.inFlight, typ)
999 return nil
1000 }
1001
1002
1003
1004 func (s *rangeState) activeRange(typ rangeType, isInitialGen bool) error {
1005 if isInitialGen {
1006 if s.hasRange(typ) {
1007 return fmt.Errorf("found named active range already in first gen: %v", typ)
1008 }
1009 s.inFlight = append(s.inFlight, typ)
1010 } else if !s.hasRange(typ) {
1011 return fmt.Errorf("resource is missing active range: %v %v", go122.Specs()[typ.typ].Name, s.inFlight)
1012 }
1013 return nil
1014 }
1015
1016
1017 func (s *rangeState) hasRange(typ rangeType) bool {
1018 for _, ftyp := range s.inFlight {
1019 if ftyp == typ {
1020 return true
1021 }
1022 }
1023 return false
1024 }
1025
1026
1027
1028
1029 func (s *rangeState) endRange(typ event.Type) (stringID, error) {
1030 st := go122.Specs()[typ].StartEv
1031 idx := -1
1032 for i, r := range s.inFlight {
1033 if r.typ == st {
1034 idx = i
1035 break
1036 }
1037 }
1038 if idx < 0 {
1039 return 0, fmt.Errorf("tried to end event %v, but not in-flight", go122.Specs()[st].Name)
1040 }
1041
1042 desc := s.inFlight[idx].desc
1043 s.inFlight[idx], s.inFlight[len(s.inFlight)-1] = s.inFlight[len(s.inFlight)-1], s.inFlight[idx]
1044 s.inFlight = s.inFlight[:len(s.inFlight)-1]
1045 return desc, nil
1046 }
1047
1048
1049 type seqCounter struct {
1050 gen uint64
1051 seq uint64
1052 }
1053
1054
1055 func makeSeq(gen, seq uint64) seqCounter {
1056 return seqCounter{gen: gen, seq: seq}
1057 }
1058
1059
1060 func (a seqCounter) succeeds(b seqCounter) bool {
1061 return a.gen == b.gen && a.seq == b.seq+1
1062 }
1063
1064
1065 func (c seqCounter) String() string {
1066 return fmt.Sprintf("%d (gen=%d)", c.seq, c.gen)
1067 }
1068
1069 func dumpOrdering(order *ordering) string {
1070 var sb strings.Builder
1071 for id, state := range order.gStates {
1072 fmt.Fprintf(&sb, "G %d [status=%s seq=%s]\n", id, state.status, state.seq)
1073 }
1074 fmt.Fprintln(&sb)
1075 for id, state := range order.pStates {
1076 fmt.Fprintf(&sb, "P %d [status=%s seq=%s]\n", id, state.status, state.seq)
1077 }
1078 fmt.Fprintln(&sb)
1079 for id, state := range order.mStates {
1080 fmt.Fprintf(&sb, "M %d [g=%d p=%d]\n", id, state.g, state.p)
1081 }
1082 fmt.Fprintln(&sb)
1083 fmt.Fprintf(&sb, "GC %d %s\n", order.gcSeq, order.gcState)
1084 return sb.String()
1085 }
1086
1087
1088 type taskState struct {
1089
1090 name string
1091
1092
1093 parentID TaskID
1094 }
1095
View as plain text