golang.org/x/exp@v0.0.0-20240506185415-9bf2ced13842/trace/internal/oldtrace/order.go (about) 1 // Copyright 2024 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // Code generated by "gen.bash" from internal/trace/v2; DO NOT EDIT. 6 7 //go:build go1.21 8 9 package oldtrace 10 11 import "errors" 12 13 type orderEvent struct { 14 ev Event 15 proc *proc 16 } 17 18 type gStatus int 19 20 type gState struct { 21 seq uint64 22 status gStatus 23 } 24 25 const ( 26 gDead gStatus = iota 27 gRunnable 28 gRunning 29 gWaiting 30 31 unordered = ^uint64(0) 32 garbage = ^uint64(0) - 1 33 noseq = ^uint64(0) 34 seqinc = ^uint64(0) - 1 35 ) 36 37 // stateTransition returns goroutine state (sequence and status) when the event 38 // becomes ready for merging (init) and the goroutine state after the event (next). 39 func stateTransition(ev *Event) (g uint64, init, next gState) { 40 // Note that we have an explicit return in each case, as that produces slightly better code (tested on Go 1.19). 41 42 switch ev.Type { 43 case EvGoCreate: 44 g = ev.Args[0] 45 init = gState{0, gDead} 46 next = gState{1, gRunnable} 47 return 48 case EvGoWaiting, EvGoInSyscall: 49 g = ev.G 50 init = gState{1, gRunnable} 51 next = gState{2, gWaiting} 52 return 53 case EvGoStart, EvGoStartLabel: 54 g = ev.G 55 init = gState{ev.Args[1], gRunnable} 56 next = gState{ev.Args[1] + 1, gRunning} 57 return 58 case EvGoStartLocal: 59 // noseq means that this event is ready for merging as soon as 60 // frontier reaches it (EvGoStartLocal is emitted on the same P 61 // as the corresponding EvGoCreate/EvGoUnblock, and thus the latter 62 // is already merged). 63 // seqinc is a stub for cases when event increments g sequence, 64 // but since we don't know current seq we also don't know next seq. 65 g = ev.G 66 init = gState{noseq, gRunnable} 67 next = gState{seqinc, gRunning} 68 return 69 case EvGoBlock, EvGoBlockSend, EvGoBlockRecv, EvGoBlockSelect, 70 EvGoBlockSync, EvGoBlockCond, EvGoBlockNet, EvGoSleep, 71 EvGoSysBlock, EvGoBlockGC: 72 g = ev.G 73 init = gState{noseq, gRunning} 74 next = gState{noseq, gWaiting} 75 return 76 case EvGoSched, EvGoPreempt: 77 g = ev.G 78 init = gState{noseq, gRunning} 79 next = gState{noseq, gRunnable} 80 return 81 case EvGoUnblock, EvGoSysExit: 82 g = ev.Args[0] 83 init = gState{ev.Args[1], gWaiting} 84 next = gState{ev.Args[1] + 1, gRunnable} 85 return 86 case EvGoUnblockLocal, EvGoSysExitLocal: 87 g = ev.Args[0] 88 init = gState{noseq, gWaiting} 89 next = gState{seqinc, gRunnable} 90 return 91 case EvGCStart: 92 g = garbage 93 init = gState{ev.Args[0], gDead} 94 next = gState{ev.Args[0] + 1, gDead} 95 return 96 default: 97 // no ordering requirements 98 g = unordered 99 return 100 } 101 } 102 103 func transitionReady(g uint64, curr, init gState) bool { 104 return g == unordered || (init.seq == noseq || init.seq == curr.seq) && init.status == curr.status 105 } 106 107 func transition(gs map[uint64]gState, g uint64, init, next gState) error { 108 if g == unordered { 109 return nil 110 } 111 curr := gs[g] 112 if !transitionReady(g, curr, init) { 113 // See comment near the call to transition, where we're building the frontier, for details on how this could 114 // possibly happen. 115 return errors.New("encountered impossible goroutine state transition") 116 } 117 switch next.seq { 118 case noseq: 119 next.seq = curr.seq 120 case seqinc: 121 next.seq = curr.seq + 1 122 } 123 gs[g] = next 124 return nil 125 } 126 127 type orderEventList []orderEvent 128 129 func (l *orderEventList) Less(i, j int) bool { 130 return (*l)[i].ev.Ts < (*l)[j].ev.Ts 131 } 132 133 type eventList []Event 134 135 func (l *eventList) Len() int { 136 return len(*l) 137 } 138 139 func (l *eventList) Less(i, j int) bool { 140 return (*l)[i].Ts < (*l)[j].Ts 141 } 142 143 func (l *eventList) Swap(i, j int) { 144 (*l)[i], (*l)[j] = (*l)[j], (*l)[i] 145 } 146 147 func (h *orderEventList) Push(x orderEvent) { 148 *h = append(*h, x) 149 heapUp(h, len(*h)-1) 150 } 151 152 func (h *orderEventList) Pop() orderEvent { 153 n := len(*h) - 1 154 (*h)[0], (*h)[n] = (*h)[n], (*h)[0] 155 heapDown(h, 0, n) 156 x := (*h)[len(*h)-1] 157 *h = (*h)[:len(*h)-1] 158 return x 159 } 160 161 func heapUp(h *orderEventList, j int) { 162 for { 163 i := (j - 1) / 2 // parent 164 if i == j || !h.Less(j, i) { 165 break 166 } 167 (*h)[i], (*h)[j] = (*h)[j], (*h)[i] 168 j = i 169 } 170 } 171 172 func heapDown(h *orderEventList, i0, n int) bool { 173 i := i0 174 for { 175 j1 := 2*i + 1 176 if j1 >= n || j1 < 0 { // j1 < 0 after int overflow 177 break 178 } 179 j := j1 // left child 180 if j2 := j1 + 1; j2 < n && h.Less(j2, j1) { 181 j = j2 // = 2*i + 2 // right child 182 } 183 if !h.Less(j, i) { 184 break 185 } 186 (*h)[i], (*h)[j] = (*h)[j], (*h)[i] 187 i = j 188 } 189 return i > i0 190 }