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  }