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