mirror of git://gcc.gnu.org/git/gcc.git
				
				
				
			
		
			
				
	
	
		
			181 lines
		
	
	
		
			4.2 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			181 lines
		
	
	
		
			4.2 KiB
		
	
	
	
		
			Go
		
	
	
	
// Copyright 2014 The Go Authors. All rights reserved.
 | 
						|
// Use of this source code is governed by a BSD-style
 | 
						|
// license that can be found in the LICENSE file.
 | 
						|
 | 
						|
package trace
 | 
						|
 | 
						|
// GDesc contains statistics about execution of a single goroutine.
 | 
						|
type GDesc struct {
 | 
						|
	ID           uint64
 | 
						|
	Name         string
 | 
						|
	PC           uint64
 | 
						|
	CreationTime int64
 | 
						|
	StartTime    int64
 | 
						|
	EndTime      int64
 | 
						|
 | 
						|
	ExecTime      int64
 | 
						|
	SchedWaitTime int64
 | 
						|
	IOTime        int64
 | 
						|
	BlockTime     int64
 | 
						|
	SyscallTime   int64
 | 
						|
	GCTime        int64
 | 
						|
	SweepTime     int64
 | 
						|
	TotalTime     int64
 | 
						|
 | 
						|
	*gdesc // private part
 | 
						|
}
 | 
						|
 | 
						|
// gdesc is a private part of GDesc that is required only during analysis.
 | 
						|
type gdesc struct {
 | 
						|
	lastStartTime    int64
 | 
						|
	blockNetTime     int64
 | 
						|
	blockSyncTime    int64
 | 
						|
	blockSyscallTime int64
 | 
						|
	blockSweepTime   int64
 | 
						|
	blockGCTime      int64
 | 
						|
	blockSchedTime   int64
 | 
						|
}
 | 
						|
 | 
						|
// GoroutineStats generates statistics for all goroutines in the trace.
 | 
						|
