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  }