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