1 // 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 5 package trace 6 7 // GDesc contains statistics about execution of a single goroutine. 8 type 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. 29 type 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. 40 func 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. 161 func 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 } 181