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