github.com/hikaru7719/go@v0.0.0-20181025140707-c8b2ac68906a/src/internal/traceparser/events.go (about) 1 // Copyright 2018 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 traceparser 6 7 import ( 8 "fmt" 9 "sort" 10 ) 11 12 // convert raw events into Events 13 14 func (p *Parsed) createEvents(f func(string)) error { 15 // multiple passes: 16 // create some Events 17 // sort them by time (and adjust their times to be nanonseconds) 18 // remove events not in the desired time interval 19 // make the events consistent (adding initializing events at the beginning) 20 // remove the futile events 21 // add links (and do final checking) 22 23 // shared by firstEvents 24 p.byproc = make(map[int][]*Event) 25 p.lastGs = make(map[int]uint64) 26 27 // p.batches are always sorted by time. otherwise a batch for one p that is totally 28 // later than another batch might be done first, confusing us about g's 29 for i, b := range p.batches { 30 if b.raws == nil { 31 continue 32 } 33 if err := p.firstEvents(b); err != nil { 34 return fmt.Errorf("%v", err) // PJW: this is not useful 35 } 36 // we done with b.raws now 37 p.batches[i].raws = nil 38 } 39 f("firstEvents finished") 40 sorted := []*Event{} 41 for _, v := range p.byproc { 42 sorted = append(sorted, v...) 43 } 44 // PJW: are we done with p.byproc now? Yes. This shrinks a little. 45 p.byproc = nil 46 // Why wasn't this done earlier? Or, why do it at all? 47 for _, ev := range sorted { 48 switch ev.Type { 49 case EvGoStartLocal: 50 ev.Type = EvGoStart 51 case EvGoUnblockLocal: 52 ev.Type = EvGoUnblock 53 case EvGoSysExitLocal: 54 ev.Type = EvGoSysExit 55 } 56 } 57 // change to nanoseconds 58 freq := 1e9 / float64(p.TicksPerSec) 59 for i, ev := range sorted { 60 // Move timers and syscalls to separate fake Ps. 61 // This could be done in the loop at line 38 62 // or maybe after robust fixes things. 63 if p.timerGoids[ev.G] && ev.Type == EvGoUnblock { 64 ev.Args[2] = uint64(ev.P) // save for robust() to use 65 ev.P = TimerP 66 } 67 // sometimes the ts is not what it should be 68 if ev.Type == EvGoSysExit { 69 ev.P = SyscallP 70 if ev.Args[2] != 0 { 71 // PJW: test for this being safe. There might be no preceding 72 // EvSysBlock, EvGoInSyscall, or its time might be later than this 73 ev.Ts = int64(ev.Args[2]) 74 } 75 } 76 if ev.Type == EvGCStart { 77 ev.P = GCP 78 } 79 t := ev.Ts - p.minticks 80 if t < 0 { 81 return fmt.Errorf("event %d %s would be %d mints=%x", i, ev, t, p.minticks) 82 } 83 ev.Ts = int64(float64(ev.Ts-p.minticks) * freq) 84 } 85 // Stable for the case of equal Ts's. 86 sort.SliceStable(sorted, func(i, j int) bool { return sorted[i].Ts < sorted[j].Ts }) 87 f("sorted") 88 // and ignore the ones with times out of bounds 89 firstwant, lastwant := 0, len(sorted) 90 for i, ev := range sorted { 91 if ev.Ts < p.MinWant { 92 firstwant = i + 1 93 } else if ev.Ts > p.MaxWant { // closed interval [minwant, maxwant] 94 lastwant = i 95 break // sorted by Ts 96 } 97 } 98 f("nanoseconds") 99 var err error 100 sorted, _, err = p.robust(sorted[firstwant:lastwant]) // PJW: copy info from aux 101 f("consistent") 102 if err != nil { 103 return err 104 } 105 events, cnt := p.removeFutile(sorted) // err is always nil here. 106 f(fmt.Sprintf("removed %d futiles", cnt)) 107 // and finally, do some checks and put in links 108 err = p.postProcess(events) 109 f("post processed") 110 if err != nil { 111 return err // PJW: is this enough? NO 112 } 113 p.Events = events 114 return nil 115 } 116 117 // Special P identifiers. 118 const ( 119 FakeP = 1000000 + iota 120 TimerP // depicts timer unblocks 121 NetpollP // depicts network unblocks 122 SyscallP // depicts returns from syscalls 123 GCP // depicts GC state 124 ) 125 126 // convert the raw events for a batch into Events, and keep track of 127 // which G is running on the P that is common to the batch. 128 func (p *Parsed) firstEvents(b batch) error { 129 for _, raw := range b.raws { 130 desc := EventDescriptions[raw.typ] 131 narg := p.rawArgNum(&raw) 132 if p.Err != nil { 133 return p.Err 134 } 135 if raw.typ == EvBatch { 136 // first event, record information about P, G, and Ts 137 p.lastGs[p.lastP] = p.lastG // 0 the first time through 138 p.lastP = int(raw.Arg(0)) 139 p.lastG = p.lastGs[p.lastP] 140 p.lastTs = int64(raw.Arg(1)) 141 continue 142 } 143 e := &Event{Type: raw.typ, P: int32(p.lastP), G: p.lastG} 144 var argoffset int 145 if p.Version < 1007 { // can't happen. 146 e.Ts = p.lastTs + int64(raw.Arg(1)) 147 argoffset = 2 148 } else { 149 e.Ts = p.lastTs + int64(raw.Arg(0)) 150 argoffset = 1 151 } 152 p.lastTs = e.Ts 153 // collect the args for the raw event e 154 for i := argoffset; i < narg; i++ { 155 // evade one byte of corruption (from fuzzing typically) 156 if raw.args == nil { 157 return fmt.Errorf("raw.args is nil %s", evname(raw.typ)) 158 } 159 if i > 0 && i-1 >= len(*raw.args) { 160 return fmt.Errorf("%s wants arg %d of %d", evname(raw.typ), i, len(*raw.args)) 161 } 162 if i == narg-1 && desc.Stack { 163 e.StkID = uint32(raw.Arg(i)) 164 } else { 165 e.Args[i-argoffset] = raw.Arg(i) 166 } 167 } 168 switch raw.typ { 169 case EvGoSysCall, EvGCSweepDone, EvGCSweepStart: 170 if e.G == 0 { 171 // missing some earlier G's from this P 172 continue // so we don't know which G is doing it 173 } 174 case EvGoStart, EvGoStartLocal, EvGoStartLabel: 175 p.lastG = e.Args[0] 176 e.G = p.lastG 177 if raw.typ == EvGoStartLabel { 178 e.SArgs = []string{p.Strings[e.Args[2]]} 179 } 180 case EvGCSTWStart: 181 e.G = 0 182 switch e.Args[0] { 183 case 0: 184 e.SArgs = []string{"mark termination"} 185 case 1: 186 e.SArgs = []string{"sweep termination"} 187 default: 188 return fmt.Errorf("unknown STW kind %d!=0,1 %s", e.Args[0], e) 189 } 190 case EvGCStart, EvGCDone, EvGCSTWDone: 191 e.G = 0 192 case EvGoEnd, EvGoStop, EvGoSched, EvGoPreempt, 193 EvGoSleep, EvGoBlock, EvGoBlockSend, EvGoBlockRecv, 194 EvGoBlockSelect, EvGoBlockSync, EvGoBlockCond, EvGoBlockNet, 195 EvGoSysBlock, EvGoBlockGC: 196 p.lastG = 0 197 if e.G == 0 { 198 // missing some earlier G's from this P 199 continue // so we don't know which G is doing it 200 } 201 case EvGoSysExit, EvGoWaiting, EvGoInSyscall: 202 e.G = e.Args[0] 203 case EvUserTaskCreate: 204 // e.Args 0: taskID, 1:parentID, 2:nameID 205 e.SArgs = []string{p.Strings[e.Args[2]]} 206 case EvUserRegion: 207 if e.G == 0 { 208 continue // don't know its G 209 } 210 // e.Args 0: taskID, 1: mode, 2:nameID 211 e.SArgs = []string{p.Strings[e.Args[2]]} 212 case EvUserLog: 213 // e.Args 0: taskID, 1:keyID, 2: stackID 214 e.SArgs = []string{p.Strings[e.Args[1]], raw.sarg} 215 } 216 p.byproc[p.lastP] = append(p.byproc[p.lastP], e) 217 } 218 return nil 219 } 220 221 func (p *Parsed) removeFutile(events []*Event) ([]*Event, int) { 222 // Phase 1: determine futile wakeup sequences. 223 type G struct { 224 futile bool 225 wakeup []*Event // wakeup sequence (subject for removal) 226 } 227 gs := make(map[uint64]G) 228 futile := make(map[*Event]bool) 229 cnt := 0 230 for _, ev := range events { 231 switch ev.Type { 232 case EvGoUnblock: 233 g := gs[ev.Args[0]] 234 g.wakeup = []*Event{ev} 235 gs[ev.Args[0]] = g 236 case EvGoStart, EvGoPreempt, EvFutileWakeup: 237 g := gs[ev.G] 238 g.wakeup = append(g.wakeup, ev) 239 if ev.Type == EvFutileWakeup { 240 g.futile = true 241 } 242 gs[ev.G] = g 243 case EvGoBlock, EvGoBlockSend, EvGoBlockRecv, EvGoBlockSelect, 244 EvGoBlockSync, EvGoBlockCond: 245 g := gs[ev.G] 246 if g.futile { 247 futile[ev] = true 248 for _, ev1 := range g.wakeup { 249 futile[ev1] = true 250 } 251 } 252 delete(gs, ev.G) 253 cnt++ 254 } 255 } 256 // Phase 2: remove futile wakeup sequences. 257 newEvents := events[:0] // overwrite the original slice 258 for _, ev := range events { 259 if !futile[ev] { 260 newEvents = append(newEvents, ev) 261 } 262 } 263 return newEvents, cnt // PJW: cnt doesn't count the futile[]s 264 } 265 266 // Arg gets the n-th arg from a raw event 267 func (r *rawEvent) Arg(n int) uint64 { 268 if n == 0 { 269 return r.arg0 270 } 271 return (*r.args)[n-1] 272 } 273 274 // report the number of arguments. (historical differences) 275 func (p *Parsed) rawArgNum(ev *rawEvent) int { 276 desc := EventDescriptions[ev.typ] 277 switch ev.typ { 278 case EvStack, EvFrequency, EvTimerGoroutine: 279 p.Err = fmt.Errorf("%s unexpected in rawArgNum", evname(ev.typ)) 280 return 0 281 } 282 narg := len(desc.Args) 283 if desc.Stack { 284 narg++ 285 } 286 if ev.typ == EvBatch { 287 if p.Version < 1007 { 288 narg++ // used to be an extra unused arg 289 } 290 return narg 291 } 292 narg++ // timestamp 293 if p.Version < 1007 { 294 narg++ // sequence 295 } 296 // various special historical cases 297 switch ev.typ { 298 case EvGCSweepDone: 299 if p.Version < 1009 { 300 narg -= 2 // 1.9 added 2 args 301 } 302 case EvGCStart, EvGoStart, EvGoUnblock: 303 if p.Version < 1007 { 304 narg-- // one more since 1.7 305 } 306 case EvGCSTWStart: 307 if p.Version < 1010 { 308 narg-- // 1.10 added an argument 309 } 310 } 311 return narg 312 }