func GoroutineStats(events []*Event) map[uint64]*GDesc {
 | 
						|
	gs := make(map[uint64]*GDesc)
 | 
						|
	var lastTs int64
 | 
						|
	var gcStartTime int64
 | 
						|
	for _, ev := range events {
 | 
						|
		lastTs = ev.Ts
 | 
						|
		switch ev.Type {
 | 
						|
		case EvGoCreate:
 | 
						|
			g := &GDesc{ID: ev.Args[0], CreationTime: ev.Ts, gdesc: new(gdesc)}
 | 
						|
			g.blockSchedTime = ev.Ts
 | 
						|
			gs[g.ID] = g
 | 
						|
		case EvGoStart:
 | 
						|
			g := gs[ev.G]
 | 
						|
			if g.PC == 0 {
 | 
						|
				g.PC = ev.Stk[0].PC
 | 
						|
				g.Name = ev.Stk[0].Fn
 | 
						|
			}
 | 
						|
			g.lastStartTime = ev.Ts
 | 
						|
			if g.StartTime == 0 {
 | 
						|
				g.StartTime = ev.Ts
 | 
						|
			}
 | 
						|
			if g.blockSchedTime != 0 {
 | 
						|
				g.SchedWaitTime += ev.Ts - g.blockSchedTime
 | 
						|
				g.blockSchedTime = 0
 | 
						|
			}
 | 
						|
		case EvGoEnd, EvGoStop:
 | 
						|
			g := gs[ev.G]
 | 
						|
			g.ExecTime += ev.Ts - g.lastStartTime
 | 
						|
			g.TotalTime = ev.Ts - g.CreationTime
 | 
						|
			g.EndTime = ev.Ts
 | 
						|
		case EvGoBlockSend, EvGoBlockRecv, EvGoBlockSelect,
 | 
						|
			EvGoBlockSync, EvGoBlockCond:
 | 
						|
			g := gs[ev.G]
 | 
						|
			g.ExecTime += ev.Ts - g.lastStartTime
 | 
						|
			g.blockSyncTime = ev.Ts
 | 
						|
		case EvGoSched, EvGoPreempt:
 | 
						|
			g := gs[ev.G]
 | 
						|
			g.ExecTime += ev.Ts - g.lastStartTime
 | 
						|
			g.blockSchedTime = ev.Ts
 | 
						|
		case EvGoSleep, EvGoBlock:
 | 
						|
			g := gs[ev.G]
 | 
						|
			g.ExecTime += ev.Ts - g.lastStartTime
 | 
						|
		case EvGoBlockNet:
 | 
						|
			g := gs[ev.G]
 | 
						|
			g.ExecTime += ev.Ts - g.lastStartTime
 | 
						|
			g.blockNetTime = ev.Ts
 | 
						|
		case EvGoUnblock:
 | 
						|
			g := gs[ev.Args[0]]
 | 
						|
			if g.blockNetTime != 0 {
 | 
						|
				g.IOTime += ev.Ts - g.blockNetTime
 | 
						|
				g.blockNetTime = 0
 | 
						|
			}
 | 
						|
			if g.blockSyncTime != 0 {
 | 
						|
				g.BlockTime += ev.Ts - g.blockSyncTime
 | 
						|
				g.blockSyncTime = 0
 | 
						|
			}
 | 
						|
			g.blockSchedTime = ev.Ts
 | 
						|
		case EvGoSysBlock:
 | 
						|
			g := gs[ev.G]
 | 
						|
			g.ExecTime += ev.Ts - g.lastStartTime
 | 
						|
			g.blockSyscallTime = ev.Ts
 | 
						|
		case EvGoSysExit:
 | 
						|
			g := gs[ev.G]
 | 
						|
			if g.blockSyscallTime != 0 {
 | 
						|
				g.SyscallTime += ev.Ts - g.blockSyscallTime
 | 
						|
				g.blockSyscallTime = 0
 | 
						|
			}
 | 
						|
			g.blockSchedTime = ev.Ts
 | 
						|
		case EvGCSweepStart:
 | 
						|
			g := gs[ev.G]
 | 
						|
			if g != nil {
 | 
						|
				// Sweep can happen during GC on system goroutine.
 | 
						|
				g.blockSweepTime = ev.Ts
 | 
						|
			}
 | 
						|
		case EvGCSweepDone:
 | 
						|
			g := gs[ev.G]
 | 
						|
			if g != nil && g.blockSweepTime != 0 {
 | 
						|
				g.SweepTime += ev.Ts - g.blockSweepTime
 | 
						|
				g.blockSweepTime = 0
 | 
						|
			}
 | 
						|
		case EvGCStart:
 | 
						|
			gcStartTime = ev.Ts
 | 
						|
		case EvGCDone:
 | 
						|
			for _, g := range gs {
 | 
						|
				if g.EndTime == 0 {
 | 
						|
					g.GCTime += ev.Ts - gcStartTime
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	for _, g := range gs {
 | 
						|
		if g.TotalTime == 0 {
 | 
						|
			g.TotalTime = lastTs - g.CreationTime
 | 
						|
		}
 | 
						|
		if g.EndTime == 0 {
 | 
						|
			g.EndTime = lastTs
 | 
						|
		}
 | 
						|
		if g.blockNetTime != 0 {
 | 
						|
			g.IOTime += lastTs - g.blockNetTime
 | 
						|
			g.blockNetTime = 0
 | 
						|
		}
 | 
						|
		if g.blockSyncTime != 0 {
 | 
						|
			g.BlockTime += lastTs - g.blockSyncTime
 | 
						|
			g.blockSyncTime = 0
 | 
						|
		}
 | 
						|
		if g.blockSyscallTime != 0 {
 | 
						|
			g.SyscallTime += lastTs - g.blockSyscallTime
 | 
						|
			g.blockSyscallTime = 0
 | 
						|
		}
 | 
						|
		if g.blockSchedTime != 0 {
 | 
						|
			g.SchedWaitTime += lastTs - g.blockSchedTime
 | 
						|
			g.blockSchedTime = 0
 | 
						|
		}
 | 
						|
		g.gdesc = nil
 | 
						|
	}
 | 
						|
 | 
						|
	return gs
 | 
						|
}
 | 
						|
 | 
						|
// RelatedGoroutines finds a set of goroutines related to goroutine goid.
 | 
						|
func RelatedGoroutines(events []*Event, goid uint64) map[uint64]bool {
 | 
						|
	// BFS of depth 2 over "unblock" edges
 | 
						|
	// (what goroutines unblock goroutine goid?).
 | 
						|
	gmap := make(map[uint64]bool)
 | 
						|
	gmap[goid] = true
 | 
						|
	for i := 0; i < 2; i++ {
 | 
						|
		gmap1 := make(map[uint64]bool)
 | 
						|
		for g := range gmap {
 | 
						|
			gmap1[g] = true
 | 
						|
		}
 | 
						|
		for _, ev := range events {
 | 
						|
			if ev.Type == EvGoUnblock && gmap[ev.Args[0]] {
 | 
						|
				gmap1[ev.G] = true
 | 
						|
			}
 | 
						|
		}
 | 
						|
		gmap = gmap1
 | 
						|
	}
 | 
						|
	gmap[0] = true // for GC events
 | 
						|
	return gmap
 | 
						|
}
 |