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
149 Arg: format.SchedCtxArg{
150 ProcID: uint64(st.Resource.Proc()),
151 ThreadID: uint64(ev.Thread()),
152 },
153 }
154
155 from, to := st.Proc()
156 if from == to {
157
158 return
159 }
160 if to.Executing() {
161 start := ev.Time()
162 if from == trace.ProcUndetermined {
163 start = ctx.startTime
164 }
165 viewerEv.Name = "proc start"
166 viewerEv.Ts = ctx.elapsed(start)
167 ctx.IncThreadStateCount(ctx.elapsed(start), traceviewer.ThreadStateRunning, 1)
168 }
169 if from.Executing() {
170 start := ev.Time()
171 viewerEv.Name = "proc stop"
172 viewerEv.Ts = ctx.elapsed(start)
173 ctx.IncThreadStateCount(ctx.elapsed(start), traceviewer.ThreadStateRunning, -1)
174
175
176
177
178
179
180
181
182
183 gs, ok := g.inSyscall[proc]
184 if ok {
185
186 gs.syscallEnd(start, true, ctx)
187 gs.stop(start, ev.Stack(), ctx)
188 delete(g.inSyscall, proc)
189 }
190 }
191
192
193
194
195 if viewerEv.Name != "" {
196 ctx.Instant(viewerEv)
197 }
198 }
199
200 func (g *procGenerator) Finish(ctx *traceContext) {
201 ctx.SetResourceType("PROCS")
202
203
204
205
206 g.procRangeGenerator.Finish(ctx)
207 g.globalRangeGenerator.Finish(ctx)
208
209
210 for _, gs := range g.gStates {
211 gs.finish(ctx)
212 }
213
214
215 for i := uint64(0); i <= uint64(g.maxProc); i++ {
216 ctx.Resource(i, fmt.Sprintf("Proc %v", i))
217 }
218 }
219
View as plain text