Source file
src/cmd/trace/procgen.go
1
2
3
4
5 package main
6
7 import (
8 "fmt"
9 "internal/trace"
10 "internal/trace/traceviewer"
11 "internal/trace/traceviewer/format"
12 )
13
14 var _ generator = &procGenerator{}
15
16 type procGenerator struct {
17 globalRangeGenerator
18 globalMetricGenerator
19 procRangeGenerator
20 stackSampleGenerator[trace.ProcID]
21 logEventGenerator[trace.ProcID]
22
23 gStates map[trace.GoID]*gState[trace.ProcID]
24 inSyscall map[trace.ProcID]*gState[trace.ProcID]
25 maxProc trace.ProcID
26 }
27
28 func newProcGenerator() *procGenerator {
29 pg := new(procGenerator)
30 rg := func(ev *trace.Event) trace.ProcID {
31 return ev.Proc()
32 }
33 pg.stackSampleGenerator.getResource = rg
34 pg.logEventGenerator.getResource = rg
35 pg.gStates = make(map[trace.GoID]*gState[trace.ProcID])
36 pg.inSyscall = make(map[trace.ProcID]*gState[trace.ProcID])
37 return pg
38 }
39
40 func (g *procGenerator) Sync() {
41 g.globalRangeGenerator.Sync()
42 g.procRangeGenerator.Sync()
43 }
44
45 func (g *procGenerator) GoroutineLabel(ctx *traceContext, ev *trace.Event) {
46 l := ev.Label()
47 g.gStates[l.Resource.Goroutine()].setLabel(l.Label)
48 }
49
50 func (g *procGenerator) GoroutineRange(ctx *traceContext, ev *trace.Event) {
51 r := ev.Range()
52 switch ev.Kind() {
53 case trace.EventRangeBegin:
54 g.gStates[r.Scope.Goroutine()].rangeBegin(ev.Time(), r.Name, ev.Stack())
55 case trace.EventRangeActive:
56 g.gStates[r.Scope.Goroutine()].rangeActive(r.Name)
57 case trace.EventRangeEnd:
58 gs := g.gStates[r.Scope.Goroutine()]
59 gs.rangeEnd(ev.Time(), r.Name, ev.Stack(), ctx)
60 }
61 }
62
63 func (g *procGenerator) GoroutineTransition(ctx *traceContext, ev *trace.Event) {
64 st := ev.StateTransition()
65 goID := st.Resource.Goroutine()
66
67
68
69 gs, ok := g.gStates[goID]
70 if !ok {
71 gs = newGState[trace.ProcID](goID)
72 g.gStates[goID] = gs
73 }
74
75 gs.augmentName(st.Stack)
76
77
78 from, to := st.Goroutine()
79 if from == to {
80
81 return
82 }
83 if from == trace.GoRunning && !to.Executing() {
84 if to == trace.GoWaiting {
85
86 gs.block(ev.Time(), ev.Stack(), st.Reason, ctx)
87 } else {
88 gs.stop(ev.Time(), ev.Stack(), ctx)
89 }
90 }
91 if !from.Executing() && to == trace.GoRunning {
92 start := ev.Time()
93 if from == trace.GoUndetermined {
94
95 start = ctx.startTime
96 }
97 gs.start(start, ev.Proc(), ctx)
98 }
99
100 if from == trace.GoWaiting {
101
102 gs.unblock(ev.Time(), ev.Stack(), ev.Proc(), ctx)
103 }
104 if from == trace.GoNotExist && to == trace.GoRunnable {
105
106 gs.created(ev.Time(), ev.Proc(), ev.Stack())
107 }
108 if from == trace.GoSyscall && to != trace.GoRunning {
109
110 gs.blockedSyscallEnd(ev.Time(), ev.Stack(), ctx)
111 }
112
113
114 if to == trace.GoSyscall && ev.Proc() != trace.NoProc {
115 start := ev.Time()
116 if from == trace.GoUndetermined {
117
118 start = ctx.startTime
119 }
120
121
122
123 gs.syscallBegin(start, ev.Proc(), ev.Stack())
124 g.inSyscall[ev.Proc()] = gs
125 }
126
127 _, didNotBlock := g.inSyscall[ev.Proc()]
128 if from == trace.GoSyscall && didNotBlock {
129 gs.syscallEnd(ev.Time(), false, ctx)
130 delete(g.inSyscall, ev.Proc())
131 }
132
133
134 _, inMarkAssist := gs.activeRanges["GC mark assist"]
135 ctx.GoroutineTransition(ctx.elapsed(ev.Time()), viewerGState(from, inMarkAssist), viewerGState(to, inMarkAssist))
136 }
137
138 func (g *procGenerator) ProcTransition(ctx *traceContext, ev *trace.Event) {
139 st := ev.StateTransition()
140 proc := st.Resource.Proc()
141
142 g.maxProc = max(g.maxProc, proc)
143 viewerEv := traceviewer.InstantEvent{
144 Resource: uint64(proc),
145 Stack: ctx.Stack(viewerFrames(ev.Stack())),
146 }
147
148 from, to := st.Proc()
149 if from == to {
150
151 return
152 }
153 if to.Executing() {
154 start := ev.Time()
155 if from == trace.ProcUndetermined {
156 start = ctx.startTime
157 }
158 viewerEv.Name = "proc start"
159 viewerEv.Arg = format.ThreadIDArg{ThreadID: uint64(ev.Thread())}
160 viewerEv.Ts = ctx.elapsed(start)
161 ctx.IncThreadStateCount(ctx.elapsed(start), traceviewer.ThreadStateRunning, 1)
162 }
163 if from.Executing() {
164 start := ev.Time()
165 viewerEv.Name = "proc stop"
166 viewerEv.Ts = ctx.elapsed(start)
167 ctx.IncThreadStateCount(ctx.elapsed(start), traceviewer.ThreadStateRunning, -1)
168
169
170
171
172
173
174
175
176
177 gs, ok := g.inSyscall[proc]
178 if ok {
179
180 gs.syscallEnd(start, true, ctx)
181 gs.stop(start, ev.Stack(), ctx)
182 delete(g.inSyscall, proc)
183 }
184 }
185
186
187
188
189 if viewerEv.Name != "" {
190 ctx.Instant(viewerEv)
191 }
192 }
193
194 func (g *procGenerator) Finish(ctx *traceContext) {
195 ctx.SetResourceType("PROCS")
196
197
198
199
200 g.procRangeGenerator.Finish(ctx)
201 g.globalRangeGenerator.Finish(ctx)
202
203
204 for _, gs := range g.gStates {
205 gs.finish(ctx)
206 }
207
208
209 for i := uint64(0); i <= uint64(g.maxProc); i++ {
210 ctx.Resource(i, fmt.Sprintf("Proc %v", i))
211 }
212 }
213
View as plain text