1
2
3
4
5 package trace
6
7 import (
8 "fmt"
9 "strings"
10
11 "internal/trace/event"
12 "internal/trace/event/go122"
13 "internal/trace/version"
14 )
15
16
17
18
19
20
21
22
23 type ordering struct {
24 gStates map[GoID]*gState
25 pStates map[ProcID]*pState
26 mStates map[ThreadID]*mState
27 activeTasks map[TaskID]taskState
28 gcSeq uint64
29 gcState gcState
30 initialGen uint64
31 queue queue[Event]
32 }
33
34
35
36
37
38
39
40
41
42
43
44
45
46 func (o *ordering) Advance(ev *baseEvent, evt *evTable, m ThreadID, gen uint64) (bool, error) {
47 if o.initialGen == 0 {
48
49 o.initialGen = gen
50 }
51
52 var curCtx, newCtx schedCtx
53 curCtx.M = m
54 newCtx.M = m
55
56 var ms *mState
57 if m == NoThread {
58 curCtx.P = NoProc
59 curCtx.G = NoGoroutine
60 newCtx = curCtx
61 } else {
62
63 var ok bool
64 ms, ok = o.mStates[m]
65 if !ok {
66 ms = &mState{
67 g: NoGoroutine,
68 p: NoProc,
69 }
70 o.mStates[m] = ms
71 }
72 curCtx.P = ms.p
73 curCtx.G = ms.g
74 newCtx = curCtx
75 }
76
77 f := orderingDispatch[ev.typ]
78 if f == nil {
79 return false, fmt.Errorf("bad event type found while ordering: %v", ev.typ)
80 }
81 newCtx, ok, err := f(o, ev, evt, m, gen, curCtx)
82 if err == nil && ok && ms != nil {
83
84 ms.p = newCtx.P
85 ms.g = newCtx.G
86 }
87 return ok, err
88 }
89
90 type orderingHandleFunc func(o *ordering, ev *baseEvent, evt *evTable, m ThreadID, gen uint64, curCtx schedCtx) (schedCtx, bool, error)
91
92 var orderingDispatch = [256]orderingHandleFunc{
93
94 go122.EvProcsChange: (*ordering).advanceAnnotation,
95 go122.EvProcStart: (*ordering).advanceProcStart,
96 go122.EvProcStop: (*ordering).advanceProcStop,
97 go122.EvProcSteal: (*ordering).advanceProcSteal,
98 go122.EvProcStatus: (*ordering).advanceProcStatus,
99
100
101 go122.EvGoCreate: (*ordering).advanceGoCreate,
102 go122.EvGoCreateSyscall: (*ordering).advanceGoCreateSyscall,
103 go122.EvGoStart: (*ordering).advanceGoStart,
104 go122.EvGoDestroy: (*ordering).advanceGoStopExec,
105 go122.EvGoDestroySyscall: (*ordering).advanceGoDestroySyscall,
106 go122.EvGoStop: (*ordering).advanceGoStopExec,
107 go122.EvGoBlock: (*ordering).advanceGoStopExec,
108 go122.EvGoUnblock: (*ordering).advanceGoUnblock,
109 go122.EvGoSyscallBegin: (*ordering).advanceGoSyscallBegin,
110 go122.EvGoSyscallEnd: (*ordering).advanceGoSyscallEnd,
111 go122.EvGoSyscallEndBlocked: (*ordering).advanceGoSyscallEndBlocked,
112 go122.EvGoStatus: (*ordering).advanceGoStatus,
113
114
115 go122.EvSTWBegin: (*ordering).advanceGoRangeBegin,
116 go122.EvSTWEnd: (*ordering).advanceGoRangeEnd,
117
118
119 go122.EvGCActive: (*ordering).advanceGCActive,
120 go122.EvGCBegin: (*ordering).advanceGCBegin,
121 go122.EvGCEnd: (*ordering).advanceGCEnd,
122 go122.EvGCSweepActive: (*ordering).advanceGCSweepActive,
123 go122.EvGCSweepBegin: (*ordering).advanceGCSweepBegin,
124 go122.EvGCSweepEnd: (*ordering).advanceGCSweepEnd,
125 go122.EvGCMarkAssistActive: (*ordering).advanceGoRangeActive,
126 go122.EvGCMarkAssistBegin: (*ordering).advanceGoRangeBegin,
127 go122.EvGCMarkAssistEnd: (*ordering).advanceGoRangeEnd,
128 go122.EvHeapAlloc: (*ordering).advanceHeapMetric,
129 go122.EvHeapGoal: (*ordering).advanceHeapMetric,
130
131
132 go122.EvGoLabel: (*ordering).advanceAnnotation,
133 go122.EvUserTaskBegin: (*ordering).advanceUserTaskBegin,
134 go122.EvUserTaskEnd: (*ordering).advanceUserTaskEnd,
135 go122.EvUserRegionBegin: (*ordering).advanceUserRegionBegin,
136 go122.EvUserRegionEnd: (*ordering).advanceUserRegionEnd,
137 go122.EvUserLog: (*ordering).advanceAnnotation,
138
139
140 go122.EvGoSwitch: (*ordering).advanceGoSwitch,
141 go122.EvGoSwitchDestroy: (*ordering).advanceGoSwitch,
142 go122.EvGoCreateBlocked: (*ordering).advanceGoCreate,
143
144
145 go122.EvGoStatusStack: (*ordering).advanceGoStatus,
146
147
148
149
150 go122.EvSpan: (*ordering).advanceAllocFree,
151 go122.EvSpanAlloc: (*ordering).advanceAllocFree,
152 go122.EvSpanFree: (*ordering).advanceAllocFree,
153
154
155 go122.EvHeapObject: (*ordering).advanceAllocFree,
156 go122.EvHeapObjectAlloc: (*ordering).advanceAllocFree,
157 go122.EvHeapObjectFree: (*ordering).advanceAllocFree,
158
159
160 go122.EvGoroutineStack: (*ordering).advanceAllocFree,
161 go122.EvGoroutineStackAlloc: (*ordering).advanceAllocFree,
162 go122.EvGoroutineStackFree: (*ordering).advanceAllocFree,
163 }
164
165 func (o *ordering) advanceProcStatus(ev *baseEvent, evt *evTable, m ThreadID, gen uint64, curCtx schedCtx) (schedCtx, bool, error) {
166 pid := ProcID(ev.args[0])
167 status := go122.ProcStatus(ev.args[1])
168 if int(status) >= len(go122ProcStatus2ProcState) {
169 return curCtx, false, fmt.Errorf("invalid status for proc %d: %d", pid, status)
170 }
171 oldState := go122ProcStatus2ProcState[status]
172 if s, ok := o.pStates[pid]; ok {
173 if status == go122.ProcSyscallAbandoned && s.status == go122.ProcSyscall {
174
175
176
177 oldState = ProcRunning
178 ev.args[1] = uint64(go122.ProcSyscall)
179 } else if status == go122.ProcSyscallAbandoned && s.status == go122.ProcSyscallAbandoned {
180
181
182
183 oldState = ProcIdle
184 ev.args[1] = uint64(go122.ProcSyscallAbandoned)
185 } else if s.status != status {
186 return curCtx, false, fmt.Errorf("inconsistent status for proc %d: old %v vs. new %v", pid, s.status, status)
187 }
188 s.seq = makeSeq(gen, 0)
189 } else {
190 o.pStates[pid] = &pState{id: pid, status: status, seq: makeSeq(gen, 0)}
191 if gen == o.initialGen {
192 oldState = ProcUndetermined
193 } else {
194 oldState = ProcNotExist
195 }
196 }
197 ev.extra(version.Go122)[0] = uint64(oldState)
198
199
200 newCtx := curCtx
201 if status == go122.ProcRunning || status == go122.ProcSyscall {
202 newCtx.P = pid
203 }
204
205
206
207
208
209
210 if status == go122.ProcSyscallAbandoned && oldState == ProcRunning {
211
212 found := false
213 for mid, ms := range o.mStates {
214 if ms.p == pid {
215 curCtx.M = mid
216 curCtx.P = pid
217 curCtx.G = ms.g
218 found = true
219 }
220 }
221 if !found {
222 return curCtx, false, fmt.Errorf("failed to find sched context for proc %d that's about to be stolen", pid)
223 }
224 }
225 o.queue.push(Event{table: evt, ctx: curCtx, base: *ev})
226 return newCtx, true, nil
227 }
228
229 func (o *ordering) advanceProcStart(ev *baseEvent, evt *evTable, m ThreadID, gen uint64, curCtx schedCtx) (schedCtx, bool, error) {
230 pid := ProcID(ev.args[0])
231 seq := makeSeq(gen, ev.args[1])
232
233
234
235
236 state, ok := o.pStates[pid]
237 if !ok || state.status != go122.ProcIdle || !seq.succeeds(state.seq) || curCtx.P != NoProc {
238
239
240
241
242
243 return curCtx, false, nil
244 }
245
246
247
248 reqs := event.SchedReqs{Thread: event.MustHave, Proc: event.MustNotHave, Goroutine: event.MayHave}
249 if err := validateCtx(curCtx, reqs); err != nil {
250 return curCtx, false, err
251 }
252 state.status = go122.ProcRunning
253 state.seq = seq
254 newCtx := curCtx
255 newCtx.P = pid
256 o.queue.push(Event{table: evt, ctx: curCtx, base: *ev})
257 return newCtx, true, nil
258 }
259
260 func (o *ordering) advanceProcStop(ev *baseEvent, evt *evTable, m ThreadID, gen uint64, curCtx schedCtx) (schedCtx, bool, error) {
261
262
263
264
265
266
267
268
269
270 state, ok := o.pStates[curCtx.P]
271 if !ok {
272 return curCtx, false, fmt.Errorf("event %s for proc (%v) that doesn't exist", go122.EventString(ev.typ), curCtx.P)
273 }
274 if state.status != go122.ProcRunning && state.status != go122.ProcSyscall {
275 return curCtx, false, fmt.Errorf("%s event for proc that's not %s or %s", go122.EventString(ev.typ), go122.ProcRunning, go122.ProcSyscall)
276 }
277 reqs := event.SchedReqs{Thread: event.MustHave, Proc: event.MustHave, Goroutine: event.MayHave}
278 if err := validateCtx(curCtx, reqs); err != nil {
279 return curCtx, false, err
280 }
281 state.status = go122.ProcIdle
282 newCtx := curCtx
283 newCtx.P = NoProc
284 o.queue.push(Event{table: evt, ctx: curCtx, base: *ev})
285 return newCtx, true, nil
286 }
287
288 func (o *ordering) advanceProcSteal(ev *baseEvent, evt *evTable, m ThreadID, gen uint64, curCtx schedCtx) (schedCtx, bool, error) {
289 pid := ProcID(ev.args[0])
290 seq := makeSeq(gen, ev.args[1])
291 state, ok := o.pStates[pid]
292 if !ok || (state.status != go122.ProcSyscall && state.status != go122.ProcSyscallAbandoned) || !seq.succeeds(state.seq) {
293
294
295
296 return curCtx, false, nil
297 }
298
299 reqs := event.SchedReqs{Thread: event.MustHave, Proc: event.MayHave, Goroutine: event.MayHave}
300 if err := validateCtx(curCtx, reqs); err != nil {
301 return curCtx, false, err
302 }
303
304
305
306
307
308
309 oldStatus := state.status
310 ev.extra(version.Go122)[0] = uint64(oldStatus)
311
312
313 state.status = go122.ProcIdle
314 state.seq = seq
315
316
317
318 if oldStatus == go122.ProcSyscallAbandoned {
319 o.queue.push(Event{table: evt, ctx: curCtx, base: *ev})
320 return curCtx, true, nil
321 }
322
323
324 mid := ThreadID(ev.args[2])
325
326 newCtx := curCtx
327 if mid == curCtx.M {
328
329 if curCtx.P != pid {
330 return curCtx, false, fmt.Errorf("tried to self-steal proc %d (thread %d), but got proc %d instead", pid, mid, curCtx.P)
331 }
332 newCtx.P = NoProc
333 o.queue.push(Event{table: evt, ctx: curCtx, base: *ev})
334 return newCtx, true, nil
335 }
336
337
338 mState, ok := o.mStates[mid]
339 if !ok {
340 return curCtx, false, fmt.Errorf("stole proc from non-existent thread %d", mid)
341 }
342
343
344 if mState.p != pid {
345 return curCtx, false, fmt.Errorf("tried to steal proc %d from thread %d, but got proc %d instead", pid, mid, mState.p)
346 }
347
348
349
350
351
352
353
354 mState.p = NoProc
355 o.queue.push(Event{table: evt, ctx: curCtx, base: *ev})
356 return newCtx, true, nil
357 }
358
359 func (o *ordering) advanceGoStatus(ev *baseEvent, evt *evTable, m ThreadID, gen uint64, curCtx schedCtx) (schedCtx, bool, error) {
360 gid := GoID(ev.args[0])
361 mid := ThreadID(ev.args[1])
362 status := go122.GoStatus(ev.args[2])
363
364 if int(status) >= len(go122GoStatus2GoState) {
365 return curCtx, false, fmt.Errorf("invalid status for goroutine %d: %d", gid, status)
366 }
367 oldState := go122GoStatus2GoState[status]
368 if s, ok := o.gStates[gid]; ok {
369 if s.status != status {
370 return curCtx, false, fmt.Errorf("inconsistent status for goroutine %d: old %v vs. new %v", gid, s.status, status)
371 }
372 s.seq = makeSeq(gen, 0)
373 } else if gen == o.initialGen {
374
375 o.gStates[gid] = &gState{id: gid, status: status, seq: makeSeq(gen, 0)}
376 oldState = GoUndetermined
377 } else {
378 return curCtx, false, fmt.Errorf("found goroutine status for new goroutine after the first generation: id=%v status=%v", gid, status)
379 }
380 ev.args[2] = uint64(oldState)<<32 | uint64(status)
381
382 newCtx := curCtx
383 switch status {
384 case go122.GoRunning:
385
386 newCtx.G = gid
387 case go122.GoSyscall:
388 if mid == NoThread {
389 return curCtx, false, fmt.Errorf("found goroutine %d in syscall without a thread", gid)
390 }
391
392
393
394 if mid == curCtx.M {
395 if gen != o.initialGen && curCtx.G != gid {
396
397
398
399
400 return curCtx, false, fmt.Errorf("inconsistent thread for syscalling goroutine %d: thread has goroutine %d", gid, curCtx.G)
401 }
402 newCtx.G = gid
403 break
404 }
405
406
407
408
409
410 ms, ok := o.mStates[mid]
411 if ok {
412
413
414 if ms.g != gid {
415
416 return curCtx, false, fmt.Errorf("inconsistent thread for syscalling goroutine %d: thread has goroutine %d", gid, ms.g)
417 }
418
419
420 curCtx.G = ms.g
421 } else if !ok {
422
423
424
425 o.mStates[mid] = &mState{g: gid, p: NoProc}
426
427
428 }
429
430 curCtx.M = mid
431 }
432 o.queue.push(Event{table: evt, ctx: curCtx, base: *ev})
433 return newCtx, true, nil
434 }
435
436 func (o *ordering) advanceGoCreate(ev *baseEvent, evt *evTable, m ThreadID, gen uint64, curCtx schedCtx) (schedCtx, bool, error) {
437
438
439 reqs := event.SchedReqs{Thread: event.MustHave, Proc: event.MustHave, Goroutine: event.MayHave}
440 if err := validateCtx(curCtx, reqs); err != nil {
441 return curCtx, false, err
442 }
443
444 if state, ok := o.gStates[curCtx.G]; ok && state.status != go122.GoRunning {
445 return curCtx, false, fmt.Errorf("%s event for goroutine that's not %s", go122.EventString(ev.typ), GoRunning)
446 }
447
448 newgid := GoID(ev.args[0])
449 if _, ok := o.gStates[newgid]; ok {
450 return curCtx, false, fmt.Errorf("tried to create goroutine (%v) that already exists", newgid)
451 }
452 status := go122.GoRunnable
453 if ev.typ == go122.EvGoCreateBlocked {
454 status = go122.GoWaiting
455 }
456 o.gStates[newgid] = &gState{id: newgid, status: status, seq: makeSeq(gen, 0)}
457 o.queue.push(Event{table: evt, ctx: curCtx, base: *ev})
458 return curCtx, true, nil
459 }
460
461 func (o *ordering) advanceGoStopExec(ev *baseEvent, evt *evTable, m ThreadID, gen uint64, curCtx schedCtx) (schedCtx, bool, error) {
462
463
464
465 if err := validateCtx(curCtx, event.UserGoReqs); err != nil {
466 return curCtx, false, err
467 }
468 state, ok := o.gStates[curCtx.G]
469 if !ok {
470 return curCtx, false, fmt.Errorf("event %s for goroutine (%v) that doesn't exist", go122.EventString(ev.typ), curCtx.G)
471 }
472 if state.status != go122.GoRunning {
473 return curCtx, false, fmt.Errorf("%s event for goroutine that's not %s", go122.EventString(ev.typ), GoRunning)
474 }
475
476
477 newCtx := curCtx
478 switch ev.typ {
479 case go122.EvGoDestroy:
480
481 delete(o.gStates, curCtx.G)
482 newCtx.G = NoGoroutine
483 case go122.EvGoStop:
484
485 state.status = go122.GoRunnable
486 newCtx.G = NoGoroutine
487 case go122.EvGoBlock:
488
489 state.status = go122.GoWaiting
490 newCtx.G = NoGoroutine
491 }
492 o.queue.push(Event{table: evt, ctx: curCtx, base: *ev})
493 return newCtx, true, nil
494 }
495
496 func (o *ordering) advanceGoStart(ev *baseEvent, evt *evTable, m ThreadID, gen uint64, curCtx schedCtx) (schedCtx, bool, error) {
497 gid := GoID(ev.args[0])
498 seq := makeSeq(gen, ev.args[1])
499 state, ok := o.gStates[gid]
500 if !ok || state.status != go122.GoRunnable || !seq.succeeds(state.seq) {
501
502
503
504 return curCtx, false, nil
505 }
506
507 reqs := event.SchedReqs{Thread: event.MustHave, Proc: event.MustHave, Goroutine: event.MustNotHave}
508 if err := validateCtx(curCtx, reqs); err != nil {
509 return curCtx, false, err
510 }
511 state.status = go122.GoRunning
512 state.seq = seq
513 newCtx := curCtx
514 newCtx.G = gid
515 o.queue.push(Event{table: evt, ctx: curCtx, base: *ev})
516 return newCtx, true, nil
517 }
518
519 func (o *ordering) advanceGoUnblock(ev *baseEvent, evt *evTable, m ThreadID, gen uint64, curCtx schedCtx) (schedCtx, bool, error) {
520
521 gid := GoID(ev.args[0])
522 seq := makeSeq(gen, ev.args[1])
523 state, ok := o.gStates[gid]
524 if !ok || state.status != go122.GoWaiting || !seq.succeeds(state.seq) {
525
526
527
528 return curCtx, false, nil
529 }
530 state.status = go122.GoRunnable
531 state.seq = seq
532
533
534 o.queue.push(Event{table: evt, ctx: curCtx, base: *ev})
535 return curCtx, true, nil
536 }
537
538 func (o *ordering) advanceGoSwitch(ev *baseEvent, evt *evTable, m ThreadID, gen uint64, curCtx schedCtx) (schedCtx, bool, error) {
539
540
541
542
543
544
545
546
547
548 if err := validateCtx(curCtx, event.UserGoReqs); err != nil {
549 return curCtx, false, err
550 }
551 curGState, ok := o.gStates[curCtx.G]
552 if !ok {
553 return curCtx, false, fmt.Errorf("event %s for goroutine (%v) that doesn't exist", go122.EventString(ev.typ), curCtx.G)
554 }
555 if curGState.status != go122.GoRunning {
556 return curCtx, false, fmt.Errorf("%s event for goroutine that's not %s", go122.EventString(ev.typ), GoRunning)
557 }
558 nextg := GoID(ev.args[0])
559 seq := makeSeq(gen, ev.args[1])
560 nextGState, ok := o.gStates[nextg]
561 if !ok || nextGState.status != go122.GoWaiting || !seq.succeeds(nextGState.seq) {
562
563
564
565 return curCtx, false, nil
566 }
567 o.queue.push(Event{table: evt, ctx: curCtx, base: *ev})
568
569
570
571
572 switch ev.typ {
573 case go122.EvGoSwitch:
574
575 curGState.status = go122.GoWaiting
576
577
578
579 o.queue.push(makeEvent(evt, curCtx, go122.EvGoBlock, ev.time, 0 , 0 ))
580 case go122.EvGoSwitchDestroy:
581
582 delete(o.gStates, curCtx.G)
583
584
585 o.queue.push(makeEvent(evt, curCtx, go122.EvGoDestroy, ev.time))
586 }
587
588 nextGState.status = go122.GoRunning
589 nextGState.seq = seq
590 newCtx := curCtx
591 newCtx.G = nextg
592
593
594 startCtx := curCtx
595 startCtx.G = NoGoroutine
596 o.queue.push(makeEvent(evt, startCtx, go122.EvGoStart, ev.time, uint64(nextg), ev.args[1]))
597 return newCtx, true, nil
598 }
599
600 func (o *ordering) advanceGoSyscallBegin(ev *baseEvent, evt *evTable, m ThreadID, gen uint64, curCtx schedCtx) (schedCtx, bool, error) {
601
602
603 if err := validateCtx(curCtx, event.UserGoReqs); err != nil {
604 return curCtx, false, err
605 }
606 state, ok := o.gStates[curCtx.G]
607 if !ok {
608 return curCtx, false, fmt.Errorf("event %s for goroutine (%v) that doesn't exist", go122.EventString(ev.typ), curCtx.G)
609 }
610 if state.status != go122.GoRunning {
611 return curCtx, false, fmt.Errorf("%s event for goroutine that's not %s", go122.EventString(ev.typ), GoRunning)
612 }
613
614 state.status = go122.GoSyscall
615 pState, ok := o.pStates[curCtx.P]
616 if !ok {
617 return curCtx, false, fmt.Errorf("uninitialized proc %d found during %s", curCtx.P, go122.EventString(ev.typ))
618 }
619 pState.status = go122.ProcSyscall
620
621
622
623
624
625
626
627
628
629
630
631 pSeq := makeSeq(gen, ev.args[0])
632 if !pSeq.succeeds(pState.seq) {
633 return curCtx, false, fmt.Errorf("failed to advance %s: can't make sequence: %s -> %s", go122.EventString(ev.typ), pState.seq, pSeq)
634 }
635 pState.seq = pSeq
636 o.queue.push(Event{table: evt, ctx: curCtx, base: *ev})
637 return curCtx, true, nil
638 }
639
640 func (o *ordering) advanceGoSyscallEnd(ev *baseEvent, evt *evTable, m ThreadID, gen uint64, curCtx schedCtx) (schedCtx, bool, error) {
641
642
643
644 if err := validateCtx(curCtx, event.UserGoReqs); err != nil {
645 return curCtx, false, err
646 }
647 state, ok := o.gStates[curCtx.G]
648 if !ok {
649 return curCtx, false, fmt.Errorf("event %s for goroutine (%v) that doesn't exist", go122.EventString(ev.typ), curCtx.G)
650 }
651 if state.status != go122.GoSyscall {
652 return curCtx, false, fmt.Errorf("%s event for goroutine that's not %s", go122.EventString(ev.typ), GoRunning)
653 }
654 state.status = go122.GoRunning
655
656
657 pState, ok := o.pStates[curCtx.P]
658 if !ok {
659 return curCtx, false, fmt.Errorf("uninitialized proc %d found during %s", curCtx.P, go122.EventString(ev.typ))
660 }
661 if pState.status != go122.ProcSyscall {
662 return curCtx, false, fmt.Errorf("expected proc %d in state %v, but got %v instead", curCtx.P, go122.ProcSyscall, pState.status)
663 }
664 pState.status = go122.ProcRunning
665 o.queue.push(Event{table: evt, ctx: curCtx, base: *ev})
666 return curCtx, true, nil
667 }
668
669 func (o *ordering) advanceGoSyscallEndBlocked(ev *baseEvent, evt *evTable, m ThreadID, gen uint64, curCtx schedCtx) (schedCtx, bool, error) {
670
671
672
673
674
675
676
677
678
679
680 if curCtx.P != NoProc {
681 pState, ok := o.pStates[curCtx.P]
682 if !ok {
683 return curCtx, false, fmt.Errorf("uninitialized proc %d found during %s", curCtx.P, go122.EventString(ev.typ))
684 }
685 if pState.status == go122.ProcSyscall {
686 return curCtx, false, nil
687 }
688 }
689
690
691 if err := validateCtx(curCtx, event.SchedReqs{Thread: event.MustHave, Proc: event.MayHave, Goroutine: event.MustHave}); err != nil {
692 return curCtx, false, err
693 }
694 state, ok := o.gStates[curCtx.G]
695 if !ok {
696 return curCtx, false, fmt.Errorf("event %s for goroutine (%v) that doesn't exist", go122.EventString(ev.typ), curCtx.G)
697 }
698 if state.status != go122.GoSyscall {
699 return curCtx, false, fmt.Errorf("%s event for goroutine that's not %s", go122.EventString(ev.typ), GoRunning)
700 }
701 newCtx := curCtx
702 newCtx.G = NoGoroutine
703 state.status = go122.GoRunnable
704 o.queue.push(Event{table: evt, ctx: curCtx, base: *ev})
705 return newCtx, true, nil
706 }
707
708 func (o *ordering) advanceGoCreateSyscall(ev *baseEvent, evt *evTable, m ThreadID, gen uint64, curCtx schedCtx) (schedCtx, bool, error) {
709
710
711
712 if err := validateCtx(curCtx, event.SchedReqs{Thread: event.MustHave, Proc: event.MayHave, Goroutine: event.MustNotHave}); err != nil {
713 return curCtx, false, err
714 }
715
716 newgid := GoID(ev.args[0])
717 if _, ok := o.gStates[newgid]; ok {
718 return curCtx, false, fmt.Errorf("tried to create goroutine (%v) in syscall that already exists", newgid)
719 }
720 o.gStates[newgid] = &gState{id: newgid, status: go122.GoSyscall, seq: makeSeq(gen, 0)}
721
722 newCtx := curCtx
723 newCtx.G = newgid
724 o.queue.push(Event{table: evt, ctx: curCtx, base: *ev})
725 return newCtx, true, nil
726 }
727
728 func (o *ordering) advanceGoDestroySyscall(ev *baseEvent, evt *evTable, m ThreadID, gen uint64, curCtx schedCtx) (schedCtx, bool, error) {
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745 if err := validateCtx(curCtx, event.SchedReqs{Thread: event.MustHave, Proc: event.MayHave, Goroutine: event.MustHave}); err != nil {
746 return curCtx, false, err
747 }
748
749 state, ok := o.gStates[curCtx.G]
750 if !ok {
751 return curCtx, false, fmt.Errorf("event %s for goroutine (%v) that doesn't exist", go122.EventString(ev.typ), curCtx.G)
752 }
753 if state.status != go122.GoSyscall {
754 return curCtx, false, fmt.Errorf("%s event for goroutine that's not %v", go122.EventString(ev.typ), GoSyscall)
755 }
756
757 delete(o.gStates, curCtx.G)
758 newCtx := curCtx
759 newCtx.G = NoGoroutine
760
761
762 if curCtx.P != NoProc {
763 pState, ok := o.pStates[curCtx.P]
764 if !ok {
765 return curCtx, false, fmt.Errorf("found invalid proc %d during %s", curCtx.P, go122.EventString(ev.typ))
766 }
767 if pState.status != go122.ProcSyscall {
768 return curCtx, false, fmt.Errorf("proc %d in unexpected state %s during %s", curCtx.P, pState.status, go122.EventString(ev.typ))
769 }
770
771 pState.status = go122.ProcSyscallAbandoned
772 newCtx.P = NoProc
773
774
775 extra := makeEvent(evt, curCtx, go122.EvProcSteal, ev.time, uint64(curCtx.P))
776 extra.base.extra(version.Go122)[0] = uint64(go122.ProcSyscall)
777 o.queue.push(extra)
778 }
779 o.queue.push(Event{table: evt, ctx: curCtx, base: *ev})
780 return newCtx, true, nil
781 }
782
783 func (o *ordering) advanceUserTaskBegin(ev *baseEvent, evt *evTable, m ThreadID, gen uint64, curCtx schedCtx) (schedCtx, bool, error) {
784
785
786
787
788
789
790
791 id := TaskID(ev.args[0])
792 if _, ok := o.activeTasks[id]; ok {
793 return curCtx, false, fmt.Errorf("task ID conflict: %d", id)
794 }
795
796
797 parentID := TaskID(ev.args[1])
798 if parentID == BackgroundTask {
799
800
801
802 parentID = NoTask
803 ev.args[1] = uint64(NoTask)
804 }
805
806
807
808 nameID := stringID(ev.args[2])
809 name, ok := evt.strings.get(nameID)
810 if !ok {
811 return curCtx, false, fmt.Errorf("invalid string ID %v for %v event", nameID, ev.typ)
812 }
813 o.activeTasks[id] = taskState{name: name, parentID: parentID}
814 if err := validateCtx(curCtx, event.UserGoReqs); err != nil {
815 return curCtx, false, err
816 }
817 o.queue.push(Event{table: evt, ctx: curCtx, base: *ev})
818 return curCtx, true, nil
819 }
820
821 func (o *ordering) advanceUserTaskEnd(ev *baseEvent, evt *evTable, m ThreadID, gen uint64, curCtx schedCtx) (schedCtx, bool, error) {
822 id := TaskID(ev.args[0])
823 if ts, ok := o.activeTasks[id]; ok {
824
825
826
827 ev.extra(version.Go122)[0] = uint64(ts.parentID)
828 ev.extra(version.Go122)[1] = uint64(evt.addExtraString(ts.name))
829 delete(o.activeTasks, id)
830 } else {
831
832 ev.extra(version.Go122)[0] = uint64(NoTask)
833 ev.extra(version.Go122)[1] = uint64(evt.addExtraString(""))
834 }
835 if err := validateCtx(curCtx, event.UserGoReqs); err != nil {
836 return curCtx, false, err
837 }
838 o.queue.push(Event{table: evt, ctx: curCtx, base: *ev})
839 return curCtx, true, nil
840 }
841
842 func (o *ordering) advanceUserRegionBegin(ev *baseEvent, evt *evTable, m ThreadID, gen uint64, curCtx schedCtx) (schedCtx, bool, error) {
843 if err := validateCtx(curCtx, event.UserGoReqs); err != nil {
844 return curCtx, false, err
845 }
846 tid := TaskID(ev.args[0])
847 nameID := stringID(ev.args[1])
848 name, ok := evt.strings.get(nameID)
849 if !ok {
850 return curCtx, false, fmt.Errorf("invalid string ID %v for %v event", nameID, ev.typ)
851 }
852 gState, ok := o.gStates[curCtx.G]
853 if !ok {
854 return curCtx, false, fmt.Errorf("encountered EvUserRegionBegin without known state for current goroutine %d", curCtx.G)
855 }
856 if err := gState.beginRegion(userRegion{tid, name}); err != nil {
857 return curCtx, false, err
858 }
859 o.queue.push(Event{table: evt, ctx: curCtx, base: *ev})
860 return curCtx, true, nil
861 }
862
863 func (o *ordering) advanceUserRegionEnd(ev *baseEvent, evt *evTable, m ThreadID, gen uint64, curCtx schedCtx) (schedCtx, bool, error) {
864 if err := validateCtx(curCtx, event.UserGoReqs); err != nil {
865 return curCtx, false, err
866 }
867 tid := TaskID(ev.args[0])
868 nameID := stringID(ev.args[1])
869 name, ok := evt.strings.get(nameID)
870 if !ok {
871 return curCtx, false, fmt.Errorf("invalid string ID %v for %v event", nameID, ev.typ)
872 }
873 gState, ok := o.gStates[curCtx.G]
874 if !ok {
875 return curCtx, false, fmt.Errorf("encountered EvUserRegionEnd without known state for current goroutine %d", curCtx.G)
876 }
877 if err := gState.endRegion(userRegion{tid, name}); err != nil {
878 return curCtx, false, err
879 }
880 o.queue.push(Event{table: evt, ctx: curCtx, base: *ev})
881 return curCtx, true, nil
882 }
883
884
885
886
887
888
889
890
891 func (o *ordering) advanceGCActive(ev *baseEvent, evt *evTable, m ThreadID, gen uint64, curCtx schedCtx) (schedCtx, bool, error) {
892 seq := ev.args[0]
893 if gen == o.initialGen {
894 if o.gcState != gcUndetermined {
895 return curCtx, false, fmt.Errorf("GCActive in the first generation isn't first GC event")
896 }
897 o.gcSeq = seq
898 o.gcState = gcRunning
899 o.queue.push(Event{table: evt, ctx: curCtx, base: *ev})
900 return curCtx, true, nil
901 }
902 if seq != o.gcSeq+1 {
903
904 return curCtx, false, nil
905 }
906 if o.gcState != gcRunning {
907 return curCtx, false, fmt.Errorf("encountered GCActive while GC was not in progress")
908 }
909 o.gcSeq = seq
910 if err := validateCtx(curCtx, event.UserGoReqs); err != nil {
911 return curCtx, false, err
912 }
913 o.queue.push(Event{table: evt, ctx: curCtx, base: *ev})
914 return curCtx, true, nil
915 }
916
917 func (o *ordering) advanceGCBegin(ev *baseEvent, evt *evTable, m ThreadID, gen uint64, curCtx schedCtx) (schedCtx, bool, error) {
918 seq := ev.args[0]
919 if o.gcState == gcUndetermined {
920 o.gcSeq = seq
921 o.gcState = gcRunning
922 o.queue.push(Event{table: evt, ctx: curCtx, base: *ev})
923 return curCtx, true, nil
924 }
925 if seq != o.gcSeq+1 {
926
927 return curCtx, false, nil
928 }
929 if o.gcState == gcRunning {
930 return curCtx, false, fmt.Errorf("encountered GCBegin while GC was already in progress")
931 }
932 o.gcSeq = seq
933 o.gcState = gcRunning
934 if err := validateCtx(curCtx, event.UserGoReqs); err != nil {
935 return curCtx, false, err
936 }
937 o.queue.push(Event{table: evt, ctx: curCtx, base: *ev})
938 return curCtx, true, nil
939 }
940
941 func (o *ordering) advanceGCEnd(ev *baseEvent, evt *evTable, m ThreadID, gen uint64, curCtx schedCtx) (schedCtx, bool, error) {
942 seq := ev.args[0]
943 if seq != o.gcSeq+1 {
944
945 return curCtx, false, nil
946 }
947 if o.gcState == gcNotRunning {
948 return curCtx, false, fmt.Errorf("encountered GCEnd when GC was not in progress")
949 }
950 if o.gcState == gcUndetermined {
951 return curCtx, false, fmt.Errorf("encountered GCEnd when GC was in an undetermined state")
952 }
953 o.gcSeq = seq
954 o.gcState = gcNotRunning
955 if err := validateCtx(curCtx, event.UserGoReqs); err != nil {
956 return curCtx, false, err
957 }
958 o.queue.push(Event{table: evt, ctx: curCtx, base: *ev})
959 return curCtx, true, nil
960 }
961
962 func (o *ordering) advanceAnnotation(ev *baseEvent, evt *evTable, m ThreadID, gen uint64, curCtx schedCtx) (schedCtx, bool, error) {
963
964 if err := validateCtx(curCtx, event.UserGoReqs); err != nil {
965 return curCtx, false, err
966 }
967 o.queue.push(Event{table: evt, ctx: curCtx, base: *ev})
968 return curCtx, true, nil
969 }
970
971 func (o *ordering) advanceHeapMetric(ev *baseEvent, evt *evTable, m ThreadID, gen uint64, curCtx schedCtx) (schedCtx, bool, error) {
972
973 if err := validateCtx(curCtx, event.SchedReqs{Thread: event.MustHave, Proc: event.MustHave, Goroutine: event.MayHave}); err != nil {
974 return curCtx, false, err
975 }
976 o.queue.push(Event{table: evt, ctx: curCtx, base: *ev})
977 return curCtx, true, nil
978 }
979
980 func (o *ordering) advanceGCSweepBegin(ev *baseEvent, evt *evTable, m ThreadID, gen uint64, curCtx schedCtx) (schedCtx, bool, error) {
981
982 if err := validateCtx(curCtx, event.SchedReqs{Thread: event.MustHave, Proc: event.MustHave, Goroutine: event.MayHave}); err != nil {
983 return curCtx, false, err
984 }
985 if err := o.pStates[curCtx.P].beginRange(makeRangeType(ev.typ, 0)); err != nil {
986 return curCtx, false, err
987 }
988 o.queue.push(Event{table: evt, ctx: curCtx, base: *ev})
989 return curCtx, true, nil
990 }
991
992 func (o *ordering) advanceGCSweepActive(ev *baseEvent, evt *evTable, m ThreadID, gen uint64, curCtx schedCtx) (schedCtx, bool, error) {
993 pid := ProcID(ev.args[0])
994
995
996
997
998 pState, ok := o.pStates[pid]
999 if !ok {
1000 return curCtx, false, fmt.Errorf("encountered GCSweepActive for unknown proc %d", pid)
1001 }
1002 if err := pState.activeRange(makeRangeType(ev.typ, 0), gen == o.initialGen); err != nil {
1003 return curCtx, false, err
1004 }
1005 o.queue.push(Event{table: evt, ctx: curCtx, base: *ev})
1006 return curCtx, true, nil
1007 }
1008
1009 func (o *ordering) advanceGCSweepEnd(ev *baseEvent, evt *evTable, m ThreadID, gen uint64, curCtx schedCtx) (schedCtx, bool, error) {
1010 if err := validateCtx(curCtx, event.SchedReqs{Thread: event.MustHave, Proc: event.MustHave, Goroutine: event.MayHave}); err != nil {
1011 return curCtx, false, err
1012 }
1013 _, err := o.pStates[curCtx.P].endRange(ev.typ)
1014 if err != nil {
1015 return curCtx, false, err
1016 }
1017 o.queue.push(Event{table: evt, ctx: curCtx, base: *ev})
1018 return curCtx, true, nil
1019 }
1020
1021 func (o *ordering) advanceGoRangeBegin(ev *baseEvent, evt *evTable, m ThreadID, gen uint64, curCtx schedCtx) (schedCtx, bool, error) {
1022
1023 if err := validateCtx(curCtx, event.UserGoReqs); err != nil {
1024 return curCtx, false, err
1025 }
1026 desc := stringID(0)
1027 if ev.typ == go122.EvSTWBegin {
1028 desc = stringID(ev.args[0])
1029 }
1030 gState, ok := o.gStates[curCtx.G]
1031 if !ok {
1032 return curCtx, false, fmt.Errorf("encountered event of type %d without known state for current goroutine %d", ev.typ, curCtx.G)
1033 }
1034 if err := gState.beginRange(makeRangeType(ev.typ, desc)); err != nil {
1035 return curCtx, false, err
1036 }
1037 o.queue.push(Event{table: evt, ctx: curCtx, base: *ev})
1038 return curCtx, true, nil
1039 }
1040
1041 func (o *ordering) advanceGoRangeActive(ev *baseEvent, evt *evTable, m ThreadID, gen uint64, curCtx schedCtx) (schedCtx, bool, error) {
1042 gid := GoID(ev.args[0])
1043
1044
1045
1046 gState, ok := o.gStates[gid]
1047 if !ok {
1048 return curCtx, false, fmt.Errorf("uninitialized goroutine %d found during %s", gid, go122.EventString(ev.typ))
1049 }
1050 if err := gState.activeRange(makeRangeType(ev.typ, 0), gen == o.initialGen); err != nil {
1051 return curCtx, false, err
1052 }
1053 o.queue.push(Event{table: evt, ctx: curCtx, base: *ev})
1054 return curCtx, true, nil
1055 }
1056
1057 func (o *ordering) advanceGoRangeEnd(ev *baseEvent, evt *evTable, m ThreadID, gen uint64, curCtx schedCtx) (schedCtx, bool, error) {
1058 if err := validateCtx(curCtx, event.UserGoReqs); err != nil {
1059 return curCtx, false, err
1060 }
1061 gState, ok := o.gStates[curCtx.G]
1062 if !ok {
1063 return curCtx, false, fmt.Errorf("encountered event of type %d without known state for current goroutine %d", ev.typ, curCtx.G)
1064 }
1065 desc, err := gState.endRange(ev.typ)
1066 if err != nil {
1067 return curCtx, false, err
1068 }
1069 if ev.typ == go122.EvSTWEnd {
1070
1071
1072 ev.args[0] = uint64(desc)
1073 }
1074 o.queue.push(Event{table: evt, ctx: curCtx, base: *ev})
1075 return curCtx, true, nil
1076 }
1077
1078 func (o *ordering) advanceAllocFree(ev *baseEvent, evt *evTable, m ThreadID, gen uint64, curCtx schedCtx) (schedCtx, bool, error) {
1079
1080 if err := validateCtx(curCtx, event.SchedReqs{Thread: event.MustHave, Proc: event.MayHave, Goroutine: event.MayHave}); err != nil {
1081 return curCtx, false, err
1082 }
1083 o.queue.push(Event{table: evt, ctx: curCtx, base: *ev})
1084 return curCtx, true, nil
1085 }
1086
1087
1088 func (o *ordering) Next() (Event, bool) {
1089 return o.queue.pop()
1090 }
1091
1092
1093 type schedCtx struct {
1094 G GoID
1095 P ProcID
1096 M ThreadID
1097 }
1098
1099
1100
1101 func validateCtx(ctx schedCtx, reqs event.SchedReqs) error {
1102
1103 if reqs.Thread == event.MustHave && ctx.M == NoThread {
1104 return fmt.Errorf("expected a thread but didn't have one")
1105 } else if reqs.Thread == event.MustNotHave && ctx.M != NoThread {
1106 return fmt.Errorf("expected no thread but had one")
1107 }
1108
1109
1110 if reqs.Proc == event.MustHave && ctx.P == NoProc {
1111 return fmt.Errorf("expected a proc but didn't have one")
1112 } else if reqs.Proc == event.MustNotHave && ctx.P != NoProc {
1113 return fmt.Errorf("expected no proc but had one")
1114 }
1115
1116
1117 if reqs.Goroutine == event.MustHave && ctx.G == NoGoroutine {
1118 return fmt.Errorf("expected a goroutine but didn't have one")
1119 } else if reqs.Goroutine == event.MustNotHave && ctx.G != NoGoroutine {
1120 return fmt.Errorf("expected no goroutine but had one")
1121 }
1122 return nil
1123 }
1124
1125
1126
1127
1128 type gcState uint8
1129
1130 const (
1131 gcUndetermined gcState = iota
1132 gcNotRunning
1133 gcRunning
1134 )
1135
1136
1137 func (s gcState) String() string {
1138 switch s {
1139 case gcUndetermined:
1140 return "Undetermined"
1141 case gcNotRunning:
1142 return "NotRunning"
1143 case gcRunning:
1144 return "Running"
1145 }
1146 return "Bad"
1147 }
1148
1149
1150 type userRegion struct {
1151
1152
1153
1154 taskID TaskID
1155 name string
1156 }
1157
1158
1159
1160
1161
1162
1163 type rangeType struct {
1164 typ event.Type
1165 desc stringID
1166 }
1167
1168
1169 func makeRangeType(typ event.Type, desc stringID) rangeType {
1170 if styp := go122.Specs()[typ].StartEv; styp != go122.EvNone {
1171 typ = styp
1172 }
1173 return rangeType{typ, desc}
1174 }
1175
1176
1177 type gState struct {
1178 id GoID
1179 status go122.GoStatus
1180 seq seqCounter
1181
1182
1183 regions []userRegion
1184
1185
1186 rangeState
1187 }
1188
1189
1190 func (s *gState) beginRegion(r userRegion) error {
1191 s.regions = append(s.regions, r)
1192 return nil
1193 }
1194
1195
1196 func (s *gState) endRegion(r userRegion) error {
1197 if len(s.regions) == 0 {
1198
1199 return nil
1200 }
1201 if next := s.regions[len(s.regions)-1]; next != r {
1202 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)
1203 }
1204 s.regions = s.regions[:len(s.regions)-1]
1205 return nil
1206 }
1207
1208
1209 type pState struct {
1210 id ProcID
1211 status go122.ProcStatus
1212 seq seqCounter
1213
1214
1215 rangeState
1216 }
1217
1218
1219 type mState struct {
1220 g GoID
1221 p ProcID
1222 }
1223
1224
1225 type rangeState struct {
1226
1227 inFlight []rangeType
1228 }
1229
1230
1231
1232
1233 func (s *rangeState) beginRange(typ rangeType) error {
1234 if s.hasRange(typ) {
1235 return fmt.Errorf("discovered event already in-flight for when starting event %v", go122.Specs()[typ.typ].Name)
1236 }
1237 s.inFlight = append(s.inFlight, typ)
1238 return nil
1239 }
1240
1241
1242
1243 func (s *rangeState) activeRange(typ rangeType, isInitialGen bool) error {
1244 if isInitialGen {
1245 if s.hasRange(typ) {
1246 return fmt.Errorf("found named active range already in first gen: %v", typ)
1247 }
1248 s.inFlight = append(s.inFlight, typ)
1249 } else if !s.hasRange(typ) {
1250 return fmt.Errorf("resource is missing active range: %v %v", go122.Specs()[typ.typ].Name, s.inFlight)
1251 }
1252 return nil
1253 }
1254
1255
1256 func (s *rangeState) hasRange(typ rangeType) bool {
1257 for _, ftyp := range s.inFlight {
1258 if ftyp == typ {
1259 return true
1260 }
1261 }
1262 return false
1263 }
1264
1265
1266
1267
1268 func (s *rangeState) endRange(typ event.Type) (stringID, error) {
1269 st := go122.Specs()[typ].StartEv
1270 idx := -1
1271 for i, r := range s.inFlight {
1272 if r.typ == st {
1273 idx = i
1274 break
1275 }
1276 }
1277 if idx < 0 {
1278 return 0, fmt.Errorf("tried to end event %v, but not in-flight", go122.Specs()[st].Name)
1279 }
1280
1281 desc := s.inFlight[idx].desc
1282 s.inFlight[idx], s.inFlight[len(s.inFlight)-1] = s.inFlight[len(s.inFlight)-1], s.inFlight[idx]
1283 s.inFlight = s.inFlight[:len(s.inFlight)-1]
1284 return desc, nil
1285 }
1286
1287
1288 type seqCounter struct {
1289 gen uint64
1290 seq uint64
1291 }
1292
1293
1294 func makeSeq(gen, seq uint64) seqCounter {
1295 return seqCounter{gen: gen, seq: seq}
1296 }
1297
1298
1299 func (a seqCounter) succeeds(b seqCounter) bool {
1300 return a.gen == b.gen && a.seq == b.seq+1
1301 }
1302
1303
1304 func (c seqCounter) String() string {
1305 return fmt.Sprintf("%d (gen=%d)", c.seq, c.gen)
1306 }
1307
1308 func dumpOrdering(order *ordering) string {
1309 var sb strings.Builder
1310 for id, state := range order.gStates {
1311 fmt.Fprintf(&sb, "G %d [status=%s seq=%s]\n", id, state.status, state.seq)
1312 }
1313 fmt.Fprintln(&sb)
1314 for id, state := range order.pStates {
1315 fmt.Fprintf(&sb, "P %d [status=%s seq=%s]\n", id, state.status, state.seq)
1316 }
1317 fmt.Fprintln(&sb)
1318 for id, state := range order.mStates {
1319 fmt.Fprintf(&sb, "M %d [g=%d p=%d]\n", id, state.g, state.p)
1320 }
1321 fmt.Fprintln(&sb)
1322 fmt.Fprintf(&sb, "GC %d %s\n", order.gcSeq, order.gcState)
1323 return sb.String()
1324 }
1325
1326
1327 type taskState struct {
1328
1329 name string
1330
1331
1332 parentID TaskID
1333 }
1334
1335
1336 type queue[T any] struct {
1337 start, end int
1338 buf []T
1339 }
1340
1341
1342 func (q *queue[T]) push(value T) {
1343 if q.end-q.start == len(q.buf) {
1344 q.grow()
1345 }
1346 q.buf[q.end%len(q.buf)] = value
1347 q.end++
1348 }
1349
1350
1351 func (q *queue[T]) grow() {
1352 if len(q.buf) == 0 {
1353 q.buf = make([]T, 2)
1354 return
1355 }
1356
1357
1358 newBuf := make([]T, len(q.buf)*2)
1359 pivot := q.start % len(q.buf)
1360 first, last := q.buf[pivot:], q.buf[:pivot]
1361 copy(newBuf[:len(first)], first)
1362 copy(newBuf[len(first):], last)
1363
1364
1365 q.start = 0
1366 q.end = len(q.buf)
1367 q.buf = newBuf
1368 }
1369
1370
1371
1372 func (q *queue[T]) pop() (T, bool) {
1373 if q.end-q.start == 0 {
1374 return *new(T), false
1375 }
1376 elem := &q.buf[q.start%len(q.buf)]
1377 value := *elem
1378 *elem = *new(T)
1379 q.start++
1380 return value, true
1381 }
1382
1383
1384
1385
1386
1387
1388 func makeEvent(table *evTable, ctx schedCtx, typ event.Type, time Time, args ...uint64) Event {
1389 ev := Event{
1390 table: table,
1391 ctx: ctx,
1392 base: baseEvent{
1393 typ: typ,
1394 time: time,
1395 },
1396 }
1397 copy(ev.base.args[:], args)
1398 return ev
1399 }
1400
View as plain text