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