1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28 package trace
29
30 import (
31 "errors"
32 "fmt"
33 "internal/trace/event"
34 "internal/trace/event/go122"
35 "internal/trace/internal/oldtrace"
36 "io"
37 )
38
39 type oldTraceConverter struct {
40 trace oldtrace.Trace
41 evt *evTable
42 preInit bool
43 createdPreInit map[GoID]struct{}
44 events oldtrace.Events
45 extra []Event
46 extraArr [3]Event
47 tasks map[TaskID]taskState
48 seenProcs map[ProcID]struct{}
49 lastTs Time
50 procMs map[ProcID]ThreadID
51 lastStwReason uint64
52
53 inlineToStringID []uint64
54 builtinToStringID []uint64
55 }
56
57 const (
58
59 sForever = iota
60 sPreempted
61 sGosched
62 sSleep
63 sChanSend
64 sChanRecv
65 sNetwork
66 sSync
67 sSyncCond
68 sSelect
69 sEmpty
70 sMarkAssistWait
71
72
73 sSTWUnknown
74 sSTWGCMarkTermination
75 sSTWGCSweepTermination
76 sSTWWriteHeapDump
77 sSTWGoroutineProfile
78 sSTWGoroutineProfileCleanup
79 sSTWAllGoroutinesStackTrace
80 sSTWReadMemStats
81 sSTWAllThreadsSyscall
82 sSTWGOMAXPROCS
83 sSTWStartTrace
84 sSTWStopTrace
85 sSTWCountPagesInUse
86 sSTWReadMetricsSlow
87 sSTWReadMemStatsSlow
88 sSTWPageCachePagesLeaked
89 sSTWResetDebugLog
90
91 sLast
92 )
93
94 func (it *oldTraceConverter) init(pr oldtrace.Trace) error {
95 it.trace = pr
96 it.preInit = true
97 it.createdPreInit = make(map[GoID]struct{})
98 it.evt = &evTable{pcs: make(map[uint64]frame)}
99 it.events = pr.Events
100 it.extra = it.extraArr[:0]
101 it.tasks = make(map[TaskID]taskState)
102 it.seenProcs = make(map[ProcID]struct{})
103 it.procMs = make(map[ProcID]ThreadID)
104 it.lastTs = -1
105
106 evt := it.evt
107
108
109 var max uint64
110 for id, s := range pr.Strings {
111 evt.strings.insert(stringID(id), s)
112 if id > max {
113 max = id
114 }
115 }
116 pr.Strings = nil
117
118
119
120 if max+uint64(len(pr.InlineStrings)) < max {
121 return errors.New("trace contains too many strings")
122 }
123 var addErr error
124 add := func(id stringID, s string) {
125 if err := evt.strings.insert(id, s); err != nil && addErr == nil {
126 addErr = err
127 }
128 }
129 for id, s := range pr.InlineStrings {
130 nid := max + 1 + uint64(id)
131 it.inlineToStringID = append(it.inlineToStringID, nid)
132 add(stringID(nid), s)
133 }
134 max += uint64(len(pr.InlineStrings))
135 pr.InlineStrings = nil
136
137
138 if max+uint64(sLast) < max {
139 return errors.New("trace contains too many strings")
140 }
141 it.builtinToStringID = make([]uint64, sLast)
142 addBuiltin := func(c int, s string) {
143 nid := max + 1 + uint64(c)
144 it.builtinToStringID[c] = nid
145 add(stringID(nid), s)
146 }
147 addBuiltin(sForever, "forever")
148 addBuiltin(sPreempted, "preempted")
149 addBuiltin(sGosched, "runtime.Gosched")
150 addBuiltin(sSleep, "sleep")
151 addBuiltin(sChanSend, "chan send")
152 addBuiltin(sChanRecv, "chan receive")
153 addBuiltin(sNetwork, "network")
154 addBuiltin(sSync, "sync")
155 addBuiltin(sSyncCond, "sync.(*Cond).Wait")
156 addBuiltin(sSelect, "select")
157 addBuiltin(sEmpty, "")
158 addBuiltin(sMarkAssistWait, "GC mark assist wait for work")
159 addBuiltin(sSTWUnknown, "")
160 addBuiltin(sSTWGCMarkTermination, "GC mark termination")
161 addBuiltin(sSTWGCSweepTermination, "GC sweep termination")
162 addBuiltin(sSTWWriteHeapDump, "write heap dump")
163 addBuiltin(sSTWGoroutineProfile, "goroutine profile")
164 addBuiltin(sSTWGoroutineProfileCleanup, "goroutine profile cleanup")
165 addBuiltin(sSTWAllGoroutinesStackTrace, "all goroutine stack trace")
166 addBuiltin(sSTWReadMemStats, "read mem stats")
167 addBuiltin(sSTWAllThreadsSyscall, "AllThreadsSyscall")
168 addBuiltin(sSTWGOMAXPROCS, "GOMAXPROCS")
169 addBuiltin(sSTWStartTrace, "start trace")
170 addBuiltin(sSTWStopTrace, "stop trace")
171 addBuiltin(sSTWCountPagesInUse, "CountPagesInUse (test)")
172 addBuiltin(sSTWReadMetricsSlow, "ReadMetricsSlow (test)")
173 addBuiltin(sSTWReadMemStatsSlow, "ReadMemStatsSlow (test)")
174 addBuiltin(sSTWPageCachePagesLeaked, "PageCachePagesLeaked (test)")
175 addBuiltin(sSTWResetDebugLog, "ResetDebugLog (test)")
176
177 if addErr != nil {
178
179 return fmt.Errorf("couldn't add strings: %w", addErr)
180 }
181
182 it.evt.strings.compactify()
183
184
185 for id, stk := range pr.Stacks {
186 evt.stacks.insert(stackID(id), stack{pcs: stk})
187 }
188
189
190
191 for pc, f := range pr.PCs {
192 evt.pcs[pc] = frame{
193 pc: pc,
194 funcID: stringID(f.Fn),
195 fileID: stringID(f.File),
196 line: uint64(f.Line),
197 }
198 }
199 pr.Stacks = nil
200 pr.PCs = nil
201 evt.stacks.compactify()
202 return nil
203 }
204
205
206
207 func (it *oldTraceConverter) next() (Event, error) {
208 if len(it.extra) > 0 {
209 ev := it.extra[0]
210 it.extra = it.extra[1:]
211
212 if len(it.extra) == 0 {
213 it.extra = it.extraArr[:0]
214 }
215
216
217 if ev.base.time <= it.lastTs {
218 ev.base.time = it.lastTs + 1
219 }
220 it.lastTs = ev.base.time
221 return ev, nil
222 }
223
224 oev, ok := it.events.Pop()
225 if !ok {
226 return Event{}, io.EOF
227 }
228
229 ev, err := it.convertEvent(oev)
230
231 if err == errSkip {
232 return it.next()
233 } else if err != nil {
234 return Event{}, err
235 }
236
237
238
239 if ev.base.time <= it.lastTs {
240 ev.base.time = it.lastTs + 1
241 }
242 it.lastTs = ev.base.time
243 return ev, nil
244 }
245
246 var errSkip = errors.New("skip event")
247
248
249
250
251
252
253
254
255 func (it *oldTraceConverter) convertEvent(ev *oldtrace.Event) (OUT Event, ERR error) {
256 var mappedType event.Type
257 var mappedArgs timedEventArgs
258 copy(mappedArgs[:], ev.Args[:])
259
260 switch ev.Type {
261 case oldtrace.EvGomaxprocs:
262 mappedType = go122.EvProcsChange
263 if it.preInit {
264
265
266 it.preInit = false
267 for gid := range it.createdPreInit {
268
269
270
271 it.extra = append(it.extra, Event{
272 ctx: schedCtx{
273
274 G: NoGoroutine,
275 P: NoProc,
276 M: NoThread,
277 },
278 table: it.evt,
279 base: baseEvent{
280 typ: go122.EvGoStatus,
281 time: Time(ev.Ts),
282 args: timedEventArgs{uint64(gid), ^uint64(0), uint64(go122.GoRunnable)},
283 },
284 })
285 }
286 it.createdPreInit = nil
287 return Event{}, errSkip
288 }
289 case oldtrace.EvProcStart:
290 it.procMs[ProcID(ev.P)] = ThreadID(ev.Args[0])
291 if _, ok := it.seenProcs[ProcID(ev.P)]; ok {
292 mappedType = go122.EvProcStart
293 mappedArgs = timedEventArgs{uint64(ev.P)}
294 } else {
295 it.seenProcs[ProcID(ev.P)] = struct{}{}
296 mappedType = go122.EvProcStatus
297 mappedArgs = timedEventArgs{uint64(ev.P), uint64(go122.ProcRunning)}
298 }
299 case oldtrace.EvProcStop:
300 if _, ok := it.seenProcs[ProcID(ev.P)]; ok {
301 mappedType = go122.EvProcStop
302 mappedArgs = timedEventArgs{uint64(ev.P)}
303 } else {
304 it.seenProcs[ProcID(ev.P)] = struct{}{}
305 mappedType = go122.EvProcStatus
306 mappedArgs = timedEventArgs{uint64(ev.P), uint64(go122.ProcIdle)}
307 }
308 case oldtrace.EvGCStart:
309 mappedType = go122.EvGCBegin
310 case oldtrace.EvGCDone:
311 mappedType = go122.EvGCEnd
312 case oldtrace.EvSTWStart:
313 sid := it.builtinToStringID[sSTWUnknown+it.trace.STWReason(ev.Args[0])]
314 it.lastStwReason = sid
315 mappedType = go122.EvSTWBegin
316 mappedArgs = timedEventArgs{uint64(sid)}
317 case oldtrace.EvSTWDone:
318 mappedType = go122.EvSTWEnd
319 mappedArgs = timedEventArgs{it.lastStwReason}
320 case oldtrace.EvGCSweepStart:
321 mappedType = go122.EvGCSweepBegin
322 case oldtrace.EvGCSweepDone:
323 mappedType = go122.EvGCSweepEnd
324 case oldtrace.EvGoCreate:
325 if it.preInit {
326 it.createdPreInit[GoID(ev.Args[0])] = struct{}{}
327 return Event{}, errSkip
328 }
329 mappedType = go122.EvGoCreate
330 case oldtrace.EvGoStart:
331 if it.preInit {
332 mappedType = go122.EvGoStatus
333 mappedArgs = timedEventArgs{ev.Args[0], ^uint64(0), uint64(go122.GoRunning)}
334 delete(it.createdPreInit, GoID(ev.Args[0]))
335 } else {
336 mappedType = go122.EvGoStart
337 }
338 case oldtrace.EvGoStartLabel:
339 it.extra = []Event{{
340 ctx: schedCtx{
341 G: GoID(ev.G),
342 P: ProcID(ev.P),
343 M: it.procMs[ProcID(ev.P)],
344 },
345 table: it.evt,
346 base: baseEvent{
347 typ: go122.EvGoLabel,
348 time: Time(ev.Ts),
349 args: timedEventArgs{ev.Args[2]},
350 },
351 }}
352 return Event{
353 ctx: schedCtx{
354 G: GoID(ev.G),
355 P: ProcID(ev.P),
356 M: it.procMs[ProcID(ev.P)],
357 },
358 table: it.evt,
359 base: baseEvent{
360 typ: go122.EvGoStart,
361 time: Time(ev.Ts),
362 args: mappedArgs,
363 },
364 }, nil
365 case oldtrace.EvGoEnd:
366 mappedType = go122.EvGoDestroy
367 case oldtrace.EvGoStop:
368 mappedType = go122.EvGoBlock
369 mappedArgs = timedEventArgs{uint64(it.builtinToStringID[sForever]), uint64(ev.StkID)}
370 case oldtrace.EvGoSched:
371 mappedType = go122.EvGoStop
372 mappedArgs = timedEventArgs{uint64(it.builtinToStringID[sGosched]), uint64(ev.StkID)}
373 case oldtrace.EvGoPreempt:
374 mappedType = go122.EvGoStop
375 mappedArgs = timedEventArgs{uint64(it.builtinToStringID[sPreempted]), uint64(ev.StkID)}
376 case oldtrace.EvGoSleep:
377 mappedType = go122.EvGoBlock
378 mappedArgs = timedEventArgs{uint64(it.builtinToStringID[sSleep]), uint64(ev.StkID)}
379 case oldtrace.EvGoBlock:
380 mappedType = go122.EvGoBlock
381 mappedArgs = timedEventArgs{uint64(it.builtinToStringID[sEmpty]), uint64(ev.StkID)}
382 case oldtrace.EvGoUnblock:
383 mappedType = go122.EvGoUnblock
384 case oldtrace.EvGoBlockSend:
385 mappedType = go122.EvGoBlock
386 mappedArgs = timedEventArgs{uint64(it.builtinToStringID[sChanSend]), uint64(ev.StkID)}
387 case oldtrace.EvGoBlockRecv:
388 mappedType = go122.EvGoBlock
389 mappedArgs = timedEventArgs{uint64(it.builtinToStringID[sChanRecv]), uint64(ev.StkID)}
390 case oldtrace.EvGoBlockSelect:
391 mappedType = go122.EvGoBlock
392 mappedArgs = timedEventArgs{uint64(it.builtinToStringID[sSelect]), uint64(ev.StkID)}
393 case oldtrace.EvGoBlockSync:
394 mappedType = go122.EvGoBlock
395 mappedArgs = timedEventArgs{uint64(it.builtinToStringID[sSync]), uint64(ev.StkID)}
396 case oldtrace.EvGoBlockCond:
397 mappedType = go122.EvGoBlock
398 mappedArgs = timedEventArgs{uint64(it.builtinToStringID[sSyncCond]), uint64(ev.StkID)}
399 case oldtrace.EvGoBlockNet:
400 mappedType = go122.EvGoBlock
401 mappedArgs = timedEventArgs{uint64(it.builtinToStringID[sNetwork]), uint64(ev.StkID)}
402 case oldtrace.EvGoBlockGC:
403 mappedType = go122.EvGoBlock
404 mappedArgs = timedEventArgs{uint64(it.builtinToStringID[sMarkAssistWait]), uint64(ev.StkID)}
405 case oldtrace.EvGoSysCall:
406
407
408 blocked := false
409 it.events.All()(func(nev *oldtrace.Event) bool {
410 if nev.G != ev.G {
411 return true
412 }
413
414
415
416 if nev.Type == oldtrace.EvGoSysBlock {
417 blocked = true
418 }
419 return false
420 })
421 if blocked {
422 mappedType = go122.EvGoSyscallBegin
423 mappedArgs = timedEventArgs{1: uint64(ev.StkID)}
424 } else {
425
426
427
428 out1 := Event{
429 ctx: schedCtx{
430 G: GoID(ev.G),
431 P: ProcID(ev.P),
432 M: it.procMs[ProcID(ev.P)],
433 },
434 table: it.evt,
435 base: baseEvent{
436 typ: go122.EvGoSyscallBegin,
437 time: Time(ev.Ts),
438 args: timedEventArgs{1: uint64(ev.StkID)},
439 },
440 }
441
442 out2 := Event{
443 ctx: out1.ctx,
444 table: it.evt,
445 base: baseEvent{
446 typ: go122.EvGoSyscallEnd,
447 time: Time(ev.Ts + 1),
448 args: timedEventArgs{},
449 },
450 }
451
452 it.extra = append(it.extra, out2)
453 return out1, nil
454 }
455
456 case oldtrace.EvGoSysExit:
457 mappedType = go122.EvGoSyscallEndBlocked
458 case oldtrace.EvGoSysBlock:
459 return Event{}, errSkip
460 case oldtrace.EvGoWaiting:
461 mappedType = go122.EvGoStatus
462 mappedArgs = timedEventArgs{ev.Args[0], ^uint64(0), uint64(go122.GoWaiting)}
463 delete(it.createdPreInit, GoID(ev.Args[0]))
464 case oldtrace.EvGoInSyscall:
465 mappedType = go122.EvGoStatus
466
467
468
469 mappedArgs = timedEventArgs{ev.Args[0], ^uint64(0), uint64(go122.GoSyscall)}
470 delete(it.createdPreInit, GoID(ev.Args[0]))
471 case oldtrace.EvHeapAlloc:
472 mappedType = go122.EvHeapAlloc
473 case oldtrace.EvHeapGoal:
474 mappedType = go122.EvHeapGoal
475 case oldtrace.EvGCMarkAssistStart:
476 mappedType = go122.EvGCMarkAssistBegin
477 case oldtrace.EvGCMarkAssistDone:
478 mappedType = go122.EvGCMarkAssistEnd
479 case oldtrace.EvUserTaskCreate:
480 mappedType = go122.EvUserTaskBegin
481 parent := ev.Args[1]
482 if parent == 0 {
483 parent = uint64(NoTask)
484 }
485 mappedArgs = timedEventArgs{ev.Args[0], parent, ev.Args[2], uint64(ev.StkID)}
486 name, _ := it.evt.strings.get(stringID(ev.Args[2]))
487 it.tasks[TaskID(ev.Args[0])] = taskState{name: name, parentID: TaskID(ev.Args[1])}
488 case oldtrace.EvUserTaskEnd:
489 mappedType = go122.EvUserTaskEnd
490
491
492 ts, ok := it.tasks[TaskID(ev.Args[0])]
493 if ok {
494 delete(it.tasks, TaskID(ev.Args[0]))
495 mappedArgs = timedEventArgs{
496 ev.Args[0],
497 ev.Args[1],
498 uint64(ts.parentID),
499 uint64(it.evt.addExtraString(ts.name)),
500 }
501 } else {
502 mappedArgs = timedEventArgs{ev.Args[0], ev.Args[1], uint64(NoTask), uint64(it.evt.addExtraString(""))}
503 }
504 case oldtrace.EvUserRegion:
505 switch ev.Args[1] {
506 case 0:
507 mappedType = go122.EvUserRegionBegin
508 case 1:
509 mappedType = go122.EvUserRegionEnd
510 }
511 mappedArgs = timedEventArgs{ev.Args[0], ev.Args[2], uint64(ev.StkID)}
512 case oldtrace.EvUserLog:
513 mappedType = go122.EvUserLog
514 mappedArgs = timedEventArgs{ev.Args[0], ev.Args[1], it.inlineToStringID[ev.Args[3]], uint64(ev.StkID)}
515 case oldtrace.EvCPUSample:
516 mappedType = go122.EvCPUSample
517
518
519
520
521
522 mappedArgs = timedEventArgs{uint64(ev.StkID), ^uint64(0), uint64(ev.P), ev.G}
523 default:
524 return Event{}, fmt.Errorf("unexpected event type %v", ev.Type)
525 }
526
527 if oldtrace.EventDescriptions[ev.Type].Stack {
528 if stackIDs := go122.Specs()[mappedType].StackIDs; len(stackIDs) > 0 {
529 mappedArgs[stackIDs[0]-1] = uint64(ev.StkID)
530 }
531 }
532
533 m := NoThread
534 if ev.P != -1 && ev.Type != oldtrace.EvCPUSample {
535 if t, ok := it.procMs[ProcID(ev.P)]; ok {
536 m = ThreadID(t)
537 }
538 }
539 if ev.Type == oldtrace.EvProcStop {
540 delete(it.procMs, ProcID(ev.P))
541 }
542 g := GoID(ev.G)
543 if g == 0 {
544 g = NoGoroutine
545 }
546 out := Event{
547 ctx: schedCtx{
548 G: GoID(g),
549 P: ProcID(ev.P),
550 M: m,
551 },
552 table: it.evt,
553 base: baseEvent{
554 typ: mappedType,
555 time: Time(ev.Ts),
556 args: mappedArgs,
557 },
558 }
559 return out, nil
560 }
561
562
563
564 func convertOldFormat(pr oldtrace.Trace) *oldTraceConverter {
565 it := &oldTraceConverter{}
566 it.init(pr)
567 return it
568 }
569
View as plain text