github.com/hikaru7719/go@v0.0.0-20181025140707-c8b2ac68906a/src/internal/traceparser/robust.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 // there are panics for impossible situations. probably an error would be better 8 // (if only it were certain these are impossible) 9 10 import ( 11 "fmt" 12 "log" 13 ) 14 15 // repair an incomplete or possibly damaged interval of Events 16 // so that postProcess is happy 17 18 // errors returned by checkRunning() 19 const ( 20 ok = 0 21 badRunning = 1 << iota 22 badP 23 badG0 24 ) 25 26 // states of g's and p's 27 type gdesc struct { 28 state gStatus 29 ev, evStart, evCreate, evMarkAssist *Event 30 } 31 32 type pdesc struct { 33 running bool 34 g uint64 35 evSTW, evSweep *Event 36 } 37 38 func locstr(ev *Event) string { 39 if ev == nil { 40 return "<nil>" 41 } 42 return fmt.Sprintf("%s:%x", evname(ev.Type), ev.Ts) 43 } 44 func (p pdesc) String() string { 45 return fmt.Sprintf("[%v %d %s %s]", p.running, p.g, locstr(p.evSTW), locstr(p.evSweep)) 46 } 47 48 func (g gdesc) String() string { 49 var nm string 50 switch g.state { 51 case gDead: 52 nm = "dead" 53 case gWaiting: 54 nm = "waiting" 55 case gRunnable: 56 nm = "runnable" 57 case gRunning: 58 nm = "running" 59 } 60 f := locstr 61 return fmt.Sprintf("[%s %s,%s,%s,%s]", nm, f(g.ev), f(g.evStart), 62 f(g.evCreate), f(g.evMarkAssist)) 63 } 64 65 func checkRunning(pd pdesc, gd gdesc, ev *Event, okG0 bool) int { 66 ret := ok 67 if gd.state != gRunning { 68 ret |= badRunning 69 } 70 if pd.g != ev.G { 71 ret |= badP 72 } 73 if !okG0 && ev.G == 0 { 74 ret |= badG0 75 } 76 return ret 77 } 78 79 type aux struct { 80 pref []*Event // prefix 81 evs []*Event // copies and inserted 82 deleted map[byte]int // count by Type 83 inserted map[byte]int // count by Type 84 gs map[uint64]gdesc 85 ps map[int32]pdesc 86 g gdesc 87 px pdesc 88 my *Parsed 89 input []*Event // events in call to robust() 90 last int // last index handled by reorder 91 err error // report inconsistent trace files 92 } 93 94 func (a *aux) preftime() int64 { 95 ts := a.my.MinWant - 1000 96 if ts < 0 { 97 ts = 0 98 } 99 if len(a.pref) > 0 { 100 ts = a.pref[len(a.pref)-1].Ts + 1 101 } 102 return ts 103 } 104 func (a *aux) delete(i int, ev *Event) { 105 a.deleted[ev.Type]++ 106 } 107 func (a *aux) prefix(typ byte, g uint64, p int32) { 108 ts := a.preftime() 109 ev := &Event{Type: typ, G: g, P: p, Ts: ts, 110 Args: [3]uint64{0, 0, 1}} 111 a.pref = append(a.pref, ev) 112 } 113 func (a *aux) procstart(p int32) { 114 if p >= FakeP || a.px.running { 115 return 116 } 117 a.prefix(EvProcStart, 0, p) 118 a.px.running = true 119 } 120 func (a *aux) makewaiting(i int, g uint64, typ byte) { 121 // GoCreate, g=0 args[0]=g; maybe it exists already? 122 // GoWaiting or GoInSysCall 123 p := int32(a.my.batches[0].P) 124 ev := &Event{Type: EvGoCreate, P: p, 125 Ts: a.preftime(), Args: [3]uint64{g, 0, 2}} 126 a.pref = append(a.pref, ev) 127 a.gs[g] = gdesc{state: gRunnable, ev: ev, evCreate: ev} 128 ev = &Event{Type: typ, G: g, P: p, 129 Ts: a.preftime(), Args: [3]uint64{g, 0, 3}} 130 a.pref = append(a.pref, ev) 131 switch typ { 132 default: 133 panic(fmt.Sprintf("weird typ %s in makewaiting", evname(typ))) 134 case EvGoWaiting, EvGoInSyscall: 135 // ok 136 } 137 } 138 139 func (a *aux) makerunnable(i int, ev *Event) { 140 // Create, Sched, Preempt, or Unblock 141 switch a.gs[ev.G].state { 142 case gDead: 143 p := int32(a.my.batches[0].P) 144 ev := &Event{Type: EvGoCreate, P: p, 145 Ts: a.preftime(), Args: [3]uint64{ev.G, 0, 4}} 146 a.pref = append(a.pref, ev) 147 a.gs[ev.Args[0]] = gdesc{state: gRunnable, ev: ev, evCreate: ev} 148 case gRunnable: 149 return 150 case gRunning: 151 //a.prevs(i) 152 a.err = fmt.Errorf("gRunning %d:%s", i, ev) 153 case gWaiting: 154 //a.prevs(i) 155 a.err = fmt.Errorf("no consistent ordering possible %d:%s", i, ev) 156 } 157 } 158 func (a *aux) makerunning(i int, ev *Event) { 159 // GoStart once it is runnable 160 switch a.g.state { 161 case gDead: 162 a.makerunnable(i, ev) 163 case gRunnable: 164 break 165 case gRunning: 166 return 167 case gWaiting: 168 a.err = fmt.Errorf("gWaiting in makerunnable %d:%s %+v", i, ev, a.g) 169 } 170 // PJW: which P? Probably need a ProcStart once 171 if !a.px.running { 172 a.procstart(ev.P) 173 } 174 p := ev.P 175 if p == TimerP { 176 p = int32(ev.Args[2]) // from events.go:71 177 ev.Args[2] = 0 178 } 179 x := &Event{Type: EvGoStart, G: ev.G, P: p, Args: [3]uint64{ev.G, 0, 5}} 180 x.Ts = ev.Ts - 1 181 a.evs = append(a.evs, x) 182 a.g.state = gRunning 183 a.g.evStart = x 184 a.px.g = x.G 185 a.inserted[EvGoStart]++ 186 } 187 188 func (p *Parsed) robust(events []*Event) ([]*Event, *aux, error) { // *aux for debugging (CheckRobust) 189 a := new(aux) 190 a.gs = make(map[uint64]gdesc) 191 a.ps = make(map[int32]pdesc) 192 var evGC, evSTW *Event 193 tasks := make(map[uint64]*Event) // task id to create 194 activeSpans := make(map[uint64][]*Event) 195 a.gs[0] = gdesc{state: gRunning} // bootstrap 196 a.deleted = make(map[byte]int) 197 a.inserted = make(map[byte]int) 198 a.my = p 199 a.input = events 200 201 for i, ev := range events { 202 if a.err != nil { 203 break 204 } 205 if i < len(events)-1 && ev.Ts == events[i+1].Ts && 206 i > a.last { 207 // sigh. dragonfly, or similar trouble. 208 // a.last is to avoid overlapping calls 209 // This is a placeholder if needed. 210 //a.reorder(i, events) 211 ev = events[i] 212 } 213 var gok, pok bool 214 a.g, gok = a.gs[ev.G] 215 a.px, pok = a.ps[ev.P] 216 switch ev.Type { 217 case EvProcStart: 218 if a.px.running { // This doesn't happen, but to be safe 219 a.delete(i, ev) // already started 220 continue 221 } 222 a.px.running = true 223 case EvProcStop: 224 if !pok { // Ok to delete, as we've never heard of it 225 a.delete(i, ev) 226 continue 227 } 228 if !a.px.running { 229 a.procstart(ev.P) 230 } 231 if a.px.g != 0 { 232 // p is running a g! Stop the g? Ignore the Stop? 233 // Ignore the Stop. I don't think this happens. 234 // (unless there are equal Ts's or the file is corrupt) 235 a.err = fmt.Errorf("unexpected %d:%s %v", i, ev, a.px) 236 // a.delete(i, ev) // PJW 237 continue 238 } 239 a.px.running = false 240 case EvGCStart: 241 if evGC != nil { 242 // already running; doesn't happen 243 a.delete(i, ev) 244 continue 245 } 246 evGC = ev 247 case EvGCDone: 248 if evGC == nil { 249 // no GCStart to link it to: choice is lying about 250 // the duration or the existence. Do the latter 251 a.delete(i, ev) 252 continue 253 } 254 evGC = nil 255 case EvGCSTWStart: 256 evp := &evSTW 257 if p.Version < 1010 { 258 // Before 1.10, EvGCSTWStart was per-P. 259 evp = &a.px.evSTW 260 } 261 if *evp != nil { 262 // still running; doesn't happen 263 a.delete(i, ev) 264 continue 265 } 266 *evp = ev 267 case EvGCSTWDone: 268 evp := &evSTW 269 if p.Version < 1010 { 270 // Before 1.10, EvGCSTWDone was per-P. 271 evp = &a.px.evSTW 272 } 273 if *evp == nil { 274 // no STWStart to link to: choice is lying about 275 // duration or the existence. Do the latter. 276 a.delete(i, ev) 277 continue 278 } 279 *evp = nil 280 case EvGCMarkAssistStart: 281 if a.g.evMarkAssist != nil { 282 // already running; doesn't happen 283 a.delete(i, ev) 284 continue 285 } 286 a.g.evMarkAssist = ev 287 case EvGCMarkAssistDone: 288 // ok to be in progress 289 a.g.evMarkAssist = nil 290 case EvGCSweepStart: 291 if a.px.evSweep != nil { 292 // older one still running; doesn't happen 293 a.delete(i, ev) 294 continue 295 } 296 a.px.evSweep = ev 297 case EvGCSweepDone: 298 if a.px.evSweep == nil { 299 // no Start to link to: choice is lying about 300 // duration or existence. Do the latter. 301 a.delete(i, ev) 302 continue 303 } 304 a.px.evSweep = nil 305 case EvGoWaiting: 306 if a.g.state != gRunnable { 307 a.makerunnable(i, ev) 308 } 309 a.g.state = gWaiting 310 a.g.ev = ev 311 case EvGoInSyscall: // PJW: same as GoWaiting 312 if a.g.state != gRunnable { 313 a.makerunnable(i, ev) 314 } 315 a.g.state = gWaiting 316 a.g.ev = ev 317 case EvGoCreate: 318 if _, ok := a.gs[ev.Args[0]]; ok { 319 // this g already exists; doesn't happen 320 a.delete(i, ev) 321 continue 322 } 323 ret := checkRunning(a.px, a.g, ev, true) 324 if ret&badRunning != 0 { 325 a.makerunning(i, ev) 326 a.g.state = gRunning 327 } 328 if ret&badP != 0 { 329 a.procstart(ev.P) 330 } 331 a.gs[ev.Args[0]] = gdesc{state: gRunnable, ev: ev, 332 evCreate: ev} 333 case EvGoStart, EvGoStartLabel: 334 if a.g.state != gRunnable { 335 a.makerunnable(i, ev) 336 } 337 if a.px.g != 0 { 338 //a.prevs(i) 339 a.err = fmt.Errorf("p already running %d, %d:%s", 340 a.px.g, i, ev) 341 } 342 a.g.state = gRunning 343 a.g.evStart = ev // PJW: do we need g.evStart? 344 a.px.g = ev.G 345 a.g.evCreate = nil // PJW: do we need g.evCreate? 346 case EvGoEnd, EvGoStop: 347 if !gok { 348 // never heard of it; act as if it never existed 349 a.delete(i, ev) 350 continue 351 } 352 ret := checkRunning(a.px, a.g, ev, false) 353 if ret&badRunning != 0 { 354 a.makerunning(i, ev) 355 a.g.state = gRunning 356 } 357 if ret&badP != 0 { 358 a.procstart(ev.P) 359 } 360 if ret&badG0 != 0 { 361 // gok should have been false 362 panic(fmt.Sprintf("badG0 %d:%s", i, ev)) 363 } 364 a.g.evStart = nil 365 a.g.state = gDead 366 a.px.g = 0 367 case EvGoSched, EvGoPreempt: 368 ret := checkRunning(a.px, a.g, ev, false) 369 if ret&badG0 != 0 { 370 // hopeless, we think. Don't know g 371 a.delete(i, ev) 372 } 373 if ret&badRunning != 0 { 374 a.makerunning(i, ev) 375 a.g.state = gRunning 376 } 377 if ret&badP != 0 { 378 a.procstart(ev.P) 379 } 380 a.g.state = gRunnable 381 a.g.evStart = nil 382 a.px.g = 0 383 a.g.ev = ev 384 case EvGoUnblock: 385 // g == 0 is ok here (PJW) and elsewhere? 386 if a.g.state != gRunning { 387 a.makerunning(i, ev) 388 a.g.state = gRunning 389 } 390 if ev.P != TimerP && a.px.g != ev.G { 391 //a.prevs(i) 392 a.err = fmt.Errorf("%v not running %d:%s", 393 a.px, i, ev) 394 continue 395 } 396 g1, _ := a.gs[ev.Args[0]] 397 if g1.state != gWaiting { 398 a.makewaiting(i, ev.Args[0], EvGoWaiting) 399 g1.state = gWaiting 400 } 401 g1.state = gRunnable 402 g1.ev = ev 403 a.gs[ev.Args[0]] = g1 404 // if p == TimerP, clean up from events.go:71 405 ev.Args[2] = 0 // no point in checking p 406 case EvGoSysCall: 407 if ev.G == 0 { 408 // hopeless; don't know how to repair 409 a.delete(i, ev) 410 continue 411 } 412 ret := checkRunning(a.px, a.g, ev, false) 413 if ret&badRunning != 0 { 414 a.makerunning(i, ev) 415 a.g.state = gRunning 416 } 417 if ret&badP != 0 { 418 a.procstart(ev.P) 419 } 420 a.g.ev = ev 421 case EvGoSysBlock: 422 if ev.G == 0 { 423 // hopeless to repair 424 a.delete(i, ev) 425 } 426 ret := checkRunning(a.px, a.g, ev, false) 427 if ret&badRunning != 0 { 428 a.makerunning(i, ev) 429 a.g.state = gRunning 430 } 431 if ret&badP != 0 { 432 a.procstart(ev.P) 433 } 434 a.g.state = gWaiting 435 a.g.evStart = nil 436 a.px.g = 0 437 case EvGoSysExit: 438 if ev.G == 0 { 439 // don't know how to repair 440 a.delete(i, ev) 441 continue 442 } 443 if a.g.state != gWaiting { 444 a.makewaiting(i, ev.G, EvGoInSyscall) 445 } 446 a.g.state = gRunnable 447 a.g.ev = ev 448 case EvGoSleep, EvGoBlock, EvGoBlockSend, EvGoBlockRecv, 449 EvGoBlockSelect, EvGoBlockSync, EvGoBlockCond, 450 EvGoBlockNet, EvGoBlockGC: 451 if ev.G == 0 { // don't know how to repair 452 a.delete(i, ev) 453 continue 454 } 455 ret := checkRunning(a.px, a.g, ev, false) 456 if ret&badRunning != 0 { 457 a.makerunning(i, ev) 458 a.g.state = gRunning 459 } 460 if ret&badP != 0 { 461 a.procstart(ev.P) 462 } 463 a.g.state = gWaiting 464 a.g.ev = ev 465 a.g.evStart = nil 466 a.px.g = 0 467 case EvHeapAlloc, EvGomaxprocs, EvNextGC, EvUserLog: 468 a.makerunning(i, ev) 469 a.g.state = gRunning 470 a.px.g = ev.G 471 default: 472 return nil, nil, fmt.Errorf("robust: unexpected %d:%s", i, ev) 473 case EvUserTaskCreate: 474 taskid := ev.Args[0] 475 if _, ok := tasks[taskid]; ok { 476 // task id conflict, kill this one, believe the earlier one 477 a.delete(i, ev) 478 continue 479 } 480 tasks[ev.Args[0]] = ev 481 case EvUserTaskEnd: // nothing to do 482 case EvUserRegion: 483 mode := ev.Args[1] 484 spans := activeSpans[ev.G] 485 if mode == 0 { 486 activeSpans[ev.G] = append(spans, ev) 487 } else if mode == 1 { // span end 488 n := len(spans) 489 if n > 0 { 490 // check that spans match up; clean up if not 491 s := spans[n-1] 492 if s.Args[0] != ev.Args[0] || 493 s.SArgs[0] != ev.SArgs[0] { 494 // try to fix it 495 var ok bool 496 spans, ok = fixSpan(spans, ev) 497 if !ok { 498 // unfixed, toss this event 499 a.delete(i, ev) 500 continue 501 } 502 } 503 n = len(spans) 504 if n > 1 { 505 activeSpans[ev.G] = spans[:n-1] 506 } else { 507 delete(activeSpans, ev.G) 508 } 509 } 510 } else { 511 // invalid mode, toss it 512 a.delete(i, ev) 513 continue 514 } 515 } 516 a.gs[ev.G] = a.g 517 a.ps[ev.P] = a.px 518 a.evs = append(a.evs, ev) 519 } 520 ans := a.pref 521 ans = append(ans, a.evs...) 522 p.Preflen = len(a.pref) 523 p.Added = len(a.inserted) 524 p.Ignored = len(a.deleted) 525 return ans, a, a.err 526 } 527 528 func fixSpan(spans []*Event, ev *Event) ([]*Event, bool) { 529 // probably indicates a corrupt trace file 530 panic("implement") 531 } 532 533 type same struct { 534 ev *Event 535 g gdesc 536 p pdesc 537 } 538 539 // This is a placeholder, to organize intervals with equal time stamps 540 func (a *aux) reorder(n int, events []*Event) { 541 // bunch of Events with equal time stamps 542 // We care about GoCreate, GoWaiting, GoInSyscall, 543 // GoStart (StartLocal, StartLabel), GoBlock*, 544 // GosSched, GoPreempt, GoUnblock, GoSysExit, 545 // (UnblockLocal, SysExitLocal), GCStart. 546 // maybe ProcStart and ProcStop? 547 repair := []same{} 548 i := n 549 for ; i < len(events) && events[i].Ts == events[n].Ts; i++ { 550 ev := events[i] 551 repair = append(repair, same{ev, a.gs[ev.G], 552 a.ps[ev.P]}) 553 } 554 a.last = i - 1 555 log.Println("BEFORE:") 556 for i, r := range repair { 557 log.Printf("x%d:%s %v %v", i+n, r.ev, r.g, r.p) 558 } 559 if true { // PJW 560 return // we're not doing anything yet 561 } 562 // sorting is not going to be enough. 563 log.Println("DID NOTHING!") 564 log.Println("after") 565 for i, r := range repair { 566 log.Printf("y%d:%s %v %v", i+n, r.ev, r.g, r.p) 567 } 568 for i, r := range repair { 569 events[n+i] = r.ev 570 } 571 } 572 573 // printing for debugging 574 func (a *aux) prevs(n int) { 575 for i := 0; i < len(a.pref); i++ { 576 log.Printf("p%3d %s", i, a.pref[i]) 577 } 578 start := 0 579 if n > 50 { 580 start = n - 50 581 } 582 for i := start; i <= n+1 && i < len(a.input); i++ { 583 log.Printf("%4d %s", i, a.input[i]) 584 } 585 }