1
2
3
4
5 package trace
6
7 import (
8 "fmt"
9 "sort"
10 )
11
12 type eventBatch struct {
13 events []*Event
14 selected bool
15 }
16
17 type orderEvent struct {
18 ev *Event
19 batch int
20 g uint64
21 init gState
22 next gState
23 }
24
25 type gStatus int
26
27 type gState struct {
28 seq uint64
29 status gStatus
30 }
31
32 const (
33 gDead gStatus = iota
34 gRunnable
35 gRunning
36 gWaiting
37
38 unordered = ^uint64(0)
39 garbage = ^uint64(0) - 1
40 noseq = ^uint64(0)
41 seqinc = ^uint64(0) - 1
42 )
43
44
45
46
47
48
49
50
51
52
53 func order1007(m map[int][]*Event) (events []*Event, err error) {
54 pending := 0
55 var batches []*eventBatch
56 for _, v := range m {
57 pending += len(v)
58 batches = append(batches, &eventBatch{v, false})
59 }
60 gs := make(map[uint64]gState)
61 var frontier []orderEvent
62 for ; pending != 0; pending-- {
63 for i, b := range batches {
64 if b.selected || len(b.events) == 0 {
65 continue
66 }
67 ev := b.events[0]
68 g, init, next := stateTransition(ev)
69 if !transitionReady(g, gs[g], init) {
70 continue
71 }
72 frontier = append(frontier, orderEvent{ev, i, g, init, next})
73 b.events = b.events[1:]
74 b.selected = true
75
76 switch ev.Type {
77 case EvGoStartLocal:
78 ev.Type = EvGoStart
79 case EvGoUnblockLocal:
80 ev.Type = EvGoUnblock
81 case EvGoSysExitLocal:
82 ev.Type = EvGoSysExit
83 }
84 }
85 if len(frontier) == 0 {
86 return nil, fmt.Errorf("no consistent ordering of events possible")
87 }
88 sort.Sort(orderEventList(frontier))
89 f := frontier[0]
90 frontier[0] = frontier[len(frontier)-1]
91 frontier = frontier[:len(frontier)-1]
92 events = append(events, f.ev)
93 transition(gs, f.g, f.init, f.next)
94 if !batches[f.batch].selected {
95 panic("frontier batch is not selected")
96 }
97 batches[f.batch].selected = false
98 }
99
100
101
102
103 if !sort.IsSorted(eventList(events)) {
104 return nil, ErrTimeOrder
105 }
106
107
108
109
110
111
112
113
114
115
116 lastSysBlock := make(map[uint64]int64)
117 for _, ev := range events {
118 switch ev.Type {
119 case EvGoSysBlock, EvGoInSyscall:
120 lastSysBlock[ev.G] = ev.Ts
121 case EvGoSysExit:
122 ts := int64(ev.Args[2])
123 if ts == 0 {
124 continue
125 }
126 block := lastSysBlock[ev.G]
127 if block == 0 {
128 return nil, fmt.Errorf("stray syscall exit")
129 }
130 if ts < block {
131 return nil, ErrTimeOrder
132 }
133 ev.Ts = ts
134 }
135 }
136 sort.Stable(eventList(events))
137
138 return
139 }
140
141
142
143 func stateTransition(ev *Event) (g uint64, init, next gState) {
144 switch ev.Type {
145 case EvGoCreate:
146 g = ev.Args[0]
147 init = gState{0, gDead}
148 next = gState{1, gRunnable}
149 case EvGoWaiting, EvGoInSyscall:
150 g = ev.G
151 init = gState{1, gRunnable}
152 next = gState{2, gWaiting}
153 case EvGoStart, EvGoStartLabel:
154 g = ev.G
155 init = gState{ev.Args[1], gRunnable}
156 next = gState{ev.Args[1] + 1, gRunning}
157 case EvGoStartLocal:
158
159
160
161
162
163
164 g = ev.G
165 init = gState{noseq, gRunnable}
166 next = gState{seqinc, gRunning}
167 case EvGoBlock, EvGoBlockSend, EvGoBlockRecv, EvGoBlockSelect,
168 EvGoBlockSync, EvGoBlockCond, EvGoBlockNet, EvGoSleep,
169 EvGoSysBlock, EvGoBlockGC:
170 g = ev.G
171 init = gState{noseq, gRunning}
172 next = gState{noseq, gWaiting}
173 case EvGoSched, EvGoPreempt:
174 g = ev.G
175 init = gState{noseq, gRunning}
176 next = gState{noseq, gRunnable}
177 case EvGoUnblock, EvGoSysExit:
178 g = ev.Args[0]
179 init = gState{ev.Args[1], gWaiting}
180 next = gState{ev.Args[1] + 1, gRunnable}
181 case EvGoUnblockLocal, EvGoSysExitLocal:
182 g = ev.Args[0]
183 init = gState{noseq, gWaiting}
184 next = gState{seqinc, gRunnable}
185 case EvGCStart:
186 g = garbage
187 init = gState{ev.Args[0], gDead}
188 next = gState{ev.Args[0] + 1, gDead}
189 default:
190
191 g = unordered
192 }
193 return
194 }
195
196 func transitionReady(g uint64, curr, init gState) bool {
197 return g == unordered || (init.seq == noseq || init.seq == curr.seq) && init.status == curr.status
198 }
199
200 func transition(gs map[uint64]gState, g uint64, init, next gState) {
201 if g == unordered {
202 return
203 }
204 curr := gs[g]
205 if !transitionReady(g, curr, init) {
206 panic("event sequences are broken")
207 }
208 switch next.seq {
209 case noseq:
210 next.seq = curr.seq
211 case seqinc:
212 next.seq = curr.seq + 1
213 }
214 gs[g] = next
215 }
216
217
218 func order1005(m map[int][]*Event) (events []*Event, err error) {
219 for _, batch := range m {
220 events = append(events, batch...)
221 }
222 for _, ev := range events {
223 if ev.Type == EvGoSysExit {
224
225
226 ev.seq = int64(ev.Args[1])
227 if ev.Args[2] != 0 {
228 ev.Ts = int64(ev.Args[2])
229 }
230 }
231 }
232 sort.Sort(eventSeqList(events))
233 if !sort.IsSorted(eventList(events)) {
234 return nil, ErrTimeOrder
235 }
236 return
237 }
238
239 type orderEventList []orderEvent
240
241 func (l orderEventList) Len() int {
242 return len(l)
243 }
244
245 func (l orderEventList) Less(i, j int) bool {
246 return l[i].ev.Ts < l[j].ev.Ts
247 }
248
249 func (l orderEventList) Swap(i, j int) {
250 l[i], l[j] = l[j], l[i]
251 }
252
253 type eventList []*Event
254
255 func (l eventList) Len() int {
256 return len(l)
257 }
258
259 func (l eventList) Less(i, j int) bool {
260 return l[i].Ts < l[j].Ts
261 }
262
263 func (l eventList) Swap(i, j int) {
264 l[i], l[j] = l[j], l[i]
265 }
266
267 type eventSeqList []*Event
268
269 func (l eventSeqList) Len() int {
270 return len(l)
271 }
272
273 func (l eventSeqList) Less(i, j int) bool {
274 return l[i].seq < l[j].seq
275 }
276
277 func (l eventSeqList) Swap(i, j int) {
278 l[i], l[j] = l[j], l[i]
279 }
280
View as plain text