mirror of
https://github.com/autc04/Retro68.git
synced 2024-11-28 05:51:04 +00:00
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
|
|
}
|