github.com/goproxy0/go@v0.0.0-20171111080102-49cc0c489d2c/src/internal/trace/goroutines.go (about) 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, EvGoStartLabel: 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 EvGoBlockGC: 87 g := gs[ev.G] 88 g.ExecTime += ev.Ts - g.lastStartTime 89 g.blockGCTime = ev.Ts 90 case EvGoUnblock: 91 g := gs[ev.Args[0]] 92 if g.blockNetTime != 0 { 93 g.IOTime += ev.Ts - g.blockNetTime 94 g.blockNetTime = 0 95 } 96 if g.blockSyncTime != 0 { 97 g.BlockTime += ev.Ts - g.blockSyncTime 98 g.blockSyncTime = 0 99 } 100 g.blockSchedTime = ev.Ts 101 case EvGoSysBlock: 102 g := gs[ev.G] 103 g.ExecTime += ev.Ts - g.lastStartTime 104 g.blockSyscallTime = ev.Ts 105 case EvGoSysExit: 106 g := gs[ev.G] 107 if g.blockSyscallTime != 0 { 108 g.SyscallTime += ev.Ts - g.blockSyscallTime 109 g.blockSyscallTime = 0 110 } 111 g.blockSchedTime = ev.Ts 112 case EvGCSweepStart: 113 g := gs[ev.G] 114 if g != nil { 115 // Sweep can happen during GC on system goroutine. 116 g.blockSweepTime = ev.Ts 117 } 118 case EvGCSweepDone: 119 g := gs[ev.G] 120 if g != nil && g.blockSweepTime != 0 { 121 g.SweepTime += ev.Ts - g.blockSweepTime 122 g.blockSweepTime = 0 123 } 124 case EvGCStart: 125 gcStartTime = ev.Ts 126 case EvGCDone: 127 for _, g := range gs { 128 if g.EndTime == 0 { 129 g.GCTime += ev.Ts - gcStartTime 130 } 131 } 132 } 133 } 134 135 for _, g := range gs { 136 if g.TotalTime == 0 { 137 g.TotalTime = lastTs - g.CreationTime 138 } 139 if g.EndTime == 0 { 140 g.EndTime = lastTs 141 } 142 if g.blockNetTime != 0 { 143 g.IOTime += lastTs - g.blockNetTime 144 g.blockNetTime = 0 145 } 146 if g.blockSyncTime != 0 { 147 g.BlockTime += lastTs - g.blockSyncTime 148 g.blockSyncTime = 0 149 } 150 if g.blockSyscallTime != 0 { 151 g.SyscallTime += lastTs - g.blockSyscallTime 152 g.blockSyscallTime = 0 153 } 154 if g.blockSchedTime != 0 { 155 g.SchedWaitTime += lastTs - g.blockSchedTime 156 g.blockSchedTime = 0 157 } 158 g.gdesc = nil 159 } 160 161 return gs 162 } 163 164 // RelatedGoroutines finds a set of goroutines related to goroutine goid. 165 func RelatedGoroutines(events []*Event, goid uint64) map[uint64]bool { 166 // BFS of depth 2 over "unblock" edges 167 // (what goroutines unblock goroutine goid?). 168 gmap := make(map[uint64]bool) 169 gmap[goid] = true 170 for i := 0; i < 2; i++ { 171 gmap1 := make(map[uint64]bool) 172 for g := range gmap { 173 gmap1[g] = true 174 } 175 for _, ev := range events { 176 if ev.Type == EvGoUnblock && gmap[ev.Args[0]] { 177 gmap1[ev.G] = true 178 } 179 } 180 gmap = gmap1 181 } 182 gmap[0] = true // for GC events 183 return gmap 184 }