blob: f8673e20bc2301cc5f1cea21df068fe3145fb302 [file] [log] [blame]
Dmitry Vyukov7b0c73a2015-03-10 19:40:09 +03001// Copyright 2014 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package trace
6
7// GDesc contains statistics about execution of a single goroutine.
8type GDesc struct {
9 ID uint64
10 Name string
11 PC uint64
12 CreationTime int64
13 StartTime int64
14 EndTime int64
15
16 ExecTime int64
17 SchedWaitTime int64
18 IOTime int64
19 BlockTime int64
20 SyscallTime int64
21 GCTime int64
22 SweepTime int64
23 TotalTime int64
24
25 *gdesc // private part
26}
27
28// gdesc is a private part of GDesc that is required only during analysis.
29type gdesc struct {
30 lastStartTime int64
31 blockNetTime int64
32 blockSyncTime int64
33 blockSyscallTime int64
34 blockSweepTime int64
35 blockGCTime int64
36 blockSchedTime int64
37}
38
39// GoroutineStats generates statistics for all goroutines in the trace.
40func GoroutineStats(events []*Event) map[uint64]*GDesc {
41 gs := make(map[uint64]*GDesc)
42 var lastTs int64
43 var gcStartTime int64
44 for _, ev := range events {
45 lastTs = ev.Ts
46 switch ev.Type {
47 case EvGoCreate:
48 g := &GDesc{ID: ev.Args[0], CreationTime: ev.Ts, gdesc: new(gdesc)}
49 g.blockSchedTime = ev.Ts
50 gs[g.ID] = g
51 case EvGoStart:
52 g := gs[ev.G]
53 if g.PC == 0 {
54 g.PC = ev.Stk[0].PC
55 g.Name = ev.Stk[0].Fn
56 }
57 g.lastStartTime = ev.Ts
58 if g.StartTime == 0 {
59 g.StartTime = ev.Ts
60 }
61 if g.blockSchedTime != 0 {
62 g.SchedWaitTime += ev.Ts - g.blockSchedTime
63 g.blockSchedTime = 0
64 }
65 case EvGoEnd, EvGoStop:
66 g := gs[ev.G]
67 g.ExecTime += ev.Ts - g.lastStartTime
68 g.TotalTime = ev.Ts - g.CreationTime
69 g.EndTime = ev.Ts
70 case EvGoBlockSend, EvGoBlockRecv, EvGoBlockSelect,
71 EvGoBlockSync, EvGoBlockCond:
72 g := gs[ev.G]
73 g.ExecTime += ev.Ts - g.lastStartTime
74 g.blockSyncTime = ev.Ts
75 case EvGoSched, EvGoPreempt:
76 g := gs[ev.G]
77 g.ExecTime += ev.Ts - g.lastStartTime
78 g.blockSchedTime = ev.Ts
79 case EvGoSleep, EvGoBlock:
80 g := gs[ev.G]
81 g.ExecTime += ev.Ts - g.lastStartTime
82 case EvGoBlockNet:
83 g := gs[ev.G]
84 g.ExecTime += ev.Ts - g.lastStartTime
85 g.blockNetTime = ev.Ts
86 case EvGoUnblock:
87 g := gs[ev.Args[0]]
88 if g.blockNetTime != 0 {
89 g.IOTime += ev.Ts - g.blockNetTime
90 g.blockNetTime = 0
91 }
92 if g.blockSyncTime != 0 {
93 g.BlockTime += ev.Ts - g.blockSyncTime
94 g.blockSyncTime = 0
95 }
96 g.blockSchedTime = ev.Ts
97 case EvGoSysBlock:
98 g := gs[ev.G]
99 g.ExecTime += ev.Ts - g.lastStartTime
100 g.blockSyscallTime = ev.Ts
101 case EvGoSysExit:
102 g := gs[ev.G]
103 if g.blockSyscallTime != 0 {
104 g.SyscallTime += ev.Ts - g.blockSyscallTime
105 g.blockSyscallTime = 0
106 }
107 g.blockSchedTime = ev.Ts
108 case EvGCSweepStart:
109 g := gs[ev.G]
110 if g != nil {
111 // Sweep can happen during GC on system goroutine.
112 g.blockSweepTime = ev.Ts
113 }
114 case EvGCSweepDone:
115 g := gs[ev.G]
116 if g != nil && g.blockSweepTime != 0 {
117 g.SweepTime += ev.Ts - g.blockSweepTime
118 g.blockSweepTime = 0
119 }
120 case EvGCStart:
121 gcStartTime = ev.Ts
122 case EvGCDone:
123 for _, g := range gs {
124 if g.EndTime == 0 {
125 g.GCTime += ev.Ts - gcStartTime
126 }
127 }
128 }
129 }
130
131 for _, g := range gs {
132 if g.TotalTime == 0 {
133 g.TotalTime = lastTs - g.CreationTime
134 }
135 if g.EndTime == 0 {
136 g.EndTime = lastTs
137 }
138 if g.blockNetTime != 0 {
139 g.IOTime += lastTs - g.blockNetTime
140 g.blockNetTime = 0
141 }
142 if g.blockSyncTime != 0 {
143 g.BlockTime += lastTs - g.blockSyncTime
144 g.blockSyncTime = 0
145 }
146 if g.blockSyscallTime != 0 {
147 g.SyscallTime += lastTs - g.blockSyscallTime
148 g.blockSyscallTime = 0
149 }
150 if g.blockSchedTime != 0 {
151 g.SchedWaitTime += lastTs - g.blockSchedTime
152 g.blockSchedTime = 0
153 }
154 g.gdesc = nil
155 }
156
157 return gs
158}
159
160// RelatedGoroutines finds a set of goroutines related to goroutine goid.
161func RelatedGoroutines(events []*Event, goid uint64) map[uint64]bool {
162 // BFS of depth 2 over "unblock" edges
163 // (what goroutines unblock goroutine goid?).
164 gmap := make(map[uint64]bool)
165 gmap[goid] = true
166 for i := 0; i < 2; i++ {
167 gmap1 := make(map[uint64]bool)
168 for g := range gmap {
169 gmap1[g] = true
170 }
171 for _, ev := range events {
172 if ev.Type == EvGoUnblock && gmap[ev.Args[0]] {
173 gmap1[ev.G] = true
174 }
175 }
176 gmap = gmap1
177 }
178 gmap[0] = true // for GC events
179 return gmap
180}