...
1
2
3
4
5 package trace
6
7 import (
8 "sort"
9 "strings"
10 )
11
12
13 type GDesc struct {
14 ID uint64
15 Name string
16 PC uint64
17 CreationTime int64
18 StartTime int64
19 EndTime int64
20
21
22 Regions []*UserRegionDesc
23
24
25 GExecutionStat
26
27 *gdesc
28 }
29
30
31
32 type UserRegionDesc struct {
33 TaskID uint64
34 Name string
35
36
37
38
39 Start *Event
40
41
42
43
44 End *Event
45
46 GExecutionStat
47 }
48
49
50
51 type GExecutionStat struct {
52 ExecTime int64
53 SchedWaitTime int64
54 IOTime int64
55 BlockTime int64
56 SyscallTime int64
57 GCTime int64
58 SweepTime int64
59 TotalTime int64
60 }
61
62
63 func (s GExecutionStat) sub(v GExecutionStat) (r GExecutionStat) {
64 r = s
65 r.ExecTime -= v.ExecTime
66 r.SchedWaitTime -= v.SchedWaitTime
67 r.IOTime -= v.IOTime
68 r.BlockTime -= v.BlockTime
69 r.SyscallTime -= v.SyscallTime
70 r.GCTime -= v.GCTime
71 r.SweepTime -= v.SweepTime
72 r.TotalTime -= v.TotalTime
73 return r
74 }
75
76
77
78
79
80 func (g *GDesc) snapshotStat(lastTs, activeGCStartTime int64) (ret GExecutionStat) {
81 ret = g.GExecutionStat
82
83 if g.gdesc == nil {
84 return ret
85 }
86
87 if activeGCStartTime != 0 {
88 if g.CreationTime < activeGCStartTime {
89 ret.GCTime += lastTs - activeGCStartTime
90 } else {
91
92
93 ret.GCTime += lastTs - g.CreationTime
94 }
95 }
96
97 if g.TotalTime == 0 {
98 ret.TotalTime = lastTs - g.CreationTime
99 }
100
101 if g.lastStartTime != 0 {
102 ret.ExecTime += lastTs - g.lastStartTime
103 }
104 if g.blockNetTime != 0 {
105 ret.IOTime += lastTs - g.blockNetTime
106 }
107 if g.blockSyncTime != 0 {
108 ret.BlockTime += lastTs - g.blockSyncTime
109 }
110 if g.blockSyscallTime != 0 {
111 ret.SyscallTime += lastTs - g.blockSyscallTime
112 }
113 if g.blockSchedTime != 0 {
114 ret.SchedWaitTime += lastTs - g.blockSchedTime
115 }
116 if g.blockSweepTime != 0 {
117 ret.SweepTime += lastTs - g.blockSweepTime
118 }
119 return ret
120 }
121
122
123
124
125 func (g *GDesc) finalize(lastTs, activeGCStartTime int64, trigger *Event) {
126 if trigger != nil {
127 g.EndTime = trigger.Ts
128 }
129 finalStat := g.snapshotStat(lastTs, activeGCStartTime)
130
131 g.GExecutionStat = finalStat
132
133
134
135
136
137 if !IsSystemGoroutine(g.Name) {
138 for _, s := range g.activeRegions {
139 s.End = trigger
140 s.GExecutionStat = finalStat.sub(s.GExecutionStat)
141 g.Regions = append(g.Regions, s)
142 }
143 }
144 *(g.gdesc) = gdesc{}
145 }
146
147
148 type gdesc struct {
149 lastStartTime int64
150 blockNetTime int64
151 blockSyncTime int64
152 blockSyscallTime int64
153 blockSweepTime int64
154 blockGCTime int64
155 blockSchedTime int64
156
157 activeRegions []*UserRegionDesc
158 }
159
160
161 func GoroutineStats(events []*Event) map[uint64]*GDesc {
162 gs := make(map[uint64]*GDesc)
163 var lastTs int64
164 var gcStartTime int64
165 for _, ev := range events {
166 lastTs = ev.Ts
167 switch ev.Type {
168 case EvGoCreate:
169 g := &GDesc{ID: ev.Args[0], CreationTime: ev.Ts, gdesc: new(gdesc)}
170 g.blockSchedTime = ev.Ts
171
172
173
174
175
176
177
178 if creatorG := gs[ev.G]; creatorG != nil && len(creatorG.gdesc.activeRegions) > 0 {
179 regions := creatorG.gdesc.activeRegions
180 s := regions[len(regions)-1]
181 if s.TaskID != 0 {
182 g.gdesc.activeRegions = []*UserRegionDesc{
183 {TaskID: s.TaskID, Start: ev},
184 }
185 }
186 }
187 gs[g.ID] = g
188 case EvGoStart, EvGoStartLabel:
189 g := gs[ev.G]
190 if g.PC == 0 && len(ev.Stk) > 0 {
191 g.PC = ev.Stk[0].PC
192 g.Name = ev.Stk[0].Fn
193 }
194 g.lastStartTime = ev.Ts
195 if g.StartTime == 0 {
196 g.StartTime = ev.Ts
197 }
198 if g.blockSchedTime != 0 {
199 g.SchedWaitTime += ev.Ts - g.blockSchedTime
200 g.blockSchedTime = 0
201 }
202 case EvGoEnd, EvGoStop:
203 g := gs[ev.G]
204 g.finalize(ev.Ts, gcStartTime, ev)
205 case EvGoBlockSend, EvGoBlockRecv, EvGoBlockSelect,
206 EvGoBlockSync, EvGoBlockCond:
207 g := gs[ev.G]
208 g.ExecTime += ev.Ts - g.lastStartTime
209 g.lastStartTime = 0
210 g.blockSyncTime = ev.Ts
211 case EvGoSched, EvGoPreempt:
212 g := gs[ev.G]
213 g.ExecTime += ev.Ts - g.lastStartTime
214 g.lastStartTime = 0
215 g.blockSchedTime = ev.Ts
216 case EvGoSleep, EvGoBlock:
217 g := gs[ev.G]
218 g.ExecTime += ev.Ts - g.lastStartTime
219 g.lastStartTime = 0
220 case EvGoBlockNet:
221 g := gs[ev.G]
222 g.ExecTime += ev.Ts - g.lastStartTime
223 g.lastStartTime = 0
224 g.blockNetTime = ev.Ts
225 case EvGoBlockGC:
226 g := gs[ev.G]
227 g.ExecTime += ev.Ts - g.lastStartTime
228 g.lastStartTime = 0
229 g.blockGCTime = ev.Ts
230 case EvGoUnblock:
231 g := gs[ev.Args[0]]
232 if g.blockNetTime != 0 {
233 g.IOTime += ev.Ts - g.blockNetTime
234 g.blockNetTime = 0
235 }
236 if g.blockSyncTime != 0 {
237 g.BlockTime += ev.Ts - g.blockSyncTime
238 g.blockSyncTime = 0
239 }
240 g.blockSchedTime = ev.Ts
241 case EvGoSysBlock:
242 g := gs[ev.G]
243 g.ExecTime += ev.Ts - g.lastStartTime
244 g.lastStartTime = 0
245 g.blockSyscallTime = ev.Ts
246 case EvGoSysExit:
247 g := gs[ev.G]
248 if g.blockSyscallTime != 0 {
249 g.SyscallTime += ev.Ts - g.blockSyscallTime
250 g.blockSyscallTime = 0
251 }
252 g.blockSchedTime = ev.Ts
253 case EvGCSweepStart:
254 g := gs[ev.G]
255 if g != nil {
256
257 g.blockSweepTime = ev.Ts
258 }
259 case EvGCSweepDone:
260 g := gs[ev.G]
261 if g != nil && g.blockSweepTime != 0 {
262 g.SweepTime += ev.Ts - g.blockSweepTime
263 g.blockSweepTime = 0
264 }
265 case EvGCStart:
266 gcStartTime = ev.Ts
267 case EvGCDone:
268 for _, g := range gs {
269 if g.EndTime != 0 {
270 continue
271 }
272 if gcStartTime < g.CreationTime {
273 g.GCTime += ev.Ts - g.CreationTime
274 } else {
275 g.GCTime += ev.Ts - gcStartTime
276 }
277 }
278 gcStartTime = 0
279 case EvUserRegion:
280 g := gs[ev.G]
281 switch mode := ev.Args[1]; mode {
282 case 0:
283 g.activeRegions = append(g.activeRegions, &UserRegionDesc{
284 Name: ev.SArgs[0],
285 TaskID: ev.Args[0],
286 Start: ev,
287 GExecutionStat: g.snapshotStat(lastTs, gcStartTime),
288 })
289 case 1:
290 var sd *UserRegionDesc
291 if regionStk := g.activeRegions; len(regionStk) > 0 {
292 n := len(regionStk)
293 sd = regionStk[n-1]
294 regionStk = regionStk[:n-1]
295 g.activeRegions = regionStk
296 } else {
297 sd = &UserRegionDesc{
298 Name: ev.SArgs[0],
299 TaskID: ev.Args[0],
300 }
301 }
302 sd.GExecutionStat = g.snapshotStat(lastTs, gcStartTime).sub(sd.GExecutionStat)
303 sd.End = ev
304 g.Regions = append(g.Regions, sd)
305 }
306 }
307 }
308
309 for _, g := range gs {
310 g.finalize(lastTs, gcStartTime, nil)
311
312
313 sort.Slice(g.Regions, func(i, j int) bool {
314 x := g.Regions[i].Start
315 y := g.Regions[j].Start
316 if x == nil {
317 return true
318 }
319 if y == nil {
320 return false
321 }
322 return x.Ts < y.Ts
323 })
324
325 g.gdesc = nil
326 }
327
328 return gs
329 }
330
331
332 func RelatedGoroutines(events []*Event, goid uint64) map[uint64]bool {
333
334
335 gmap := make(map[uint64]bool)
336 gmap[goid] = true
337 for i := 0; i < 2; i++ {
338 gmap1 := make(map[uint64]bool)
339 for g := range gmap {
340 gmap1[g] = true
341 }
342 for _, ev := range events {
343 if ev.Type == EvGoUnblock && gmap[ev.Args[0]] {
344 gmap1[ev.G] = true
345 }
346 }
347 gmap = gmap1
348 }
349 gmap[0] = true
350 return gmap
351 }
352
353 func IsSystemGoroutine(entryFn string) bool {
354
355
356
357 return entryFn == "" || entryFn != "runtime.main" && strings.HasPrefix(entryFn, "runtime.")
358 }
359
View as plain text