Skip to content

Commit 61f92ee

Browse files
committed
internal/trace: fix GC time computation of short goroutines
Goroutine analysis reports the sum of all overlapping GC intervals as the GCTime of a goroutine. The computation is done by adding the length of a completed GC interval to 'active' goroutines when processing the corresponding EvGCDone event. This change fixes the two corner cases the current implementation ignores: 1) Goroutine that ends during GC. Previously, this goroutine was ignored and GC time was undercounted. We handle this case by setting the gcStartTime only when GC is active and handling non-zero gcStartTime when processing EvGoStop and EvGoStart. 2) Goroutine that starts during GC. Previously, the entire GC interval length was added to the Goroutine's GCTime which resulted in overcount of GC time. We handle this case by computing the length of overlapped period precisely. Change-Id: Ifa8e82672ec341b5ff87837209f4311fa7262b7f Reviewed-on: https://go-review.googlesource.com/100842 Reviewed-by: Heschi Kreinick <[email protected]> Run-TryBot: Heschi Kreinick <[email protected]> TryBot-Result: Gobot Gobot <[email protected]>
1 parent cceee68 commit 61f92ee

File tree

1 file changed

+17
-2
lines changed

1 file changed

+17
-2
lines changed

src/internal/trace/goroutines.go

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ type gdesc struct {
4040
func GoroutineStats(events []*Event) map[uint64]*GDesc {
4141
gs := make(map[uint64]*GDesc)
4242
var lastTs int64
43-
var gcStartTime int64
43+
var gcStartTime int64 // gcStartTime == 0 indicates gc is inactive.
4444
for _, ev := range events {
4545
lastTs = ev.Ts
4646
switch ev.Type {
@@ -67,6 +67,15 @@ func GoroutineStats(events []*Event) map[uint64]*GDesc {
6767
g.ExecTime += ev.Ts - g.lastStartTime
6868
g.TotalTime = ev.Ts - g.CreationTime
6969
g.EndTime = ev.Ts
70+
if gcStartTime != 0 {
71+
if g.CreationTime < gcStartTime {
72+
g.GCTime += ev.Ts - gcStartTime
73+
} else {
74+
// The goroutine's lifetime overlaps
75+
// with a GC completely.
76+
g.GCTime += ev.Ts - g.CreationTime
77+
}
78+
}
7079
case EvGoBlockSend, EvGoBlockRecv, EvGoBlockSelect,
7180
EvGoBlockSync, EvGoBlockCond:
7281
g := gs[ev.G]
@@ -125,10 +134,16 @@ func GoroutineStats(events []*Event) map[uint64]*GDesc {
125134
gcStartTime = ev.Ts
126135
case EvGCDone:
127136
for _, g := range gs {
128-
if g.EndTime == 0 {
137+
if g.EndTime != 0 {
138+
continue
139+
}
140+
if gcStartTime < g.CreationTime {
141+
g.GCTime += ev.Ts - g.CreationTime
142+
} else {
129143
g.GCTime += ev.Ts - gcStartTime
130144
}
131145
}
146+
gcStartTime = 0 // indicates gc is inactive.
132147
}
133148
}
134149

0 commit comments

Comments
 (0)