aboutsummaryrefslogtreecommitdiff
path: root/libgo/go/internal/trace/parser.go
diff options
context:
space:
mode:
Diffstat (limited to 'libgo/go/internal/trace/parser.go')
-rw-r--r--libgo/go/internal/trace/parser.go510
1 files changed, 331 insertions, 179 deletions
diff --git a/libgo/go/internal/trace/parser.go b/libgo/go/internal/trace/parser.go
index 11f9aba..c31517f 100644
--- a/libgo/go/internal/trace/parser.go
+++ b/libgo/go/internal/trace/parser.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors. All rights reserved.
+// 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.
@@ -9,18 +9,19 @@ import (
"bytes"
"fmt"
"io"
+ "math/rand"
"os"
"os/exec"
- "sort"
"strconv"
"strings"
+ _ "unsafe"
)
// Event describes one event in the trace.
type Event struct {
Off int // offset in input file (for debugging and error reporting)
Type byte // one of Ev*
- Seq int64 // sequence number
+ seq int64 // sequence number
Ts int64 // timestamp in nanoseconds
P int // P on which the event happened (can be one of TimerP, NetpollP, SyscallP)
G uint64 // G on which the event happened
@@ -58,24 +59,48 @@ const (
)
// Parse parses, post-processes and verifies the trace.
-func Parse(r io.Reader) ([]*Event, error) {
- rawEvents, err := readTrace(r)
+func Parse(r io.Reader, bin string) ([]*Event, error) {
+ ver, events, err := parse(r, bin)
if err != nil {
return nil, err
}
- events, err := parseEvents(rawEvents)
+ if ver < 1007 && bin == "" {
+ return nil, fmt.Errorf("for traces produced by go 1.6 or below, the binary argument must be provided")
+ }
+ return events, nil
+}
+
+// parse parses, post-processes and verifies the trace. It returns the
+// trace version and the list of events.
+func parse(r io.Reader, bin string) (int, []*Event, error) {
+ ver, rawEvents, strings, err := readTrace(r)
if err != nil {
- return nil, err
+ return 0, nil, err
+ }
+ events, stacks, err := parseEvents(ver, rawEvents, strings)
+ if err != nil {
+ return 0, nil, err
}
events, err = removeFutile(events)
if err != nil {
- return nil, err
+ return 0, nil, err
}
- err = postProcessTrace(events)
+ err = postProcessTrace(ver, events)
if err != nil {
- return nil, err
+ return 0, nil, err
}
- return events, nil
+ // Attach stack traces.
+ for _, ev := range events {
+ if ev.StkID != 0 {
+ ev.Stk = stacks[ev.StkID]
+ }
+ }
+ if ver < 1007 && bin != "" {
+ if err := symbolize(events, bin); err != nil {
+ return 0, nil, err
+ }
+ }
+ return ver, events, nil
}
// rawEvent is a helper type used during parsing.
@@ -87,107 +112,187 @@ type rawEvent struct {
// readTrace does wire-format parsing and verification.
// It does not care about specific event types and argument meaning.
-func readTrace(r io.Reader) ([]rawEvent, error) {
+func readTrace(r io.Reader) (ver int, events []rawEvent, strings map[uint64]string, err error) {
// Read and validate trace header.
var buf [16]byte
- off, err := r.Read(buf[:])
- if off != 16 || err != nil {
- return nil, fmt.Errorf("failed to read header: read %v, err %v", off, err)
+ off, err := io.ReadFull(r, buf[:])
+ if err != nil {
+ err = fmt.Errorf("failed to read header: read %v, err %v", off, err)
+ return
+ }
+ ver, err = parseHeader(buf[:])
+ if err != nil {
+ return
}
- if bytes.Compare(buf[:], []byte("go 1.5 trace\x00\x00\x00\x00")) != 0 {
- return nil, fmt.Errorf("not a trace file")
+ switch ver {
+ case 1005, 1007:
+ break
+ default:
+ err = fmt.Errorf("unsupported trace file version %v.%v (update Go toolchain) %v", ver/1000, ver%1000, ver)
+ return
}
// Read events.
- var events []rawEvent
+ strings = make(map[uint64]string)
for {
// Read event type and number of arguments (1 byte).
off0 := off
- n, err := r.Read(buf[:1])
+ var n int
+ n, err = r.Read(buf[:1])
if err == io.EOF {
+ err = nil
break
}
if err != nil || n != 1 {
- return nil, fmt.Errorf("failed to read trace at offset 0x%x: n=%v err=%v", off0, n, err)
+ err = fmt.Errorf("failed to read trace at offset 0x%x: n=%v err=%v", off0, n, err)
+ return
}
off += n
typ := buf[0] << 2 >> 2
- narg := buf[0] >> 6
+ narg := buf[0]>>6 + 1
+ inlineArgs := byte(4)
+ if ver < 1007 {
+ narg++
+ inlineArgs++
+ }
+ if typ == EvNone || typ >= EvCount || EventDescriptions[typ].minVersion > ver {
+ err = fmt.Errorf("unknown event type %v at offset 0x%x", typ, off0)
+ return
+ }
+ if typ == EvString {
+ // String dictionary entry [ID, length, string].
+ var id uint64
+ id, off, err = readVal(r, off)
+ if err != nil {
+ return
+ }
+ if id == 0 {
+ err = fmt.Errorf("string at offset %d has invalid id 0", off)
+ return
+ }
+ if strings[id] != "" {
+ err = fmt.Errorf("string at offset %d has duplicate id %v", off, id)
+ return
+ }
+ var ln uint64
+ ln, off, err = readVal(r, off)
+ if err != nil {
+ return
+ }
+ if ln == 0 {
+ err = fmt.Errorf("string at offset %d has invalid length 0", off)
+ return
+ }
+ if ln > 1e6 {
+ err = fmt.Errorf("string at offset %d has too large length %v", off, ln)
+ return
+ }
+ buf := make([]byte, ln)
+ var n int
+ n, err = io.ReadFull(r, buf)
+ if err != nil {
+ err = fmt.Errorf("failed to read trace at offset %d: read %v, want %v, error %v", off, n, ln, err)
+ return
+ }
+ off += n
+ strings[id] = string(buf)
+ continue
+ }
ev := rawEvent{typ: typ, off: off0}
- if narg < 3 {
- for i := 0; i < int(narg)+2; i++ { // sequence number and time stamp are present but not counted in narg
+ if narg < inlineArgs {
+ for i := 0; i < int(narg); i++ {
var v uint64
v, off, err = readVal(r, off)
if err != nil {
- return nil, err
+ err = fmt.Errorf("failed to read event %v argument at offset %v (%v)", typ, off, err)
+ return
}
ev.args = append(ev.args, v)
}
} else {
- // If narg == 3, the first value is length of the event in bytes.
+ // More than inlineArgs args, the first value is length of the event in bytes.
var v uint64
v, off, err = readVal(r, off)
if err != nil {
- return nil, err
+ err = fmt.Errorf("failed to read event %v argument at offset %v (%v)", typ, off, err)
+ return
}
evLen := v
off1 := off
for evLen > uint64(off-off1) {
v, off, err = readVal(r, off)
if err != nil {
- return nil, err
+ err = fmt.Errorf("failed to read event %v argument at offset %v (%v)", typ, off, err)
+ return
}
ev.args = append(ev.args, v)
}
if evLen != uint64(off-off1) {
- return nil, fmt.Errorf("event has wrong length at offset 0x%x: want %v, got %v", off0, evLen, off-off1)
+ err = fmt.Errorf("event has wrong length at offset 0x%x: want %v, got %v", off0, evLen, off-off1)
+ return
}
}
events = append(events, ev)
}
- return events, nil
+ return
+}
+
+// parseHeader parses trace header of the form "go 1.7 trace\x00\x00\x00\x00"
+// and returns parsed version as 1007.
+func parseHeader(buf []byte) (int, error) {
+ if len(buf) != 16 {
+ return 0, fmt.Errorf("bad header length")
+ }
+ if buf[0] != 'g' || buf[1] != 'o' || buf[2] != ' ' ||
+ buf[3] < '1' || buf[3] > '9' ||
+ buf[4] != '.' ||
+ buf[5] < '1' || buf[5] > '9' {
+ return 0, fmt.Errorf("not a trace file")
+ }
+ ver := int(buf[5] - '0')
+ i := 0
+ for ; buf[6+i] >= '0' && buf[6+i] <= '9' && i < 2; i++ {
+ ver = ver*10 + int(buf[6+i]-'0')
+ }
+ ver += int(buf[3]-'0') * 1000
+ if !bytes.Equal(buf[6+i:], []byte(" trace\x00\x00\x00\x00")[:10-i]) {
+ return 0, fmt.Errorf("not a trace file")
+ }
+ return ver, nil
}
// Parse events transforms raw events into events.
// It does analyze and verify per-event-type arguments.
-func parseEvents(rawEvents []rawEvent) (events []*Event, err error) {
+func parseEvents(ver int, rawEvents []rawEvent, strings map[uint64]string) (events []*Event, stacks map[uint64][]*Frame, err error) {
var ticksPerSec, lastSeq, lastTs int64
var lastG, timerGoid uint64
var lastP int
lastGs := make(map[int]uint64) // last goroutine running on P
- stacks := make(map[uint64][]*Frame)
+ stacks = make(map[uint64][]*Frame)
+ batches := make(map[int][]*Event) // events by P
for _, raw := range rawEvents {
- if raw.typ == EvNone || raw.typ >= EvCount {
- err = fmt.Errorf("unknown event type %v at offset 0x%x", raw.typ, raw.off)
- return
- }
desc := EventDescriptions[raw.typ]
if desc.Name == "" {
err = fmt.Errorf("missing description for event type %v", raw.typ)
return
}
- if raw.typ != EvStack {
- narg := len(desc.Args)
- if desc.Stack {
- narg++
- }
- if raw.typ != EvBatch && raw.typ != EvFrequency && raw.typ != EvTimerGoroutine {
- narg++ // sequence number
- narg++ // timestamp
- }
- if len(raw.args) != narg {
- err = fmt.Errorf("%v has wrong number of arguments at offset 0x%x: want %v, got %v",
- desc.Name, raw.off, narg, len(raw.args))
- return
- }
+ narg := argNum(raw, ver)
+ if len(raw.args) != narg {
+ err = fmt.Errorf("%v has wrong number of arguments at offset 0x%x: want %v, got %v",
+ desc.Name, raw.off, narg, len(raw.args))
+ return
}
switch raw.typ {
case EvBatch:
lastGs[lastP] = lastG
lastP = int(raw.args[0])
lastG = lastGs[lastP]
- lastSeq = int64(raw.args[1])
- lastTs = int64(raw.args[2])
+ if ver < 1007 {
+ lastSeq = int64(raw.args[1])
+ lastTs = int64(raw.args[2])
+ } else {
+ lastTs = int64(raw.args[1])
+ }
case EvFrequency:
ticksPerSec = int64(raw.args[0])
if ticksPerSec <= 0 {
@@ -211,33 +316,53 @@ func parseEvents(rawEvents []rawEvent) (events []*Event, err error) {
raw.off, size)
return
}
- if uint64(len(raw.args)) != size+2 {
+ want := 2 + 4*size
+ if ver < 1007 {
+ want = 2 + size
+ }
+ if uint64(len(raw.args)) != want {
err = fmt.Errorf("EvStack has wrong number of arguments at offset 0x%x: want %v, got %v",
- raw.off, size+2, len(raw.args))
+ raw.off, want, len(raw.args))
return
}
id := raw.args[0]
if id != 0 && size > 0 {
stk := make([]*Frame, size)
for i := 0; i < int(size); i++ {
- stk[i] = &Frame{PC: raw.args[i+2]}
+ if ver < 1007 {
+ stk[i] = &Frame{PC: raw.args[2+i]}
+ } else {
+ pc := raw.args[2+i*4+0]
+ fn := raw.args[2+i*4+1]
+ file := raw.args[2+i*4+2]
+ line := raw.args[2+i*4+3]
+ stk[i] = &Frame{PC: pc, Fn: strings[fn], File: strings[file], Line: int(line)}
+ }
}
stacks[id] = stk
}
default:
e := &Event{Off: raw.off, Type: raw.typ, P: lastP, G: lastG}
- e.Seq = lastSeq + int64(raw.args[0])
- e.Ts = lastTs + int64(raw.args[1])
- lastSeq = e.Seq
- lastTs = e.Ts
- for i := range desc.Args {
- e.Args[i] = raw.args[i+2]
+ var argOffset int
+ if ver < 1007 {
+ e.seq = lastSeq + int64(raw.args[0])
+ e.Ts = lastTs + int64(raw.args[1])
+ lastSeq = e.seq
+ argOffset = 2
+ } else {
+ e.Ts = lastTs + int64(raw.args[0])
+ argOffset = 1
}
- if desc.Stack {
- e.StkID = raw.args[len(desc.Args)+2]
+ lastTs = e.Ts
+ for i := argOffset; i < narg; i++ {
+ if i == narg-1 && desc.Stack {
+ e.StkID = raw.args[i]
+ } else {
+ e.Args[i-argOffset] = raw.args[i]
+ }
}
switch raw.typ {
- case EvGoStart:
+ case EvGoStart, EvGoStartLocal:
lastG = e.Args[0]
e.G = lastG
case EvGCStart, EvGCDone, EvGCScanStart, EvGCScanDone:
@@ -247,45 +372,51 @@ func parseEvents(rawEvents []rawEvent) (events []*Event, err error) {
EvGoBlockSelect, EvGoBlockSync, EvGoBlockCond, EvGoBlockNet,
EvGoSysBlock:
lastG = 0
- case EvGoSysExit:
- // EvGoSysExit emission is delayed until the thread has a P.
- // Give it the real sequence number and time stamp.
- e.Seq = int64(e.Args[1])
- if e.Args[2] != 0 {
- e.Ts = int64(e.Args[2])
- }
+ case EvGoSysExit, EvGoWaiting, EvGoInSyscall:
+ e.G = e.Args[0]
}
- events = append(events, e)
+ batches[lastP] = append(batches[lastP], e)
}
}
- if len(events) == 0 {
+ if len(batches) == 0 {
err = fmt.Errorf("trace is empty")
return
}
-
- // Attach stack traces.
- for _, ev := range events {
- if ev.StkID != 0 {
- ev.Stk = stacks[ev.StkID]
- }
- }
-
- // Sort by sequence number and translate cpu ticks to real time.
- sort.Sort(eventList(events))
if ticksPerSec == 0 {
err = fmt.Errorf("no EvFrequency event")
return
}
+ if BreakTimestampsForTesting {
+ var batchArr [][]*Event
+ for _, batch := range batches {
+ batchArr = append(batchArr, batch)
+ }
+ for i := 0; i < 5; i++ {
+ batch := batchArr[rand.Intn(len(batchArr))]
+ batch[rand.Intn(len(batch))].Ts += int64(rand.Intn(2000) - 1000)
+ }
+ }
+ if ver < 1007 {
+ events, err = order1005(batches)
+ } else {
+ events, err = order1007(batches)
+ }
+ if err != nil {
+ return
+ }
+
+ // Translate cpu ticks to real time.
minTs := events[0].Ts
+ // Use floating point to avoid integer overflows.
+ freq := 1e9 / float64(ticksPerSec)
for _, ev := range events {
- ev.Ts = (ev.Ts - minTs) * 1e9 / ticksPerSec
+ ev.Ts = int64(float64(ev.Ts-minTs) * freq)
// Move timers and syscalls to separate fake Ps.
if timerGoid != 0 && ev.G == timerGoid && ev.Type == EvGoUnblock {
ev.P = TimerP
}
if ev.Type == EvGoSysExit {
ev.P = SyscallP
- ev.G = ev.Args[0]
}
}
@@ -355,7 +486,7 @@ var ErrTimeOrder = fmt.Errorf("time stamps out of order")
// The resulting trace is guaranteed to be consistent
// (for example, a P does not run two Gs at the same time, or a G is indeed
// blocked before an unblock event).
-func postProcessTrace(events []*Event) error {
+func postProcessTrace(ver int, events []*Event) error {
const (
gDead = iota
gRunnable
@@ -446,19 +577,15 @@ func postProcessTrace(events []*Event) error {
p.evSweep.Link = ev
p.evSweep = nil
case EvGoWaiting:
- g1 := gs[ev.Args[0]]
- if g1.state != gRunnable {
- return fmt.Errorf("g %v is not runnable before EvGoWaiting (offset %v, time %v)", ev.Args[0], ev.Off, ev.Ts)
+ if g.state != gRunnable {
+ return fmt.Errorf("g %v is not runnable before EvGoWaiting (offset %v, time %v)", ev.G, ev.Off, ev.Ts)
}
- g1.state = gWaiting
- gs[ev.Args[0]] = g1
+ g.state = gWaiting
case EvGoInSyscall:
- g1 := gs[ev.Args[0]]
- if g1.state != gRunnable {
- return fmt.Errorf("g %v is not runnable before EvGoInSyscall (offset %v, time %v)", ev.Args[0], ev.Off, ev.Ts)
+ if g.state != gRunnable {
+ return fmt.Errorf("g %v is not runnable before EvGoInSyscall (offset %v, time %v)", ev.G, ev.Off, ev.Ts)
}
- g1.state = gWaiting
- gs[ev.Args[0]] = g1
+ g.state = gWaiting
case EvGoCreate:
if err := checkRunning(p, g, ev, true); err != nil {
return err
@@ -478,8 +605,12 @@ func postProcessTrace(events []*Event) error {
g.evStart = ev
p.g = ev.G
if g.evCreate != nil {
- // +1 because symbolizer expects return pc.
- ev.Stk = []*Frame{{PC: g.evCreate.Args[1] + 1}}
+ if ver < 1007 {
+ // +1 because symbolizer expects return pc.
+ ev.Stk = []*Frame{{PC: g.evCreate.Args[1] + 1}}
+ } else {
+ ev.StkID = g.evCreate.Args[1]
+ }
g.evCreate = nil
}
@@ -565,23 +696,11 @@ func postProcessTrace(events []*Event) error {
// TODO(dvyukov): restore stacks for EvGoStart events.
// TODO(dvyukov): test that all EvGoStart events has non-nil Link.
- // Last, after all the other consistency checks,
- // make sure time stamps respect sequence numbers.
- // The tests will skip (not fail) the test case if they see this error,
- // so check everything else that could possibly be wrong first.
- lastTs := int64(0)
- for _, ev := range events {
- if ev.Ts < lastTs {
- return ErrTimeOrder
- }
- lastTs = ev.Ts
- }
-
return nil
}
-// symbolizeTrace attaches func/file/line info to stack traces.
-func Symbolize(events []*Event, bin string) error {
+// symbolize attaches func/file/line info to stack traces.
+func symbolize(events []*Event, bin string) error {
// First, collect and dedup all pcs.
pcs := make(map[uint64]*Frame)
for _, ev := range events {
@@ -672,57 +791,81 @@ func readVal(r io.Reader, off0 int) (v uint64, off int, err error) {
return 0, 0, fmt.Errorf("bad value at offset 0x%x", off0)
}
-type eventList []*Event
-
-func (l eventList) Len() int {
- return len(l)
-}
-
-func (l eventList) Less(i, j int) bool {
- return l[i].Seq < l[j].Seq
+// Print dumps events to stdout. For debugging.
+func Print(events []*Event) {
+ for _, ev := range events {
+ PrintEvent(ev)
+ }
}
-func (l eventList) Swap(i, j int) {
- l[i], l[j] = l[j], l[i]
+// PrintEvent dumps the event to stdout. For debugging.
+func PrintEvent(ev *Event) {
+ desc := EventDescriptions[ev.Type]
+ fmt.Printf("%v %v p=%v g=%v off=%v", ev.Ts, desc.Name, ev.P, ev.G, ev.Off)
+ for i, a := range desc.Args {
+ fmt.Printf(" %v=%v", a, ev.Args[i])
+ }
+ fmt.Printf("\n")
}
-// Print dumps events to stdout. For debugging.
-func Print(events []*Event) {
- for _, ev := range events {
- desc := EventDescriptions[ev.Type]
- fmt.Printf("%v %v p=%v g=%v off=%v", ev.Ts, desc.Name, ev.P, ev.G, ev.Off)
- for i, a := range desc.Args {
- fmt.Printf(" %v=%v", a, ev.Args[i])
+// argNum returns total number of args for the event accounting for timestamps,
+// sequence numbers and differences between trace format versions.
+func argNum(raw rawEvent, ver int) int {
+ desc := EventDescriptions[raw.typ]
+ if raw.typ == EvStack {
+ return len(raw.args)
+ }
+ narg := len(desc.Args)
+ if desc.Stack {
+ narg++
+ }
+ switch raw.typ {
+ case EvBatch, EvFrequency, EvTimerGoroutine:
+ if ver < 1007 {
+ narg++ // there was an unused arg before 1.7
+ }
+ case EvGCStart, EvGoStart, EvGoUnblock:
+ if ver < 1007 {
+ narg-- // 1.7 added an additional seq arg
+ }
+ fallthrough
+ default:
+ narg++ // timestamp
+ if ver < 1007 {
+ narg++ // sequence
}
- fmt.Printf("\n")
}
+ return narg
}
+// BreakTimestampsForTesting causes the parser to randomly alter timestamps (for testing of broken cputicks).
+var BreakTimestampsForTesting bool
+
// Event types in the trace.
// Verbatim copy from src/runtime/trace.go.
const (
EvNone = 0 // unused
EvBatch = 1 // start of per-P batch of events [pid, timestamp]
EvFrequency = 2 // contains tracer timer frequency [frequency (ticks per second)]
- EvStack = 3 // stack [stack id, number of PCs, array of PCs]
+ EvStack = 3 // stack [stack id, number of PCs, array of {PC, func string ID, file string ID, line}]
EvGomaxprocs = 4 // current value of GOMAXPROCS [timestamp, GOMAXPROCS, stack id]
EvProcStart = 5 // start of P [timestamp, thread id]
EvProcStop = 6 // stop of P [timestamp]
- EvGCStart = 7 // GC start [timestamp, stack id]
+ EvGCStart = 7 // GC start [timestamp, seq, stack id]
EvGCDone = 8 // GC done [timestamp]
EvGCScanStart = 9 // GC scan start [timestamp]
EvGCScanDone = 10 // GC scan done [timestamp]
EvGCSweepStart = 11 // GC sweep start [timestamp, stack id]
EvGCSweepDone = 12 // GC sweep done [timestamp]
- EvGoCreate = 13 // goroutine creation [timestamp, new goroutine id, start PC, stack id]
- EvGoStart = 14 // goroutine starts running [timestamp, goroutine id]
+ EvGoCreate = 13 // goroutine creation [timestamp, new goroutine id, new stack id, stack id]
+ EvGoStart = 14 // goroutine starts running [timestamp, goroutine id, seq]
EvGoEnd = 15 // goroutine ends [timestamp]
EvGoStop = 16 // goroutine stops (like in select{}) [timestamp, stack]
EvGoSched = 17 // goroutine calls Gosched [timestamp, stack]
EvGoPreempt = 18 // goroutine is preempted [timestamp, stack]
EvGoSleep = 19 // goroutine calls Sleep [timestamp, stack]
EvGoBlock = 20 // goroutine blocks [timestamp, stack]
- EvGoUnblock = 21 // goroutine is unblocked [timestamp, goroutine id, stack]
+ EvGoUnblock = 21 // goroutine is unblocked [timestamp, goroutine id, seq, stack]
EvGoBlockSend = 22 // goroutine blocks on chan send [timestamp, stack]
EvGoBlockRecv = 23 // goroutine blocks on chan recv [timestamp, stack]
EvGoBlockSelect = 24 // goroutine blocks on select [timestamp, stack]
@@ -730,57 +873,66 @@ const (
EvGoBlockCond = 26 // goroutine blocks on Cond [timestamp, stack]
EvGoBlockNet = 27 // goroutine blocks on network [timestamp, stack]
EvGoSysCall = 28 // syscall enter [timestamp, stack]
- EvGoSysExit = 29 // syscall exit [timestamp, goroutine id, real timestamp]
+ EvGoSysExit = 29 // syscall exit [timestamp, goroutine id, seq, real timestamp]
EvGoSysBlock = 30 // syscall blocks [timestamp]
- EvGoWaiting = 31 // denotes that goroutine is blocked when tracing starts [goroutine id]
- EvGoInSyscall = 32 // denotes that goroutine is in syscall when tracing starts [goroutine id]
- EvHeapAlloc = 33 // memstats.heap_alloc change [timestamp, heap_alloc]
+ EvGoWaiting = 31 // denotes that goroutine is blocked when tracing starts [timestamp, goroutine id]
+ EvGoInSyscall = 32 // denotes that goroutine is in syscall when tracing starts [timestamp, goroutine id]
+ EvHeapAlloc = 33 // memstats.heap_live change [timestamp, heap_alloc]
EvNextGC = 34 // memstats.next_gc change [timestamp, next_gc]
EvTimerGoroutine = 35 // denotes timer goroutine [timer goroutine id]
EvFutileWakeup = 36 // denotes that the previous wakeup of this goroutine was futile [timestamp]
- EvCount = 37
+ EvString = 37 // string dictionary entry [ID, length, string]
+ EvGoStartLocal = 38 // goroutine starts running on the same P as the last event [timestamp, goroutine id]
+ EvGoUnblockLocal = 39 // goroutine is unblocked on the same P as the last event [timestamp, goroutine id, stack]
+ EvGoSysExitLocal = 40 // syscall exit on the same P as the last event [timestamp, goroutine id, real timestamp]
+ EvCount = 41
)
var EventDescriptions = [EvCount]struct {
- Name string
- Stack bool
- Args []string
+ Name string
+ minVersion int
+ Stack bool
+ Args []string
}{
- EvNone: {"None", false, []string{}},
- EvBatch: {"Batch", false, []string{"p", "seq", "ticks"}},
- EvFrequency: {"Frequency", false, []string{"freq", "unused"}},
- EvStack: {"Stack", false, []string{"id", "siz"}},
- EvGomaxprocs: {"Gomaxprocs", true, []string{"procs"}},
- EvProcStart: {"ProcStart", false, []string{"thread"}},
- EvProcStop: {"ProcStop", false, []string{}},
- EvGCStart: {"GCStart", true, []string{}},
- EvGCDone: {"GCDone", false, []string{}},
- EvGCScanStart: {"GCScanStart", false, []string{}},
- EvGCScanDone: {"GCScanDone", false, []string{}},
- EvGCSweepStart: {"GCSweepStart", true, []string{}},
- EvGCSweepDone: {"GCSweepDone", false, []string{}},
- EvGoCreate: {"GoCreate", true, []string{"g", "pc"}},
- EvGoStart: {"GoStart", false, []string{"g"}},
- EvGoEnd: {"GoEnd", false, []string{}},
- EvGoStop: {"GoStop", true, []string{}},
- EvGoSched: {"GoSched", true, []string{}},
- EvGoPreempt: {"GoPreempt", true, []string{}},
- EvGoSleep: {"GoSleep", true, []string{}},
- EvGoBlock: {"GoBlock", true, []string{}},
- EvGoUnblock: {"GoUnblock", true, []string{"g"}},
- EvGoBlockSend: {"GoBlockSend", true, []string{}},
- EvGoBlockRecv: {"GoBlockRecv", true, []string{}},
- EvGoBlockSelect: {"GoBlockSelect", true, []string{}},
- EvGoBlockSync: {"GoBlockSync", true, []string{}},
- EvGoBlockCond: {"GoBlockCond", true, []string{}},
- EvGoBlockNet: {"GoBlockNet", true, []string{}},
- EvGoSysCall: {"GoSysCall", true, []string{}},
- EvGoSysExit: {"GoSysExit", false, []string{"g", "seq", "ts"}},
- EvGoSysBlock: {"GoSysBlock", false, []string{}},
- EvGoWaiting: {"GoWaiting", false, []string{"g"}},
- EvGoInSyscall: {"GoInSyscall", false, []string{"g"}},
- EvHeapAlloc: {"HeapAlloc", false, []string{"mem"}},
- EvNextGC: {"NextGC", false, []string{"mem"}},
- EvTimerGoroutine: {"TimerGoroutine", false, []string{"g", "unused"}},
- EvFutileWakeup: {"FutileWakeup", false, []string{}},
+ EvNone: {"None", 1005, false, []string{}},
+ EvBatch: {"Batch", 1005, false, []string{"p", "ticks"}}, // in 1.5 format it was {"p", "seq", "ticks"}
+ EvFrequency: {"Frequency", 1005, false, []string{"freq"}}, // in 1.5 format it was {"freq", "unused"}
+ EvStack: {"Stack", 1005, false, []string{"id", "siz"}},
+ EvGomaxprocs: {"Gomaxprocs", 1005, true, []string{"procs"}},
+ EvProcStart: {"ProcStart", 1005, false, []string{"thread"}},
+ EvProcStop: {"ProcStop", 1005, false, []string{}},
+ EvGCStart: {"GCStart", 1005, true, []string{"seq"}}, // in 1.5 format it was {}
+ EvGCDone: {"GCDone", 1005, false, []string{}},
+ EvGCScanStart: {"GCScanStart", 1005, false, []string{}},
+ EvGCScanDone: {"GCScanDone", 1005, false, []string{}},
+ EvGCSweepStart: {"GCSweepStart", 1005, true, []string{}},
+ EvGCSweepDone: {"GCSweepDone", 1005, false, []string{}},
+ EvGoCreate: {"GoCreate", 1005, true, []string{"g", "stack"}},
+ EvGoStart: {"GoStart", 1005, false, []string{"g", "seq"}}, // in 1.5 format it was {"g"}
+ EvGoEnd: {"GoEnd", 1005, false, []string{}},
+ EvGoStop: {"GoStop", 1005, true, []string{}},
+ EvGoSched: {"GoSched", 1005, true, []string{}},
+ EvGoPreempt: {"GoPreempt", 1005, true, []string{}},
+ EvGoSleep: {"GoSleep", 1005, true, []string{}},
+ EvGoBlock: {"GoBlock", 1005, true, []string{}},
+ EvGoUnblock: {"GoUnblock", 1005, true, []string{"g", "seq"}}, // in 1.5 format it was {"g"}
+ EvGoBlockSend: {"GoBlockSend", 1005, true, []string{}},
+ EvGoBlockRecv: {"GoBlockRecv", 1005, true, []string{}},
+ EvGoBlockSelect: {"GoBlockSelect", 1005, true, []string{}},
+ EvGoBlockSync: {"GoBlockSync", 1005, true, []string{}},
+ EvGoBlockCond: {"GoBlockCond", 1005, true, []string{}},
+ EvGoBlockNet: {"GoBlockNet", 1005, true, []string{}},
+ EvGoSysCall: {"GoSysCall", 1005, true, []string{}},
+ EvGoSysExit: {"GoSysExit", 1005, false, []string{"g", "seq", "ts"}},
+ EvGoSysBlock: {"GoSysBlock", 1005, false, []string{}},
+ EvGoWaiting: {"GoWaiting", 1005, false, []string{"g"}},
+ EvGoInSyscall: {"GoInSyscall", 1005, false, []string{"g"}},
+ EvHeapAlloc: {"HeapAlloc", 1005, false, []string{"mem"}},
+ EvNextGC: {"NextGC", 1005, false, []string{"mem"}},
+ EvTimerGoroutine: {"TimerGoroutine", 1005, false, []string{"g"}}, // in 1.5 format it was {"g", "unused"}
+ EvFutileWakeup: {"FutileWakeup", 1005, false, []string{}},
+ EvString: {"String", 1007, false, []string{}},
+ EvGoStartLocal: {"GoStartLocal", 1007, false, []string{"g"}},
+ EvGoUnblockLocal: {"GoUnblockLocal", 1007, true, []string{"g"}},
+ EvGoSysExitLocal: {"GoSysExitLocal", 1007, false, []string{"g", "ts"}},
}