blob: 78f081808ab8ae6f3425d72e2c88b7e4c91ea747 [file] [log] [blame]
// Copyright 2024 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Code generated by "gen.bash" from internal/trace/v2; DO NOT EDIT.
//go:build go1.21
package oldtrace
import "errors"
type orderEvent struct {
ev Event
proc *proc
}
type gStatus int
type gState struct {
seq uint64
status gStatus
}
const (
gDead gStatus = iota
gRunnable
gRunning
gWaiting
unordered = ^uint64(0)
garbage = ^uint64(0) - 1
noseq = ^uint64(0)
seqinc = ^uint64(0) - 1
)
// stateTransition returns goroutine state (sequence and status) when the event
// becomes ready for merging (init) and the goroutine state after the event (next).
func stateTransition(ev *Event) (g uint64, init, next gState) {
// Note that we have an explicit return in each case, as that produces slightly better code (tested on Go 1.19).
switch ev.Type {
case EvGoCreate:
g = ev.Args[0]
init = gState{0, gDead}
next = gState{1, gRunnable}
return
case EvGoWaiting, EvGoInSyscall:
g = ev.G
init = gState{1, gRunnable}
next = gState{2, gWaiting}
return
case EvGoStart, EvGoStartLabel:
g = ev.G
init = gState{ev.Args[1], gRunnable}
next = gState{ev.Args[1] + 1, gRunning}
return
case EvGoStartLocal:
// noseq means that this event is ready for merging as soon as
// frontier reaches it (EvGoStartLocal is emitted on the same P
// as the corresponding EvGoCreate/EvGoUnblock, and thus the latter
// is already merged).
// seqinc is a stub for cases when event increments g sequence,
// but since we don't know current seq we also don't know next seq.
g = ev.G
init = gState{noseq, gRunnable}
next = gState{seqinc, gRunning}
return
case EvGoBlock, EvGoBlockSend, EvGoBlockRecv, EvGoBlockSelect,
EvGoBlockSync, EvGoBlockCond, EvGoBlockNet, EvGoSleep,
EvGoSysBlock, EvGoBlockGC:
g = ev.G
init = gState{noseq, gRunning}
next = gState{noseq, gWaiting}
return
case EvGoSched, EvGoPreempt:
g = ev.G
init = gState{noseq, gRunning}
next = gState{noseq, gRunnable}
return
case EvGoUnblock, EvGoSysExit:
g = ev.Args[0]
init = gState{ev.Args[1], gWaiting}
next = gState{ev.Args[1] + 1, gRunnable}
return
case EvGoUnblockLocal, EvGoSysExitLocal:
g = ev.Args[0]
init = gState{noseq, gWaiting}
next = gState{seqinc, gRunnable}
return
case EvGCStart:
g = garbage
init = gState{ev.Args[0], gDead}
next = gState{ev.Args[0] + 1, gDead}
return
default:
// no ordering requirements
g = unordered
return
}
}
func transitionReady(g uint64, curr, init gState) bool {
return g == unordered || (init.seq == noseq || init.seq == curr.seq) && init.status == curr.status
}
func transition(gs map[uint64]gState, g uint64, init, next gState) error {
if g == unordered {
return nil
}
curr := gs[g]
if !transitionReady(g, curr, init) {
// See comment near the call to transition, where we're building the frontier, for details on how this could
// possibly happen.
return errors.New("encountered impossible goroutine state transition")
}
switch next.seq {
case noseq:
next.seq = curr.seq
case seqinc:
next.seq = curr.seq + 1
}
gs[g] = next
return nil
}
type orderEventList []orderEvent
func (l *orderEventList) Less(i, j int) bool {
return (*l)[i].ev.Ts < (*l)[j].ev.Ts
}
type eventList []Event
func (l *eventList) Len() int {
return len(*l)
}
func (l *eventList) Less(i, j int) bool {
return (*l)[i].Ts < (*l)[j].Ts
}
func (l *eventList) Swap(i, j int) {
(*l)[i], (*l)[j] = (*l)[j], (*l)[i]
}
func (h *orderEventList) Push(x orderEvent) {
*h = append(*h, x)
heapUp(h, len(*h)-1)
}
func (h *orderEventList) Pop() orderEvent {
n := len(*h) - 1
(*h)[0], (*h)[n] = (*h)[n], (*h)[0]
heapDown(h, 0, n)
x := (*h)[len(*h)-1]
*h = (*h)[:len(*h)-1]
return x
}
func heapUp(h *orderEventList, j int) {
for {
i := (j - 1) / 2 // parent
if i == j || !h.Less(j, i) {
break
}
(*h)[i], (*h)[j] = (*h)[j], (*h)[i]
j = i
}
}
func heapDown(h *orderEventList, i0, n int) bool {
i := i0
for {
j1 := 2*i + 1
if j1 >= n || j1 < 0 { // j1 < 0 after int overflow
break
}
j := j1 // left child
if j2 := j1 + 1; j2 < n && h.Less(j2, j1) {
j = j2 // = 2*i + 2 // right child
}
if !h.Less(j, i) {
break
}
(*h)[i], (*h)[j] = (*h)[j], (*h)[i]
i = j
}
return i > i0
}