trace: regenerate experimental API from go@6d7b3c8

For golang/go#62627.

[git-generate]
trace/gen.bash 6d7b3c8cd15794811949bb1ca12172eb35ace6ab

Change-Id: I27da6561b9433762cf724229c49d7654edcddbda
Reviewed-on: https://go-review.googlesource.com/c/exp/+/544655
Reviewed-by: Michael Pratt <mpratt@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
diff --git a/trace/base.go b/trace/base.go
new file mode 100644
index 0000000..2c4db2f
--- /dev/null
+++ b/trace/base.go
@@ -0,0 +1,260 @@
+// Copyright 2023 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.
+
+// Code generated by "gen.bash" from internal/trace/v2; DO NOT EDIT.
+
+//go:build go1.21
+
+// This file contains data types that all implementations of the trace format
+// parser need to provide to the rest of the package.
+
+package trace
+
+import (
+	"fmt"
+	"strings"
+
+	"golang.org/x/exp/trace/internal/event"
+	"golang.org/x/exp/trace/internal/event/go122"
+	"golang.org/x/exp/trace/internal/version"
+)
+
+// maxArgs is the maximum number of arguments for "plain" events,
+// i.e. anything that could reasonably be represented as a Base.
+const maxArgs = 5
+
+// baseEvent is the basic unprocessed event. This serves as a common
+// fundamental data structure across.
+type baseEvent struct {
+	typ  event.Type
+	time Time
+	args [maxArgs - 1]uint64
+}
+
+// extra returns a slice representing extra available space in args
+// that the parser can use to pass data up into Event.
+func (e *baseEvent) extra(v version.Version) []uint64 {
+	switch v {
+	case version.Go122:
+		return e.args[len(go122.Specs()[e.typ].Args)-1:]
+	}
+	panic(fmt.Sprintf("unsupported version: go 1.%d", v))
+}
+
+// evTable contains the per-generation data necessary to
+// interpret an individual event.
+type evTable struct {
+	freq    frequency
+	strings dataTable[stringID, string]
+	stacks  dataTable[stackID, stack]
+
+	// extraStrings are strings that get generated during
+	// parsing but haven't come directly from the trace, so
+	// they don't appear in strings.
+	extraStrings   []string
+	extraStringIDs map[string]extraStringID
+	nextExtra      extraStringID
+}
+
+// addExtraString adds an extra string to the evTable and returns
+// a unique ID for the string in the table.
+func (t *evTable) addExtraString(s string) extraStringID {
+	if s == "" {
+		return 0
+	}
+	if t.extraStringIDs == nil {
+		t.extraStringIDs = make(map[string]extraStringID)
+	}
+	if id, ok := t.extraStringIDs[s]; ok {
+		return id
+	}
+	t.nextExtra++
+	id := t.nextExtra
+	t.extraStrings = append(t.extraStrings, s)
+	t.extraStringIDs[s] = id
+	return id
+}
+
+// getExtraString returns the extra string for the provided ID.
+// The ID must have been produced by addExtraString for this evTable.
+func (t *evTable) getExtraString(id extraStringID) string {
+	if id == 0 {
+		return ""
+	}
+	return t.extraStrings[id-1]
+}
+
+// dataTable is a mapping from EIs to Es.
+type dataTable[EI ~uint64, E any] struct {
+	present []uint8
+	dense   []E
+	sparse  map[EI]E
+}
+
+// insert tries to add a mapping from id to s.
+//
+// Returns an error if a mapping for id already exists, regardless
+// of whether or not s is the same in content. This should be used
+// for validation during parsing.
+func (d *dataTable[EI, E]) insert(id EI, data E) error {
+	if d.sparse == nil {
+		d.sparse = make(map[EI]E)
+	}
+	if existing, ok := d.get(id); ok {
+		return fmt.Errorf("multiple %Ts with the same ID: id=%d, new=%v, existing=%v", data, id, data, existing)
+	}
+	d.sparse[id] = data
+	return nil
+}
+
+// compactify attempts to compact sparse into dense.
+//
+// This is intended to be called only once after insertions are done.
+func (d *dataTable[EI, E]) compactify() {
+	if d.sparse == nil || len(d.dense) != 0 {
+		// Already compactified.
+		return
+	}
+	// Find the range of IDs.
+	maxID := EI(0)
+	minID := ^EI(0)
+	for id := range d.sparse {
+		if id > maxID {
+			maxID = id
+		}
+		if id < minID {
+			minID = id
+		}
+	}
+	// We're willing to waste at most 2x memory.
+	if int(maxID-minID) > 2*len(d.sparse) {
+		return
+	}
+	if int(minID) > len(d.sparse) {
+		return
+	}
+	size := int(maxID) + 1
+	d.present = make([]uint8, (size+7)/8)
+	d.dense = make([]E, size)
+	for id, data := range d.sparse {
+		d.dense[id] = data
+		d.present[id/8] |= uint8(1) << (id % 8)
+	}
+	d.sparse = nil
+}
+
+// get returns the E for id or false if it doesn't
+// exist. This should be used for validation during parsing.
+func (d *dataTable[EI, E]) get(id EI) (E, bool) {
+	if id == 0 {
+		return *new(E), true
+	}
+	if int(id) < len(d.dense) {
+		if d.present[id/8]&(uint8(1)<<(id%8)) != 0 {
+			return d.dense[id], true
+		}
+	} else if d.sparse != nil {
+		if data, ok := d.sparse[id]; ok {
+			return data, true
+		}
+	}
+	return *new(E), false
+}
+
+// forEach iterates over all ID/value pairs in the data table.
+func (d *dataTable[EI, E]) forEach(yield func(EI, E) bool) bool {
+	for id, value := range d.dense {
+		if d.present[id/8]&(uint8(1)<<(id%8)) == 0 {
+			continue
+		}
+		if !yield(EI(id), value) {
+			return false
+		}
+	}
+	if d.sparse == nil {
+		return true
+	}
+	for id, value := range d.sparse {
+		if !yield(id, value) {
+			return false
+		}
+	}
+	return true
+}
+
+// mustGet returns the E for id or panics if it fails.
+//
+// This should only be used if id has already been validated.
+func (d *dataTable[EI, E]) mustGet(id EI) E {
+	data, ok := d.get(id)
+	if !ok {
+		panic(fmt.Sprintf("expected id %d in %T table", id, data))
+	}
+	return data
+}
+
+// frequency is nanoseconds per timestamp unit.
+type frequency float64
+
+// mul multiplies an unprocessed to produce a time in nanoseconds.
+func (f frequency) mul(t timestamp) Time {
+	return Time(float64(t) * float64(f))
+}
+
+// stringID is an index into the string table for a generation.
+type stringID uint64
+
+// extraStringID is an index into the extra string table for a generation.
+type extraStringID uint64
+
+// stackID is an index into the stack table for a generation.
+type stackID uint64
+
+// cpuSample represents a CPU profiling sample captured by the trace.
+type cpuSample struct {
+	schedCtx
+	time  Time
+	stack stackID
+}
+
+// asEvent produces a complete Event from a cpuSample. It needs
+// the evTable from the generation that created it.
+//
+// We don't just store it as an Event in generation to minimize
+// the amount of pointer data floating around.
+func (s cpuSample) asEvent(table *evTable) Event {
+	// TODO(mknyszek): This is go122-specific, but shouldn't be.
+	// Generalize this in the future.
+	e := Event{
+		table: table,
+		ctx:   s.schedCtx,
+		base: baseEvent{
+			typ:  go122.EvCPUSample,
+			time: s.time,
+		},
+	}
+	e.base.args[0] = uint64(s.stack)
+	return e
+}
+
+// stack represents a goroutine stack sample.
+type stack struct {
+	frames []frame
+}
+
+func (s stack) String() string {
+	var sb strings.Builder
+	for _, frame := range s.frames {
+		fmt.Fprintf(&sb, "\t%#v\n", frame)
+	}
+	return sb.String()
+}
+
+// frame represents a single stack frame.
+type frame struct {
+	pc     uint64
+	funcID stringID
+	fileID stringID
+	line   uint64
+}
diff --git a/trace/batch.go b/trace/batch.go
new file mode 100644
index 0000000..9fafac9
--- /dev/null
+++ b/trace/batch.go
@@ -0,0 +1,101 @@
+// Copyright 2023 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.
+
+// Code generated by "gen.bash" from internal/trace/v2; DO NOT EDIT.
+
+//go:build go1.21
+
+package trace
+
+import (
+	"bufio"
+	"bytes"
+	"encoding/binary"
+	"fmt"
+	"io"
+
+	"golang.org/x/exp/trace/internal/event"
+	"golang.org/x/exp/trace/internal/event/go122"
+)
+
+// timestamp is an unprocessed timestamp.
+type timestamp uint64
+
+// batch represents a batch of trace events.
+// It is unparsed except for its header.
+type batch struct {
+	m    ThreadID
+	time timestamp
+	data []byte
+}
+
+func (b *batch) isStringsBatch() bool {
+	return len(b.data) > 0 && event.Type(b.data[0]) == go122.EvStrings
+}
+
+func (b *batch) isStacksBatch() bool {
+	return len(b.data) > 0 && event.Type(b.data[0]) == go122.EvStacks
+}
+
+func (b *batch) isCPUSamplesBatch() bool {
+	return len(b.data) > 0 && event.Type(b.data[0]) == go122.EvCPUSamples
+}
+
+func (b *batch) isFreqBatch() bool {
+	return len(b.data) > 0 && event.Type(b.data[0]) == go122.EvFrequency
+}
+
+// readBatch reads the next full batch from r.
+func readBatch(r *bufio.Reader) (batch, uint64, error) {
+	// Read batch header byte.
+	b, err := r.ReadByte()
+	if err != nil {
+		return batch{}, 0, err
+	}
+	if typ := event.Type(b); typ != go122.EvEventBatch {
+		return batch{}, 0, fmt.Errorf("expected batch event (%s), got %s", go122.EventString(go122.EvEventBatch), go122.EventString(typ))
+	}
+
+	// Read the batch header: gen (generation), thread (M) ID, base timestamp
+	// for the batch.
+	gen, err := binary.ReadUvarint(r)
+	if err != nil {
+		return batch{}, gen, fmt.Errorf("error reading batch gen: %w", err)
+	}
+	m, err := binary.ReadUvarint(r)
+	if err != nil {
+		return batch{}, gen, fmt.Errorf("error reading batch M ID: %w", err)
+	}
+	ts, err := binary.ReadUvarint(r)
+	if err != nil {
+		return batch{}, gen, fmt.Errorf("error reading batch timestamp: %w", err)
+	}
+
+	// Read in the size of the batch to follow.
+	size, err := binary.ReadUvarint(r)
+	if err != nil {
+		return batch{}, gen, fmt.Errorf("error reading batch size: %w", err)
+	}
+	if size > go122.MaxBatchSize {
+		return batch{}, gen, fmt.Errorf("invalid batch size %d, maximum is %d", size, go122.MaxBatchSize)
+	}
+
+	// Copy out the batch for later processing.
+	var data bytes.Buffer
+	data.Grow(int(size))
+	n, err := io.CopyN(&data, r, int64(size))
+	if n != int64(size) {
+		return batch{}, gen, fmt.Errorf("failed to read full batch: read %d but wanted %d", n, size)
+	}
+	if err != nil {
+		return batch{}, gen, fmt.Errorf("copying batch data: %w", err)
+	}
+
+	// Return the batch.
+	return batch{
+		m:    ThreadID(m),
+		time: timestamp(ts),
+		data: data.Bytes(),
+	}, gen, nil
+}
diff --git a/trace/batchcursor.go b/trace/batchcursor.go
new file mode 100644
index 0000000..f8fc3fd
--- /dev/null
+++ b/trace/batchcursor.go
@@ -0,0 +1,172 @@
+// Copyright 2023 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.
+
+// Code generated by "gen.bash" from internal/trace/v2; DO NOT EDIT.
+
+//go:build go1.21
+
+package trace
+
+import (
+	"cmp"
+	"encoding/binary"
+	"fmt"
+
+	"golang.org/x/exp/trace/internal/event"
+	"golang.org/x/exp/trace/internal/event/go122"
+)
+
+type batchCursor struct {
+	m       ThreadID
+	lastTs  Time
+	idx     int       // next index into []batch
+	dataOff int       // next index into batch.data
+	ev      baseEvent // last read event
+}
+
+func (b *batchCursor) nextEvent(batches []batch, freq frequency) (ok bool, err error) {
+	// Batches should generally always have at least one event,
+	// but let's be defensive about that and accept empty batches.
+	for b.idx < len(batches) && len(batches[b.idx].data) == b.dataOff {
+		b.idx++
+		b.dataOff = 0
+		b.lastTs = 0
+	}
+	// Have we reached the end of the batches?
+	if b.idx == len(batches) {
+		return false, nil
+	}
+	// Initialize lastTs if it hasn't been yet.
+	if b.lastTs == 0 {
+		b.lastTs = freq.mul(batches[b.idx].time)
+	}
+	// Read an event out.
+	n, tsdiff, err := readTimedBaseEvent(batches[b.idx].data[b.dataOff:], &b.ev)
+	if err != nil {
+		return false, err
+	}
+	// Complete the timestamp from the cursor's last timestamp.
+	b.ev.time = freq.mul(tsdiff) + b.lastTs
+
+	// Move the cursor's timestamp forward.
+	b.lastTs = b.ev.time
+
+	// Move the cursor forward.
+	b.dataOff += n
+	return true, nil
+}
+
+func (b *batchCursor) compare(a *batchCursor) int {
+	return cmp.Compare(b.ev.time, a.ev.time)
+}
+
+// readTimedBaseEvent reads out the raw event data from b
+// into e. It does not try to interpret the arguments
+// but it does validate that the event is a regular
+// event with a timestamp (vs. a structural event).
+//
+// It requires that the event its reading be timed, which must
+// be the case for every event in a plain EventBatch.
+func readTimedBaseEvent(b []byte, e *baseEvent) (int, timestamp, error) {
+	// Get the event type.
+	typ := event.Type(b[0])
+	specs := go122.Specs()
+	if int(typ) > len(specs) {
+		return 0, 0, fmt.Errorf("found invalid event type: %v", typ)
+	}
+	e.typ = typ
+
+	// Get spec.
+	spec := &specs[typ]
+	if len(spec.Args) == 0 || !spec.IsTimedEvent {
+		return 0, 0, fmt.Errorf("found event without a timestamp: type=%v", typ)
+	}
+	n := 1
+
+	// Read timestamp diff.
+	ts, nb := binary.Uvarint(b[n:])
+	n += nb
+
+	// Read the rest of the arguments.
+	for i := 0; i < len(spec.Args)-1; i++ {
+		arg, nb := binary.Uvarint(b[n:])
+		e.args[i] = arg
+		n += nb
+	}
+	return n, timestamp(ts), nil
+}
+
+func heapInsert(heap []*batchCursor, bc *batchCursor) []*batchCursor {
+	// Add the cursor to the end of the heap.
+	heap = append(heap, bc)
+
+	// Sift the new entry up to the right place.
+	heapSiftUp(heap, len(heap)-1)
+	return heap
+}
+
+func heapUpdate(heap []*batchCursor, i int) {
+	// Try to sift up.
+	if heapSiftUp(heap, i) != i {
+		return
+	}
+	// Try to sift down, if sifting up failed.
+	heapSiftDown(heap, i)
+}
+
+func heapRemove(heap []*batchCursor, i int) []*batchCursor {
+	// Sift index i up to the root, ignoring actual values.
+	for i > 0 {
+		heap[(i-1)/2], heap[i] = heap[i], heap[(i-1)/2]
+		i = (i - 1) / 2
+	}
+	// Swap the root with the last element, then remove it.
+	heap[0], heap[len(heap)-1] = heap[len(heap)-1], heap[0]
+	heap = heap[:len(heap)-1]
+	// Sift the root down.
+	heapSiftDown(heap, 0)
+	return heap
+}
+
+func heapSiftUp(heap []*batchCursor, i int) int {
+	for i > 0 && heap[(i-1)/2].ev.time > heap[i].ev.time {
+		heap[(i-1)/2], heap[i] = heap[i], heap[(i-1)/2]
+		i = (i - 1) / 2
+	}
+	return i
+}
+
+func heapSiftDown(heap []*batchCursor, i int) int {
+	for {
+		m := min3(heap, i, 2*i+1, 2*i+2)
+		if m == i {
+			// Heap invariant already applies.
+			break
+		}
+		heap[i], heap[m] = heap[m], heap[i]
+		i = m
+	}
+	return i
+}
+
+func min3(b []*batchCursor, i0, i1, i2 int) int {
+	minIdx := i0
+	minT := maxTime
+	if i0 < len(b) {
+		minT = b[i0].ev.time
+	}
+	if i1 < len(b) {
+		if t := b[i1].ev.time; t < minT {
+			minT = t
+			minIdx = i1
+		}
+	}
+	if i2 < len(b) {
+		if t := b[i2].ev.time; t < minT {
+			minT = t
+			minIdx = i2
+		}
+	}
+	return minIdx
+}
diff --git a/trace/batchcursor_test.go b/trace/batchcursor_test.go
new file mode 100644
index 0000000..b13dbc1
--- /dev/null
+++ b/trace/batchcursor_test.go
@@ -0,0 +1,130 @@
+// Copyright 2023 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.
+
+// Code generated by "gen.bash" from internal/trace/v2; DO NOT EDIT.
+
+//go:build go1.21
+
+package trace
+
+import (
+	"fmt"
+	"strings"
+	"testing"
+
+	"slices"
+)
+
+func TestHeap(t *testing.T) {
+	var heap []*batchCursor
+
+	// Insert a bunch of values into the heap.
+	checkHeap(t, heap)
+	heap = heapInsert(heap, makeBatchCursor(5))
+	checkHeap(t, heap)
+	for i := int64(-20); i < 20; i++ {
+		heap = heapInsert(heap, makeBatchCursor(i))
+		checkHeap(t, heap)
+	}
+
+	// Update an element in the middle to be the new minimum.
+	for i := range heap {
+		if heap[i].ev.time == 5 {
+			heap[i].ev.time = -21
+			heapUpdate(heap, i)
+			break
+		}
+	}
+	checkHeap(t, heap)
+	if heap[0].ev.time != -21 {
+		t.Fatalf("heap update failed, expected %d as heap min: %s", -21, heapDebugString(heap))
+	}
+
+	// Update the minimum element to be smaller. There should be no change.
+	heap[0].ev.time = -22
+	heapUpdate(heap, 0)
+	checkHeap(t, heap)
+	if heap[0].ev.time != -22 {
+		t.Fatalf("heap update failed, expected %d as heap min: %s", -22, heapDebugString(heap))
+	}
+
+	// Update the last element to be larger. There should be no change.
+	heap[len(heap)-1].ev.time = 21
+	heapUpdate(heap, len(heap)-1)
+	checkHeap(t, heap)
+	if heap[len(heap)-1].ev.time != 21 {
+		t.Fatalf("heap update failed, expected %d as heap min: %s", 21, heapDebugString(heap))
+	}
+
+	// Update the last element to be smaller.
+	heap[len(heap)-1].ev.time = 7
+	heapUpdate(heap, len(heap)-1)
+	checkHeap(t, heap)
+	if heap[len(heap)-1].ev.time == 21 {
+		t.Fatalf("heap update failed, unexpected %d as heap min: %s", 21, heapDebugString(heap))
+	}
+
+	// Remove an element in the middle.
+	for i := range heap {
+		if heap[i].ev.time == 5 {
+			heap = heapRemove(heap, i)
+			break
+		}
+	}
+	checkHeap(t, heap)
+	for i := range heap {
+		if heap[i].ev.time == 5 {
+			t.Fatalf("failed to remove heap elem with time %d: %s", 5, heapDebugString(heap))
+		}
+	}
+
+	// Remove tail.
+	heap = heapRemove(heap, len(heap)-1)
+	checkHeap(t, heap)
+
+	// Remove from the head, and make sure the result is sorted.
+	l := len(heap)
+	var removed []*batchCursor
+	for i := 0; i < l; i++ {
+		removed = append(removed, heap[0])
+		heap = heapRemove(heap, 0)
+		checkHeap(t, heap)
+	}
+	if !slices.IsSortedFunc(removed, (*batchCursor).compare) {
+		t.Fatalf("heap elements not removed in sorted order, got: %s", heapDebugString(removed))
+	}
+}
+
+func makeBatchCursor(v int64) *batchCursor {
+	return &batchCursor{ev: baseEvent{time: Time(v)}}
+}
+
+func heapDebugString(heap []*batchCursor) string {
+	var sb strings.Builder
+	fmt.Fprintf(&sb, "[")
+	for i := range heap {
+		if i != 0 {
+			fmt.Fprintf(&sb, ", ")
+		}
+		fmt.Fprintf(&sb, "%d", heap[i].ev.time)
+	}
+	fmt.Fprintf(&sb, "]")
+	return sb.String()
+}
+
+func checkHeap(t *testing.T, heap []*batchCursor) {
+	t.Helper()
+
+	for i := range heap {
+		if i == 0 {
+			continue
+		}
+		if heap[(i-1)/2].compare(heap[i]) > 0 {
+			t.Errorf("heap invariant not maintained between index %d and parent %d: %s", i, i/2, heapDebugString(heap))
+		}
+	}
+	if t.Failed() {
+		t.FailNow()
+	}
+}
diff --git a/trace/cmd/gotraceraw/main.go b/trace/cmd/gotraceraw/main.go
new file mode 100644
index 0000000..840548f
--- /dev/null
+++ b/trace/cmd/gotraceraw/main.go
@@ -0,0 +1,92 @@
+// Copyright 2023 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.
+
+// Code generated by "gen.bash" from internal/trace/v2; DO NOT EDIT.
+
+//go:build go1.21
+
+package main
+
+import (
+	"flag"
+	"fmt"
+	"io"
+	"log"
+	"os"
+
+	"golang.org/x/exp/trace/internal/raw"
+	"golang.org/x/exp/trace/internal/version"
+)
+
+func init() {
+	flag.Usage = func() {
+		fmt.Fprintf(flag.CommandLine.Output(), "Usage: %s [mode]\n", os.Args[0])
+		fmt.Fprintf(flag.CommandLine.Output(), "\n")
+		fmt.Fprintf(flag.CommandLine.Output(), "Supported modes:")
+		fmt.Fprintf(flag.CommandLine.Output(), "\n")
+		fmt.Fprintf(flag.CommandLine.Output(), "* text2bytes - converts a text format trace to bytes\n")
+		fmt.Fprintf(flag.CommandLine.Output(), "* bytes2text - converts a byte format trace to text\n")
+		fmt.Fprintf(flag.CommandLine.Output(), "\n")
+		flag.PrintDefaults()
+	}
+	log.SetFlags(0)
+}
+
+func main() {
+	flag.Parse()
+	if narg := flag.NArg(); narg != 1 {
+		log.Fatal("expected exactly one positional argument: the mode to operate in; see -h output")
+	}
+
+	r := os.Stdin
+	w := os.Stdout
+
+	var tr traceReader
+	var tw traceWriter
+	var err error
+
+	switch flag.Arg(0) {
+	case "text2bytes":
+		tr, err = raw.NewTextReader(r)
+		if err != nil {
+			log.Fatal(err)
+		}
+		tw, err = raw.NewWriter(w, tr.Version())
+		if err != nil {
+			log.Fatal(err)
+		}
+	case "bytes2text":
+		tr, err = raw.NewReader(r)
+		if err != nil {
+			log.Fatal(err)
+		}
+		tw, err = raw.NewTextWriter(w, tr.Version())
+		if err != nil {
+			log.Fatal(err)
+		}
+	}
+	for {
+		ev, err := tr.ReadEvent()
+		if err == io.EOF {
+			break
+		}
+		if err != nil {
+			log.Fatal(err)
+			break
+		}
+		if err := tw.WriteEvent(ev); err != nil {
+			log.Fatal(err)
+			break
+		}
+	}
+}
+
+type traceReader interface {
+	Version() version.Version
+	ReadEvent() (raw.Event, error)
+}
+
+type traceWriter interface {
+	WriteEvent(raw.Event) error
+}
diff --git a/trace/cmd/gotracevalidate/main.go b/trace/cmd/gotracevalidate/main.go
new file mode 100644
index 0000000..cb7166c
--- /dev/null
+++ b/trace/cmd/gotracevalidate/main.go
@@ -0,0 +1,57 @@
+// Copyright 2023 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.
+
+// Code generated by "gen.bash" from internal/trace/v2; DO NOT EDIT.
+
+//go:build go1.21
+
+package main
+
+import (
+	"flag"
+	"fmt"
+	"io"
+	"log"
+	"os"
+
+	"golang.org/x/exp/trace"
+	"golang.org/x/exp/trace/internal/testtrace"
+)
+
+func init() {
+	flag.Usage = func() {
+		fmt.Fprintf(flag.CommandLine.Output(), "Usage: %s\n", os.Args[0])
+		fmt.Fprintf(flag.CommandLine.Output(), "\n")
+		fmt.Fprintf(flag.CommandLine.Output(), "Accepts a trace at stdin and validates it.\n")
+		flag.PrintDefaults()
+	}
+	log.SetFlags(0)
+}
+
+var logEvents = flag.Bool("log-events", false, "whether to log events")
+
+func main() {
+	flag.Parse()
+
+	r, err := trace.NewReader(os.Stdin)
+	if err != nil {
+		log.Fatal(err)
+	}
+	v := testtrace.NewValidator()
+	for {
+		ev, err := r.ReadEvent()
+		if err == io.EOF {
+			break
+		}
+		if err != nil {
+			log.Fatal(err)
+		}
+		if *logEvents {
+			log.Println(ev.String())
+		}
+		if err := v.Event(ev); err != nil {
+			log.Fatal(err)
+		}
+	}
+}
diff --git a/trace/event.go b/trace/event.go
new file mode 100644
index 0000000..a9d5947
--- /dev/null
+++ b/trace/event.go
@@ -0,0 +1,784 @@
+// Copyright 2023 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.
+
+// Code generated by "gen.bash" from internal/trace/v2; DO NOT EDIT.
+
+//go:build go1.21
+
+package trace
+
+import (
+	"fmt"
+	"math"
+	"strings"
+	"time"
+
+	"golang.org/x/exp/trace/internal/event"
+	"golang.org/x/exp/trace/internal/event/go122"
+	"golang.org/x/exp/trace/internal/version"
+)
+
+// EventKind indicates the kind of event this is.
+//
+// Use this information to obtain a more specific event that
+// allows access to more detailed information.
+type EventKind uint16
+
+const (
+	EventBad EventKind = iota
+
+	// EventKindSync is an event that indicates a global synchronization
+	// point in the trace. At the point of a sync event, the
+	// trace reader can be certain that all resources (e.g. threads,
+	// goroutines) that have existed until that point have been enumerated.
+	EventSync
+
+	// EventMetric is an event that represents the value of a metric at
+	// a particular point in time.
+	EventMetric
+
+	// EventLabel attaches a label to a resource.
+	EventLabel
+
+	// EventStackSample represents an execution sample, indicating what a
+	// thread/proc/goroutine was doing at a particular point in time via
+	// its backtrace.
+	//
+	// Note: Samples should be considered a close approximation of
+	// what a thread/proc/goroutine was executing at a given point in time.
+	// These events may slightly contradict the situation StateTransitions
+	// describe, so they should only be treated as a best-effort annotation.
+	EventStackSample
+
+	// EventRangeBegin and EventRangeEnd are a pair of generic events representing
+	// a special range of time. Ranges are named and scoped to some resource
+	// (identified via ResourceKind). A range that has begun but has not ended
+	// is considered active.
+	//
+	// EvRangeBegin and EvRangeEnd will share the same name, and an End will always
+	// follow a Begin on the same instance of the resource. The associated
+	// resource ID can be obtained from the Event. ResourceNone indicates the
+	// range is globally scoped. That is, any goroutine/proc/thread can start or
+	// stop, but only one such range may be active at any given time.
+	//
+	// EventRangeActive is like EventRangeBegin, but indicates that the range was
+	// already active. In this case, the resource referenced may not be in the current
+	// context.
+	EventRangeBegin
+	EventRangeActive
+	EventRangeEnd
+
+	// EvTaskBegin and EvTaskEnd are a pair of events representing a runtime/trace.Task.
+	EventTaskBegin
+	EventTaskEnd
+
+	// EventRegionBegin and EventRegionEnd are a pair of events represent a runtime/trace.Region.
+	EventRegionBegin
+	EventRegionEnd
+
+	// EventLog represents a runtime/trace.Log call.
+	EventLog
+
+	// Transitions in state for some resource.
+	EventStateTransition
+)
+
+// String returns a string form of the EventKind.
+func (e EventKind) String() string {
+	if int(e) >= len(eventKindStrings) {
+		return eventKindStrings[0]
+	}
+	return eventKindStrings[e]
+}
+
+var eventKindStrings = [...]string{
+	EventBad:             "Bad",
+	EventSync:            "Sync",
+	EventMetric:          "Metric",
+	EventLabel:           "Label",
+	EventStackSample:     "StackSample",
+	EventRangeBegin:      "RangeBegin",
+	EventRangeActive:     "RangeActive",
+	EventRangeEnd:        "RangeEnd",
+	EventTaskBegin:       "TaskBegin",
+	EventTaskEnd:         "TaskEnd",
+	EventRegionBegin:     "RegionBegin",
+	EventRegionEnd:       "RegionEnd",
+	EventLog:             "Log",
+	EventStateTransition: "StateTransition",
+}
+
+const maxTime = Time(math.MaxInt64)
+
+// Time is a timestamp in nanoseconds.
+//
+// It corresponds to the monotonic clock on the platform that the
+// trace was taken, and so is possible to correlate with timestamps
+// for other traces taken on the same machine using the same clock
+// (i.e. no reboots in between).
+//
+// The actual absolute value of the timestamp is only meaningful in
+// relation to other timestamps from the same clock.
+//
+// BUG: Timestamps coming from traces on Windows platforms are
+// only comparable with timestamps from the same trace. Timestamps
+// across traces cannot be compared, because the system clock is
+// not used as of Go 1.22.
+//
+// BUG: Traces produced by Go versions 1.21 and earlier cannot be
+// compared with timestamps from other traces taken on the same
+// machine. This is because the system clock was not used at all
+// to collect those timestamps.
+type Time int64
+
+// Sub subtracts t0 from t, returning the duration in nanoseconds.
+func (t Time) Sub(t0 Time) time.Duration {
+	return time.Duration(int64(t) - int64(t0))
+}
+
+// Metric provides details about a Metric event.
+type Metric struct {
+	// Name is the name of the sampled metric.
+	//
+	// Names follow the same convention as metric names in the
+	// runtime/metrics package, meaning they include the unit.
+	// Names that match with the runtime/metrics package represent
+	// the same quantity. Note that this corresponds to the
+	// runtime/metrics package for the Go version this trace was
+	// collected for.
+	Name string
+
+	// Value is the sampled value of the metric.
+	//
+	// The Value's Kind is tied to the name of the metric, and so is
+	// guaranteed to be the same for metric samples for the same metric.
+	Value Value
+}
+
+// Label provides details about a Label event.
+type Label struct {
+	// Label is the label applied to some resource.
+	Label string
+
+	// Resource is the resource to which this label should be applied.
+	Resource ResourceID
+}
+
+// Range provides details about a Range event.
+type Range struct {
+	// Name is a human-readable name for the range.
+	//
+	// This name can be used to identify the end of the range for the resource
+	// its scoped to, because only one of each type of range may be active on
+	// a particular resource. The relevant resource should be obtained from the
+	// Event that produced these details. The corresponding RangeEnd will have
+	// an identical name.
+	Name string
+
+	// Scope is the resource that the range is scoped to.
+	//
+	// For example, a ResourceGoroutine scope means that the same goroutine
+	// must have a start and end for the range, and that goroutine can only
+	// have one range of a particular name active at any given time. The
+	// ID that this range is scoped to may be obtained via Event.Goroutine.
+	//
+	// The ResourceNone scope means that the range is globally scoped. As a
+	// result, any goroutine/proc/thread may start or end the range, and only
+	// one such named range may be active globally at any given time.
+	//
+	// For RangeBegin and RangeEnd events, this will always reference some
+	// resource ID in the current execution context. For RangeActive events,
+	// this may reference a resource not in the current context. Prefer Scope
+	// over the current execution context.
+	Scope ResourceID
+}
+
+// RangeAttributes provides attributes about a completed Range.
+type RangeAttribute struct {
+	// Name is the human-readable name for the range.
+	Name string
+
+	// Value is the value of the attribute.
+	Value Value
+}
+
+// TaskID is the internal ID of a task used to disambiguate tasks (even if they
+// are of the same type).
+type TaskID uint64
+
+const (
+	// NoTask indicates the lack of a task.
+	NoTask = TaskID(^uint64(0))
+
+	// BackgroundTask is the global task that events are attached to if there was
+	// no other task in the context at the point the event was emitted.
+	BackgroundTask = TaskID(0)
+)
+
+// Task provides details about a Task event.
+type Task struct {
+	// ID is a unique identifier for the task.
+	//
+	// This can be used to associate the beginning of a task with its end.
+	ID TaskID
+
+	// ParentID is the ID of the parent task.
+	Parent TaskID
+
+	// Type is the taskType that was passed to runtime/trace.NewTask.
+	//
+	// May be "" if a task's TaskBegin event isn't present in the trace.
+	Type string
+}
+
+// Region provides details about a Region event.
+type Region struct {
+	// Task is the ID of the task this region is associated with.
+	Task TaskID
+
+	// Type is the regionType that was passed to runtime/trace.StartRegion or runtime/trace.WithRegion.
+	Type string
+}
+
+// Log provides details about a Log event.
+type Log struct {
+	// Task is the ID of the task this region is associated with.
+	Task TaskID
+
+	// Category is the category that was passed to runtime/trace.Log or runtime/trace.Logf.
+	Category string
+
+	// Message is the message that was passed to runtime/trace.Log or runtime/trace.Logf.
+	Message string
+}
+
+// Stack represents a stack. It's really a handle to a stack and it's trivially comparable.
+//
+// If two Stacks are equal then their Frames are guaranteed to be identical. If they are not
+// equal, however, their Frames may still be equal.
+type Stack struct {
+	table *evTable
+	id    stackID
+}
+
+// Frames is an iterator over the frames in a Stack.
+func (s Stack) Frames(yield func(f StackFrame) bool) bool {
+	if s.id == 0 {
+		return true
+	}
+	stk := s.table.stacks.mustGet(s.id)
+	for _, f := range stk.frames {
+		sf := StackFrame{
+			PC:   f.pc,
+			Func: s.table.strings.mustGet(f.funcID),
+			File: s.table.strings.mustGet(f.fileID),
+			Line: f.line,
+		}
+		if !yield(sf) {
+			return false
+		}
+	}
+	return true
+}
+
+// NoStack is a sentinel value that can be compared against any Stack value, indicating
+// a lack of a stack trace.
+var NoStack = Stack{}
+
+// StackFrame represents a single frame of a stack.
+type StackFrame struct {
+	// PC is the program counter of the function call if this
+	// is not a leaf frame. If it's a leaf frame, it's the point
+	// at which the stack trace was taken.
+	PC uint64
+
+	// Func is the name of the function this frame maps to.
+	Func string
+
+	// File is the file which contains the source code of Func.
+	File string
+
+	// Line is the line number within File which maps to PC.
+	Line uint64
+}
+
+// Event represents a single event in the trace.
+type Event struct {
+	table *evTable
+	ctx   schedCtx
+	base  baseEvent
+}
+
+// Kind returns the kind of event that this is.
+func (e Event) Kind() EventKind {
+	return go122Type2Kind[e.base.typ]
+}
+
+// Time returns the timestamp of the event.
+func (e Event) Time() Time {
+	return e.base.time
+}
+
+// Goroutine returns the ID of the goroutine that was executing when
+// this event happened. It describes part of the execution context
+// for this event.
+//
+// Note that for goroutine state transitions this always refers to the
+// state before the transition. For example, if a goroutine is just
+// starting to run on this thread and/or proc, then this will return
+// NoGoroutine. In this case, the goroutine starting to run will be
+// can be found at Event.StateTransition().Resource.
+func (e Event) Goroutine() GoID {
+	return e.ctx.G
+}
+
+// Proc returns the ID of the proc this event event pertains to.
+//
+// Note that for proc state transitions this always refers to the
+// state before the transition. For example, if a proc is just
+// starting to run on this thread, then this will return NoProc.
+func (e Event) Proc() ProcID {
+	return e.ctx.P
+}
+
+// Thread returns the ID of the thread this event pertains to.
+//
+// Note that for thread state transitions this always refers to the
+// state before the transition. For example, if a thread is just
+// starting to run, then this will return NoThread.
+//
+// Note: tracking thread state is not currently supported, so this
+// will always return a valid thread ID. However thread state transitions
+// may be tracked in the future, and callers must be robust to this
+// possibility.
+func (e Event) Thread() ThreadID {
+	return e.ctx.M
+}
+
+// Stack returns a handle to a stack associated with the event.
+//
+// This represents a stack trace at the current moment in time for
+// the current execution context.
+func (e Event) Stack() Stack {
+	if e.base.typ == evSync {
+		return NoStack
+	}
+	if e.base.typ == go122.EvCPUSample {
+		return Stack{table: e.table, id: stackID(e.base.args[0])}
+	}
+	spec := go122.Specs()[e.base.typ]
+	if len(spec.StackIDs) == 0 {
+		return NoStack
+	}
+	// The stack for the main execution context is always the
+	// first stack listed in StackIDs. Subtract one from this
+	// because we've peeled away the timestamp argument.
+	id := stackID(e.base.args[spec.StackIDs[0]-1])
+	if id == 0 {
+		return NoStack
+	}
+	return Stack{table: e.table, id: id}
+}
+
+// Metric returns details about a Metric event.
+//
+// Panics if Kind != EventMetric.
+func (e Event) Metric() Metric {
+	if e.Kind() != EventMetric {
+		panic("Metric called on non-Metric event")
+	}
+	var m Metric
+	switch e.base.typ {
+	case go122.EvProcsChange:
+		m.Name = "/sched/gomaxprocs:threads"
+		m.Value = Value{kind: ValueUint64, scalar: e.base.args[0]}
+	case go122.EvHeapAlloc:
+		m.Name = "/memory/classes/heap/objects:bytes"
+		m.Value = Value{kind: ValueUint64, scalar: e.base.args[0]}
+	case go122.EvHeapGoal:
+		m.Name = "/gc/heap/goal:bytes"
+		m.Value = Value{kind: ValueUint64, scalar: e.base.args[0]}
+	default:
+		panic(fmt.Sprintf("internal error: unexpected event type for Metric kind: %s", go122.EventString(e.base.typ)))
+	}
+	return m
+}
+
+// Label returns details about a Label event.
+//
+// Panics if Kind != EventLabel.
+func (e Event) Label() Label {
+	if e.Kind() != EventLabel {
+		panic("Label called on non-Label event")
+	}
+	if e.base.typ != go122.EvGoLabel {
+		panic(fmt.Sprintf("internal error: unexpected event type for Label kind: %s", go122.EventString(e.base.typ)))
+	}
+	return Label{
+		Label:    e.table.strings.mustGet(stringID(e.base.args[0])),
+		Resource: ResourceID{Kind: ResourceGoroutine, id: int64(e.ctx.G)},
+	}
+}
+
+// Range returns details about an EventRangeBegin, EventRangeActive, or EventRangeEnd event.
+//
+// Panics if Kind != EventRangeBegin, Kind != EventRangeActive, and Kind != EventRangeEnd.
+func (e Event) Range() Range {
+	if kind := e.Kind(); kind != EventRangeBegin && kind != EventRangeActive && kind != EventRangeEnd {
+		panic("Range called on non-Range event")
+	}
+	var r Range
+	switch e.base.typ {
+	case go122.EvSTWBegin, go122.EvSTWEnd:
+		// N.B. ordering.advance smuggles in the STW reason as e.base.args[0]
+		// for go122.EvSTWEnd (it's already there for Begin).
+		r.Name = "stop-the-world (" + e.table.strings.mustGet(stringID(e.base.args[0])) + ")"
+		r.Scope = ResourceID{Kind: ResourceGoroutine, id: int64(e.Goroutine())}
+	case go122.EvGCBegin, go122.EvGCActive, go122.EvGCEnd:
+		r.Name = "GC concurrent mark phase"
+		r.Scope = ResourceID{Kind: ResourceNone}
+	case go122.EvGCSweepBegin, go122.EvGCSweepActive, go122.EvGCSweepEnd:
+		r.Name = "GC incremental sweep"
+		r.Scope = ResourceID{Kind: ResourceProc}
+		if e.base.typ == go122.EvGCSweepActive {
+			r.Scope.id = int64(e.base.args[0])
+		} else {
+			r.Scope.id = int64(e.Proc())
+		}
+		r.Scope.id = int64(e.Proc())
+	case go122.EvGCMarkAssistBegin, go122.EvGCMarkAssistActive, go122.EvGCMarkAssistEnd:
+		r.Name = "GC mark assist"
+		r.Scope = ResourceID{Kind: ResourceGoroutine}
+		if e.base.typ == go122.EvGCMarkAssistActive {
+			r.Scope.id = int64(e.base.args[0])
+		} else {
+			r.Scope.id = int64(e.Goroutine())
+		}
+	default:
+		panic(fmt.Sprintf("internal error: unexpected event type for Range kind: %s", go122.EventString(e.base.typ)))
+	}
+	return r
+}
+
+// RangeAttributes returns attributes for a completed range.
+//
+// Panics if Kind != EventRangeEnd.
+func (e Event) RangeAttributes() []RangeAttribute {
+	if e.Kind() != EventRangeEnd {
+		panic("Range called on non-Range event")
+	}
+	if e.base.typ != go122.EvGCSweepEnd {
+		return nil
+	}
+	return []RangeAttribute{
+		{
+			Name:  "bytes swept",
+			Value: Value{kind: ValueUint64, scalar: e.base.args[0]},
+		},
+		{
+			Name:  "bytes reclaimed",
+			Value: Value{kind: ValueUint64, scalar: e.base.args[1]},
+		},
+	}
+}
+
+// Task returns details about a TaskBegin or TaskEnd event.
+//
+// Panics if Kind != EventTaskBegin and Kind != EventTaskEnd.
+func (e Event) Task() Task {
+	if kind := e.Kind(); kind != EventTaskBegin && kind != EventTaskEnd {
+		panic("Task called on non-Task event")
+	}
+	parentID := NoTask
+	var typ string
+	switch e.base.typ {
+	case go122.EvUserTaskBegin:
+		parentID = TaskID(e.base.args[1])
+		typ = e.table.strings.mustGet(stringID(e.base.args[2]))
+	case go122.EvUserTaskEnd:
+		parentID = TaskID(e.base.extra(version.Go122)[0])
+		typ = e.table.getExtraString(extraStringID(e.base.extra(version.Go122)[1]))
+	default:
+		panic(fmt.Sprintf("internal error: unexpected event type for Task kind: %s", go122.EventString(e.base.typ)))
+	}
+	return Task{
+		ID:     TaskID(e.base.args[0]),
+		Parent: parentID,
+		Type:   typ,
+	}
+}
+
+// Region returns details about a RegionBegin or RegionEnd event.
+//
+// Panics if Kind != EventRegionBegin and Kind != EventRegionEnd.
+func (e Event) Region() Region {
+	if kind := e.Kind(); kind != EventRegionBegin && kind != EventRegionEnd {
+		panic("Region called on non-Region event")
+	}
+	if e.base.typ != go122.EvUserRegionBegin && e.base.typ != go122.EvUserRegionEnd {
+		panic(fmt.Sprintf("internal error: unexpected event type for Region kind: %s", go122.EventString(e.base.typ)))
+	}
+	return Region{
+		Task: TaskID(e.base.args[0]),
+		Type: e.table.strings.mustGet(stringID(e.base.args[1])),
+	}
+}
+
+// Log returns details about a Log event.
+//
+// Panics if Kind != EventLog.
+func (e Event) Log() Log {
+	if e.Kind() != EventLog {
+		panic("Log called on non-Log event")
+	}
+	if e.base.typ != go122.EvUserLog {
+		panic(fmt.Sprintf("internal error: unexpected event type for Log kind: %s", go122.EventString(e.base.typ)))
+	}
+	return Log{
+		Task:     TaskID(e.base.args[0]),
+		Category: e.table.strings.mustGet(stringID(e.base.args[1])),
+		Message:  e.table.strings.mustGet(stringID(e.base.args[2])),
+	}
+}
+
+// StateTransition returns details about a StateTransition event.
+//
+// Panics if Kind != EventStateTransition.
+func (e Event) StateTransition() StateTransition {
+	if e.Kind() != EventStateTransition {
+		panic("StateTransition called on non-StateTransition event")
+	}
+	var s StateTransition
+	switch e.base.typ {
+	case go122.EvProcStart:
+		s = procStateTransition(ProcID(e.base.args[0]), ProcIdle, ProcRunning)
+	case go122.EvProcStop:
+		s = procStateTransition(e.ctx.P, ProcRunning, ProcIdle)
+	case go122.EvProcSteal:
+		// N.B. ordering.advance populates e.base.extra.
+		beforeState := ProcRunning
+		if go122.ProcStatus(e.base.extra(version.Go122)[0]) == go122.ProcSyscallAbandoned {
+			// We've lost information because this ProcSteal advanced on a
+			// SyscallAbandoned state. Treat the P as idle because ProcStatus
+			// treats SyscallAbandoned as Idle. Otherwise we'll have an invalid
+			// transition.
+			beforeState = ProcIdle
+		}
+		s = procStateTransition(ProcID(e.base.args[0]), beforeState, ProcIdle)
+	case go122.EvProcStatus:
+		// N.B. ordering.advance populates e.base.extra.
+		s = procStateTransition(ProcID(e.base.args[0]), ProcState(e.base.extra(version.Go122)[0]), go122ProcStatus2ProcState[e.base.args[1]])
+	case go122.EvGoCreate:
+		s = goStateTransition(GoID(e.base.args[0]), GoNotExist, GoRunnable)
+		s.Stack = Stack{table: e.table, id: stackID(e.base.args[1])}
+	case go122.EvGoCreateSyscall:
+		s = goStateTransition(GoID(e.base.args[0]), GoNotExist, GoSyscall)
+	case go122.EvGoStart:
+		s = goStateTransition(GoID(e.base.args[0]), GoRunnable, GoRunning)
+	case go122.EvGoDestroy:
+		s = goStateTransition(e.ctx.G, GoRunning, GoNotExist)
+		s.Stack = e.Stack() // This event references the resource the event happened on.
+	case go122.EvGoDestroySyscall:
+		s = goStateTransition(e.ctx.G, GoSyscall, GoNotExist)
+	case go122.EvGoStop:
+		s = goStateTransition(e.ctx.G, GoRunning, GoRunnable)
+		s.Reason = e.table.strings.mustGet(stringID(e.base.args[0]))
+		s.Stack = e.Stack() // This event references the resource the event happened on.
+	case go122.EvGoBlock:
+		s = goStateTransition(e.ctx.G, GoRunning, GoWaiting)
+		s.Reason = e.table.strings.mustGet(stringID(e.base.args[0]))
+		s.Stack = e.Stack() // This event references the resource the event happened on.
+	case go122.EvGoUnblock:
+		s = goStateTransition(GoID(e.base.args[0]), GoWaiting, GoRunnable)
+	case go122.EvGoSyscallBegin:
+		s = goStateTransition(e.ctx.G, GoRunning, GoSyscall)
+		s.Stack = e.Stack() // This event references the resource the event happened on.
+	case go122.EvGoSyscallEnd:
+		s = goStateTransition(e.ctx.G, GoSyscall, GoRunning)
+		s.Stack = e.Stack() // This event references the resource the event happened on.
+	case go122.EvGoSyscallEndBlocked:
+		s = goStateTransition(e.ctx.G, GoSyscall, GoRunnable)
+		s.Stack = e.Stack() // This event references the resource the event happened on.
+	case go122.EvGoStatus:
+		// N.B. ordering.advance populates e.base.extra.
+		s = goStateTransition(GoID(e.base.args[0]), GoState(e.base.extra(version.Go122)[0]), go122GoStatus2GoState[e.base.args[2]])
+	default:
+		panic(fmt.Sprintf("internal error: unexpected event type for StateTransition kind: %s", go122.EventString(e.base.typ)))
+	}
+	return s
+}
+
+const evSync = ^event.Type(0)
+
+var go122Type2Kind = [...]EventKind{
+	go122.EvCPUSample:           EventStackSample,
+	go122.EvProcsChange:         EventMetric,
+	go122.EvProcStart:           EventStateTransition,
+	go122.EvProcStop:            EventStateTransition,
+	go122.EvProcSteal:           EventStateTransition,
+	go122.EvProcStatus:          EventStateTransition,
+	go122.EvGoCreate:            EventStateTransition,
+	go122.EvGoCreateSyscall:     EventStateTransition,
+	go122.EvGoStart:             EventStateTransition,
+	go122.EvGoDestroy:           EventStateTransition,
+	go122.EvGoDestroySyscall:    EventStateTransition,
+	go122.EvGoStop:              EventStateTransition,
+	go122.EvGoBlock:             EventStateTransition,
+	go122.EvGoUnblock:           EventStateTransition,
+	go122.EvGoSyscallBegin:      EventStateTransition,
+	go122.EvGoSyscallEnd:        EventStateTransition,
+	go122.EvGoSyscallEndBlocked: EventStateTransition,
+	go122.EvGoStatus:            EventStateTransition,
+	go122.EvSTWBegin:            EventRangeBegin,
+	go122.EvSTWEnd:              EventRangeEnd,
+	go122.EvGCActive:            EventRangeActive,
+	go122.EvGCBegin:             EventRangeBegin,
+	go122.EvGCEnd:               EventRangeEnd,
+	go122.EvGCSweepActive:       EventRangeActive,
+	go122.EvGCSweepBegin:        EventRangeBegin,
+	go122.EvGCSweepEnd:          EventRangeEnd,
+	go122.EvGCMarkAssistActive:  EventRangeActive,
+	go122.EvGCMarkAssistBegin:   EventRangeBegin,
+	go122.EvGCMarkAssistEnd:     EventRangeEnd,
+	go122.EvHeapAlloc:           EventMetric,
+	go122.EvHeapGoal:            EventMetric,
+	go122.EvGoLabel:             EventLabel,
+	go122.EvUserTaskBegin:       EventTaskBegin,
+	go122.EvUserTaskEnd:         EventTaskEnd,
+	go122.EvUserRegionBegin:     EventRegionBegin,
+	go122.EvUserRegionEnd:       EventRegionEnd,
+	go122.EvUserLog:             EventLog,
+	evSync:                      EventSync,
+}
+
+var go122GoStatus2GoState = [...]GoState{
+	go122.GoRunnable: GoRunnable,
+	go122.GoRunning:  GoRunning,
+	go122.GoWaiting:  GoWaiting,
+	go122.GoSyscall:  GoSyscall,
+}
+
+var go122ProcStatus2ProcState = [...]ProcState{
+	go122.ProcRunning:          ProcRunning,
+	go122.ProcIdle:             ProcIdle,
+	go122.ProcSyscall:          ProcRunning,
+	go122.ProcSyscallAbandoned: ProcIdle,
+}
+
+// String returns the event as a human-readable string.
+//
+// The format of the string is intended for debugging and is subject to change.
+func (e Event) String() string {
+	var sb strings.Builder
+	fmt.Fprintf(&sb, "M=%d P=%d G=%d", e.Thread(), e.Proc(), e.Goroutine())
+	fmt.Fprintf(&sb, " %s Time=%d", e.Kind(), e.Time())
+	// Kind-specific fields.
+	switch kind := e.Kind(); kind {
+	case EventMetric:
+		m := e.Metric()
+		fmt.Fprintf(&sb, " Name=%q Value=%s", m.Name, valueAsString(m.Value))
+	case EventLabel:
+		l := e.Label()
+		fmt.Fprintf(&sb, " Label=%q Resource=%s", l.Label, l.Resource)
+	case EventRangeBegin, EventRangeActive, EventRangeEnd:
+		r := e.Range()
+		fmt.Fprintf(&sb, " Name=%q Scope=%s", r.Name, r.Scope)
+		if kind == EventRangeEnd {
+			fmt.Fprintf(&sb, " Attributes=[")
+			for i, attr := range e.RangeAttributes() {
+				if i != 0 {
+					fmt.Fprintf(&sb, " ")
+				}
+				fmt.Fprintf(&sb, "%q=%s", attr.Name, valueAsString(attr.Value))
+			}
+			fmt.Fprintf(&sb, "]")
+		}
+	case EventTaskBegin, EventTaskEnd:
+		t := e.Task()
+		fmt.Fprintf(&sb, " ID=%d Parent=%d Type=%q", t.ID, t.Parent, t.Type)
+	case EventRegionBegin, EventRegionEnd:
+		r := e.Region()
+		fmt.Fprintf(&sb, " Task=%d Type=%q", r.Task, r.Type)
+	case EventLog:
+		l := e.Log()
+		fmt.Fprintf(&sb, " Task=%d Category=%q Message=%q", l.Task, l.Category, l.Message)
+	case EventStateTransition:
+		s := e.StateTransition()
+		fmt.Fprintf(&sb, " Resource=%s Reason=%q", s.Resource, s.Reason)
+		switch s.Resource.Kind {
+		case ResourceGoroutine:
+			id := s.Resource.Goroutine()
+			old, new := s.Goroutine()
+			fmt.Fprintf(&sb, " GoID=%d %s->%s", id, old, new)
+		case ResourceProc:
+			id := s.Resource.Proc()
+			old, new := s.Proc()
+			fmt.Fprintf(&sb, " ProcID=%d %s->%s", id, old, new)
+		}
+		if s.Stack != NoStack {
+			fmt.Fprintln(&sb)
+			fmt.Fprintln(&sb, "TransitionStack=")
+			s.Stack.Frames(func(f StackFrame) bool {
+				fmt.Fprintf(&sb, "\t%s @ 0x%x\n", f.Func, f.PC)
+				fmt.Fprintf(&sb, "\t\t%s:%d\n", f.File, f.Line)
+				return true
+			})
+		}
+	}
+	if stk := e.Stack(); stk != NoStack {
+		fmt.Fprintln(&sb)
+		fmt.Fprintln(&sb, "Stack=")
+		stk.Frames(func(f StackFrame) bool {
+			fmt.Fprintf(&sb, "\t%s @ 0x%x\n", f.Func, f.PC)
+			fmt.Fprintf(&sb, "\t\t%s:%d\n", f.File, f.Line)
+			return true
+		})
+	}
+	return sb.String()
+}
+
+// validateTableIDs checks to make sure lookups in e.table
+// will work.
+func (e Event) validateTableIDs() error {
+	if e.base.typ == evSync {
+		return nil
+	}
+	spec := go122.Specs()[e.base.typ]
+
+	// Check stacks.
+	for _, i := range spec.StackIDs {
+		id := stackID(e.base.args[i-1])
+		_, ok := e.table.stacks.get(id)
+		if !ok {
+			return fmt.Errorf("found invalid stack ID %d for event %s", id, spec.Name)
+		}
+	}
+	// N.B. Strings referenced by stack frames are validated
+	// early on, when reading the stacks in to begin with.
+
+	// Check strings.
+	for _, i := range spec.StringIDs {
+		id := stringID(e.base.args[i-1])
+		_, ok := e.table.strings.get(id)
+		if !ok {
+			return fmt.Errorf("found invalid string ID %d for event %s", id, spec.Name)
+		}
+	}
+	return nil
+}
+
+func syncEvent(table *evTable, ts Time) Event {
+	return Event{
+		table: table,
+		ctx: schedCtx{
+			G: NoGoroutine,
+			P: NoProc,
+			M: NoThread,
+		},
+		base: baseEvent{
+			typ:  evSync,
+			time: ts,
+		},
+	}
+}
diff --git a/trace/event_test.go b/trace/event_test.go
new file mode 100644
index 0000000..453c485
--- /dev/null
+++ b/trace/event_test.go
@@ -0,0 +1,47 @@
+// Copyright 2023 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.
+
+// Code generated by "gen.bash" from internal/trace/v2; DO NOT EDIT.
+
+//go:build go1.21
+
+package trace
+
+import "testing"
+
+func TestPanicEvent(t *testing.T) {
+	// Use a sync event for this because it doesn't have any extra metadata.
+	ev := syncEvent(nil, 0)
+
+	mustPanic(t, func() {
+		_ = ev.Range()
+	})
+	mustPanic(t, func() {
+		_ = ev.Metric()
+	})
+	mustPanic(t, func() {
+		_ = ev.Log()
+	})
+	mustPanic(t, func() {
+		_ = ev.Task()
+	})
+	mustPanic(t, func() {
+		_ = ev.Region()
+	})
+	mustPanic(t, func() {
+		_ = ev.Label()
+	})
+	mustPanic(t, func() {
+		_ = ev.RangeAttributes()
+	})
+}
+
+func mustPanic(t *testing.T, f func()) {
+	defer func() {
+		if r := recover(); r == nil {
+			t.Fatal("failed to panic")
+		}
+	}()
+	f()
+}
diff --git a/trace/generation.go b/trace/generation.go
new file mode 100644
index 0000000..9364b43
--- /dev/null
+++ b/trace/generation.go
@@ -0,0 +1,403 @@
+// Copyright 2023 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.
+
+// Code generated by "gen.bash" from internal/trace/v2; DO NOT EDIT.
+
+//go:build go1.21
+
+package trace
+
+import (
+	"bufio"
+	"bytes"
+	"cmp"
+	"encoding/binary"
+	"fmt"
+	"io"
+	"slices"
+	"strings"
+
+	"golang.org/x/exp/trace/internal/event"
+	"golang.org/x/exp/trace/internal/event/go122"
+)
+
+// generation contains all the trace data for a single
+// trace generation. It is purely data: it does not
+// track any parse state nor does it contain a cursor
+// into the generation.
+type generation struct {
+	gen        uint64
+	batches    map[ThreadID][]batch
+	cpuSamples []cpuSample
+	*evTable
+}
+
+// spilledBatch represents a batch that was read out for the next generation,
+// while reading the previous one. It's passed on when parsing the next
+// generation.
+type spilledBatch struct {
+	gen uint64
+	*batch
+}
+
+// readGeneration buffers and decodes the structural elements of a trace generation
+// out of r. spill is the first batch of the new generation (already buffered and
+// parsed from reading the last generation). Returns the generation and the first
+// batch read of the next generation, if any.
+func readGeneration(r *bufio.Reader, spill *spilledBatch) (*generation, *spilledBatch, error) {
+	g := &generation{
+		evTable: new(evTable),
+		batches: make(map[ThreadID][]batch),
+	}
+	// Process the spilled batch.
+	if spill != nil {
+		g.gen = spill.gen
+		if err := processBatch(g, *spill.batch); err != nil {
+			return nil, nil, err
+		}
+		spill = nil
+	}
+	// Read batches one at a time until we either hit EOF or
+	// the next generation.
+	for {
+		b, gen, err := readBatch(r)
+		if err == io.EOF {
+			break
+		}
+		if err != nil {
+			return nil, nil, err
+		}
+		if gen == 0 {
+			// 0 is a sentinel used by the runtime, so we'll never see it.
+			return nil, nil, fmt.Errorf("invalid generation number %d", gen)
+		}
+		if g.gen == 0 {
+			// Initialize gen.
+			g.gen = gen
+		}
+		if gen == g.gen+1 { // TODO: advance this the same way the runtime does.
+			spill = &spilledBatch{gen: gen, batch: &b}
+			break
+		}
+		if gen != g.gen {
+			// N.B. Fail as fast as possible if we see this. At first it
+			// may seem prudent to be fault-tolerant and assume we have a
+			// complete generation, parsing and returning that first. However,
+			// if the batches are mixed across generations then it's likely
+			// we won't be able to parse this generation correctly at all.
+			// Rather than return a cryptic error in that case, indicate the
+			// problem as soon as we see it.
+			return nil, nil, fmt.Errorf("generations out of order")
+		}
+		if err := processBatch(g, b); err != nil {
+			return nil, nil, err
+		}
+	}
+
+	// Check some invariants.
+	if g.freq == 0 {
+		return nil, nil, fmt.Errorf("no frequency event found")
+	}
+	// N.B. Trust that the batch order is correct. We can't validate the batch order
+	// by timestamp because the timestamps could just be plain wrong. The source of
+	// truth is the order things appear in the trace and the partial order sequence
+	// numbers on certain events. If it turns out the batch order is actually incorrect
+	// we'll very likely fail to advance a partial order from the frontier.
+
+	// Compactify stacks and strings for better lookup performance later.
+	g.stacks.compactify()
+	g.strings.compactify()
+
+	// Validate stacks.
+	if err := validateStackStrings(&g.stacks, &g.strings); err != nil {
+		return nil, nil, err
+	}
+
+	// Fix up the CPU sample timestamps, now that we have freq.
+	for i := range g.cpuSamples {
+		s := &g.cpuSamples[i]
+		s.time = g.freq.mul(timestamp(s.time))
+	}
+	// Sort the CPU samples.
+	slices.SortFunc(g.cpuSamples, func(a, b cpuSample) int {
+		return cmp.Compare(a.time, b.time)
+	})
+	return g, spill, nil
+}
+
+// processBatch adds the batch to the generation.
+func processBatch(g *generation, b batch) error {
+	switch {
+	case b.isStringsBatch():
+		if err := addStrings(&g.strings, b); err != nil {
+			return err
+		}
+	case b.isStacksBatch():
+		if err := addStacks(&g.stacks, b); err != nil {
+			return err
+		}
+	case b.isCPUSamplesBatch():
+		samples, err := addCPUSamples(g.cpuSamples, b)
+		if err != nil {
+			return err
+		}
+		g.cpuSamples = samples
+	case b.isFreqBatch():
+		freq, err := parseFreq(b)
+		if err != nil {
+			return err
+		}
+		if g.freq != 0 {
+			return fmt.Errorf("found multiple frequency events")
+		}
+		g.freq = freq
+	default:
+		g.batches[b.m] = append(g.batches[b.m], b)
+	}
+	return nil
+}
+
+// validateStackStrings makes sure all the string references in
+// the stack table are present in the string table.
+func validateStackStrings(stacks *dataTable[stackID, stack], strings *dataTable[stringID, string]) error {
+	var err error
+	stacks.forEach(func(id stackID, stk stack) bool {
+		for _, frame := range stk.frames {
+			_, ok := strings.get(frame.funcID)
+			if !ok {
+				err = fmt.Errorf("found invalid func string ID %d for stack %d", frame.funcID, id)
+				return false
+			}
+			_, ok = strings.get(frame.fileID)
+			if !ok {
+				err = fmt.Errorf("found invalid file string ID %d for stack %d", frame.fileID, id)
+				return false
+			}
+		}
+		return true
+	})
+	return err
+}
+
+// addStrings takes a batch whose first byte is an EvStrings event
+// (indicating that the batch contains only strings) and adds each
+// string contained therein to the provided strings map.
+func addStrings(stringTable *dataTable[stringID, string], b batch) error {
+	if !b.isStringsBatch() {
+		return fmt.Errorf("internal error: addStrings called on non-string batch")
+	}
+	r := bytes.NewReader(b.data)
+	hdr, err := r.ReadByte() // Consume the EvStrings byte.
+	if err != nil || event.Type(hdr) != go122.EvStrings {
+		return fmt.Errorf("missing strings batch header")
+	}
+
+	var sb strings.Builder
+	for r.Len() != 0 {
+		// Read the header.
+		ev, err := r.ReadByte()
+		if err != nil {
+			return err
+		}
+		if event.Type(ev) != go122.EvString {
+			return fmt.Errorf("expected string event, got %d", ev)
+		}
+
+		// Read the string's ID.
+		id, err := binary.ReadUvarint(r)
+		if err != nil {
+			return err
+		}
+
+		// Read the string's length.
+		len, err := binary.ReadUvarint(r)
+		if err != nil {
+			return err
+		}
+		if len > go122.MaxStringSize {
+			return fmt.Errorf("invalid string size %d, maximum is %d", len, go122.MaxStringSize)
+		}
+
+		// Copy out the string.
+		n, err := io.CopyN(&sb, r, int64(len))
+		if n != int64(len) {
+			return fmt.Errorf("failed to read full string: read %d but wanted %d", n, len)
+		}
+		if err != nil {
+			return fmt.Errorf("copying string data: %w", err)
+		}
+
+		// Add the string to the map.
+		s := sb.String()
+		sb.Reset()
+		if err := stringTable.insert(stringID(id), s); err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+// addStacks takes a batch whose first byte is an EvStacks event
+// (indicating that the batch contains only stacks) and adds each
+// string contained therein to the provided stacks map.
+func addStacks(stackTable *dataTable[stackID, stack], b batch) error {
+	if !b.isStacksBatch() {
+		return fmt.Errorf("internal error: addStacks called on non-stacks batch")
+	}
+	r := bytes.NewReader(b.data)
+	hdr, err := r.ReadByte() // Consume the EvStacks byte.
+	if err != nil || event.Type(hdr) != go122.EvStacks {
+		return fmt.Errorf("missing stacks batch header")
+	}
+
+	for r.Len() != 0 {
+		// Read the header.
+		ev, err := r.ReadByte()
+		if err != nil {
+			return err
+		}
+		if event.Type(ev) != go122.EvStack {
+			return fmt.Errorf("expected stack event, got %d", ev)
+		}
+
+		// Read the stack's ID.
+		id, err := binary.ReadUvarint(r)
+		if err != nil {
+			return err
+		}
+
+		// Read how many frames are in each stack.
+		nFrames, err := binary.ReadUvarint(r)
+		if err != nil {
+			return err
+		}
+		if nFrames > go122.MaxFramesPerStack {
+			return fmt.Errorf("invalid stack size %d, maximum is %d", nFrames, go122.MaxFramesPerStack)
+		}
+
+		// Each frame consists of 4 fields: pc, funcID (string), fileID (string), line.
+		frames := make([]frame, 0, nFrames)
+		for i := uint64(0); i < nFrames; i++ {
+			// Read the frame data.
+			pc, err := binary.ReadUvarint(r)
+			if err != nil {
+				return fmt.Errorf("reading frame %d's PC for stack %d: %w", i+1, id, err)
+			}
+			funcID, err := binary.ReadUvarint(r)
+			if err != nil {
+				return fmt.Errorf("reading frame %d's funcID for stack %d: %w", i+1, id, err)
+			}
+			fileID, err := binary.ReadUvarint(r)
+			if err != nil {
+				return fmt.Errorf("reading frame %d's fileID for stack %d: %w", i+1, id, err)
+			}
+			line, err := binary.ReadUvarint(r)
+			if err != nil {
+				return fmt.Errorf("reading frame %d's line for stack %d: %w", i+1, id, err)
+			}
+			frames = append(frames, frame{
+				pc:     pc,
+				funcID: stringID(funcID),
+				fileID: stringID(fileID),
+				line:   line,
+			})
+		}
+
+		// Add the stack to the map.
+		if err := stackTable.insert(stackID(id), stack{frames: frames}); err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+// addCPUSamples takes a batch whose first byte is an EvCPUSamples event
+// (indicating that the batch contains only CPU samples) and adds each
+// sample contained therein to the provided samples list.
+func addCPUSamples(samples []cpuSample, b batch) ([]cpuSample, error) {
+	if !b.isCPUSamplesBatch() {
+		return nil, fmt.Errorf("internal error: addStrings called on non-string batch")
+	}
+	r := bytes.NewReader(b.data)
+	hdr, err := r.ReadByte() // Consume the EvCPUSamples byte.
+	if err != nil || event.Type(hdr) != go122.EvCPUSamples {
+		return nil, fmt.Errorf("missing CPU samples batch header")
+	}
+
+	for r.Len() != 0 {
+		// Read the header.
+		ev, err := r.ReadByte()
+		if err != nil {
+			return nil, err
+		}
+		if event.Type(ev) != go122.EvCPUSample {
+			return nil, fmt.Errorf("expected CPU sample event, got %d", ev)
+		}
+
+		// Read the sample's timestamp.
+		ts, err := binary.ReadUvarint(r)
+		if err != nil {
+			return nil, err
+		}
+
+		// Read the sample's M.
+		m, err := binary.ReadUvarint(r)
+		if err != nil {
+			return nil, err
+		}
+		mid := ThreadID(m)
+
+		// Read the sample's P.
+		p, err := binary.ReadUvarint(r)
+		if err != nil {
+			return nil, err
+		}
+		pid := ProcID(p)
+
+		// Read the sample's G.
+		g, err := binary.ReadUvarint(r)
+		if err != nil {
+			return nil, err
+		}
+		goid := GoID(g)
+		if g == 0 {
+			goid = NoGoroutine
+		}
+
+		// Read the sample's stack.
+		s, err := binary.ReadUvarint(r)
+		if err != nil {
+			return nil, err
+		}
+
+		// Add the sample to the slice.
+		samples = append(samples, cpuSample{
+			schedCtx: schedCtx{
+				M: mid,
+				P: pid,
+				G: goid,
+			},
+			time:  Time(ts), // N.B. this is really a "timestamp," not a Time.
+			stack: stackID(s),
+		})
+	}
+	return samples, nil
+}
+
+// parseFreq parses out a lone EvFrequency from a batch.
+func parseFreq(b batch) (frequency, error) {
+	if !b.isFreqBatch() {
+		return 0, fmt.Errorf("internal error: parseFreq called on non-frequency batch")
+	}
+	r := bytes.NewReader(b.data)
+	r.ReadByte() // Consume the EvFrequency byte.
+
+	// Read the frequency. It'll come out as timestamp units per second.
+	f, err := binary.ReadUvarint(r)
+	if err != nil {
+		return 0, err
+	}
+	// Convert to nanoseconds per timestamp unit.
+	return frequency(1.0 / (float64(f) / 1e9)), nil
+}
diff --git a/trace/internal/event/event.go b/trace/internal/event/event.go
new file mode 100644
index 0000000..4b5da1f
--- /dev/null
+++ b/trace/internal/event/event.go
@@ -0,0 +1,93 @@
+// Copyright 2023 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.
+
+// Code generated by "gen.bash" from internal/trace/v2; DO NOT EDIT.
+
+//go:build go1.21
+
+package event
+
+// Type is the common in-memory representation of the low-leve
+type Type uint8
+
+// Spec is a specification for a trace event. It contains sufficient information
+// to perform basic parsing of any trace event for any version of Go.
+type Spec struct {
+	// Name is the human-readable name of the trace event.
+	Name string
+
+	// Args contains the names of each trace event's argument.
+	// Its length determines the number of arguments an event has.
+	//
+	// Argument names follow a certain structure and this structure
+	// is relied on by the testing framework to type-check arguments.
+	// The structure is is:
+	//
+	//     (?P<name>[A-Za-z]+_)?(?P<type>[A-Za-z]+)
+	//
+	// In sum, it's an optional name followed by a type. If the name
+	// is present, it is separated from the type with an underscore.
+	// The valid argument types and the Go types they map to are listed
+	// in the ArgTypes variable.
+	Args []string
+
+	// StartEv indicates the event type of the corresponding "start"
+	// event, if this event is an "end," for a pair of events that
+	// represent a time range.
+	StartEv Type
+
+	// IsTimedEvent indicates whether this is an event that both
+	// appears in the main event stream and is surfaced to the
+	// trace reader.
+	//
+	// Events that are not "timed" are considered "structural"
+	// since they either need significant reinterpretation or
+	// otherwise aren't actually surfaced by the trace reader.
+	IsTimedEvent bool
+
+	// HasData is true if the event has trailer consisting of a
+	// varint length followed by unencoded bytes of some data.
+	HasData bool
+
+	// StringIDs indicates which of the arguments are string IDs.
+	StringIDs []int
+
+	// StackIDs indicates which of the arguments are stack IDs.
+	//
+	// The list is not sorted. The first index always refers to
+	// the main stack for the current execution context of the event.
+	StackIDs []int
+
+	// IsStack indicates that the event represents a complete
+	// stack trace. Specifically, it means that after the arguments
+	// there's a varint length, followed by 4*length varints. Each
+	// group of 4 represents the PC, file ID, func ID, and line number
+	// in that order.
+	IsStack bool
+}
+
+// ArgTypes is a list of valid argument types for use in Args.
+//
+// See the documentation of Args for more details.
+var ArgTypes = [...]string{
+	"seq",     // sequence number
+	"pstatus", // P status
+	"gstatus", // G status
+	"g",       // trace.GoID
+	"m",       // trace.ThreadID
+	"p",       // trace.ProcID
+	"string",  // string ID
+	"stack",   // stack ID
+	"value",   // uint64
+	"task",    // trace.TaskID
+}
+
+// Names is a helper that produces a mapping of event names to event types.
+func Names(specs []Spec) map[string]Type {
+	nameToType := make(map[string]Type)
+	for i, spec := range specs {
+		nameToType[spec.Name] = Type(byte(i))
+	}
+	return nameToType
+}
diff --git a/trace/internal/event/go122/event.go b/trace/internal/event/go122/event.go
new file mode 100644
index 0000000..9d0977e
--- /dev/null
+++ b/trace/internal/event/go122/event.go
@@ -0,0 +1,392 @@
+// Copyright 2023 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.
+
+// Code generated by "gen.bash" from internal/trace/v2; DO NOT EDIT.
+
+//go:build go1.21
+
+package go122
+
+import (
+	"fmt"
+	"golang.org/x/exp/trace/internal/event"
+)
+
+const (
+	EvNone event.Type = iota // unused
+
+	// Structural events.
+	EvEventBatch // start of per-M batch of events [generation, M ID, timestamp, batch length]
+	EvStacks     // start of a section of the stack table [...EvStack]
+	EvStack      // stack table entry [ID, ...{PC, func string ID, file string ID, line #}]
+	EvStrings    // start of a section of the string dictionary [...EvString]
+	EvString     // string dictionary entry [ID, length, string]
+	EvCPUSamples // start of a section of CPU samples [...EvCPUSample]
+	EvCPUSample  // CPU profiling sample [timestamp, M ID, P ID, goroutine ID, stack ID]
+	EvFrequency  // timestamp units per sec [freq]
+
+	// Procs.
+	EvProcsChange // current value of GOMAXPROCS [timestamp, GOMAXPROCS, stack ID]
+	EvProcStart   // start of P [timestamp, P ID, P seq]
+	EvProcStop    // stop of P [timestamp]
+	EvProcSteal   // P was stolen [timestamp, P ID, P seq, M ID]
+	EvProcStatus  // P status at the start of a generation [timestamp, P ID, status]
+
+	// Goroutines.
+	EvGoCreate            // goroutine creation [timestamp, new goroutine ID, new stack ID, stack ID]
+	EvGoCreateSyscall     // goroutine appears in syscall (cgo callback) [timestamp, new goroutine ID]
+	EvGoStart             // goroutine starts running [timestamp, goroutine ID, goroutine seq]
+	EvGoDestroy           // goroutine ends [timestamp]
+	EvGoDestroySyscall    // goroutine ends in syscall (cgo callback) [timestamp]
+	EvGoStop              // goroutine yields its time, but is runnable [timestamp, reason, stack ID]
+	EvGoBlock             // goroutine blocks [timestamp, reason, stack ID]
+	EvGoUnblock           // goroutine is unblocked [timestamp, goroutine ID, goroutine seq, stack ID]
+	EvGoSyscallBegin      // syscall enter [timestamp, P seq, stack ID]
+	EvGoSyscallEnd        // syscall exit [timestamp]
+	EvGoSyscallEndBlocked // syscall exit and it blocked at some point [timestamp]
+	EvGoStatus            // goroutine status at the start of a generation [timestamp, goroutine ID, status]
+
+	// STW.
+	EvSTWBegin // STW start [timestamp, kind]
+	EvSTWEnd   // STW done [timestamp]
+
+	// GC events.
+	EvGCActive           // GC active [timestamp, seq]
+	EvGCBegin            // GC start [timestamp, seq, stack ID]
+	EvGCEnd              // GC done [timestamp, seq]
+	EvGCSweepActive      // GC sweep active [timestamp, P ID]
+	EvGCSweepBegin       // GC sweep start [timestamp, stack ID]
+	EvGCSweepEnd         // GC sweep done [timestamp, swept bytes, reclaimed bytes]
+	EvGCMarkAssistActive // GC mark assist active [timestamp, goroutine ID]
+	EvGCMarkAssistBegin  // GC mark assist start [timestamp, stack ID]
+	EvGCMarkAssistEnd    // GC mark assist done [timestamp]
+	EvHeapAlloc          // gcController.heapLive change [timestamp, heap alloc in bytes]
+	EvHeapGoal           // gcController.heapGoal() change [timestamp, heap goal in bytes]
+
+	// Annotations.
+	EvGoLabel         // apply string label to current running goroutine [timestamp, label string ID]
+	EvUserTaskBegin   // trace.NewTask [timestamp, internal task ID, internal parent task ID, name string ID, stack ID]
+	EvUserTaskEnd     // end of a task [timestamp, internal task ID, stack ID]
+	EvUserRegionBegin // trace.{Start,With}Region [timestamp, internal task ID, name string ID, stack ID]
+	EvUserRegionEnd   // trace.{End,With}Region [timestamp, internal task ID, name string ID, stack ID]
+	EvUserLog         // trace.Log [timestamp, internal task ID, key string ID, stack, value string ID]
+)
+
+// EventString returns the name of a Go 1.22 event.
+func EventString(typ event.Type) string {
+	if int(typ) < len(specs) {
+		return specs[typ].Name
+	}
+	return fmt.Sprintf("Invalid(%d)", typ)
+}
+
+func Specs() []event.Spec {
+	return specs[:]
+}
+
+var specs = [...]event.Spec{
+	// "Structural" Events.
+	EvEventBatch: {
+		Name: "EventBatch",
+		Args: []string{"gen", "m", "time", "size"},
+	},
+	EvStacks: {
+		Name: "Stacks",
+	},
+	EvStack: {
+		Name:    "Stack",
+		Args:    []string{"id", "nframes"},
+		IsStack: true,
+	},
+	EvStrings: {
+		Name: "Strings",
+	},
+	EvString: {
+		Name:    "String",
+		Args:    []string{"id"},
+		HasData: true,
+	},
+	EvCPUSamples: {
+		Name: "CPUSamples",
+	},
+	EvCPUSample: {
+		Name: "CPUSample",
+		Args: []string{"time", "p", "g", "m", "stack"},
+		// N.B. There's clearly a timestamp here, but these Events
+		// are special in that they don't appear in the regular
+		// M streams.
+	},
+	EvFrequency: {
+		Name: "Frequency",
+		Args: []string{"freq"},
+	},
+
+	// "Timed" Events.
+	EvProcsChange: {
+		Name:         "ProcsChange",
+		Args:         []string{"dt", "procs_value", "stack"},
+		IsTimedEvent: true,
+		StackIDs:     []int{2},
+	},
+	EvProcStart: {
+		Name:         "ProcStart",
+		Args:         []string{"dt", "p", "p_seq"},
+		IsTimedEvent: true,
+	},
+	EvProcStop: {
+		Name:         "ProcStop",
+		Args:         []string{"dt"},
+		IsTimedEvent: true,
+	},
+	EvProcSteal: {
+		Name:         "ProcSteal",
+		Args:         []string{"dt", "p", "p_seq", "m"},
+		IsTimedEvent: true,
+	},
+	EvProcStatus: {
+		Name:         "ProcStatus",
+		Args:         []string{"dt", "p", "pstatus"},
+		IsTimedEvent: true,
+	},
+	EvGoCreate: {
+		Name:         "GoCreate",
+		Args:         []string{"dt", "new_g", "new_stack", "stack"},
+		IsTimedEvent: true,
+		StackIDs:     []int{3, 2},
+	},
+	EvGoCreateSyscall: {
+		Name:         "GoCreateSyscall",
+		Args:         []string{"dt", "new_g"},
+		IsTimedEvent: true,
+	},
+	EvGoStart: {
+		Name:         "GoStart",
+		Args:         []string{"dt", "g", "g_seq"},
+		IsTimedEvent: true,
+	},
+	EvGoDestroy: {
+		Name:         "GoDestroy",
+		Args:         []string{"dt"},
+		IsTimedEvent: true,
+	},
+	EvGoDestroySyscall: {
+		Name:         "GoDestroySyscall",
+		Args:         []string{"dt"},
+		IsTimedEvent: true,
+	},
+	EvGoStop: {
+		Name:         "GoStop",
+		Args:         []string{"dt", "reason_string", "stack"},
+		IsTimedEvent: true,
+		StackIDs:     []int{2},
+		StringIDs:    []int{1},
+	},
+	EvGoBlock: {
+		Name:         "GoBlock",
+		Args:         []string{"dt", "reason_string", "stack"},
+		IsTimedEvent: true,
+		StackIDs:     []int{2},
+		StringIDs:    []int{1},
+	},
+	EvGoUnblock: {
+		Name:         "GoUnblock",
+		Args:         []string{"dt", "g", "g_seq", "stack"},
+		IsTimedEvent: true,
+		StackIDs:     []int{3},
+	},
+	EvGoSyscallBegin: {
+		Name:         "GoSyscallBegin",
+		Args:         []string{"dt", "p_seq", "stack"},
+		IsTimedEvent: true,
+		StackIDs:     []int{2},
+	},
+	EvGoSyscallEnd: {
+		Name:         "GoSyscallEnd",
+		Args:         []string{"dt"},
+		StartEv:      EvGoSyscallBegin,
+		IsTimedEvent: true,
+	},
+	EvGoSyscallEndBlocked: {
+		Name:         "GoSyscallEndBlocked",
+		Args:         []string{"dt"},
+		StartEv:      EvGoSyscallBegin,
+		IsTimedEvent: true,
+	},
+	EvGoStatus: {
+		Name:         "GoStatus",
+		Args:         []string{"dt", "g", "m", "gstatus"},
+		IsTimedEvent: true,
+	},
+	EvSTWBegin: {
+		Name:         "STWBegin",
+		Args:         []string{"dt", "kind_string", "stack"},
+		IsTimedEvent: true,
+		StackIDs:     []int{2},
+		StringIDs:    []int{1},
+	},
+	EvSTWEnd: {
+		Name:         "STWEnd",
+		Args:         []string{"dt"},
+		StartEv:      EvSTWBegin,
+		IsTimedEvent: true,
+	},
+	EvGCActive: {
+		Name:         "GCActive",
+		Args:         []string{"dt", "gc_seq"},
+		IsTimedEvent: true,
+		StartEv:      EvGCBegin,
+	},
+	EvGCBegin: {
+		Name:         "GCBegin",
+		Args:         []string{"dt", "gc_seq", "stack"},
+		IsTimedEvent: true,
+		StackIDs:     []int{2},
+	},
+	EvGCEnd: {
+		Name:         "GCEnd",
+		Args:         []string{"dt", "gc_seq"},
+		StartEv:      EvGCBegin,
+		IsTimedEvent: true,
+	},
+	EvGCSweepActive: {
+		Name:         "GCSweepActive",
+		Args:         []string{"dt", "p"},
+		StartEv:      EvGCSweepBegin,
+		IsTimedEvent: true,
+	},
+	EvGCSweepBegin: {
+		Name:         "GCSweepBegin",
+		Args:         []string{"dt", "stack"},
+		IsTimedEvent: true,
+		StackIDs:     []int{1},
+	},
+	EvGCSweepEnd: {
+		Name:         "GCSweepEnd",
+		Args:         []string{"dt", "swept_value", "reclaimed_value"},
+		StartEv:      EvGCSweepBegin,
+		IsTimedEvent: true,
+	},
+	EvGCMarkAssistActive: {
+		Name:         "GCMarkAssistActive",
+		Args:         []string{"dt", "g"},
+		StartEv:      EvGCMarkAssistBegin,
+		IsTimedEvent: true,
+	},
+	EvGCMarkAssistBegin: {
+		Name:         "GCMarkAssistBegin",
+		Args:         []string{"dt", "stack"},
+		IsTimedEvent: true,
+		StackIDs:     []int{1},
+	},
+	EvGCMarkAssistEnd: {
+		Name:         "GCMarkAssistEnd",
+		Args:         []string{"dt"},
+		StartEv:      EvGCMarkAssistBegin,
+		IsTimedEvent: true,
+	},
+	EvHeapAlloc: {
+		Name:         "HeapAlloc",
+		Args:         []string{"dt", "heapalloc_value"},
+		IsTimedEvent: true,
+	},
+	EvHeapGoal: {
+		Name:         "HeapGoal",
+		Args:         []string{"dt", "heapgoal_value"},
+		IsTimedEvent: true,
+	},
+	EvGoLabel: {
+		Name:         "GoLabel",
+		Args:         []string{"dt", "label_string"},
+		IsTimedEvent: true,
+		StringIDs:    []int{1},
+	},
+	EvUserTaskBegin: {
+		Name:         "UserTaskBegin",
+		Args:         []string{"dt", "task", "parent_task", "name_string", "stack"},
+		IsTimedEvent: true,
+		StackIDs:     []int{4},
+		StringIDs:    []int{3},
+	},
+	EvUserTaskEnd: {
+		Name:         "UserTaskEnd",
+		Args:         []string{"dt", "task", "stack"},
+		IsTimedEvent: true,
+		StackIDs:     []int{2},
+	},
+	EvUserRegionBegin: {
+		Name:         "UserRegionBegin",
+		Args:         []string{"dt", "task", "name_string", "stack"},
+		IsTimedEvent: true,
+		StackIDs:     []int{3},
+		StringIDs:    []int{2},
+	},
+	EvUserRegionEnd: {
+		Name:         "UserRegionEnd",
+		Args:         []string{"dt", "task", "name_string", "stack"},
+		StartEv:      EvUserRegionBegin,
+		IsTimedEvent: true,
+		StackIDs:     []int{3},
+		StringIDs:    []int{2},
+	},
+	EvUserLog: {
+		Name:         "UserLog",
+		Args:         []string{"dt", "task", "key_string", "value_string", "stack"},
+		IsTimedEvent: true,
+		StackIDs:     []int{4},
+		StringIDs:    []int{2, 3},
+	},
+}
+
+type GoStatus uint8
+
+const (
+	GoBad GoStatus = iota
+	GoRunnable
+	GoRunning
+	GoSyscall
+	GoWaiting
+)
+
+func (s GoStatus) String() string {
+	switch s {
+	case GoRunnable:
+		return "Runnable"
+	case GoRunning:
+		return "Running"
+	case GoSyscall:
+		return "Syscall"
+	case GoWaiting:
+		return "Waiting"
+	}
+	return "Bad"
+}
+
+type ProcStatus uint8
+
+const (
+	ProcBad ProcStatus = iota
+	ProcRunning
+	ProcIdle
+	ProcSyscall
+	ProcSyscallAbandoned
+)
+
+func (s ProcStatus) String() string {
+	switch s {
+	case ProcRunning:
+		return "Running"
+	case ProcIdle:
+		return "Idle"
+	case ProcSyscall:
+		return "Syscall"
+	}
+	return "Bad"
+}
+
+const (
+	// Various format-specific constants.
+	MaxBatchSize      = 64 << 10
+	MaxFramesPerStack = 128
+	MaxStringSize     = 1 << 10
+)
diff --git a/trace/internal/event/requirements.go b/trace/internal/event/requirements.go
new file mode 100644
index 0000000..4f41171
--- /dev/null
+++ b/trace/internal/event/requirements.go
@@ -0,0 +1,30 @@
+// Copyright 2023 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.
+
+// Code generated by "gen.bash" from internal/trace/v2; DO NOT EDIT.
+
+//go:build go1.21
+
+package event
+
+// SchedReqs is a set of constraints on what the scheduling
+// context must look like.
+type SchedReqs struct {
+	Thread    Constraint
+	Proc      Constraint
+	Goroutine Constraint
+}
+
+// Constraint represents a various presence requirements.
+type Constraint uint8
+
+const (
+	MustNotHave Constraint = iota
+	MayHave
+	MustHave
+)
+
+// UserGoReqs is a common requirement among events that are running
+// or are close to running user code.
+var UserGoReqs = SchedReqs{Thread: MustHave, Proc: MustHave, Goroutine: MustHave}
diff --git a/trace/internal/raw/doc.go b/trace/internal/raw/doc.go
new file mode 100644
index 0000000..149c606
--- /dev/null
+++ b/trace/internal/raw/doc.go
@@ -0,0 +1,70 @@
+// Copyright 2023 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.
+
+// Code generated by "gen.bash" from internal/trace/v2; DO NOT EDIT.
+
+//go:build go1.21
+
+/*
+Package raw provides an interface to interpret and emit Go execution traces.
+It can interpret and emit execution traces in its wire format as well as a
+bespoke but simple text format.
+
+The readers and writers in this package perform no validation on or ordering of
+the input, and so are generally unsuitable for analysis. However, they're very
+useful for testing and debugging the tracer in the runtime and more sophisticated
+trace parsers.
+
+# Text format specification
+
+The trace text format produced and consumed by this package is a line-oriented
+format.
+
+The first line in each text trace is the header line.
+
+	Trace Go1.XX
+
+Following that is a series of event lines. Each event begins with an
+event name, followed by zero or more named unsigned integer arguments.
+Names are separated from their integer values by an '=' sign. Names can
+consist of any UTF-8 character except '='.
+
+For example:
+
+	EventName arg1=23 arg2=55 arg3=53
+
+Any amount of whitespace is allowed to separate each token. Whitespace
+is identified via unicode.IsSpace.
+
+Some events have additional data on following lines. There are two such
+special cases.
+
+The first special case consists of events with trailing byte-oriented data.
+The trailer begins on the following line from the event. That line consists
+of a single argument 'data' and a Go-quoted string representing the byte data
+within. Note: an explicit argument for the length is elided, because it's
+just the length of the unquoted string.
+
+For example:
+
+	String id=5
+		data="hello world\x00"
+
+These events are identified in their spec by the HasData flag.
+
+The second special case consists of stack events. These events are identified
+by the IsStack flag. These events also have a trailing unsigned integer argument
+describing the number of stack frame descriptors that follow. Each stack frame
+descriptor is on its own line following the event, consisting of four signed
+integer arguments: the PC, an integer describing the function name, an integer
+describing the file name, and the line number in that file that function was at
+at the time the stack trace was taken.
+
+For example:
+
+	Stack id=5 n=2
+		pc=1241251 func=3 file=6 line=124
+		pc=7534345 func=6 file=3 line=64
+*/
+package raw
diff --git a/trace/internal/raw/event.go b/trace/internal/raw/event.go
new file mode 100644
index 0000000..b7db017
--- /dev/null
+++ b/trace/internal/raw/event.go
@@ -0,0 +1,64 @@
+// Copyright 2023 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.
+
+// Code generated by "gen.bash" from internal/trace/v2; DO NOT EDIT.
+
+//go:build go1.21
+
+package raw
+
+import (
+	"strconv"
+	"strings"
+
+	"golang.org/x/exp/trace/internal/event"
+	"golang.org/x/exp/trace/internal/version"
+)
+
+// Event is a simple representation of a trace event.
+//
+// Note that this typically includes much more than just
+// timestamped events, and it also represents parts of the
+// trace format's framing. (But not interpreted.)
+type Event struct {
+	Version version.Version
+	Ev      event.Type
+	Args    []uint64
+	Data    []byte
+}
+
+// String returns the canonical string representation of the event.
+//
+// This format is the same format that is parsed by the TextReader
+// and emitted by the TextWriter.
+func (e *Event) String() string {
+	spec := e.Version.Specs()[e.Ev]
+
+	var s strings.Builder
+	s.WriteString(spec.Name)
+	for i := range spec.Args {
+		s.WriteString(" ")
+		s.WriteString(spec.Args[i])
+		s.WriteString("=")
+		s.WriteString(strconv.FormatUint(e.Args[i], 10))
+	}
+	if spec.IsStack {
+		frames := e.Args[len(spec.Args):]
+		for i := 0; i < len(frames); i++ {
+			if i%4 == 0 {
+				s.WriteString("\n\t")
+			} else {
+				s.WriteString(" ")
+			}
+			s.WriteString(frameFields[i%4])
+			s.WriteString("=")
+			s.WriteString(strconv.FormatUint(frames[i], 10))
+		}
+	}
+	if e.Data != nil {
+		s.WriteString("\n\tdata=")
+		s.WriteString(strconv.Quote(string(e.Data)))
+	}
+	return s.String()
+}
diff --git a/trace/internal/raw/reader.go b/trace/internal/raw/reader.go
new file mode 100644
index 0000000..bf3ef18
--- /dev/null
+++ b/trace/internal/raw/reader.go
@@ -0,0 +1,114 @@
+// Copyright 2023 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.
+
+// Code generated by "gen.bash" from internal/trace/v2; DO NOT EDIT.
+
+//go:build go1.21
+
+package raw
+
+import (
+	"bufio"
+	"encoding/binary"
+	"fmt"
+	"io"
+
+	"golang.org/x/exp/trace/internal/event"
+	"golang.org/x/exp/trace/internal/version"
+)
+
+// Reader parses trace bytes with only very basic validation
+// into an event stream.
+type Reader struct {
+	r     *bufio.Reader
+	v     version.Version
+	specs []event.Spec
+}
+
+// NewReader creates a new reader for the trace wire format.
+func NewReader(r io.Reader) (*Reader, error) {
+	br := bufio.NewReader(r)
+	v, err := version.ReadHeader(br)
+	if err != nil {
+		return nil, err
+	}
+	return &Reader{r: br, v: v, specs: v.Specs()}, nil
+}
+
+// Version returns the version of the trace that we're reading.
+func (r *Reader) Version() version.Version {
+	return r.v
+}
+
+// ReadEvent reads and returns the next trace event in the byte stream.
+func (r *Reader) ReadEvent() (Event, error) {
+	evb, err := r.r.ReadByte()
+	if err == io.EOF {
+		return Event{}, io.EOF
+	}
+	if err != nil {
+		return Event{}, err
+	}
+	if int(evb) >= len(r.specs) || evb == 0 {
+		return Event{}, fmt.Errorf("invalid event type: %d", evb)
+	}
+	ev := event.Type(evb)
+	spec := r.specs[ev]
+	args, err := r.readArgs(len(spec.Args))
+	if err != nil {
+		return Event{}, err
+	}
+	if spec.IsStack {
+		len := int(args[1])
+		for i := 0; i < len; i++ {
+			// Each stack frame has four args: pc, func ID, file ID, line number.
+			frame, err := r.readArgs(4)
+			if err != nil {
+				return Event{}, err
+			}
+			args = append(args, frame...)
+		}
+	}
+	var data []byte
+	if spec.HasData {
+		data, err = r.readData()
+		if err != nil {
+			return Event{}, err
+		}
+	}
+	return Event{
+		Version: r.v,
+		Ev:      ev,
+		Args:    args,
+		Data:    data,
+	}, nil
+}
+
+func (r *Reader) readArgs(n int) ([]uint64, error) {
+	var args []uint64
+	for i := 0; i < n; i++ {
+		val, err := binary.ReadUvarint(r.r)
+		if err != nil {
+			return nil, err
+		}
+		args = append(args, val)
+	}
+	return args, nil
+}
+
+func (r *Reader) readData() ([]byte, error) {
+	len, err := binary.ReadUvarint(r.r)
+	if err != nil {
+		return nil, err
+	}
+	var data []byte
+	for i := 0; i < int(len); i++ {
+		b, err := r.r.ReadByte()
+		if err != nil {
+			return nil, err
+		}
+		data = append(data, b)
+	}
+	return data, nil
+}
diff --git a/trace/internal/raw/textreader.go b/trace/internal/raw/textreader.go
new file mode 100644
index 0000000..05de34c
--- /dev/null
+++ b/trace/internal/raw/textreader.go
@@ -0,0 +1,221 @@
+// Copyright 2023 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.
+
+// Code generated by "gen.bash" from internal/trace/v2; DO NOT EDIT.
+
+//go:build go1.21
+
+package raw
+
+import (
+	"bufio"
+	"fmt"
+	"io"
+	"strconv"
+	"strings"
+	"unicode"
+
+	"golang.org/x/exp/trace/internal/event"
+	"golang.org/x/exp/trace/internal/version"
+)
+
+// TextReader parses a text format trace with only very basic validation
+// into an event stream.
+type TextReader struct {
+	v     version.Version
+	specs []event.Spec
+	names map[string]event.Type
+	s     *bufio.Scanner
+}
+
+// NewTextReader creates a new reader for the trace text format.
+func NewTextReader(r io.Reader) (*TextReader, error) {
+	tr := &TextReader{s: bufio.NewScanner(r)}
+	line, err := tr.nextLine()
+	if err != nil {
+		return nil, err
+	}
+	trace, line := readToken(line)
+	if trace != "Trace" {
+		return nil, fmt.Errorf("failed to parse header")
+	}
+	gover, line := readToken(line)
+	if !strings.HasPrefix(gover, "Go1.") {
+		return nil, fmt.Errorf("failed to parse header Go version")
+	}
+	rawv, err := strconv.ParseUint(gover[len("Go1."):], 10, 64)
+	if err != nil {
+		return nil, fmt.Errorf("failed to parse header Go version: %v", err)
+	}
+	v := version.Version(rawv)
+	if !v.Valid() {
+		return nil, fmt.Errorf("unknown or unsupported Go version 1.%d", v)
+	}
+	tr.v = v
+	tr.specs = v.Specs()
+	tr.names = event.Names(tr.specs)
+	for _, r := range line {
+		if !unicode.IsSpace(r) {
+			return nil, fmt.Errorf("encountered unexpected non-space at the end of the header: %q", line)
+		}
+	}
+	return tr, nil
+}
+
+// Version returns the version of the trace that we're reading.
+func (r *TextReader) Version() version.Version {
+	return r.v
+}
+
+// ReadEvent reads and returns the next trace event in the text stream.
+func (r *TextReader) ReadEvent() (Event, error) {
+	line, err := r.nextLine()
+	if err != nil {
+		return Event{}, err
+	}
+	evStr, line := readToken(line)
+	ev, ok := r.names[evStr]
+	if !ok {
+		return Event{}, fmt.Errorf("unidentified event: %s", evStr)
+	}
+	spec := r.specs[ev]
+	args, err := readArgs(line, spec.Args)
+	if err != nil {
+		return Event{}, fmt.Errorf("reading args for %s: %v", evStr, err)
+	}
+	if spec.IsStack {
+		len := int(args[1])
+		for i := 0; i < len; i++ {
+			line, err := r.nextLine()
+			if err == io.EOF {
+				return Event{}, fmt.Errorf("unexpected EOF while reading stack: args=%v", args)
+			}
+			if err != nil {
+				return Event{}, err
+			}
+			frame, err := readArgs(line, frameFields)
+			if err != nil {
+				return Event{}, err
+			}
+			args = append(args, frame...)
+		}
+	}
+	var data []byte
+	if spec.HasData {
+		line, err := r.nextLine()
+		if err == io.EOF {
+			return Event{}, fmt.Errorf("unexpected EOF while reading data for %s: args=%v", evStr, args)
+		}
+		if err != nil {
+			return Event{}, err
+		}
+		data, err = readData(line)
+		if err != nil {
+			return Event{}, err
+		}
+	}
+	return Event{
+		Version: r.v,
+		Ev:      ev,
+		Args:    args,
+		Data:    data,
+	}, nil
+}
+
+func (r *TextReader) nextLine() (string, error) {
+	for {
+		if !r.s.Scan() {
+			if err := r.s.Err(); err != nil {
+				return "", err
+			}
+			return "", io.EOF
+		}
+		txt := r.s.Text()
+		tok, _ := readToken(txt)
+		if tok == "" {
+			continue // Empty line or comment.
+		}
+		return txt, nil
+	}
+}
+
+var frameFields = []string{"pc", "func", "file", "line"}
+
+func readArgs(s string, names []string) ([]uint64, error) {
+	var args []uint64
+	for _, name := range names {
+		arg, value, rest, err := readArg(s)
+		if err != nil {
+			return nil, err
+		}
+		if arg != name {
+			return nil, fmt.Errorf("expected argument %q, but got %q", name, arg)
+		}
+		args = append(args, value)
+		s = rest
+	}
+	for _, r := range s {
+		if !unicode.IsSpace(r) {
+			return nil, fmt.Errorf("encountered unexpected non-space at the end of an event: %q", s)
+		}
+	}
+	return args, nil
+}
+
+func readArg(s string) (arg string, value uint64, rest string, err error) {
+	var tok string
+	tok, rest = readToken(s)
+	if len(tok) == 0 {
+		return "", 0, s, fmt.Errorf("no argument")
+	}
+	parts := strings.SplitN(tok, "=", 2)
+	if len(parts) < 2 {
+		return "", 0, s, fmt.Errorf("malformed argument: %q", tok)
+	}
+	arg = parts[0]
+	value, err = strconv.ParseUint(parts[1], 10, 64)
+	if err != nil {
+		return arg, value, s, fmt.Errorf("failed to parse argument value %q for arg %q", parts[1], parts[0])
+	}
+	return
+}
+
+func readToken(s string) (token, rest string) {
+	tkStart := -1
+	for i, r := range s {
+		if r == '#' {
+			return "", ""
+		}
+		if !unicode.IsSpace(r) {
+			tkStart = i
+			break
+		}
+	}
+	if tkStart < 0 {
+		return "", ""
+	}
+	tkEnd := -1
+	for i, r := range s[tkStart:] {
+		if unicode.IsSpace(r) || r == '#' {
+			tkEnd = i + tkStart
+			break
+		}
+	}
+	if tkEnd < 0 {
+		return s[tkStart:], ""
+	}
+	return s[tkStart:tkEnd], s[tkEnd:]
+}
+
+func readData(line string) ([]byte, error) {
+	parts := strings.SplitN(line, "=", 2)
+	if len(parts) < 2 || strings.TrimSpace(parts[0]) != "data" {
+		return nil, fmt.Errorf("malformed data: %q", line)
+	}
+	data, err := strconv.Unquote(strings.TrimSpace(parts[1]))
+	if err != nil {
+		return nil, fmt.Errorf("failed to parse data: %q: %v", line, err)
+	}
+	return []byte(data), nil
+}
diff --git a/trace/internal/raw/textwriter.go b/trace/internal/raw/textwriter.go
new file mode 100644
index 0000000..8eaf359
--- /dev/null
+++ b/trace/internal/raw/textwriter.go
@@ -0,0 +1,43 @@
+// Copyright 2023 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.
+
+// Code generated by "gen.bash" from internal/trace/v2; DO NOT EDIT.
+
+//go:build go1.21
+
+package raw
+
+import (
+	"fmt"
+	"io"
+
+	"golang.org/x/exp/trace/internal/version"
+)
+
+// TextWriter emits the text format of a trace.
+type TextWriter struct {
+	w io.Writer
+	v version.Version
+}
+
+// NewTextWriter creates a new write for the trace text format.
+func NewTextWriter(w io.Writer, v version.Version) (*TextWriter, error) {
+	_, err := fmt.Fprintf(w, "Trace Go1.%d\n", v)
+	if err != nil {
+		return nil, err
+	}
+	return &TextWriter{w: w, v: v}, nil
+}
+
+// WriteEvent writes a single event to the stream.
+func (w *TextWriter) WriteEvent(e Event) error {
+	// Check version.
+	if e.Version != w.v {
+		return fmt.Errorf("mismatched version between writer (go 1.%d) and event (go 1.%d)", w.v, e.Version)
+	}
+
+	// Write event.
+	_, err := fmt.Fprintln(w.w, e.String())
+	return err
+}
diff --git a/trace/internal/raw/writer.go b/trace/internal/raw/writer.go
new file mode 100644
index 0000000..f82b559
--- /dev/null
+++ b/trace/internal/raw/writer.go
@@ -0,0 +1,79 @@
+// Copyright 2023 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.
+
+// Code generated by "gen.bash" from internal/trace/v2; DO NOT EDIT.
+
+//go:build go1.21
+
+package raw
+
+import (
+	"encoding/binary"
+	"fmt"
+	"io"
+
+	"golang.org/x/exp/trace/internal/event"
+	"golang.org/x/exp/trace/internal/version"
+)
+
+// Writer emits the wire format of a trace.
+//
+// It may not produce a byte-for-byte compatible trace from what is
+// produced by the runtime, because it may be missing extra padding
+// in the LEB128 encoding that the runtime adds but isn't necessary
+// when you know the data up-front.
+type Writer struct {
+	w     io.Writer
+	buf   []byte
+	v     version.Version
+	specs []event.Spec
+}
+
+// NewWriter creates a new byte format writer.
+func NewWriter(w io.Writer, v version.Version) (*Writer, error) {
+	_, err := version.WriteHeader(w, v)
+	return &Writer{w: w, v: v, specs: v.Specs()}, err
+}
+
+// WriteEvent writes a single event to the trace wire format stream.
+func (w *Writer) WriteEvent(e Event) error {
+	// Check version.
+	if e.Version != w.v {
+		return fmt.Errorf("mismatched version between writer (go 1.%d) and event (go 1.%d)", w.v, e.Version)
+	}
+
+	// Write event header byte.
+	w.buf = append(w.buf, uint8(e.Ev))
+
+	// Write out all arguments.
+	spec := w.specs[e.Ev]
+	for _, arg := range e.Args[:len(spec.Args)] {
+		w.buf = binary.AppendUvarint(w.buf, arg)
+	}
+	if spec.IsStack {
+		frameArgs := e.Args[len(spec.Args):]
+		for i := 0; i < len(frameArgs); i++ {
+			w.buf = binary.AppendUvarint(w.buf, frameArgs[i])
+		}
+	}
+
+	// Write out the length of the data.
+	if spec.HasData {
+		w.buf = binary.AppendUvarint(w.buf, uint64(len(e.Data)))
+	}
+
+	// Write out varint events.
+	_, err := w.w.Write(w.buf)
+	w.buf = w.buf[:0]
+	if err != nil {
+		return err
+	}
+
+	// Write out data.
+	if spec.HasData {
+		_, err := w.w.Write(e.Data)
+		return err
+	}
+	return nil
+}
diff --git a/trace/internal/testgen/go122/trace.go b/trace/internal/testgen/go122/trace.go
new file mode 100644
index 0000000..d371e0c
--- /dev/null
+++ b/trace/internal/testgen/go122/trace.go
@@ -0,0 +1,405 @@
+// Copyright 2023 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.
+
+// Code generated by "gen.bash" from internal/trace/v2; DO NOT EDIT.
+
+//go:build go1.21
+
+package testkit
+
+import (
+	"bytes"
+	"encoding/binary"
+	"fmt"
+	"os"
+	"regexp"
+	"strings"
+
+	"golang.org/x/exp/trace"
+	"golang.org/x/exp/trace/internal/event"
+	"golang.org/x/exp/trace/internal/event/go122"
+	"golang.org/x/exp/trace/internal/raw"
+	"golang.org/x/exp/trace/internal/version"
+	"golang.org/x/tools/txtar"
+)
+
+func Main(f func(*Trace)) {
+	// Create an output file.
+	out, err := os.Create(os.Args[1])
+	if err != nil {
+		panic(err.Error())
+	}
+	defer out.Close()
+
+	// Create a new trace.
+	trace := NewTrace()
+
+	// Call the generator.
+	f(trace)
+
+	// Write out the generator's state.
+	if _, err := out.Write(trace.Generate()); err != nil {
+		panic(err.Error())
+	}
+}
+
+// Trace represents an execution trace for testing.
+//
+// It does a little bit of work to ensure that the produced trace is valid,
+// just for convenience. It mainly tracks batches and batch sizes (so they're
+// trivially correct), tracks strings and stacks, and makes sure emitted string
+// and stack batches are valid. That last part can be controlled by a few options.
+//
+// Otherwise, it performs no validation on the trace at all.
+type Trace struct {
+	// Trace data state.
+	ver             version.Version
+	names           map[string]event.Type
+	specs           []event.Spec
+	events          []raw.Event
+	gens            []*Generation
+	validTimestamps bool
+
+	// Expectation state.
+	bad      bool
+	badMatch *regexp.Regexp
+}
+
+// NewTrace creates a new trace.
+func NewTrace() *Trace {
+	ver := version.Go122
+	return &Trace{
+		names:           event.Names(ver.Specs()),
+		specs:           ver.Specs(),
+		validTimestamps: true,
+	}
+}
+
+// ExpectFailure writes down that the trace should be broken. The caller
+// must provide a pattern matching the expected error produced by the parser.
+func (t *Trace) ExpectFailure(pattern string) {
+	t.bad = true
+	t.badMatch = regexp.MustCompile(pattern)
+}
+
+// ExpectSuccess writes down that the trace should successfully parse.
+func (t *Trace) ExpectSuccess() {
+	t.bad = false
+}
+
+// RawEvent emits an event into the trace. name must correspond to one
+// of the names in Specs() result for the version that was passed to
+// this trace.
+func (t *Trace) RawEvent(typ event.Type, data []byte, args ...uint64) {
+	t.events = append(t.events, t.createEvent(typ, data, args...))
+}
+
+// DisableTimestamps makes the timestamps for all events generated after
+// this call zero. Raw events are exempted from this because the caller
+// has to pass their own timestamp into those events anyway.
+func (t *Trace) DisableTimestamps() {
+	t.validTimestamps = false
+}
+
+// Generation creates a new trace generation.
+//
+// This provides more structure than Event to allow for more easily
+// creating complex traces that are mostly or completely correct.
+func (t *Trace) Generation(gen uint64) *Generation {
+	g := &Generation{
+		trace:   t,
+		gen:     gen,
+		strings: make(map[string]uint64),
+		stacks:  make(map[stack]uint64),
+	}
+	t.gens = append(t.gens, g)
+	return g
+}
+
+// Generate creates a test file for the trace.
+func (t *Trace) Generate() []byte {
+	// Trace file contents.
+	var buf bytes.Buffer
+	tw, err := raw.NewTextWriter(&buf, version.Go122)
+	if err != nil {
+		panic(err.Error())
+	}
+
+	// Write raw top-level events.
+	for _, e := range t.events {
+		tw.WriteEvent(e)
+	}
+
+	// Write generations.
+	for _, g := range t.gens {
+		g.writeEventsTo(tw)
+	}
+
+	// Expectation file contents.
+	expect := []byte("SUCCESS\n")
+	if t.bad {
+		expect = []byte(fmt.Sprintf("FAILURE %q\n", t.badMatch))
+	}
+
+	// Create the test file's contents.
+	return txtar.Format(&txtar.Archive{
+		Files: []txtar.File{
+			{Name: "expect", Data: expect},
+			{Name: "trace", Data: buf.Bytes()},
+		},
+	})
+}
+
+func (t *Trace) createEvent(ev event.Type, data []byte, args ...uint64) raw.Event {
+	spec := t.specs[ev]
+	if ev != go122.EvStack {
+		if arity := len(spec.Args); len(args) != arity {
+			panic(fmt.Sprintf("expected %d args for %s, got %d", arity, spec.Name, len(args)))
+		}
+	}
+	return raw.Event{
+		Version: version.Go122,
+		Ev:      ev,
+		Args:    args,
+		Data:    data,
+	}
+}
+
+type stack struct {
+	stk [32]trace.StackFrame
+	len int
+}
+
+var (
+	NoString = ""
+	NoStack  = []trace.StackFrame{}
+)
+
+// Generation represents a single generation in the trace.
+type Generation struct {
+	trace   *Trace
+	gen     uint64
+	batches []*Batch
+	strings map[string]uint64
+	stacks  map[stack]uint64
+
+	// Options applied when Trace.Generate is called.
+	ignoreStringBatchSizeLimit bool
+	ignoreStackBatchSizeLimit  bool
+}
+
+// Batch starts a new event batch in the trace data.
+//
+// This is convenience function for generating correct batches.
+func (g *Generation) Batch(thread trace.ThreadID, time Time) *Batch {
+	if !g.trace.validTimestamps {
+		time = 0
+	}
+	b := &Batch{
+		gen:       g,
+		thread:    thread,
+		timestamp: time,
+	}
+	g.batches = append(g.batches, b)
+	return b
+}
+
+// String registers a string with the trace.
+//
+// This is a convenience function for easily adding correct
+// strings to traces.
+func (g *Generation) String(s string) uint64 {
+	if len(s) == 0 {
+		return 0
+	}
+	if id, ok := g.strings[s]; ok {
+		return id
+	}
+	id := uint64(len(g.strings) + 1)
+	g.strings[s] = id
+	return id
+}
+
+// Stack registers a stack with the trace.
+//
+// This is a convenience function for easily adding correct
+// stacks to traces.
+func (g *Generation) Stack(stk []trace.StackFrame) uint64 {
+	if len(stk) == 0 {
+		return 0
+	}
+	if len(stk) > 32 {
+		panic("stack too big for test")
+	}
+	var stkc stack
+	copy(stkc.stk[:], stk)
+	stkc.len = len(stk)
+	if id, ok := g.stacks[stkc]; ok {
+		return id
+	}
+	id := uint64(len(g.stacks) + 1)
+	g.stacks[stkc] = id
+	return id
+}
+
+// writeEventsTo emits event batches in the generation to tw.
+func (g *Generation) writeEventsTo(tw *raw.TextWriter) {
+	// Write event batches for the generation.
+	for _, b := range g.batches {
+		b.writeEventsTo(tw)
+	}
+
+	// Write frequency.
+	b := g.newStructuralBatch()
+	b.RawEvent(go122.EvFrequency, nil, 15625000)
+	b.writeEventsTo(tw)
+
+	// Write stacks.
+	b = g.newStructuralBatch()
+	b.RawEvent(go122.EvStacks, nil)
+	for stk, id := range g.stacks {
+		stk := stk.stk[:stk.len]
+		args := []uint64{id}
+		for _, f := range stk {
+			args = append(args, f.PC, g.String(f.Func), g.String(f.File), f.Line)
+		}
+		b.RawEvent(go122.EvStack, nil, args...)
+
+		// Flush the batch if necessary.
+		if !g.ignoreStackBatchSizeLimit && b.size > go122.MaxBatchSize/2 {
+			b.writeEventsTo(tw)
+			b = g.newStructuralBatch()
+		}
+	}
+	b.writeEventsTo(tw)
+
+	// Write strings.
+	b = g.newStructuralBatch()
+	b.RawEvent(go122.EvStrings, nil)
+	for s, id := range g.strings {
+		b.RawEvent(go122.EvString, []byte(s), id)
+
+		// Flush the batch if necessary.
+		if !g.ignoreStringBatchSizeLimit && b.size > go122.MaxBatchSize/2 {
+			b.writeEventsTo(tw)
+			b = g.newStructuralBatch()
+		}
+	}
+	b.writeEventsTo(tw)
+}
+
+func (g *Generation) newStructuralBatch() *Batch {
+	return &Batch{gen: g, thread: trace.NoThread}
+}
+
+// Batch represents an event batch.
+type Batch struct {
+	gen       *Generation
+	thread    trace.ThreadID
+	timestamp Time
+	size      uint64
+	events    []raw.Event
+}
+
+// Event emits an event into a batch. name must correspond to one
+// of the names in Specs() result for the version that was passed to
+// this trace. Callers must omit the timestamp delta.
+func (b *Batch) Event(name string, args ...any) {
+	ev, ok := b.gen.trace.names[name]
+	if !ok {
+		panic(fmt.Sprintf("invalid or unknown event %s", name))
+	}
+	var uintArgs []uint64
+	argOff := 0
+	if b.gen.trace.specs[ev].IsTimedEvent {
+		if b.gen.trace.validTimestamps {
+			uintArgs = []uint64{1}
+		} else {
+			uintArgs = []uint64{0}
+		}
+		argOff = 1
+	}
+	spec := b.gen.trace.specs[ev]
+	if arity := len(spec.Args) - argOff; len(args) != arity {
+		panic(fmt.Sprintf("expected %d args for %s, got %d", arity, spec.Name, len(args)))
+	}
+	for i, arg := range args {
+		uintArgs = append(uintArgs, b.uintArgFor(arg, spec.Args[i+argOff]))
+	}
+	b.RawEvent(ev, nil, uintArgs...)
+}
+
+func (b *Batch) uintArgFor(arg any, argSpec string) uint64 {
+	components := strings.SplitN(argSpec, "_", 2)
+	typStr := components[0]
+	if len(components) == 2 {
+		typStr = components[1]
+	}
+	var u uint64
+	switch typStr {
+	case "value":
+		u = arg.(uint64)
+	case "stack":
+		u = b.gen.Stack(arg.([]trace.StackFrame))
+	case "seq":
+		u = uint64(arg.(Seq))
+	case "pstatus":
+		u = uint64(arg.(go122.ProcStatus))
+	case "gstatus":
+		u = uint64(arg.(go122.GoStatus))
+	case "g":
+		u = uint64(arg.(trace.GoID))
+	case "m":
+		u = uint64(arg.(trace.ThreadID))
+	case "p":
+		u = uint64(arg.(trace.ProcID))
+	case "string":
+		u = b.gen.String(arg.(string))
+	case "task":
+		u = uint64(arg.(trace.TaskID))
+	default:
+		panic(fmt.Sprintf("unsupported arg type %q for spec %q", typStr, argSpec))
+	}
+	return u
+}
+
+// RawEvent emits an event into a batch. name must correspond to one
+// of the names in Specs() result for the version that was passed to
+// this trace.
+func (b *Batch) RawEvent(typ event.Type, data []byte, args ...uint64) {
+	ev := b.gen.trace.createEvent(typ, data, args...)
+
+	// Compute the size of the event and add it to the batch.
+	b.size += 1 // One byte for the event header.
+	var buf [binary.MaxVarintLen64]byte
+	for _, arg := range args {
+		b.size += uint64(binary.PutUvarint(buf[:], arg))
+	}
+	if len(data) != 0 {
+		b.size += uint64(binary.PutUvarint(buf[:], uint64(len(data))))
+		b.size += uint64(len(data))
+	}
+
+	// Add the event.
+	b.events = append(b.events, ev)
+}
+
+// writeEventsTo emits events in the batch, including the batch header, to tw.
+func (b *Batch) writeEventsTo(tw *raw.TextWriter) {
+	tw.WriteEvent(raw.Event{
+		Version: version.Go122,
+		Ev:      go122.EvEventBatch,
+		Args:    []uint64{b.gen.gen, uint64(b.thread), uint64(b.timestamp), b.size},
+	})
+	for _, e := range b.events {
+		tw.WriteEvent(e)
+	}
+}
+
+// Seq represents a sequence counter.
+type Seq uint64
+
+// Time represents a low-level trace timestamp (which does not necessarily
+// correspond to nanoseconds, like trace.Time does).
+type Time uint64
diff --git a/trace/internal/testtrace/expectation.go b/trace/internal/testtrace/expectation.go
new file mode 100644
index 0000000..8caaeb9
--- /dev/null
+++ b/trace/internal/testtrace/expectation.go
@@ -0,0 +1,85 @@
+// Copyright 2023 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.
+
+// Code generated by "gen.bash" from internal/trace/v2; DO NOT EDIT.
+
+//go:build go1.21
+
+package testtrace
+
+import (
+	"bufio"
+	"bytes"
+	"fmt"
+	"regexp"
+	"strconv"
+	"strings"
+)
+
+// Expectation represents the expected result of some operation.
+type Expectation struct {
+	failure      bool
+	errorMatcher *regexp.Regexp
+}
+
+// ExpectSuccess returns an Expectation that trivially expects success.
+func ExpectSuccess() *Expectation {
+	return new(Expectation)
+}
+
+// Check validates whether err conforms to the expectation. Returns
+// an error if it does not conform.
+//
+// Conformance means that if failure is true, then err must be non-nil.
+// If err is non-nil, then it must match errorMatcher.
+func (e *Expectation) Check(err error) error {
+	if !e.failure && err != nil {
+		return fmt.Errorf("unexpected error while reading the trace: %v", err)
+	}
+	if e.failure && err == nil {
+		return fmt.Errorf("expected error while reading the trace: want something matching %q, got none", e.errorMatcher)
+	}
+	if e.failure && err != nil && !e.errorMatcher.MatchString(err.Error()) {
+		return fmt.Errorf("unexpected error while reading the trace: want something matching %q, got %s", e.errorMatcher, err.Error())
+	}
+	return nil
+}
+
+// ParseExpectation parses the serialized form of an Expectation.
+func ParseExpectation(data []byte) (*Expectation, error) {
+	exp := new(Expectation)
+	s := bufio.NewScanner(bytes.NewReader(data))
+	if s.Scan() {
+		c := strings.SplitN(s.Text(), " ", 2)
+		switch c[0] {
+		case "SUCCESS":
+		case "FAILURE":
+			exp.failure = true
+			if len(c) != 2 {
+				return exp, fmt.Errorf("bad header line for FAILURE: %q", s.Text())
+			}
+			matcher, err := parseMatcher(c[1])
+			if err != nil {
+				return exp, err
+			}
+			exp.errorMatcher = matcher
+		default:
+			return exp, fmt.Errorf("bad header line: %q", s.Text())
+		}
+		return exp, nil
+	}
+	return exp, s.Err()
+}
+
+func parseMatcher(quoted string) (*regexp.Regexp, error) {
+	pattern, err := strconv.Unquote(quoted)
+	if err != nil {
+		return nil, fmt.Errorf("malformed pattern: not correctly quoted: %s: %v", quoted, err)
+	}
+	matcher, err := regexp.Compile(pattern)
+	if err != nil {
+		return nil, fmt.Errorf("malformed pattern: not a valid regexp: %s: %v", pattern, err)
+	}
+	return matcher, nil
+}
diff --git a/trace/internal/testtrace/format.go b/trace/internal/testtrace/format.go
new file mode 100644
index 0000000..d7f61a1
--- /dev/null
+++ b/trace/internal/testtrace/format.go
@@ -0,0 +1,60 @@
+// Copyright 2023 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.
+
+// Code generated by "gen.bash" from internal/trace/v2; DO NOT EDIT.
+
+//go:build go1.21
+
+package testtrace
+
+import (
+	"bytes"
+	"fmt"
+	"golang.org/x/exp/trace/internal/raw"
+	"golang.org/x/tools/txtar"
+	"io"
+)
+
+// ParseFile parses a test file generated by the testgen package.
+func ParseFile(testPath string) (io.Reader, *Expectation, error) {
+	ar, err := txtar.ParseFile(testPath)
+	if err != nil {
+		return nil, nil, fmt.Errorf("failed to read test file for %s: %v", testPath, err)
+	}
+	if len(ar.Files) != 2 {
+		return nil, nil, fmt.Errorf("malformed test %s: wrong number of files", testPath)
+	}
+	if ar.Files[0].Name != "expect" {
+		return nil, nil, fmt.Errorf("malformed test %s: bad filename %s", testPath, ar.Files[0].Name)
+	}
+	if ar.Files[1].Name != "trace" {
+		return nil, nil, fmt.Errorf("malformed test %s: bad filename %s", testPath, ar.Files[1].Name)
+	}
+	tr, err := raw.NewTextReader(bytes.NewReader(ar.Files[1].Data))
+	if err != nil {
+		return nil, nil, fmt.Errorf("malformed test %s: bad trace file: %v", testPath, err)
+	}
+	var buf bytes.Buffer
+	tw, err := raw.NewWriter(&buf, tr.Version())
+	if err != nil {
+		return nil, nil, fmt.Errorf("failed to create trace byte writer: %v", err)
+	}
+	for {
+		ev, err := tr.ReadEvent()
+		if err == io.EOF {
+			break
+		}
+		if err != nil {
+			return nil, nil, fmt.Errorf("malformed test %s: bad trace file: %v", testPath, err)
+		}
+		if err := tw.WriteEvent(ev); err != nil {
+			return nil, nil, fmt.Errorf("internal error during %s: failed to write trace bytes: %v", testPath, err)
+		}
+	}
+	exp, err := ParseExpectation(ar.Files[0].Data)
+	if err != nil {
+		return nil, nil, fmt.Errorf("internal error during %s: failed to parse expectation %q: %v", testPath, string(ar.Files[0].Data), err)
+	}
+	return &buf, exp, nil
+}
diff --git a/trace/internal/testtrace/validation.go b/trace/internal/testtrace/validation.go
new file mode 100644
index 0000000..e9bc808
--- /dev/null
+++ b/trace/internal/testtrace/validation.go
@@ -0,0 +1,365 @@
+// Copyright 2023 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.
+
+// Code generated by "gen.bash" from internal/trace/v2; DO NOT EDIT.
+
+//go:build go1.21
+
+package testtrace
+
+import (
+	"errors"
+	"fmt"
+	"golang.org/x/exp/trace"
+	"slices"
+	"strings"
+)
+
+// Validator is a type used for validating a stream of trace.Events.
+type Validator struct {
+	lastTs   trace.Time
+	gs       map[trace.GoID]*goState
+	ps       map[trace.ProcID]*procState
+	ms       map[trace.ThreadID]*schedContext
+	ranges   map[trace.ResourceID][]string
+	tasks    map[trace.TaskID]string
+	seenSync bool
+}
+
+type schedContext struct {
+	M trace.ThreadID
+	P trace.ProcID
+	G trace.GoID
+}
+
+type goState struct {
+	state   trace.GoState
+	binding *schedContext
+}
+
+type procState struct {
+	state   trace.ProcState
+	binding *schedContext
+}
+
+// NewValidator creates a new Validator.
+func NewValidator() *Validator {
+	return &Validator{
+		gs:     make(map[trace.GoID]*goState),
+		ps:     make(map[trace.ProcID]*procState),
+		ms:     make(map[trace.ThreadID]*schedContext),
+		ranges: make(map[trace.ResourceID][]string),
+		tasks:  make(map[trace.TaskID]string),
+	}
+}
+
+// Event validates ev as the next event in a stream of trace.Events.
+//
+// Returns an error if validation fails.
+func (v *Validator) Event(ev trace.Event) error {
+	e := new(errAccumulator)
+
+	// Validate timestamp order.
+	if v.lastTs != 0 {
+		if ev.Time() <= v.lastTs {
+			e.Errorf("timestamp out-of-order for %+v", ev)
+		} else {
+			v.lastTs = ev.Time()
+		}
+	} else {
+		v.lastTs = ev.Time()
+	}
+
+	// Validate event stack.
+	checkStack(e, ev.Stack())
+
+	switch ev.Kind() {
+	case trace.EventSync:
+		// Just record that we've seen a Sync at some point.
+		v.seenSync = true
+	case trace.EventMetric:
+		m := ev.Metric()
+		if !strings.Contains(m.Name, ":") {
+			// Should have a ":" as per runtime/metrics convention.
+			e.Errorf("invalid metric name %q", m.Name)
+		}
+		// Make sure the value is OK.
+		if m.Value.Kind() == trace.ValueBad {
+			e.Errorf("invalid value")
+		}
+		switch m.Value.Kind() {
+		case trace.ValueUint64:
+			// Just make sure it doesn't panic.
+			_ = m.Value.Uint64()
+		}
+	case trace.EventLabel:
+		l := ev.Label()
+
+		// Check label.
+		if l.Label == "" {
+			e.Errorf("invalid label %q", l.Label)
+		}
+
+		// Check label resource.
+		if l.Resource.Kind == trace.ResourceNone {
+			e.Errorf("label resource none")
+		}
+		switch l.Resource.Kind {
+		case trace.ResourceGoroutine:
+			id := l.Resource.Goroutine()
+			if _, ok := v.gs[id]; !ok {
+				e.Errorf("label for invalid goroutine %d", id)
+			}
+		case trace.ResourceProc:
+			id := l.Resource.Proc()
+			if _, ok := v.ps[id]; !ok {
+				e.Errorf("label for invalid proc %d", id)
+			}
+		case trace.ResourceThread:
+			id := l.Resource.Thread()
+			if _, ok := v.ms[id]; !ok {
+				e.Errorf("label for invalid thread %d", id)
+			}
+		}
+	case trace.EventStackSample:
+		// Not much to check here. It's basically a sched context and a stack.
+		// The sched context is also not guaranteed to align with other events.
+		// We already checked the stack above.
+	case trace.EventStateTransition:
+		// Validate state transitions.
+		//
+		// TODO(mknyszek): A lot of logic is duplicated between goroutines and procs.
+		// The two are intentionally handled identically; from the perspective of the
+		// API, resources all have the same general properties. Consider making this
+		// code generic over resources and implementing validation just once.
+		tr := ev.StateTransition()
+		checkStack(e, tr.Stack)
+		switch tr.Resource.Kind {
+		case trace.ResourceGoroutine:
+			// Basic state transition validation.
+			id := tr.Resource.Goroutine()
+			old, new := tr.Goroutine()
+			if new == trace.GoUndetermined {
+				e.Errorf("transition to undetermined state for goroutine %d", id)
+			}
+			if v.seenSync && old == trace.GoUndetermined {
+				e.Errorf("undetermined goroutine %d after first global sync", id)
+			}
+			if new == trace.GoNotExist && v.hasAnyRange(trace.MakeResourceID(id)) {
+				e.Errorf("goroutine %d died with active ranges", id)
+			}
+			state, ok := v.gs[id]
+			if ok {
+				if old != state.state {
+					e.Errorf("bad old state for goroutine %d: got %s, want %s", id, old, state.state)
+				}
+				state.state = new
+			} else {
+				if old != trace.GoUndetermined && old != trace.GoNotExist {
+					e.Errorf("bad old state for unregistered goroutine %d: %s", id, old)
+				}
+				state = &goState{state: new}
+				v.gs[id] = state
+			}
+			// Validate sched context.
+			if new.Executing() {
+				ctx := v.getOrCreateThread(e, ev.Thread())
+				if ctx != nil {
+					if ctx.G != trace.NoGoroutine && ctx.G != id {
+						e.Errorf("tried to run goroutine %d when one was already executing (%d) on thread %d", id, ctx.G, ev.Thread())
+					}
+					ctx.G = id
+					state.binding = ctx
+				}
+			} else if old.Executing() && !new.Executing() {
+				if tr.Stack != ev.Stack() {
+					// This is a case where the transition is happening to a goroutine that is also executing, so
+					// these two stacks should always match.
+					e.Errorf("StateTransition.Stack doesn't match Event.Stack")
+				}
+				ctx := state.binding
+				if ctx != nil {
+					if ctx.G != id {
+						e.Errorf("tried to stop goroutine %d when it wasn't currently executing (currently executing %d) on thread %d", id, ctx.G, ev.Thread())
+					}
+					ctx.G = trace.NoGoroutine
+					state.binding = nil
+				} else {
+					e.Errorf("stopping goroutine %d not bound to any active context", id)
+				}
+			}
+		case trace.ResourceProc:
+			// Basic state transition validation.
+			id := tr.Resource.Proc()
+			old, new := tr.Proc()
+			if new == trace.ProcUndetermined {
+				e.Errorf("transition to undetermined state for proc %d", id)
+			}
+			if v.seenSync && old == trace.ProcUndetermined {
+				e.Errorf("undetermined proc %d after first global sync", id)
+			}
+			if new == trace.ProcNotExist && v.hasAnyRange(trace.MakeResourceID(id)) {
+				e.Errorf("proc %d died with active ranges", id)
+			}
+			state, ok := v.ps[id]
+			if ok {
+				if old != state.state {
+					e.Errorf("bad old state for proc %d: got %s, want %s", id, old, state.state)
+				}
+				state.state = new
+			} else {
+				if old != trace.ProcUndetermined && old != trace.ProcNotExist {
+					e.Errorf("bad old state for unregistered proc %d: %s", id, old)
+				}
+				state = &procState{state: new}
+				v.ps[id] = state
+			}
+			// Validate sched context.
+			if new.Executing() {
+				ctx := v.getOrCreateThread(e, ev.Thread())
+				if ctx != nil {
+					if ctx.P != trace.NoProc && ctx.P != id {
+						e.Errorf("tried to run proc %d when one was already executing (%d) on thread %d", id, ctx.P, ev.Thread())
+					}
+					ctx.P = id
+					state.binding = ctx
+				}
+			} else if old.Executing() && !new.Executing() {
+				ctx := state.binding
+				if ctx != nil {
+					if ctx.P != id {
+						e.Errorf("tried to stop proc %d when it wasn't currently executing (currently executing %d) on thread %d", id, ctx.P, ctx.M)
+					}
+					ctx.P = trace.NoProc
+					state.binding = nil
+				} else {
+					e.Errorf("stopping proc %d not bound to any active context", id)
+				}
+			}
+		}
+	case trace.EventRangeBegin, trace.EventRangeActive, trace.EventRangeEnd:
+		// Validate ranges.
+		r := ev.Range()
+		switch ev.Kind() {
+		case trace.EventRangeBegin:
+			if v.hasRange(r.Scope, r.Name) {
+				e.Errorf("already active range %q on %v begun again", r.Name, r.Scope)
+			}
+			v.addRange(r.Scope, r.Name)
+		case trace.EventRangeActive:
+			if !v.hasRange(r.Scope, r.Name) {
+				v.addRange(r.Scope, r.Name)
+			}
+		case trace.EventRangeEnd:
+			if !v.hasRange(r.Scope, r.Name) {
+				e.Errorf("inactive range %q on %v ended", r.Name, r.Scope)
+			}
+			v.deleteRange(r.Scope, r.Name)
+		}
+	case trace.EventTaskBegin:
+		// Validate task begin.
+		t := ev.Task()
+		if t.ID == trace.NoTask || t.ID == trace.BackgroundTask {
+			// The background task should never have an event emitted for it.
+			e.Errorf("found invalid task ID for task of type %s", t.Type)
+		}
+		if t.Parent == trace.BackgroundTask {
+			// It's not possible for a task to be a subtask of the background task.
+			e.Errorf("found background task as the parent for task of type %s", t.Type)
+		}
+		// N.B. Don't check the task type. Empty string is a valid task type.
+		v.tasks[t.ID] = t.Type
+	case trace.EventTaskEnd:
+		// Validate task end.
+		// We can see a task end without a begin, so ignore a task without information.
+		// Instead, if we've seen the task begin, just make sure the task end lines up.
+		t := ev.Task()
+		if typ, ok := v.tasks[t.ID]; ok {
+			if t.Type != typ {
+				e.Errorf("task end type %q doesn't match task start type %q for task %d", t.Type, typ, t.ID)
+			}
+			delete(v.tasks, t.ID)
+		}
+	case trace.EventLog:
+		// There's really not much here to check, except that we can
+		// generate a Log. The category and message are entirely user-created,
+		// so we can't make any assumptions as to what they are. We also
+		// can't validate the task, because proving the task's existence is very
+		// much best-effort.
+		_ = ev.Log()
+	}
+	return e.Errors()
+}
+
+func (v *Validator) hasRange(r trace.ResourceID, name string) bool {
+	ranges, ok := v.ranges[r]
+	return ok && slices.Contains(ranges, name)
+}
+
+func (v *Validator) addRange(r trace.ResourceID, name string) {
+	ranges, _ := v.ranges[r]
+	ranges = append(ranges, name)
+	v.ranges[r] = ranges
+}
+
+func (v *Validator) hasAnyRange(r trace.ResourceID) bool {
+	ranges, ok := v.ranges[r]
+	return ok && len(ranges) != 0
+}
+
+func (v *Validator) deleteRange(r trace.ResourceID, name string) {
+	ranges, ok := v.ranges[r]
+	if !ok {
+		return
+	}
+	i := slices.Index(ranges, name)
+	if i < 0 {
+		return
+	}
+	v.ranges[r] = slices.Delete(ranges, i, i+1)
+}
+
+func (v *Validator) getOrCreateThread(e *errAccumulator, m trace.ThreadID) *schedContext {
+	if m == trace.NoThread {
+		e.Errorf("must have thread, but thread ID is none")
+		return nil
+	}
+	s, ok := v.ms[m]
+	if !ok {
+		s = &schedContext{M: m, P: trace.NoProc, G: trace.NoGoroutine}
+		v.ms[m] = s
+		return s
+	}
+	return s
+}
+
+func checkStack(e *errAccumulator, stk trace.Stack) {
+	// Check for non-empty values, but we also check for crashes due to incorrect validation.
+	i := 0
+	stk.Frames(func(f trace.StackFrame) bool {
+		if i == 0 {
+			// Allow for one fully zero stack.
+			//
+			// TODO(mknyszek): Investigate why that happens.
+			return true
+		}
+		if f.Func == "" || f.File == "" || f.PC == 0 || f.Line == 0 {
+			e.Errorf("invalid stack frame %#v: missing information", f)
+		}
+		i++
+		return true
+	})
+}
+
+type errAccumulator struct {
+	errs []error
+}
+
+func (e *errAccumulator) Errorf(f string, args ...any) {
+	e.errs = append(e.errs, fmt.Errorf(f, args...))
+}
+
+func (e *errAccumulator) Errors() error {
+	return errors.Join(e.errs...)
+}
diff --git a/trace/internal/version/version.go b/trace/internal/version/version.go
new file mode 100644
index 0000000..eeb7cab
--- /dev/null
+++ b/trace/internal/version/version.go
@@ -0,0 +1,61 @@
+// Copyright 2023 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.
+
+// Code generated by "gen.bash" from internal/trace/v2; DO NOT EDIT.
+
+//go:build go1.21
+
+package version
+
+import (
+	"fmt"
+	"io"
+
+	"golang.org/x/exp/trace/internal/event"
+	"golang.org/x/exp/trace/internal/event/go122"
+)
+
+// Version represents the version of a trace file.
+type Version uint32
+
+const (
+	Go122   Version = 22
+	Current         = Go122
+)
+
+var versions = map[Version][]event.Spec{
+	Go122: go122.Specs(),
+}
+
+// Specs returns the set of event.Specs for this version.
+func (v Version) Specs() []event.Spec {
+	return versions[v]
+}
+
+func (v Version) Valid() bool {
+	_, ok := versions[v]
+	return ok
+}
+
+// headerFmt is the format of the header of all Go execution traces.
+const headerFmt = "go 1.%d trace\x00\x00\x00"
+
+// ReadHeader reads the version of the trace out of the trace file's
+// header, whose prefix must be present in v.
+func ReadHeader(r io.Reader) (Version, error) {
+	var v Version
+	_, err := fmt.Fscanf(r, headerFmt, &v)
+	if err != nil {
+		return v, fmt.Errorf("bad file format: not a Go execution trace?")
+	}
+	if !v.Valid() {
+		return v, fmt.Errorf("unknown or unsupported trace version go 1.%d", v)
+	}
+	return v, nil
+}
+
+// WriteHeader writes a header for a trace version v to w.
+func WriteHeader(w io.Writer, v Version) (int, error) {
+	return fmt.Fprintf(w, headerFmt, v)
+}
diff --git a/trace/order.go b/trace/order.go
new file mode 100644
index 0000000..c89e5da
--- /dev/null
+++ b/trace/order.go
@@ -0,0 +1,1056 @@
+// Copyright 2023 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.
+
+// Code generated by "gen.bash" from internal/trace/v2; DO NOT EDIT.
+
+//go:build go1.21
+
+package trace
+
+import (
+	"fmt"
+	"strings"
+
+	"golang.org/x/exp/trace/internal/event"
+	"golang.org/x/exp/trace/internal/event/go122"
+	"golang.org/x/exp/trace/internal/version"
+)
+
+// ordering emulates Go scheduler state for both validation and
+// for putting events in the right order.
+type ordering struct {
+	gStates     map[GoID]*gState
+	pStates     map[ProcID]*pState // TODO: The keys are dense, so this can be a slice.
+	mStates     map[ThreadID]*mState
+	activeTasks map[TaskID]taskState
+	gcSeq       uint64
+	gcState     gcState
+	initialGen  uint64
+
+	// Some events like GoDestroySyscall produce two events instead of one.
+	// extraEvent is this extra space. advance must not be called unless
+	// the extraEvent has been consumed with consumeExtraEvent.
+	//
+	// TODO(mknyszek): Replace this with a more formal queue.
+	extraEvent Event
+}
+
+// consumeExtraEvent consumes the extra event.
+func (o *ordering) consumeExtraEvent() Event {
+	if o.extraEvent.Kind() == EventBad {
+		return Event{}
+	}
+	r := o.extraEvent
+	o.extraEvent = Event{}
+	return r
+}
+
+// advance checks if it's valid to proceed with ev which came from thread m.
+//
+// Returns the schedCtx at the point of the event, whether it's OK to advance
+// with this event, and any error encountered in validation.
+//
+// It assumes the gen value passed to it is monotonically increasing across calls.
+//
+// If any error is returned, then the trace is broken and trace parsing must cease.
+// If it's not valid to advance with ev, but no error was encountered, the caller
+// should attempt to advance with other candidate events from other threads. If the
+// caller runs out of candidates, the trace is invalid.
+func (o *ordering) advance(ev *baseEvent, evt *evTable, m ThreadID, gen uint64) (schedCtx, bool, error) {
+	if o.initialGen == 0 {
+		// Set the initial gen if necessary.
+		o.initialGen = gen
+	}
+
+	var curCtx, newCtx schedCtx
+	curCtx.M = m
+	newCtx.M = m
+
+	if m == NoThread {
+		curCtx.P = NoProc
+		curCtx.G = NoGoroutine
+		newCtx = curCtx
+	} else {
+		// Pull out or create the mState for this event.
+		ms, ok := o.mStates[m]
+		if !ok {
+			ms = &mState{
+				g: NoGoroutine,
+				p: NoProc,
+			}
+			o.mStates[m] = ms
+		}
+		curCtx.P = ms.p
+		curCtx.G = ms.g
+		newCtx = curCtx
+		defer func() {
+			// Update the mState for this event.
+			ms.p = newCtx.P
+			ms.g = newCtx.G
+		}()
+	}
+
+	switch typ := ev.typ; typ {
+	// Handle procs.
+	case go122.EvProcStatus:
+		pid := ProcID(ev.args[0])
+		status := go122.ProcStatus(ev.args[1])
+		oldState := go122ProcStatus2ProcState[status]
+		if s, ok := o.pStates[pid]; ok {
+			if status == go122.ProcSyscallAbandoned && s.status == go122.ProcSyscall {
+				// ProcSyscallAbandoned is a special case of ProcSyscall. It indicates a
+				// potential loss of information, but if we're already in ProcSyscall,
+				// we haven't lost the relevant information. Promote the status and advance.
+				oldState = ProcRunning
+				ev.args[1] = uint64(go122.ProcSyscall)
+			} else if status == go122.ProcSyscallAbandoned && s.status == go122.ProcSyscallAbandoned {
+				// If we're passing through ProcSyscallAbandoned, then there's no promotion
+				// to do. We've lost the M that this P is associated with. However it got there,
+				// it's going to appear as idle in the API, so pass through as idle.
+				oldState = ProcIdle
+				ev.args[1] = uint64(go122.ProcSyscallAbandoned)
+			} else if s.status != status {
+				return curCtx, false, fmt.Errorf("inconsistent status for proc %d: old %v vs. new %v", pid, s.status, status)
+			}
+			s.seq = makeSeq(gen, 0) // Reset seq.
+		} else {
+			o.pStates[pid] = &pState{id: pid, status: status, seq: makeSeq(gen, 0)}
+			if gen == o.initialGen {
+				oldState = ProcUndetermined
+			} else {
+				oldState = ProcNotExist
+			}
+		}
+		ev.extra(version.Go122)[0] = uint64(oldState) // Smuggle in the old state for StateTransition.
+
+		// Bind the proc to the new context, if it's running.
+		if status == go122.ProcRunning || status == go122.ProcSyscall {
+			newCtx.P = pid
+		}
+		// If we're advancing through ProcSyscallAbandoned *but* oldState is running then we've
+		// promoted it to ProcSyscall. However, because it's ProcSyscallAbandoned, we know this
+		// P is about to get stolen and its status very likely isn't being emitted by the same
+		// thread it was bound to. Since this status is Running -> Running and Running is binding,
+		// we need to make sure we emit it in the right context: the context to which it is bound.
+		// Find it, and set our current context to it.
+		if status == go122.ProcSyscallAbandoned && oldState == ProcRunning {
+			// N.B. This is slow but it should be fairly rare.
+			found := false
+			for mid, ms := range o.mStates {
+				if ms.p == pid {
+					curCtx.M = mid
+					curCtx.P = pid
+					curCtx.G = ms.g
+					found = true
+				}
+			}
+			if !found {
+				return curCtx, false, fmt.Errorf("failed to find sched context for proc %d that's about to be stolen", pid)
+			}
+		}
+		return curCtx, true, nil
+	case go122.EvProcStart:
+		pid := ProcID(ev.args[0])
+		seq := makeSeq(gen, ev.args[1])
+
+		// Try to advance. We might fail here due to sequencing, because the P hasn't
+		// had a status emitted, or because we already have a P and we're in a syscall,
+		// and we haven't observed that it was stolen from us yet.
+		state, ok := o.pStates[pid]
+		if !ok || state.status != go122.ProcIdle || !seq.succeeds(state.seq) || curCtx.P != NoProc {
+			// We can't make an inference as to whether this is bad. We could just be seeing
+			// a ProcStart on a different M before the proc's state was emitted, or before we
+			// got to the right point in the trace.
+			//
+			// Note that we also don't advance here if we have a P and we're in a syscall.
+			return curCtx, false, nil
+		}
+		// We can advance this P. Check some invariants.
+		//
+		// We might have a goroutine if a goroutine is exiting a syscall.
+		reqs := event.SchedReqs{Thread: event.MustHave, Proc: event.MustNotHave, Goroutine: event.MayHave}
+		if err := validateCtx(curCtx, reqs); err != nil {
+			return curCtx, false, err
+		}
+		state.status = go122.ProcRunning
+		state.seq = seq
+		newCtx.P = pid
+		return curCtx, true, nil
+	case go122.EvProcStop:
+		// We must be able to advance this P.
+		//
+		// There are 2 ways a P can stop: ProcStop and ProcSteal. ProcStop is used when the P
+		// is stopped by the same M that started it, while ProcSteal is used when another M
+		// steals the P by stopping it from a distance.
+		//
+		// Since a P is bound to an M, and we're stopping on the same M we started, it must
+		// always be possible to advance the current M's P from a ProcStop. This is also why
+		// ProcStop doesn't need a sequence number.
+		state, ok := o.pStates[curCtx.P]
+		if !ok {
+			return curCtx, false, fmt.Errorf("event %s for proc (%v) that doesn't exist", go122.EventString(typ), curCtx.P)
+		}
+		if state.status != go122.ProcRunning && state.status != go122.ProcSyscall {
+			return curCtx, false, fmt.Errorf("%s event for proc that's not %s or %s", go122.EventString(typ), go122.ProcRunning, go122.ProcSyscall)
+		}
+		reqs := event.SchedReqs{Thread: event.MustHave, Proc: event.MustHave, Goroutine: event.MayHave}
+		if err := validateCtx(curCtx, reqs); err != nil {
+			return curCtx, false, err
+		}
+		state.status = go122.ProcIdle
+		newCtx.P = NoProc
+		return curCtx, true, nil
+	case go122.EvProcSteal:
+		pid := ProcID(ev.args[0])
+		seq := makeSeq(gen, ev.args[1])
+		state, ok := o.pStates[pid]
+		if !ok || (state.status != go122.ProcSyscall && state.status != go122.ProcSyscallAbandoned) || !seq.succeeds(state.seq) {
+			// We can't make an inference as to whether this is bad. We could just be seeing
+			// a ProcStart on a different M before the proc's state was emitted, or before we
+			// got to the right point in the trace.
+			return curCtx, false, nil
+		}
+		// We can advance this P. Check some invariants.
+		reqs := event.SchedReqs{Thread: event.MustHave, Proc: event.MayHave, Goroutine: event.MayHave}
+		if err := validateCtx(curCtx, reqs); err != nil {
+			return curCtx, false, err
+		}
+		// Smuggle in the P state that let us advance so we can surface information to the event.
+		// Specifically, we need to make sure that the event is interpreted not as a transition of
+		// ProcRunning -> ProcIdle but ProcIdle -> ProcIdle instead.
+		//
+		// ProcRunning is binding, but we may be running with a P on the current M and we can't
+		// bind another P. This P is about to go ProcIdle anyway.
+		oldStatus := state.status
+		ev.extra(version.Go122)[0] = uint64(oldStatus)
+
+		// Update the P's status and sequence number.
+		state.status = go122.ProcIdle
+		state.seq = seq
+
+		// If we've lost information then don't try to do anything with the M.
+		// It may have moved on and we can't be sure.
+		if oldStatus == go122.ProcSyscallAbandoned {
+			return curCtx, true, nil
+		}
+
+		// Validate that the M we're stealing from is what we expect.
+		mid := ThreadID(ev.args[2]) // The M we're stealing from.
+
+		if mid == curCtx.M {
+			// We're stealing from ourselves. This behaves like a ProcStop.
+			if curCtx.P != pid {
+				return curCtx, false, fmt.Errorf("tried to self-steal proc %d (thread %d), but got proc %d instead", pid, mid, curCtx.P)
+			}
+			newCtx.P = NoProc
+			return curCtx, true, nil
+		}
+
+		// We're stealing from some other M.
+		mState, ok := o.mStates[mid]
+		if !ok {
+			return curCtx, false, fmt.Errorf("stole proc from non-existent thread %d", mid)
+		}
+
+		// Make sure we're actually stealing the right P.
+		if mState.p != pid {
+			return curCtx, false, fmt.Errorf("tried to steal proc %d from thread %d, but got proc %d instead", pid, mid, mState.p)
+		}
+
+		// Tell the M it has no P so it can proceed.
+		//
+		// This is safe because we know the P was in a syscall and
+		// the other M must be trying to get out of the syscall.
+		// GoSyscallEndBlocked cannot advance until the corresponding
+		// M loses its P.
+		mState.p = NoProc
+		return curCtx, true, nil
+
+	// Handle goroutines.
+	case go122.EvGoStatus:
+		gid := GoID(ev.args[0])
+		mid := ThreadID(ev.args[1])
+		status := go122.GoStatus(ev.args[2])
+		oldState := go122GoStatus2GoState[status]
+		if s, ok := o.gStates[gid]; ok {
+			if s.status != status {
+				return curCtx, false, fmt.Errorf("inconsistent status for goroutine %d: old %v vs. new %v", gid, s.status, status)
+			}
+			s.seq = makeSeq(gen, 0) // Reset seq.
+		} else if gen == o.initialGen {
+			// Set the state.
+			o.gStates[gid] = &gState{id: gid, status: status, seq: makeSeq(gen, 0)}
+			oldState = GoUndetermined
+		} else {
+			return curCtx, false, fmt.Errorf("found goroutine status for new goroutine after the first generation: id=%v status=%v", gid, status)
+		}
+		ev.extra(version.Go122)[0] = uint64(oldState) // Smuggle in the old state for StateTransition.
+
+		switch status {
+		case go122.GoRunning:
+			// Bind the goroutine to the new context, since it's running.
+			newCtx.G = gid
+		case go122.GoSyscall:
+			if mid == NoThread {
+				return curCtx, false, fmt.Errorf("found goroutine %d in syscall without a thread", gid)
+			}
+			// Is the syscall on this thread? If so, bind it to the context.
+			// Otherwise, we're talking about a G sitting in a syscall on an M.
+			// Validate the named M.
+			if mid == curCtx.M {
+				newCtx.G = gid
+				break
+			}
+			// Now we're talking about a thread and goroutine that have been
+			// blocked on a syscall for the entire generation. This case must
+			// not have a P; the runtime makes sure that all Ps are traced at
+			// the beginning of a generation, which involves taking a P back
+			// from every thread.
+			ms, ok := o.mStates[mid]
+			if ok {
+				// This M has been seen. That means we must have seen this
+				// goroutine go into a syscall on this thread at some point.
+				if ms.g != gid {
+					// But the G on the M doesn't match. Something's wrong.
+					return curCtx, false, fmt.Errorf("inconsistent thread for syscalling goroutine %d: thread has goroutine %d", gid, ms.g)
+				}
+				// This case is just a Syscall->Syscall event, which needs to
+				// appear as having the G currently bound to this M.
+				curCtx.G = ms.g
+			} else if !ok {
+				// The M hasn't been seen yet. That means this goroutine
+				// has just been sitting in a syscall on this M. Create
+				// a state for it.
+				o.mStates[mid] = &mState{g: gid, p: NoProc}
+				// Don't set curCtx.G in this case because this event is the
+				// binding event (and curCtx represents the "before" state).
+			}
+			// Update the current context to the M we're talking about.
+			curCtx.M = mid
+		}
+		return curCtx, true, nil
+	case go122.EvGoCreate:
+		// Goroutines must be created on a running P, but may or may not be created
+		// by a running goroutine.
+		reqs := event.SchedReqs{Thread: event.MustHave, Proc: event.MustHave, Goroutine: event.MayHave}
+		if err := validateCtx(curCtx, reqs); err != nil {
+			return curCtx, false, err
+		}
+		// If we have a goroutine, it must be running.
+		if state, ok := o.gStates[curCtx.G]; ok && state.status != go122.GoRunning {
+			return curCtx, false, fmt.Errorf("%s event for goroutine that's not %s", go122.EventString(typ), GoRunning)
+		}
+		// This goroutine created another. Add a state for it.
+		newgid := GoID(ev.args[0])
+		if _, ok := o.gStates[newgid]; ok {
+			return curCtx, false, fmt.Errorf("tried to create goroutine (%v) that already exists", newgid)
+		}
+		o.gStates[newgid] = &gState{id: newgid, status: go122.GoRunnable, seq: makeSeq(gen, 0)}
+		return curCtx, true, nil
+	case go122.EvGoDestroy, go122.EvGoStop, go122.EvGoBlock:
+		// These are goroutine events that all require an active running
+		// goroutine on some thread. They must *always* be advance-able,
+		// since running goroutines are bound to their M.
+		if err := validateCtx(curCtx, event.UserGoReqs); err != nil {
+			return curCtx, false, err
+		}
+		state, ok := o.gStates[curCtx.G]
+		if !ok {
+			return curCtx, false, fmt.Errorf("event %s for goroutine (%v) that doesn't exist", go122.EventString(typ), curCtx.G)
+		}
+		if state.status != go122.GoRunning {
+			return curCtx, false, fmt.Errorf("%s event for goroutine that's not %s", go122.EventString(typ), GoRunning)
+		}
+		// Handle each case slightly differently; we just group them together
+		// because they have shared preconditions.
+		switch typ {
+		case go122.EvGoDestroy:
+			// This goroutine is exiting itself.
+			delete(o.gStates, curCtx.G)
+			newCtx.G = NoGoroutine
+		case go122.EvGoStop:
+			// Goroutine stopped (yielded). It's runnable but not running on this M.
+			state.status = go122.GoRunnable
+			newCtx.G = NoGoroutine
+		case go122.EvGoBlock:
+			// Goroutine blocked. It's waiting now and not running on this M.
+			state.status = go122.GoWaiting
+			newCtx.G = NoGoroutine
+		}
+		return curCtx, true, nil
+	case go122.EvGoStart:
+		gid := GoID(ev.args[0])
+		seq := makeSeq(gen, ev.args[1])
+		state, ok := o.gStates[gid]
+		if !ok || state.status != go122.GoRunnable || !seq.succeeds(state.seq) {
+			// We can't make an inference as to whether this is bad. We could just be seeing
+			// a GoStart on a different M before the goroutine was created, before it had its
+			// state emitted, or before we got to the right point in the trace yet.
+			return curCtx, false, nil
+		}
+		// We can advance this goroutine. Check some invariants.
+		reqs := event.SchedReqs{Thread: event.MustHave, Proc: event.MustHave, Goroutine: event.MustNotHave}
+		if err := validateCtx(curCtx, reqs); err != nil {
+			return curCtx, false, err
+		}
+		state.status = go122.GoRunning
+		state.seq = seq
+		newCtx.G = gid
+		return curCtx, true, nil
+	case go122.EvGoUnblock:
+		// N.B. These both reference the goroutine to unblock, not the current goroutine.
+		gid := GoID(ev.args[0])
+		seq := makeSeq(gen, ev.args[1])
+		state, ok := o.gStates[gid]
+		if !ok || state.status != go122.GoWaiting || !seq.succeeds(state.seq) {
+			// We can't make an inference as to whether this is bad. We could just be seeing
+			// a GoUnblock on a different M before the goroutine was created and blocked itself,
+			// before it had its state emitted, or before we got to the right point in the trace yet.
+			return curCtx, false, nil
+		}
+		state.status = go122.GoRunnable
+		state.seq = seq
+		// N.B. No context to validate. Basically anything can unblock
+		// a goroutine (e.g. sysmon).
+		return curCtx, true, nil
+	case go122.EvGoSyscallBegin:
+		// Entering a syscall requires an active running goroutine with a
+		// proc on some thread. It is always advancable.
+		if err := validateCtx(curCtx, event.UserGoReqs); err != nil {
+			return curCtx, false, err
+		}
+		state, ok := o.gStates[curCtx.G]
+		if !ok {
+			return curCtx, false, fmt.Errorf("event %s for goroutine (%v) that doesn't exist", go122.EventString(typ), curCtx.G)
+		}
+		if state.status != go122.GoRunning {
+			return curCtx, false, fmt.Errorf("%s event for goroutine that's not %s", go122.EventString(typ), GoRunning)
+		}
+		// Goroutine entered a syscall. It's still running on this P and M.
+		state.status = go122.GoSyscall
+		pState, ok := o.pStates[curCtx.P]
+		if !ok {
+			return curCtx, false, fmt.Errorf("uninitialized proc %d found during %s", curCtx.P, go122.EventString(typ))
+		}
+		pState.status = go122.ProcSyscall
+		// Validate the P sequence number on the event and advance it.
+		//
+		// We have a P sequence number for what is supposed to be a goroutine event
+		// so that we can correctly model P stealing. Without this sequence number here,
+		// the syscall from which a ProcSteal event is stealing can be ambiguous in the
+		// face of broken timestamps. See the go122-syscall-steal-proc-ambiguous test for
+		// more details.
+		//
+		// Note that because this sequence number only exists as a tool for disambiguation,
+		// we can enforce that we have the right sequence number at this point; we don't need
+		// to back off and see if any other events will advance. This is a running P.
+		pSeq := makeSeq(gen, ev.args[0])
+		if !pSeq.succeeds(pState.seq) {
+			return curCtx, false, fmt.Errorf("failed to advance %s: can't make sequence: %s -> %s", go122.EventString(typ), pState.seq, pSeq)
+		}
+		pState.seq = pSeq
+		return curCtx, true, nil
+	case go122.EvGoSyscallEnd:
+		// This event is always advance-able because it happens on the same
+		// thread that EvGoSyscallStart happened, and the goroutine can't leave
+		// that thread until its done.
+		if err := validateCtx(curCtx, event.UserGoReqs); err != nil {
+			return curCtx, false, err
+		}
+		state, ok := o.gStates[curCtx.G]
+		if !ok {
+			return curCtx, false, fmt.Errorf("event %s for goroutine (%v) that doesn't exist", go122.EventString(typ), curCtx.G)
+		}
+		if state.status != go122.GoSyscall {
+			return curCtx, false, fmt.Errorf("%s event for goroutine that's not %s", go122.EventString(typ), GoRunning)
+		}
+		state.status = go122.GoRunning
+
+		// Transfer the P back to running from syscall.
+		pState, ok := o.pStates[curCtx.P]
+		if !ok {
+			return curCtx, false, fmt.Errorf("uninitialized proc %d found during %s", curCtx.P, go122.EventString(typ))
+		}
+		if pState.status != go122.ProcSyscall {
+			return curCtx, false, fmt.Errorf("expected proc %d in state %v, but got %v instead", curCtx.P, go122.ProcSyscall, pState.status)
+		}
+		pState.status = go122.ProcRunning
+		return curCtx, true, nil
+	case go122.EvGoSyscallEndBlocked:
+		// This event becomes advanceable when its P is not in a syscall state
+		// (lack of a P altogether is also acceptable for advancing).
+		// The transfer out of ProcSyscall can happen either voluntarily via
+		// ProcStop or involuntarily via ProcSteal. We may also acquire a new P
+		// before we get here (after the transfer out) but that's OK: that new
+		// P won't be in the ProcSyscall state anymore.
+		//
+		// Basically: while we have a preemptible P, don't advance, because we
+		// *know* from the event that we're going to lose it at some point during
+		// the syscall. We shouldn't advance until that happens.
+		if curCtx.P != NoProc {
+			pState, ok := o.pStates[curCtx.P]
+			if !ok {
+				return curCtx, false, fmt.Errorf("uninitialized proc %d found during %s", curCtx.P, go122.EventString(typ))
+			}
+			if pState.status == go122.ProcSyscall {
+				return curCtx, false, nil
+			}
+		}
+		// As mentioned above, we may have a P here if we ProcStart
+		// before this event.
+		if err := validateCtx(curCtx, event.SchedReqs{Thread: event.MustHave, Proc: event.MayHave, Goroutine: event.MustHave}); err != nil {
+			return curCtx, false, err
+		}
+		state, ok := o.gStates[curCtx.G]
+		if !ok {
+			return curCtx, false, fmt.Errorf("event %s for goroutine (%v) that doesn't exist", go122.EventString(typ), curCtx.G)
+		}
+		if state.status != go122.GoSyscall {
+			return curCtx, false, fmt.Errorf("%s event for goroutine that's not %s", go122.EventString(typ), GoRunning)
+		}
+		newCtx.G = NoGoroutine
+		state.status = go122.GoRunnable
+		return curCtx, true, nil
+	case go122.EvGoCreateSyscall:
+		// This event indicates that a goroutine is effectively
+		// being created out of a cgo callback. Such a goroutine
+		// is 'created' in the syscall state.
+		if err := validateCtx(curCtx, event.SchedReqs{Thread: event.MustHave, Proc: event.MayHave, Goroutine: event.MustNotHave}); err != nil {
+			return curCtx, false, err
+		}
+		// This goroutine is effectively being created. Add a state for it.
+		newgid := GoID(ev.args[0])
+		if _, ok := o.gStates[newgid]; ok {
+			return curCtx, false, fmt.Errorf("tried to create goroutine (%v) in syscall that already exists", newgid)
+		}
+		o.gStates[newgid] = &gState{id: newgid, status: go122.GoSyscall, seq: makeSeq(gen, 0)}
+		// Goroutine is executing. Bind it to the context.
+		newCtx.G = newgid
+		return curCtx, true, nil
+	case go122.EvGoDestroySyscall:
+		// This event indicates that a goroutine created for a
+		// cgo callback is disappearing, either because the callback
+		// ending or the C thread that called it is being destroyed.
+		//
+		// Also, treat this as if we lost our P too.
+		// The thread ID may be reused by the platform and we'll get
+		// really confused if we try to steal the P is this is running
+		// with later. The new M with the same ID could even try to
+		// steal back this P from itself!
+		//
+		// The runtime is careful to make sure that any GoCreateSyscall
+		// event will enter the runtime emitting events for reacquiring a P.
+		//
+		// Note: we might have a P here. The P might not be released
+		// eagerly by the runtime, and it might get stolen back later
+		// (or never again, if the program is going to exit).
+		if err := validateCtx(curCtx, event.SchedReqs{Thread: event.MustHave, Proc: event.MayHave, Goroutine: event.MustHave}); err != nil {
+			return curCtx, false, err
+		}
+		// Check to make sure the goroutine exists in the right state.
+		state, ok := o.gStates[curCtx.G]
+		if !ok {
+			return curCtx, false, fmt.Errorf("event %s for goroutine (%v) that doesn't exist", go122.EventString(typ), curCtx.G)
+		}
+		if state.status != go122.GoSyscall {
+			return curCtx, false, fmt.Errorf("%s event for goroutine that's not %v", go122.EventString(typ), GoSyscall)
+		}
+		// This goroutine is exiting itself.
+		delete(o.gStates, curCtx.G)
+		newCtx.G = NoGoroutine
+
+		// If we have a proc, then we're dissociating from it now. See the comment at the top of the case.
+		if curCtx.P != NoProc {
+			pState, ok := o.pStates[curCtx.P]
+			if !ok {
+				return curCtx, false, fmt.Errorf("found invalid proc %d during %s", curCtx.P, go122.EventString(typ))
+			}
+			if pState.status != go122.ProcSyscall {
+				return curCtx, false, fmt.Errorf("proc %d in unexpected state %s during %s", curCtx.P, pState.status, go122.EventString(typ))
+			}
+			// See the go122-create-syscall-reuse-thread-id test case for more details.
+			pState.status = go122.ProcSyscallAbandoned
+			newCtx.P = NoProc
+
+			// Queue an extra self-ProcSteal event.
+			o.extraEvent = Event{
+				table: evt,
+				ctx:   curCtx,
+				base: baseEvent{
+					typ:  go122.EvProcSteal,
+					time: ev.time,
+				},
+			}
+			o.extraEvent.base.args[0] = uint64(curCtx.P)
+			o.extraEvent.base.extra(version.Go122)[0] = uint64(go122.ProcSyscall)
+		}
+		return curCtx, true, nil
+
+	// Handle tasks. Tasks are interesting because:
+	// - There's no Begin event required to reference a task.
+	// - End for a particular task ID can appear multiple times.
+	// As a result, there's very little to validate. The only
+	// thing we have to be sure of is that a task didn't begin
+	// after it had already begun. Task IDs are allowed to be
+	// reused, so we don't care about a Begin after an End.
+	case go122.EvUserTaskBegin:
+		id := TaskID(ev.args[0])
+		if _, ok := o.activeTasks[id]; ok {
+			return curCtx, false, fmt.Errorf("task ID conflict: %d", id)
+		}
+		// Get the parent ID, but don't validate it. There's no guarantee
+		// we actually have information on whether it's active.
+		parentID := TaskID(ev.args[1])
+		if parentID == BackgroundTask {
+			// Note: a value of 0 here actually means no parent, *not* the
+			// background task. Automatic background task attachment only
+			// applies to regions.
+			parentID = NoTask
+			ev.args[1] = uint64(NoTask)
+		}
+
+		// Validate the name and record it. We'll need to pass it through to
+		// EvUserTaskEnd.
+		nameID := stringID(ev.args[2])
+		name, ok := evt.strings.get(nameID)
+		if !ok {
+			return curCtx, false, fmt.Errorf("invalid string ID %v for %v event", nameID, typ)
+		}
+		o.activeTasks[id] = taskState{name: name, parentID: parentID}
+		return curCtx, true, validateCtx(curCtx, event.UserGoReqs)
+	case go122.EvUserTaskEnd:
+		id := TaskID(ev.args[0])
+		if ts, ok := o.activeTasks[id]; ok {
+			// Smuggle the task info. This may happen in a different generation,
+			// which may not have the name in its string table. Add it to the extra
+			// strings table so we can look it up later.
+			ev.extra(version.Go122)[0] = uint64(ts.parentID)
+			ev.extra(version.Go122)[1] = uint64(evt.addExtraString(ts.name))
+			delete(o.activeTasks, id)
+		} else {
+			// Explicitly clear the task info.
+			ev.extra(version.Go122)[0] = uint64(NoTask)
+			ev.extra(version.Go122)[1] = uint64(evt.addExtraString(""))
+		}
+		return curCtx, true, validateCtx(curCtx, event.UserGoReqs)
+
+	// Handle user regions.
+	case go122.EvUserRegionBegin:
+		if err := validateCtx(curCtx, event.UserGoReqs); err != nil {
+			return curCtx, false, err
+		}
+		tid := TaskID(ev.args[0])
+		nameID := stringID(ev.args[1])
+		name, ok := evt.strings.get(nameID)
+		if !ok {
+			return curCtx, false, fmt.Errorf("invalid string ID %v for %v event", nameID, typ)
+		}
+		if err := o.gStates[curCtx.G].beginRegion(userRegion{tid, name}); err != nil {
+			return curCtx, false, err
+		}
+		return curCtx, true, nil
+	case go122.EvUserRegionEnd:
+		if err := validateCtx(curCtx, event.UserGoReqs); err != nil {
+			return curCtx, false, err
+		}
+		tid := TaskID(ev.args[0])
+		nameID := stringID(ev.args[1])
+		name, ok := evt.strings.get(nameID)
+		if !ok {
+			return curCtx, false, fmt.Errorf("invalid string ID %v for %v event", nameID, typ)
+		}
+		if err := o.gStates[curCtx.G].endRegion(userRegion{tid, name}); err != nil {
+			return curCtx, false, err
+		}
+		return curCtx, true, nil
+
+	// Handle the GC mark phase.
+	//
+	// We have sequence numbers for both start and end because they
+	// can happen on completely different threads. We want an explicit
+	// partial order edge between start and end here, otherwise we're
+	// relying entirely on timestamps to make sure we don't advance a
+	// GCEnd for a _different_ GC cycle if timestamps are wildly broken.
+	case go122.EvGCActive:
+		seq := ev.args[0]
+		if gen == o.initialGen {
+			if o.gcState != gcUndetermined {
+				return curCtx, false, fmt.Errorf("GCActive in the first generation isn't first GC event")
+			}
+			o.gcSeq = seq
+			o.gcState = gcRunning
+			return curCtx, true, nil
+		}
+		if seq != o.gcSeq+1 {
+			// This is not the right GC cycle.
+			return curCtx, false, nil
+		}
+		if o.gcState != gcRunning {
+			return curCtx, false, fmt.Errorf("encountered GCActive while GC was not in progress")
+		}
+		o.gcSeq = seq
+		if err := validateCtx(curCtx, event.UserGoReqs); err != nil {
+			return curCtx, false, err
+		}
+		return curCtx, true, nil
+	case go122.EvGCBegin:
+		seq := ev.args[0]
+		if o.gcState == gcUndetermined {
+			o.gcSeq = seq
+			o.gcState = gcRunning
+			return curCtx, true, nil
+		}
+		if seq != o.gcSeq+1 {
+			// This is not the right GC cycle.
+			return curCtx, false, nil
+		}
+		if o.gcState == gcRunning {
+			return curCtx, false, fmt.Errorf("encountered GCBegin while GC was already in progress")
+		}
+		o.gcSeq = seq
+		o.gcState = gcRunning
+		if err := validateCtx(curCtx, event.UserGoReqs); err != nil {
+			return curCtx, false, err
+		}
+		return curCtx, true, nil
+	case go122.EvGCEnd:
+		seq := ev.args[0]
+		if seq != o.gcSeq+1 {
+			// This is not the right GC cycle.
+			return curCtx, false, nil
+		}
+		if o.gcState == gcNotRunning {
+			return curCtx, false, fmt.Errorf("encountered GCEnd when GC was not in progress")
+		}
+		if o.gcState == gcUndetermined {
+			return curCtx, false, fmt.Errorf("encountered GCEnd when GC was in an undetermined state")
+		}
+		o.gcSeq = seq
+		o.gcState = gcNotRunning
+		if err := validateCtx(curCtx, event.UserGoReqs); err != nil {
+			return curCtx, false, err
+		}
+		return curCtx, true, nil
+
+	// Handle simple instantaneous events that require a G.
+	case go122.EvGoLabel, go122.EvProcsChange, go122.EvUserLog:
+		if err := validateCtx(curCtx, event.UserGoReqs); err != nil {
+			return curCtx, false, err
+		}
+		return curCtx, true, nil
+
+	// Handle allocation states, which don't require a G.
+	case go122.EvHeapAlloc, go122.EvHeapGoal:
+		if err := validateCtx(curCtx, event.SchedReqs{Thread: event.MustHave, Proc: event.MustHave, Goroutine: event.MayHave}); err != nil {
+			return curCtx, false, err
+		}
+		return curCtx, true, nil
+
+	// Handle sweep, which is bound to a P and doesn't require a G.
+	case go122.EvGCSweepBegin:
+		if err := validateCtx(curCtx, event.SchedReqs{Thread: event.MustHave, Proc: event.MustHave, Goroutine: event.MayHave}); err != nil {
+			return curCtx, false, err
+		}
+		if err := o.pStates[curCtx.P].beginRange(makeRangeType(typ, 0)); err != nil {
+			return curCtx, false, err
+		}
+		return curCtx, true, nil
+	case go122.EvGCSweepActive:
+		pid := ProcID(ev.args[0])
+		// N.B. In practice Ps can't block while they're sweeping, so this can only
+		// ever reference curCtx.P. However, be lenient about this like we are with
+		// GCMarkAssistActive; there's no reason the runtime couldn't change to block
+		// in the middle of a sweep.
+		if err := o.pStates[pid].activeRange(makeRangeType(typ, 0), gen == o.initialGen); err != nil {
+			return curCtx, false, err
+		}
+		return curCtx, true, nil
+	case go122.EvGCSweepEnd:
+		if err := validateCtx(curCtx, event.SchedReqs{Thread: event.MustHave, Proc: event.MustHave, Goroutine: event.MayHave}); err != nil {
+			return curCtx, false, err
+		}
+		_, err := o.pStates[curCtx.P].endRange(typ)
+		if err != nil {
+			return curCtx, false, err
+		}
+		return curCtx, true, nil
+
+	// Handle special goroutine-bound event ranges.
+	case go122.EvSTWBegin, go122.EvGCMarkAssistBegin:
+		if err := validateCtx(curCtx, event.UserGoReqs); err != nil {
+			return curCtx, false, err
+		}
+		desc := stringID(0)
+		if typ == go122.EvSTWBegin {
+			desc = stringID(ev.args[0])
+		}
+		if err := o.gStates[curCtx.G].beginRange(makeRangeType(typ, desc)); err != nil {
+			return curCtx, false, err
+		}
+		return curCtx, true, nil
+	case go122.EvGCMarkAssistActive:
+		gid := GoID(ev.args[0])
+		// N.B. Like GoStatus, this can happen at any time, because it can
+		// reference a non-running goroutine. Don't check anything about the
+		// current scheduler context.
+		if err := o.gStates[gid].activeRange(makeRangeType(typ, 0), gen == o.initialGen); err != nil {
+			return curCtx, false, err
+		}
+		return curCtx, true, nil
+	case go122.EvSTWEnd, go122.EvGCMarkAssistEnd:
+		if err := validateCtx(curCtx, event.UserGoReqs); err != nil {
+			return curCtx, false, err
+		}
+		desc, err := o.gStates[curCtx.G].endRange(typ)
+		if err != nil {
+			return curCtx, false, err
+		}
+		if typ == go122.EvSTWEnd {
+			// Smuggle the kind into the event.
+			// Don't use ev.extra here so we have symmetry with STWBegin.
+			ev.args[0] = uint64(desc)
+		}
+		return curCtx, true, nil
+	}
+	return curCtx, false, fmt.Errorf("bad event type found while ordering: %v", ev.typ)
+}
+
+// schedCtx represents the scheduling resources associated with an event.
+type schedCtx struct {
+	G GoID
+	P ProcID
+	M ThreadID
+}
+
+// validateCtx ensures that ctx conforms to some reqs, returning an error if
+// it doesn't.
+func validateCtx(ctx schedCtx, reqs event.SchedReqs) error {
+	// Check thread requirements.
+	if reqs.Thread == event.MustHave && ctx.M == NoThread {
+		return fmt.Errorf("expected a thread but didn't have one")
+	} else if reqs.Thread == event.MustNotHave && ctx.M != NoThread {
+		return fmt.Errorf("expected no thread but had one")
+	}
+
+	// Check proc requirements.
+	if reqs.Proc == event.MustHave && ctx.P == NoProc {
+		return fmt.Errorf("expected a proc but didn't have one")
+	} else if reqs.Proc == event.MustNotHave && ctx.P != NoProc {
+		return fmt.Errorf("expected no proc but had one")
+	}
+
+	// Check goroutine requirements.
+	if reqs.Goroutine == event.MustHave && ctx.G == NoGoroutine {
+		return fmt.Errorf("expected a goroutine but didn't have one")
+	} else if reqs.Goroutine == event.MustNotHave && ctx.G != NoGoroutine {
+		return fmt.Errorf("expected no goroutine but had one")
+	}
+	return nil
+}
+
+// gcState is a trinary variable for the current state of the GC.
+//
+// The third state besides "enabled" and "disabled" is "undetermined."
+type gcState uint8
+
+const (
+	gcUndetermined gcState = iota
+	gcNotRunning
+	gcRunning
+)
+
+// String returns a human-readable string for the GC state.
+func (s gcState) String() string {
+	switch s {
+	case gcUndetermined:
+		return "Undetermined"
+	case gcNotRunning:
+		return "NotRunning"
+	case gcRunning:
+		return "Running"
+	}
+	return "Bad"
+}
+
+// userRegion represents a unique user region when attached to some gState.
+type userRegion struct {
+	// name must be a resolved string because the string ID for the same
+	// string may change across generations, but we care about checking
+	// the value itself.
+	taskID TaskID
+	name   string
+}
+
+// rangeType is a way to classify special ranges of time.
+//
+// These typically correspond 1:1 with "Begin" events, but
+// they may have an optional subtype that describes the range
+// in more detail.
+type rangeType struct {
+	typ  event.Type // "Begin" event.
+	desc stringID   // Optional subtype.
+}
+
+// makeRangeType constructs a new rangeType.
+func makeRangeType(typ event.Type, desc stringID) rangeType {
+	if styp := go122.Specs()[typ].StartEv; styp != go122.EvNone {
+		typ = styp
+	}
+	return rangeType{typ, desc}
+}
+
+// gState is the state of a goroutine at a point in the trace.
+type gState struct {
+	id     GoID
+	status go122.GoStatus
+	seq    seqCounter
+
+	// regions are the active user regions for this goroutine.
+	regions []userRegion
+
+	// rangeState is the state of special time ranges bound to this goroutine.
+	rangeState
+}
+
+// beginRegion starts a user region on the goroutine.
+func (s *gState) beginRegion(r userRegion) error {
+	s.regions = append(s.regions, r)
+	return nil
+}
+
+// endRegion ends a user region on the goroutine.
+func (s *gState) endRegion(r userRegion) error {
+	if next := s.regions[len(s.regions)-1]; next != r {
+		return fmt.Errorf("misuse of region in goroutine %v: region end %v when the inner-most active region start event is %v", s.id, r, next)
+	}
+	s.regions = s.regions[:len(s.regions)-1]
+	return nil
+}
+
+// pState is the state of a proc at a point in the trace.
+type pState struct {
+	id     ProcID
+	status go122.ProcStatus
+	seq    seqCounter
+
+	// rangeState is the state of special time ranges bound to this proc.
+	rangeState
+}
+
+// mState is the state of a thread at a point in the trace.
+type mState struct {
+	g GoID   // Goroutine bound to this M. (The goroutine's state is Executing.)
+	p ProcID // Proc bound to this M. (The proc's state is Executing.)
+}
+
+// rangeState represents the state of special time ranges.
+type rangeState struct {
+	// inFlight contains the rangeTypes of any ranges bound to a resource.
+	inFlight []rangeType
+}
+
+// beginRange begins a special range in time on the goroutine.
+//
+// Returns an error if the range is already in progress.
+func (s *rangeState) beginRange(typ rangeType) error {
+	if s.hasRange(typ) {
+		return fmt.Errorf("discovered event already in-flight for when starting event %v", go122.Specs()[typ.typ].Name)
+	}
+	s.inFlight = append(s.inFlight, typ)
+	return nil
+}
+
+// activeRange marks special range in time on the goroutine as active in the
+// initial generation, or confirms that it is indeed active in later generations.
+func (s *rangeState) activeRange(typ rangeType, isInitialGen bool) error {
+	if isInitialGen {
+		if s.hasRange(typ) {
+			return fmt.Errorf("found named active range already in first gen: %v", typ)
+		}
+		s.inFlight = append(s.inFlight, typ)
+	} else if !s.hasRange(typ) {
+		return fmt.Errorf("resource is missing active range: %v %v", go122.Specs()[typ.typ].Name, s.inFlight)
+	}
+	return nil
+}
+
+// hasRange returns true if a special time range on the goroutine as in progress.
+func (s *rangeState) hasRange(typ rangeType) bool {
+	for _, ftyp := range s.inFlight {
+		if ftyp == typ {
+			return true
+		}
+	}
+	return false
+}
+
+// endsRange ends a special range in time on the goroutine.
+//
+// This must line up with the start event type  of the range the goroutine is currently in.
+func (s *rangeState) endRange(typ event.Type) (stringID, error) {
+	st := go122.Specs()[typ].StartEv
+	idx := -1
+	for i, r := range s.inFlight {
+		if r.typ == st {
+			idx = i
+			break
+		}
+	}
+	if idx < 0 {
+		return 0, fmt.Errorf("tried to end event %v, but not in-flight", go122.Specs()[st].Name)
+	}
+	// Swap remove.
+	desc := s.inFlight[idx].desc
+	s.inFlight[idx], s.inFlight[len(s.inFlight)-1] = s.inFlight[len(s.inFlight)-1], s.inFlight[idx]
+	s.inFlight = s.inFlight[:len(s.inFlight)-1]
+	return desc, nil
+}
+
+// seqCounter represents a global sequence counter for a resource.
+type seqCounter struct {
+	gen uint64 // The generation for the local sequence counter seq.
+	seq uint64 // The sequence number local to the generation.
+}
+
+// makeSeq creates a new seqCounter.
+func makeSeq(gen, seq uint64) seqCounter {
+	return seqCounter{gen: gen, seq: seq}
+}
+
+// succeeds returns true if a is the immediate successor of b.
+func (a seqCounter) succeeds(b seqCounter) bool {
+	return a.gen == b.gen && a.seq == b.seq+1
+}
+
+// String returns a debug string representation of the seqCounter.
+func (c seqCounter) String() string {
+	return fmt.Sprintf("%d (gen=%d)", c.seq, c.gen)
+}
+
+func dumpOrdering(order *ordering) string {
+	var sb strings.Builder
+	for id, state := range order.gStates {
+		fmt.Fprintf(&sb, "G %d [status=%s seq=%s]\n", id, state.status, state.seq)
+	}
+	fmt.Fprintln(&sb)
+	for id, state := range order.pStates {
+		fmt.Fprintf(&sb, "P %d [status=%s seq=%s]\n", id, state.status, state.seq)
+	}
+	fmt.Fprintln(&sb)
+	for id, state := range order.mStates {
+		fmt.Fprintf(&sb, "M %d [g=%d p=%d]\n", id, state.g, state.p)
+	}
+	fmt.Fprintln(&sb)
+	fmt.Fprintf(&sb, "GC %d %s\n", order.gcSeq, order.gcState)
+	return sb.String()
+}
+
+// taskState represents an active task.
+type taskState struct {
+	// name is the type of the active task.
+	name string
+
+	// parentID is the parent ID of the active task.
+	parentID TaskID
+}
diff --git a/trace/reader.go b/trace/reader.go
new file mode 100644
index 0000000..c561d58
--- /dev/null
+++ b/trace/reader.go
@@ -0,0 +1,199 @@
+// Copyright 2023 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.
+
+// Code generated by "gen.bash" from internal/trace/v2; DO NOT EDIT.
+
+//go:build go1.21
+
+package trace
+
+import (
+	"bufio"
+	"fmt"
+	"io"
+	"slices"
+	"strings"
+
+	"golang.org/x/exp/trace/internal/event/go122"
+	"golang.org/x/exp/trace/internal/version"
+)
+
+// Reader reads a byte stream, validates it, and produces trace events.
+type Reader struct {
+	r           *bufio.Reader
+	lastTs      Time
+	gen         *generation
+	spill       *spilledBatch
+	frontier    []*batchCursor
+	cpuSamples  []cpuSample
+	order       ordering
+	emittedSync bool
+}
+
+// NewReader creates a new trace reader.
+func NewReader(r io.Reader) (*Reader, error) {
+	br := bufio.NewReader(r)
+	v, err := version.ReadHeader(br)
+	if err != nil {
+		return nil, err
+	}
+	if v != version.Go122 {
+		return nil, fmt.Errorf("unknown or unsupported version go 1.%d", v)
+	}
+	return &Reader{
+		r: br,
+		order: ordering{
+			mStates:     make(map[ThreadID]*mState),
+			pStates:     make(map[ProcID]*pState),
+			gStates:     make(map[GoID]*gState),
+			activeTasks: make(map[TaskID]taskState),
+		},
+		// Don't emit a sync event when we first go to emit events.
+		emittedSync: true,
+	}, nil
+}
+
+// ReadEvent reads a single event from the stream.
+//
+// If the stream has been exhausted, it returns an invalid
+// event and io.EOF.
+func (r *Reader) ReadEvent() (e Event, err error) {
+	// Go 1.22+ trace parsing algorithm.
+	//
+	// (1) Read in all the batches for the next generation from the stream.
+	//   (a) Use the size field in the header to quickly find all batches.
+	// (2) Parse out the strings, stacks, CPU samples, and timestamp conversion data.
+	// (3) Group each event batch by M, sorted by timestamp. (batchCursor contains the groups.)
+	// (4) Organize batchCursors in a min-heap, ordered by the timestamp of the next event for each M.
+	// (5) Try to advance the next event for the M at the top of the min-heap.
+	//   (a) On success, select that M.
+	//   (b) On failure, sort the min-heap and try to advance other Ms. Select the first M that advances.
+	//   (c) If there's nothing left to advance, goto (1).
+	// (6) Select the latest event for the selected M and get it ready to be returned.
+	// (7) Read the next event for the selected M and update the min-heap.
+	// (8) Return the selected event, goto (5) on the next call.
+
+	// Set us up to track the last timestamp and fix up
+	// the timestamp of any event that comes through.
+	defer func() {
+		if err != nil {
+			return
+		}
+		if err = e.validateTableIDs(); err != nil {
+			return
+		}
+		if e.base.time <= r.lastTs {
+			e.base.time = r.lastTs + 1
+		}
+		r.lastTs = e.base.time
+	}()
+
+	// Consume any extra events produced during parsing.
+	if ev := r.order.consumeExtraEvent(); ev.Kind() != EventBad {
+		return ev, nil
+	}
+
+	// Check if we need to refresh the generation.
+	if len(r.frontier) == 0 && len(r.cpuSamples) == 0 {
+		if !r.emittedSync {
+			r.emittedSync = true
+			return syncEvent(r.gen.evTable, r.lastTs), nil
+		}
+		if r.gen != nil && r.spill == nil {
+			// If we have a generation from the last read,
+			// and there's nothing left in the frontier, and
+			// there's no spilled batch, indicating that there's
+			// no further generation, it means we're done.
+			// Return io.EOF.
+			return Event{}, io.EOF
+		}
+		// Read the next generation.
+		r.gen, r.spill, err = readGeneration(r.r, r.spill)
+		if err != nil {
+			return Event{}, err
+		}
+
+		// Reset CPU samples cursor.
+		r.cpuSamples = r.gen.cpuSamples
+
+		// Reset frontier.
+		for m, batches := range r.gen.batches {
+			bc := &batchCursor{m: m}
+			ok, err := bc.nextEvent(batches, r.gen.freq)
+			if err != nil {
+				return Event{}, err
+			}
+			if !ok {
+				// Turns out there aren't actually any events in these batches.
+				continue
+			}
+			r.frontier = heapInsert(r.frontier, bc)
+		}
+
+		// Reset emittedSync.
+		r.emittedSync = false
+	}
+	refresh := func(i int) error {
+		bc := r.frontier[i]
+
+		// Refresh the cursor's event.
+		ok, err := bc.nextEvent(r.gen.batches[bc.m], r.gen.freq)
+		if err != nil {
+			return err
+		}
+		if ok {
+			// If we successfully refreshed, update the heap.
+			heapUpdate(r.frontier, i)
+		} else {
+			// There's nothing else to read. Delete this cursor from the frontier.
+			r.frontier = heapRemove(r.frontier, i)
+		}
+		return nil
+	}
+	// Inject a CPU sample if it comes next.
+	if len(r.cpuSamples) != 0 {
+		if len(r.frontier) == 0 || r.cpuSamples[0].time < r.frontier[0].ev.time {
+			e := r.cpuSamples[0].asEvent(r.gen.evTable)
+			r.cpuSamples = r.cpuSamples[1:]
+			return e, nil
+		}
+	}
+	// Try to advance the head of the frontier, which should have the minimum timestamp.
+	// This should be by far the most common case
+	bc := r.frontier[0]
+	if ctx, ok, err := r.order.advance(&bc.ev, r.gen.evTable, bc.m, r.gen.gen); err != nil {
+		return Event{}, err
+	} else if ok {
+		e := Event{table: r.gen.evTable, ctx: ctx, base: bc.ev}
+		return e, refresh(0)
+	}
+	// Sort the min-heap. A sorted min-heap is still a min-heap,
+	// but now we can iterate over the rest and try to advance in
+	// order. This path should be rare.
+	slices.SortFunc(r.frontier, (*batchCursor).compare)
+	// Try to advance the rest of the frontier, in timestamp order.
+	for i := 1; i < len(r.frontier); i++ {
+		bc := r.frontier[i]
+		if ctx, ok, err := r.order.advance(&bc.ev, r.gen.evTable, bc.m, r.gen.gen); err != nil {
+			return Event{}, err
+		} else if ok {
+			e := Event{table: r.gen.evTable, ctx: ctx, base: bc.ev}
+			return e, refresh(i)
+		}
+	}
+	return Event{}, fmt.Errorf("broken trace: failed to advance: frontier:\n[gen=%d]\n\n%s\n%s\n", r.gen.gen, dumpFrontier(r.frontier), dumpOrdering(&r.order))
+}
+
+func dumpFrontier(frontier []*batchCursor) string {
+	var sb strings.Builder
+	for _, bc := range frontier {
+		spec := go122.Specs()[bc.ev.typ]
+		fmt.Fprintf(&sb, "M %d [%s time=%d", bc.m, spec.Name, bc.ev.time)
+		for i, arg := range spec.Args[1:] {
+			fmt.Fprintf(&sb, " %s=%d", arg, bc.ev.args[i])
+		}
+		fmt.Fprintf(&sb, "]\n")
+	}
+	return sb.String()
+}
diff --git a/trace/reader_test.go b/trace/reader_test.go
new file mode 100644
index 0000000..84d04a6
--- /dev/null
+++ b/trace/reader_test.go
@@ -0,0 +1,129 @@
+// Copyright 2023 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.
+
+// Code generated by "gen.bash" from internal/trace/v2; DO NOT EDIT.
+
+//go:build go1.21
+
+package trace_test
+
+import (
+	"bytes"
+	"flag"
+	"fmt"
+	"io"
+	"os"
+	"path/filepath"
+	"strings"
+	"testing"
+
+	"golang.org/x/exp/trace"
+	"golang.org/x/exp/trace/internal/raw"
+	"golang.org/x/exp/trace/internal/testtrace"
+	"golang.org/x/exp/trace/internal/version"
+)
+
+var (
+	logEvents  = flag.Bool("log-events", false, "whether to log high-level events; significantly slows down tests")
+	dumpTraces = flag.Bool("dump-traces", false, "dump traces even on success")
+)
+
+func TestReaderGolden(t *testing.T) {
+	matches, err := filepath.Glob("./testdata/tests/*.test")
+	if err != nil {
+		t.Fatalf("failed to glob for tests: %v", err)
+	}
+	for _, testPath := range matches {
+		testPath := testPath
+		testName, err := filepath.Rel("./testdata", testPath)
+		if err != nil {
+			t.Fatalf("failed to relativize testdata path: %v", err)
+		}
+		t.Run(testName, func(t *testing.T) {
+			tr, exp, err := testtrace.ParseFile(testPath)
+			if err != nil {
+				t.Fatalf("failed to parse test file at %s: %v", testPath, err)
+			}
+			testReader(t, tr, exp)
+		})
+	}
+}
+
+func testReader(t *testing.T, tr io.Reader, exp *testtrace.Expectation) {
+	r, err := trace.NewReader(tr)
+	if err != nil {
+		if err := exp.Check(err); err != nil {
+			t.Error(err)
+		}
+		return
+	}
+	v := testtrace.NewValidator()
+	for {
+		ev, err := r.ReadEvent()
+		if err == io.EOF {
+			break
+		}
+		if err != nil {
+			if err := exp.Check(err); err != nil {
+				t.Error(err)
+			}
+			return
+		}
+		if *logEvents {
+			t.Log(ev.String())
+		}
+		if err := v.Event(ev); err != nil {
+			t.Error(err)
+		}
+	}
+	if err := exp.Check(nil); err != nil {
+		t.Error(err)
+	}
+}
+
+func dumpTraceToText(t *testing.T, b []byte) string {
+	t.Helper()
+
+	br, err := raw.NewReader(bytes.NewReader(b))
+	if err != nil {
+		t.Fatalf("dumping trace: %v", err)
+	}
+	var sb strings.Builder
+	tw, err := raw.NewTextWriter(&sb, version.Go122)
+	if err != nil {
+		t.Fatalf("dumping trace: %v", err)
+	}
+	for {
+		ev, err := br.ReadEvent()
+		if err == io.EOF {
+			break
+		}
+		if err != nil {
+			t.Fatalf("dumping trace: %v", err)
+		}
+		if err := tw.WriteEvent(ev); err != nil {
+			t.Fatalf("dumping trace: %v", err)
+		}
+	}
+	return sb.String()
+}
+
+func dumpTraceToFile(t *testing.T, testName string, stress bool, b []byte) string {
+	t.Helper()
+
+	desc := "default"
+	if stress {
+		desc = "stress"
+	}
+	name := fmt.Sprintf("%s.%s.trace.", testName, desc)
+	f, err := os.CreateTemp("", name)
+	if err != nil {
+		t.Fatalf("creating temp file: %v", err)
+	}
+	defer f.Close()
+	if _, err := io.Copy(f, bytes.NewReader(b)); err != nil {
+		t.Fatalf("writing trace dump to %q: %v", f.Name(), err)
+	}
+	return f.Name()
+}
diff --git a/trace/resources.go b/trace/resources.go
new file mode 100644
index 0000000..2b152eb
--- /dev/null
+++ b/trace/resources.go
@@ -0,0 +1,278 @@
+// Copyright 2023 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.
+
+// Code generated by "gen.bash" from internal/trace/v2; DO NOT EDIT.
+
+//go:build go1.21
+
+package trace
+
+import "fmt"
+
+// ThreadID is the runtime-internal M structure's ID. This is unique
+// for each OS thread.
+type ThreadID int64
+
+// NoThread indicates that the relevant events don't correspond to any
+// thread in particular.
+const NoThread = ThreadID(-1)
+
+// ProcID is the runtime-internal G structure's id field. This is unique
+// for each P.
+type ProcID int64
+
+// NoProc indicates that the relevant events don't correspond to any
+// P in particular.
+const NoProc = ProcID(-1)
+
+// GoID is the runtime-internal G structure's goid field. This is unique
+// for each goroutine.
+type GoID int64
+
+// NoGoroutine indicates that the relevant events don't correspond to any
+// goroutine in particular.
+const NoGoroutine = GoID(-1)
+
+// GoState represents the state of a goroutine.
+//
+// New GoStates may be added in the future. Users of this type must be robust
+// to that possibility.
+type GoState uint8
+
+const (
+	GoUndetermined GoState = iota // No information is known about the goroutine.
+	GoNotExist                    // Goroutine does not exist.
+	GoRunnable                    // Goroutine is runnable but not running.
+	GoRunning                     // Goroutine is running.
+	GoWaiting                     // Goroutine is waiting on something to happen.
+	GoSyscall                     // Goroutine is in a system call.
+)
+
+// Executing returns true if the state indicates that the goroutine is executing
+// and bound to its thread.
+func (s GoState) Executing() bool {
+	return s == GoRunning || s == GoSyscall
+}
+
+// String returns a human-readable representation of a GoState.
+//
+// The format of the returned string is for debugging purposes and is subject to change.
+func (s GoState) String() string {
+	switch s {
+	case GoUndetermined:
+		return "Undetermined"
+	case GoNotExist:
+		return "NotExist"
+	case GoRunnable:
+		return "Runnable"
+	case GoRunning:
+		return "Running"
+	case GoWaiting:
+		return "Waiting"
+	case GoSyscall:
+		return "Syscall"
+	}
+	return "Bad"
+}
+
+// ProcState represents the state of a proc.
+//
+// New ProcStates may be added in the future. Users of this type must be robust
+// to that possibility.
+type ProcState uint8
+
+const (
+	ProcUndetermined ProcState = iota // No information is known about the proc.
+	ProcNotExist                      // Proc does not exist.
+	ProcRunning                       // Proc is running.
+	ProcIdle                          // Proc is idle.
+)
+
+// Executing returns true if the state indicates that the proc is executing
+// and bound to its thread.
+func (s ProcState) Executing() bool {
+	return s == ProcRunning
+}
+
+// String returns a human-readable representation of a ProcState.
+//
+// The format of the returned string is for debugging purposes and is subject to change.
+func (s ProcState) String() string {
+	switch s {
+	case ProcUndetermined:
+		return "Undetermined"
+	case ProcNotExist:
+		return "NotExist"
+	case ProcRunning:
+		return "Running"
+	case ProcIdle:
+		return "Idle"
+	}
+	return "Bad"
+}
+
+// ResourceKind indicates a kind of resource that has a state machine.
+//
+// New ResourceKinds may be added in the future. Users of this type must be robust
+// to that possibility.
+type ResourceKind uint8
+
+const (
+	ResourceNone      ResourceKind = iota // No resource.
+	ResourceGoroutine                     // Goroutine.
+	ResourceProc                          // Proc.
+	ResourceThread                        // Thread.
+)
+
+// String returns a human-readable representation of a ResourceKind.
+//
+// The format of the returned string is for debugging purposes and is subject to change.
+func (r ResourceKind) String() string {
+	switch r {
+	case ResourceNone:
+		return "None"
+	case ResourceGoroutine:
+		return "Goroutine"
+	case ResourceProc:
+		return "Proc"
+	case ResourceThread:
+		return "Thread"
+	}
+	return "Bad"
+}
+
+// ResourceID represents a generic resource ID.
+type ResourceID struct {
+	// Kind is the kind of resource this ID is for.
+	Kind ResourceKind
+	id   int64
+}
+
+// MakeResourceID creates a general resource ID from a specific resource's ID.
+func MakeResourceID[T interface{ GoID | ProcID | ThreadID }](id T) ResourceID {
+	var rd ResourceID
+	var a any = id
+	switch a.(type) {
+	case GoID:
+		rd.Kind = ResourceGoroutine
+	case ProcID:
+		rd.Kind = ResourceProc
+	case ThreadID:
+		rd.Kind = ResourceThread
+	}
+	rd.id = int64(id)
+	return rd
+}
+
+// Goroutine obtains a GoID from the resource ID.
+//
+// r.Kind must be ResourceGoroutine or this function will panic.
+func (r ResourceID) Goroutine() GoID {
+	if r.Kind != ResourceGoroutine {
+		panic(fmt.Sprintf("attempted to get GoID from %s resource ID", r.Kind))
+	}
+	return GoID(r.id)
+}
+
+// Proc obtains a ProcID from the resource ID.
+//
+// r.Kind must be ResourceProc or this function will panic.
+func (r ResourceID) Proc() ProcID {
+	if r.Kind != ResourceProc {
+		panic(fmt.Sprintf("attempted to get ProcID from %s resource ID", r.Kind))
+	}
+	return ProcID(r.id)
+}
+
+// Thread obtains a ThreadID from the resource ID.
+//
+// r.Kind must be ResourceThread or this function will panic.
+func (r ResourceID) Thread() ThreadID {
+	if r.Kind != ResourceThread {
+		panic(fmt.Sprintf("attempted to get ThreadID from %s resource ID", r.Kind))
+	}
+	return ThreadID(r.id)
+}
+
+// String returns a human-readable string representation of the ResourceID.
+//
+// This representation is subject to change and is intended primarily for debugging.
+func (r ResourceID) String() string {
+	if r.Kind == ResourceNone {
+		return r.Kind.String()
+	}
+	return fmt.Sprintf("%s(%d)", r.Kind, r.id)
+}
+
+// StateTransition provides details about a StateTransition event.
+type StateTransition struct {
+	// Resource is the resource this state transition is for.
+	Resource ResourceID
+
+	// Reason is a human-readable reason for the state transition.
+	Reason string
+
+	// Stack is the stack trace of the resource making the state transition.
+	//
+	// This is distinct from the result (Event).Stack because it pertains to
+	// the transitioning resource, not any of the ones executing the event
+	// this StateTransition came from.
+	//
+	// An example of this difference is the NotExist -> Runnable transition for
+	// goroutines, which indicates goroutine creation. In this particular case,
+	// a Stack here would refer to the starting stack of the new goroutine, and
+	// an (Event).Stack would refer to the stack trace of whoever created the
+	// goroutine.
+	Stack Stack
+
+	// The actual transition data. Stored in a neutral form so that
+	// we don't need fields for every kind of resource.
+	id       int64
+	oldState uint8
+	newState uint8
+}
+
+func goStateTransition(id GoID, from, to GoState) StateTransition {
+	return StateTransition{
+		Resource: ResourceID{Kind: ResourceGoroutine, id: int64(id)},
+		oldState: uint8(from),
+		newState: uint8(to),
+	}
+}
+
+func procStateTransition(id ProcID, from, to ProcState) StateTransition {
+	return StateTransition{
+		Resource: ResourceID{Kind: ResourceProc, id: int64(id)},
+		oldState: uint8(from),
+		newState: uint8(to),
+	}
+}
+
+// Goroutine returns the state transition for a goroutine.
+//
+// Transitions to and from states that are Executing are special in that
+// they change the future execution context. In other words, future events
+// on the same thread will feature the same goroutine until it stops running.
+//
+// Panics if d.Resource.Kind is not ResourceGoroutine.
+func (d StateTransition) Goroutine() (from, to GoState) {
+	if d.Resource.Kind != ResourceGoroutine {
+		panic("Goroutine called on non-Goroutine state transition")
+	}
+	return GoState(d.oldState), GoState(d.newState)
+}
+
+// Proc returns the state transition for a proc.
+//
+// Transitions to and from states that are Executing are special in that
+// they change the future execution context. In other words, future events
+// on the same thread will feature the same goroutine until it stops running.
+//
+// Panics if d.Resource.Kind is not ResourceProc.
+func (d StateTransition) Proc() (from, to ProcState) {
+	if d.Resource.Kind != ResourceProc {
+		panic("Proc called on non-Proc state transition")
+	}
+	return ProcState(d.oldState), ProcState(d.newState)
+}
diff --git a/trace/testdata/README.md b/trace/testdata/README.md
new file mode 100644
index 0000000..0fae9ca
--- /dev/null
+++ b/trace/testdata/README.md
@@ -0,0 +1,38 @@
+# Trace test data
+
+## Trace golden tests
+
+Trace tests can be generated by running
+
+```
+go generate .
+```
+
+with the relevant toolchain in this directory.
+
+This will put the tests into a `tests` directory where the trace reader
+tests will find them.
+
+A subset of tests can be regenerated by specifying a regexp pattern for
+the names of tests to generate in the `GOTRACETEST` environment
+variable.
+Test names are defined as the name of the `.go` file that generates the
+trace, but with the `.go` extension removed.
+
+## Trace test programs
+
+The trace test programs in the `testprog` directory generate traces to
+stdout.
+Otherwise they're just normal programs.
+
+## Trace debug commands
+
+The `cmd` directory contains helpful tools for debugging traces.
+
+* `gotraceraw` parses traces without validation.
+  It can produce a text version of the trace wire format, or convert
+  the text format back into bytes.
+* `gotracevalidate` parses traces and validates them.
+  It performs more rigorous checks than the parser does on its own,
+  which helps for debugging the parser as well.
+  In fact, it performs the exact same checks that the tests do.
diff --git a/trace/testdata/generate.go b/trace/testdata/generate.go
new file mode 100644
index 0000000..81b64d2
--- /dev/null
+++ b/trace/testdata/generate.go
@@ -0,0 +1,10 @@
+// Copyright 2023 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.
+
+// Code generated by "gen.bash" from internal/trace/v2; DO NOT EDIT.
+
+//go:build go1.21
+
+//go:generate go run mktests.go
+package testdata
diff --git a/trace/testdata/generators/go122-confuse-seq-across-generations.go b/trace/testdata/generators/go122-confuse-seq-across-generations.go
new file mode 100644
index 0000000..83bb8e6
--- /dev/null
+++ b/trace/testdata/generators/go122-confuse-seq-across-generations.go
@@ -0,0 +1,66 @@
+// Copyright 2023 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.
+
+// Code generated by "gen.bash" from internal/trace/v2; DO NOT EDIT.
+
+//go:build go1.21
+
+// Regression test for an issue found in development.
+//
+// The core of the issue is that if generation counters
+// aren't considered as part of sequence numbers, then
+// it's possible to accidentally advance without a
+// GoStatus event.
+//
+// The situation is one in which it just so happens that
+// an event on the frontier for a following generation
+// has a sequence number exactly one higher than the last
+// sequence number for e.g. a goroutine in the previous
+// generation. The parser should wait to find a GoStatus
+// event before advancing into the next generation at all.
+// It turns out this situation is pretty rare; the GoStatus
+// event almost always shows up first in practice. But it
+// can and did happen.
+
+package main
+
+import (
+	"golang.org/x/exp/trace"
+	"golang.org/x/exp/trace/internal/event/go122"
+	testgen "golang.org/x/exp/trace/internal/testgen/go122"
+)
+
+func main() {
+	testgen.Main(gen)
+}
+
+func gen(t *testgen.Trace) {
+	g1 := t.Generation(1)
+
+	// A running goroutine blocks.
+	b10 := g1.Batch(trace.ThreadID(0), 0)
+	b10.Event("ProcStatus", trace.ProcID(0), go122.ProcRunning)
+	b10.Event("GoStatus", trace.GoID(1), trace.ThreadID(0), go122.GoRunning)
+	b10.Event("GoStop", "whatever", testgen.NoStack)
+
+	// The running goroutine gets unblocked.
+	b11 := g1.Batch(trace.ThreadID(1), 0)
+	b11.Event("ProcStatus", trace.ProcID(1), go122.ProcRunning)
+	b11.Event("GoStart", trace.GoID(1), testgen.Seq(1))
+	b11.Event("GoStop", "whatever", testgen.NoStack)
+
+	g2 := t.Generation(2)
+
+	// Start running the goroutine, but later.
+	b21 := g2.Batch(trace.ThreadID(1), 3)
+	b21.Event("ProcStatus", trace.ProcID(1), go122.ProcRunning)
+	b21.Event("GoStart", trace.GoID(1), testgen.Seq(2))
+
+	// The goroutine starts running, then stops, then starts again.
+	b20 := g2.Batch(trace.ThreadID(0), 5)
+	b20.Event("ProcStatus", trace.ProcID(0), go122.ProcRunning)
+	b20.Event("GoStatus", trace.GoID(1), trace.ThreadID(0), go122.GoRunnable)
+	b20.Event("GoStart", trace.GoID(1), testgen.Seq(1))
+	b20.Event("GoStop", "whatever", testgen.NoStack)
+}
diff --git a/trace/testdata/generators/go122-create-syscall-reuse-thread-id.go b/trace/testdata/generators/go122-create-syscall-reuse-thread-id.go
new file mode 100644
index 0000000..01bee41
--- /dev/null
+++ b/trace/testdata/generators/go122-create-syscall-reuse-thread-id.go
@@ -0,0 +1,65 @@
+// Copyright 2023 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.
+
+// Code generated by "gen.bash" from internal/trace/v2; DO NOT EDIT.
+
+//go:build go1.21
+
+// Tests a G being created from within a syscall.
+//
+// Specifically, it tests a scenerio wherein a C
+// thread is calling into Go, creating a goroutine in
+// a syscall (in the tracer's model). The system is free
+// to reuse thread IDs, so first a thread ID is used to
+// call into Go, and then is used for a Go-created thread.
+//
+// This is a regression test. The trace parser didn't correctly
+// model GoDestroySyscall as dropping its P (even if the runtime
+// did). It turns out this is actually fine if all the threads
+// in the trace have unique IDs, since the P just stays associated
+// with an eternally dead thread, and it's stolen by some other
+// thread later. But if thread IDs are reused, then the tracer
+// gets confused when trying to advance events on the new thread.
+// The now-dead thread which exited on a GoDestroySyscall still has
+// its P associated and this transfers to the newly-live thread
+// in the parser's state because they share a thread ID.
+
+package main
+
+import (
+	"golang.org/x/exp/trace"
+	"golang.org/x/exp/trace/internal/event/go122"
+	testgen "golang.org/x/exp/trace/internal/testgen/go122"
+)
+
+func main() {
+	testgen.Main(gen)
+}
+
+func gen(t *testgen.Trace) {
+	g := t.Generation(1)
+
+	// A C thread calls into Go and acquires a P. It returns
+	// back to C, destroying the G.
+	b0 := g.Batch(trace.ThreadID(0), 0)
+	b0.Event("GoCreateSyscall", trace.GoID(4))
+	b0.Event("GoSyscallEndBlocked")
+	b0.Event("ProcStatus", trace.ProcID(0), go122.ProcIdle)
+	b0.Event("ProcStart", trace.ProcID(0), testgen.Seq(1))
+	b0.Event("GoStatus", trace.GoID(4), trace.NoThread, go122.GoRunnable)
+	b0.Event("GoStart", trace.GoID(4), testgen.Seq(1))
+	b0.Event("GoSyscallBegin", testgen.Seq(2), testgen.NoStack)
+	b0.Event("GoDestroySyscall")
+
+	// A new Go-created thread with the same ID appears and
+	// starts running, then tries to steal the P from the
+	// first thread. The stealing is interesting because if
+	// the parser handles GoDestroySyscall wrong, then we
+	// have a self-steal here potentially that doesn't make
+	// sense.
+	b1 := g.Batch(trace.ThreadID(0), 0)
+	b1.Event("ProcStatus", trace.ProcID(1), go122.ProcIdle)
+	b1.Event("ProcStart", trace.ProcID(1), testgen.Seq(1))
+	b1.Event("ProcSteal", trace.ProcID(0), testgen.Seq(3), trace.ThreadID(0))
+}
diff --git a/trace/testdata/generators/go122-create-syscall-with-p.go b/trace/testdata/generators/go122-create-syscall-with-p.go
new file mode 100644
index 0000000..4d4d208
--- /dev/null
+++ b/trace/testdata/generators/go122-create-syscall-with-p.go
@@ -0,0 +1,56 @@
+// Copyright 2023 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.
+
+// Code generated by "gen.bash" from internal/trace/v2; DO NOT EDIT.
+
+//go:build go1.21
+
+// Tests a G being created from within a syscall.
+//
+// Specifically, it tests a scenerio wherein a C
+// thread is calling into Go, creating a goroutine in
+// a syscall (in the tracer's model). Because the actual
+// m can be reused, it's possible for that m to have never
+// had its P (in _Psyscall) stolen if the runtime doesn't
+// model the scenario correctly. Make sure we reject such
+// traces.
+
+package main
+
+import (
+	"golang.org/x/exp/trace"
+	"golang.org/x/exp/trace/internal/event/go122"
+	testgen "golang.org/x/exp/trace/internal/testgen/go122"
+)
+
+func main() {
+	testgen.Main(gen)
+}
+
+func gen(t *testgen.Trace) {
+	t.ExpectFailure(".*expected a proc but didn't have one.*")
+
+	g := t.Generation(1)
+
+	// A C thread calls into Go and acquires a P. It returns
+	// back to C, destroying the G. It then comes back to Go
+	// on the same thread and again returns to C.
+	//
+	// Note: on pthread platforms this can't happen on the
+	// same thread because the m is stashed in TLS between
+	// calls into Go, until the thread dies. This is still
+	// possible on other platforms, however.
+	b0 := g.Batch(trace.ThreadID(0), 0)
+	b0.Event("GoCreateSyscall", trace.GoID(4))
+	b0.Event("ProcStatus", trace.ProcID(0), go122.ProcIdle)
+	b0.Event("ProcStart", trace.ProcID(0), testgen.Seq(1))
+	b0.Event("GoSyscallEndBlocked")
+	b0.Event("GoStart", trace.GoID(4), testgen.Seq(1))
+	b0.Event("GoSyscallBegin", testgen.Seq(2), testgen.NoStack)
+	b0.Event("GoDestroySyscall")
+	b0.Event("GoCreateSyscall", trace.GoID(4))
+	b0.Event("GoSyscallEnd")
+	b0.Event("GoSyscallBegin", testgen.Seq(3), testgen.NoStack)
+	b0.Event("GoDestroySyscall")
+}
diff --git a/trace/testdata/generators/go122-go-create-without-running-g.go b/trace/testdata/generators/go122-go-create-without-running-g.go
new file mode 100644
index 0000000..10d0020
--- /dev/null
+++ b/trace/testdata/generators/go122-go-create-without-running-g.go
@@ -0,0 +1,37 @@
+// Copyright 2023 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.
+
+// Code generated by "gen.bash" from internal/trace/v2; DO NOT EDIT.
+
+//go:build go1.21
+
+// Regression test for an issue found in development.
+//
+// GoCreate events can happen on bare Ps in a variety of situations and
+// and earlier version of the parser assumed this wasn't possible. At
+// the time of writing, one such example is goroutines created by expiring
+// timers.
+
+package main
+
+import (
+	"golang.org/x/exp/trace"
+	"golang.org/x/exp/trace/internal/event/go122"
+	testgen "golang.org/x/exp/trace/internal/testgen/go122"
+)
+
+func main() {
+	testgen.Main(gen)
+}
+
+func gen(t *testgen.Trace) {
+	g1 := t.Generation(1)
+
+	// A goroutine gets created on a running P, then starts running.
+	b0 := g1.Batch(trace.ThreadID(0), 0)
+	b0.Event("ProcStatus", trace.ProcID(0), go122.ProcRunning)
+	b0.Event("GoCreate", trace.GoID(5), testgen.NoStack, testgen.NoStack)
+	b0.Event("GoStart", trace.GoID(5), testgen.Seq(1))
+	b0.Event("GoStop", "whatever", testgen.NoStack)
+}
diff --git a/trace/testdata/generators/go122-syscall-steal-proc-ambiguous.go b/trace/testdata/generators/go122-syscall-steal-proc-ambiguous.go
new file mode 100644
index 0000000..9b98749
--- /dev/null
+++ b/trace/testdata/generators/go122-syscall-steal-proc-ambiguous.go
@@ -0,0 +1,50 @@
+// Copyright 2023 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.
+
+// Code generated by "gen.bash" from internal/trace/v2; DO NOT EDIT.
+
+//go:build go1.21
+
+// Tests syscall P stealing.
+//
+// Specifically, it tests a scenerio wherein, without a
+// P sequence number of GoSyscallBegin, the syscall that
+// a ProcSteal applies to is ambiguous. This only happens in
+// practice when the events aren't already properly ordered
+// by timestamp, since the ProcSteal won't be seen until after
+// the correct GoSyscallBegin appears on the frontier.
+
+package main
+
+import (
+	"golang.org/x/exp/trace"
+	"golang.org/x/exp/trace/internal/event/go122"
+	testgen "golang.org/x/exp/trace/internal/testgen/go122"
+)
+
+func main() {
+	testgen.Main(gen)
+}
+
+func gen(t *testgen.Trace) {
+	t.DisableTimestamps()
+
+	g := t.Generation(1)
+
+	// One goroutine does a syscall without blocking, then another one where
+	// it's P gets stolen.
+	b0 := g.Batch(trace.ThreadID(0), 0)
+	b0.Event("ProcStatus", trace.ProcID(0), go122.ProcRunning)
+	b0.Event("GoStatus", trace.GoID(1), trace.ThreadID(0), go122.GoRunning)
+	b0.Event("GoSyscallBegin", testgen.Seq(1), testgen.NoStack)
+	b0.Event("GoSyscallEnd")
+	b0.Event("GoSyscallBegin", testgen.Seq(2), testgen.NoStack)
+	b0.Event("GoSyscallEndBlocked")
+
+	// A running goroutine steals proc 0.
+	b1 := g.Batch(trace.ThreadID(1), 0)
+	b1.Event("ProcStatus", trace.ProcID(2), go122.ProcRunning)
+	b1.Event("GoStatus", trace.GoID(2), trace.ThreadID(1), go122.GoRunning)
+	b1.Event("ProcSteal", trace.ProcID(0), testgen.Seq(3), trace.ThreadID(0))
+}
diff --git a/trace/testdata/generators/go122-syscall-steal-proc-gen-boundary-bare-m.go b/trace/testdata/generators/go122-syscall-steal-proc-gen-boundary-bare-m.go
new file mode 100644
index 0000000..1db4cd9
--- /dev/null
+++ b/trace/testdata/generators/go122-syscall-steal-proc-gen-boundary-bare-m.go
@@ -0,0 +1,37 @@
+// Copyright 2023 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.
+
+// Code generated by "gen.bash" from internal/trace/v2; DO NOT EDIT.
+
+//go:build go1.21
+
+// Tests syscall P stealing at a generation boundary.
+
+package main
+
+import (
+	"golang.org/x/exp/trace"
+	"golang.org/x/exp/trace/internal/event/go122"
+	testgen "golang.org/x/exp/trace/internal/testgen/go122"
+)
+
+func main() {
+	testgen.Main(gen)
+}
+
+func gen(t *testgen.Trace) {
+	g := t.Generation(1)
+
+	// One goroutine is exiting with a syscall. It already
+	// acquired a new P.
+	b0 := g.Batch(trace.ThreadID(0), 0)
+	b0.Event("ProcStatus", trace.ProcID(1), go122.ProcRunning)
+	b0.Event("GoStatus", trace.GoID(1), trace.ThreadID(0), go122.GoSyscall)
+	b0.Event("GoSyscallEndBlocked")
+
+	// A bare M stole the goroutine's P at the generation boundary.
+	b1 := g.Batch(trace.ThreadID(1), 0)
+	b1.Event("ProcStatus", trace.ProcID(0), go122.ProcSyscallAbandoned)
+	b1.Event("ProcSteal", trace.ProcID(0), testgen.Seq(1), trace.ThreadID(0))
+}
diff --git a/trace/testdata/generators/go122-syscall-steal-proc-gen-boundary-reacquire-new-proc-bare-m.go b/trace/testdata/generators/go122-syscall-steal-proc-gen-boundary-reacquire-new-proc-bare-m.go
new file mode 100644
index 0000000..ab0574d
--- /dev/null
+++ b/trace/testdata/generators/go122-syscall-steal-proc-gen-boundary-reacquire-new-proc-bare-m.go
@@ -0,0 +1,38 @@
+// Copyright 2023 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.
+
+// Code generated by "gen.bash" from internal/trace/v2; DO NOT EDIT.
+
+//go:build go1.21
+
+// Tests syscall P stealing at a generation boundary.
+
+package main
+
+import (
+	"golang.org/x/exp/trace"
+	"golang.org/x/exp/trace/internal/event/go122"
+	testgen "golang.org/x/exp/trace/internal/testgen/go122"
+)
+
+func main() {
+	testgen.Main(gen)
+}
+
+func gen(t *testgen.Trace) {
+	g := t.Generation(1)
+
+	// One goroutine is exiting with a syscall. It already
+	// acquired a new P.
+	b0 := g.Batch(trace.ThreadID(0), 0)
+	b0.Event("GoStatus", trace.GoID(1), trace.ThreadID(0), go122.GoSyscall)
+	b0.Event("ProcStatus", trace.ProcID(1), go122.ProcIdle)
+	b0.Event("ProcStart", trace.ProcID(1), testgen.Seq(1))
+	b0.Event("GoSyscallEndBlocked")
+
+	// A bare M stole the goroutine's P at the generation boundary.
+	b1 := g.Batch(trace.ThreadID(1), 0)
+	b1.Event("ProcStatus", trace.ProcID(0), go122.ProcSyscallAbandoned)
+	b1.Event("ProcSteal", trace.ProcID(0), testgen.Seq(1), trace.ThreadID(0))
+}
diff --git a/trace/testdata/generators/go122-syscall-steal-proc-gen-boundary-reacquire-new-proc.go b/trace/testdata/generators/go122-syscall-steal-proc-gen-boundary-reacquire-new-proc.go
new file mode 100644
index 0000000..74c6c89
--- /dev/null
+++ b/trace/testdata/generators/go122-syscall-steal-proc-gen-boundary-reacquire-new-proc.go
@@ -0,0 +1,40 @@
+// Copyright 2023 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.
+
+// Code generated by "gen.bash" from internal/trace/v2; DO NOT EDIT.
+
+//go:build go1.21
+
+// Tests syscall P stealing at a generation boundary.
+
+package main
+
+import (
+	"golang.org/x/exp/trace"
+	"golang.org/x/exp/trace/internal/event/go122"
+	testgen "golang.org/x/exp/trace/internal/testgen/go122"
+)
+
+func main() {
+	testgen.Main(gen)
+}
+
+func gen(t *testgen.Trace) {
+	g := t.Generation(1)
+
+	// One goroutine is exiting with a syscall. It already
+	// acquired a new P.
+	b0 := g.Batch(trace.ThreadID(0), 0)
+	b0.Event("GoStatus", trace.GoID(1), trace.ThreadID(0), go122.GoSyscall)
+	b0.Event("ProcStatus", trace.ProcID(1), go122.ProcIdle)
+	b0.Event("ProcStart", trace.ProcID(1), testgen.Seq(1))
+	b0.Event("GoSyscallEndBlocked")
+
+	// A running goroutine stole P0 at the generation boundary.
+	b1 := g.Batch(trace.ThreadID(1), 0)
+	b1.Event("ProcStatus", trace.ProcID(2), go122.ProcRunning)
+	b1.Event("GoStatus", trace.GoID(2), trace.ThreadID(1), go122.GoRunning)
+	b1.Event("ProcStatus", trace.ProcID(0), go122.ProcSyscallAbandoned)
+	b1.Event("ProcSteal", trace.ProcID(0), testgen.Seq(1), trace.ThreadID(0))
+}
diff --git a/trace/testdata/generators/go122-syscall-steal-proc-gen-boundary.go b/trace/testdata/generators/go122-syscall-steal-proc-gen-boundary.go
new file mode 100644
index 0000000..deb1170
--- /dev/null
+++ b/trace/testdata/generators/go122-syscall-steal-proc-gen-boundary.go
@@ -0,0 +1,39 @@
+// Copyright 2023 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.
+
+// Code generated by "gen.bash" from internal/trace/v2; DO NOT EDIT.
+
+//go:build go1.21
+
+// Tests syscall P stealing at a generation boundary.
+
+package main
+
+import (
+	"golang.org/x/exp/trace"
+	"golang.org/x/exp/trace/internal/event/go122"
+	testgen "golang.org/x/exp/trace/internal/testgen/go122"
+)
+
+func main() {
+	testgen.Main(gen)
+}
+
+func gen(t *testgen.Trace) {
+	g := t.Generation(1)
+
+	// One goroutine is exiting with a syscall. It already
+	// acquired a new P.
+	b0 := g.Batch(trace.ThreadID(0), 0)
+	b0.Event("ProcStatus", trace.ProcID(1), go122.ProcRunning)
+	b0.Event("GoStatus", trace.GoID(1), trace.ThreadID(0), go122.GoSyscall)
+	b0.Event("GoSyscallEndBlocked")
+
+	// A running goroutine stole P0 at the generation boundary.
+	b1 := g.Batch(trace.ThreadID(1), 0)
+	b1.Event("ProcStatus", trace.ProcID(2), go122.ProcRunning)
+	b1.Event("GoStatus", trace.GoID(2), trace.ThreadID(1), go122.GoRunning)
+	b1.Event("ProcStatus", trace.ProcID(0), go122.ProcSyscallAbandoned)
+	b1.Event("ProcSteal", trace.ProcID(0), testgen.Seq(1), trace.ThreadID(0))
+}
diff --git a/trace/testdata/generators/go122-syscall-steal-proc-reacquire-new-proc-bare-m.go b/trace/testdata/generators/go122-syscall-steal-proc-reacquire-new-proc-bare-m.go
new file mode 100644
index 0000000..43b6767
--- /dev/null
+++ b/trace/testdata/generators/go122-syscall-steal-proc-reacquire-new-proc-bare-m.go
@@ -0,0 +1,38 @@
+// Copyright 2023 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.
+
+// Code generated by "gen.bash" from internal/trace/v2; DO NOT EDIT.
+
+//go:build go1.21
+
+// Tests syscall P stealing.
+
+package main
+
+import (
+	"golang.org/x/exp/trace"
+	"golang.org/x/exp/trace/internal/event/go122"
+	testgen "golang.org/x/exp/trace/internal/testgen/go122"
+)
+
+func main() {
+	testgen.Main(gen)
+}
+
+func gen(t *testgen.Trace) {
+	g := t.Generation(1)
+
+	// One goroutine enters a syscall, grabs a P, and starts running.
+	b0 := g.Batch(trace.ThreadID(0), 0)
+	b0.Event("ProcStatus", trace.ProcID(1), go122.ProcIdle)
+	b0.Event("ProcStatus", trace.ProcID(0), go122.ProcRunning)
+	b0.Event("GoStatus", trace.GoID(1), trace.ThreadID(0), go122.GoRunning)
+	b0.Event("GoSyscallBegin", testgen.Seq(1), testgen.NoStack)
+	b0.Event("ProcStart", trace.ProcID(1), testgen.Seq(1))
+	b0.Event("GoSyscallEndBlocked")
+
+	// A bare M steals the goroutine's P.
+	b1 := g.Batch(trace.ThreadID(1), 0)
+	b1.Event("ProcSteal", trace.ProcID(0), testgen.Seq(2), trace.ThreadID(0))
+}
diff --git a/trace/testdata/generators/go122-syscall-steal-proc-reacquire-new-proc.go b/trace/testdata/generators/go122-syscall-steal-proc-reacquire-new-proc.go
new file mode 100644
index 0000000..187829e
--- /dev/null
+++ b/trace/testdata/generators/go122-syscall-steal-proc-reacquire-new-proc.go
@@ -0,0 +1,40 @@
+// Copyright 2023 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.
+
+// Code generated by "gen.bash" from internal/trace/v2; DO NOT EDIT.
+
+//go:build go1.21
+
+// Tests syscall P stealing.
+
+package main
+
+import (
+	"golang.org/x/exp/trace"
+	"golang.org/x/exp/trace/internal/event/go122"
+	testgen "golang.org/x/exp/trace/internal/testgen/go122"
+)
+
+func main() {
+	testgen.Main(gen)
+}
+
+func gen(t *testgen.Trace) {
+	g := t.Generation(1)
+
+	// One goroutine enters a syscall, grabs a P, and starts running.
+	b0 := g.Batch(trace.ThreadID(0), 0)
+	b0.Event("ProcStatus", trace.ProcID(1), go122.ProcIdle)
+	b0.Event("ProcStatus", trace.ProcID(0), go122.ProcRunning)
+	b0.Event("GoStatus", trace.GoID(1), trace.ThreadID(0), go122.GoRunning)
+	b0.Event("GoSyscallBegin", testgen.Seq(1), testgen.NoStack)
+	b0.Event("ProcStart", trace.ProcID(1), testgen.Seq(1))
+	b0.Event("GoSyscallEndBlocked")
+
+	// A running goroutine steals proc 0.
+	b1 := g.Batch(trace.ThreadID(1), 0)
+	b1.Event("ProcStatus", trace.ProcID(2), go122.ProcRunning)
+	b1.Event("GoStatus", trace.GoID(2), trace.ThreadID(1), go122.GoRunning)
+	b1.Event("ProcSteal", trace.ProcID(0), testgen.Seq(2), trace.ThreadID(0))
+}
diff --git a/trace/testdata/generators/go122-syscall-steal-proc-self.go b/trace/testdata/generators/go122-syscall-steal-proc-self.go
new file mode 100644
index 0000000..5abbcde
--- /dev/null
+++ b/trace/testdata/generators/go122-syscall-steal-proc-self.go
@@ -0,0 +1,41 @@
+// Copyright 2023 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.
+
+// Code generated by "gen.bash" from internal/trace/v2; DO NOT EDIT.
+
+//go:build go1.21
+
+// Tests syscall P stealing.
+//
+// Specifically, it tests a scenario where a thread 'steals'
+// a P from itself. It's just a ProcStop with extra steps when
+// it happens on the same P.
+
+package main
+
+import (
+	"golang.org/x/exp/trace"
+	"golang.org/x/exp/trace/internal/event/go122"
+	testgen "golang.org/x/exp/trace/internal/testgen/go122"
+)
+
+func main() {
+	testgen.Main(gen)
+}
+
+func gen(t *testgen.Trace) {
+	t.DisableTimestamps()
+
+	g := t.Generation(1)
+
+	// A goroutine execute a syscall and steals its own P, then starts running
+	// on that P.
+	b0 := g.Batch(trace.ThreadID(0), 0)
+	b0.Event("ProcStatus", trace.ProcID(0), go122.ProcRunning)
+	b0.Event("GoStatus", trace.GoID(1), trace.ThreadID(0), go122.GoRunning)
+	b0.Event("GoSyscallBegin", testgen.Seq(1), testgen.NoStack)
+	b0.Event("ProcSteal", trace.ProcID(0), testgen.Seq(2), trace.ThreadID(0))
+	b0.Event("ProcStart", trace.ProcID(0), testgen.Seq(3))
+	b0.Event("GoSyscallEndBlocked")
+}
diff --git a/trace/testdata/generators/go122-syscall-steal-proc-simple-bare-m.go b/trace/testdata/generators/go122-syscall-steal-proc-simple-bare-m.go
new file mode 100644
index 0000000..8e4a00b
--- /dev/null
+++ b/trace/testdata/generators/go122-syscall-steal-proc-simple-bare-m.go
@@ -0,0 +1,36 @@
+// Copyright 2023 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.
+
+// Code generated by "gen.bash" from internal/trace/v2; DO NOT EDIT.
+
+//go:build go1.21
+
+// Tests syscall P stealing.
+
+package main
+
+import (
+	"golang.org/x/exp/trace"
+	"golang.org/x/exp/trace/internal/event/go122"
+	testgen "golang.org/x/exp/trace/internal/testgen/go122"
+)
+
+func main() {
+	testgen.Main(gen)
+}
+
+func gen(t *testgen.Trace) {
+	g := t.Generation(1)
+
+	// One goroutine enters a syscall.
+	b0 := g.Batch(trace.ThreadID(0), 0)
+	b0.Event("ProcStatus", trace.ProcID(0), go122.ProcRunning)
+	b0.Event("GoStatus", trace.GoID(1), trace.ThreadID(0), go122.GoRunning)
+	b0.Event("GoSyscallBegin", testgen.Seq(1), testgen.NoStack)
+	b0.Event("GoSyscallEndBlocked")
+
+	// A bare M steals the goroutine's P.
+	b1 := g.Batch(trace.ThreadID(1), 0)
+	b1.Event("ProcSteal", trace.ProcID(0), testgen.Seq(2), trace.ThreadID(0))
+}
diff --git a/trace/testdata/generators/go122-syscall-steal-proc-simple.go b/trace/testdata/generators/go122-syscall-steal-proc-simple.go
new file mode 100644
index 0000000..e2f7a68
--- /dev/null
+++ b/trace/testdata/generators/go122-syscall-steal-proc-simple.go
@@ -0,0 +1,38 @@
+// Copyright 2023 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.
+
+// Code generated by "gen.bash" from internal/trace/v2; DO NOT EDIT.
+
+//go:build go1.21
+
+// Tests syscall P stealing.
+
+package main
+
+import (
+	"golang.org/x/exp/trace"
+	"golang.org/x/exp/trace/internal/event/go122"
+	testgen "golang.org/x/exp/trace/internal/testgen/go122"
+)
+
+func main() {
+	testgen.Main(gen)
+}
+
+func gen(t *testgen.Trace) {
+	g := t.Generation(1)
+
+	// One goroutine enters a syscall.
+	b0 := g.Batch(trace.ThreadID(0), 0)
+	b0.Event("ProcStatus", trace.ProcID(0), go122.ProcRunning)
+	b0.Event("GoStatus", trace.GoID(1), trace.ThreadID(0), go122.GoRunning)
+	b0.Event("GoSyscallBegin", testgen.Seq(1), testgen.NoStack)
+	b0.Event("GoSyscallEndBlocked")
+
+	// A running goroutine steals proc 0.
+	b1 := g.Batch(trace.ThreadID(1), 0)
+	b1.Event("ProcStatus", trace.ProcID(2), go122.ProcRunning)
+	b1.Event("GoStatus", trace.GoID(2), trace.ThreadID(1), go122.GoRunning)
+	b1.Event("ProcSteal", trace.ProcID(0), testgen.Seq(2), trace.ThreadID(0))
+}
diff --git a/trace/testdata/generators/go122-syscall-steal-proc-sitting-in-syscall.go b/trace/testdata/generators/go122-syscall-steal-proc-sitting-in-syscall.go
new file mode 100644
index 0000000..f78120d
--- /dev/null
+++ b/trace/testdata/generators/go122-syscall-steal-proc-sitting-in-syscall.go
@@ -0,0 +1,36 @@
+// Copyright 2023 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.
+
+// Code generated by "gen.bash" from internal/trace/v2; DO NOT EDIT.
+
+//go:build go1.21
+
+// Tests syscall P stealing from a goroutine and thread
+// that have been in a syscall the entire generation.
+
+package main
+
+import (
+	"golang.org/x/exp/trace"
+	"golang.org/x/exp/trace/internal/event/go122"
+	testgen "golang.org/x/exp/trace/internal/testgen/go122"
+)
+
+func main() {
+	testgen.Main(gen)
+}
+
+func gen(t *testgen.Trace) {
+	g := t.Generation(1)
+
+	// Steal proc from a goroutine that's been blocked
+	// in a syscall the entire generation.
+	b0 := g.Batch(trace.ThreadID(0), 0)
+	b0.Event("ProcStatus", trace.ProcID(0), go122.ProcSyscallAbandoned)
+	b0.Event("ProcSteal", trace.ProcID(0), testgen.Seq(1), trace.ThreadID(1))
+
+	// Status event for a goroutine blocked in a syscall for the entire generation.
+	bz := g.Batch(trace.NoThread, 0)
+	bz.Event("GoStatus", trace.GoID(1), trace.ThreadID(1), go122.GoSyscall)
+}
diff --git a/trace/testdata/generators/go122-task-across-generations.go b/trace/testdata/generators/go122-task-across-generations.go
new file mode 100644
index 0000000..1be0161
--- /dev/null
+++ b/trace/testdata/generators/go122-task-across-generations.go
@@ -0,0 +1,45 @@
+// Copyright 2023 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.
+
+// Code generated by "gen.bash" from internal/trace/v2; DO NOT EDIT.
+
+//go:build go1.21
+
+// Regression test for an issue found in development.
+//
+// The issue is that EvUserTaskEnd events don't carry the
+// task type with them, so the parser needs to track that
+// information. But if the parser just tracks the string ID
+// and not the string itself, that string ID may not be valid
+// for use in future generations.
+
+package main
+
+import (
+	"golang.org/x/exp/trace"
+	"golang.org/x/exp/trace/internal/event/go122"
+	testgen "golang.org/x/exp/trace/internal/testgen/go122"
+)
+
+func main() {
+	testgen.Main(gen)
+}
+
+func gen(t *testgen.Trace) {
+	g1 := t.Generation(1)
+
+	// A running goroutine emits a task begin.
+	b1 := g1.Batch(trace.ThreadID(0), 0)
+	b1.Event("ProcStatus", trace.ProcID(0), go122.ProcRunning)
+	b1.Event("GoStatus", trace.GoID(1), trace.ThreadID(0), go122.GoRunning)
+	b1.Event("UserTaskBegin", trace.TaskID(2), trace.TaskID(0) /* 0 means no parent, not background */, "my task", testgen.NoStack)
+
+	g2 := t.Generation(2)
+
+	// That same goroutine emits a task end in the following generation.
+	b2 := g2.Batch(trace.ThreadID(0), 5)
+	b2.Event("ProcStatus", trace.ProcID(0), go122.ProcRunning)
+	b2.Event("GoStatus", trace.GoID(1), trace.ThreadID(0), go122.GoRunning)
+	b2.Event("UserTaskEnd", trace.TaskID(2), testgen.NoStack)
+}
diff --git a/trace/testdata/tests/go122-annotations-stress.test b/trace/testdata/tests/go122-annotations-stress.test
new file mode 100644
index 0000000..fe3c84b
--- /dev/null
+++ b/trace/testdata/tests/go122-annotations-stress.test
@@ -0,0 +1,1179 @@
+-- expect --
+SUCCESS
+-- trace --
+Trace Go1.22
+EventBatch gen=1 m=18446744073709551615 time=2753926854385 size=5
+Frequency freq=15625000
+EventBatch gen=1 m=1986497 time=2753925247434 size=1430
+ProcStart dt=336 p=2 p_seq=1
+GoStart dt=191 g=19 g_seq=1
+HeapAlloc dt=389 heapalloc_value=1622016
+HeapAlloc dt=4453 heapalloc_value=1662976
+GoBlock dt=572 reason_string=12 stack=29
+ProcStop dt=26
+ProcStart dt=160734 p=2 p_seq=2
+ProcStop dt=21
+ProcStart dt=159292 p=0 p_seq=7
+GoStart dt=299 g=49 g_seq=1
+UserRegionBegin dt=183 task=8 name_string=33 stack=26
+UserLog dt=26 task=8 key_string=24 value_string=49 stack=27
+UserRegionEnd dt=8 task=8 name_string=33 stack=28
+GoDestroy dt=3
+GoStart dt=20 g=50 g_seq=1
+UserRegionBegin dt=40 task=8 name_string=35 stack=26
+UserLog dt=9 task=8 key_string=24 value_string=50 stack=27
+UserRegionEnd dt=2 task=8 name_string=35 stack=28
+GoDestroy dt=1
+ProcStop dt=18
+ProcStart dt=141801 p=4 p_seq=5
+ProcStop dt=18
+ProcStart dt=16860 p=4 p_seq=6
+GoUnblock dt=53 g=1 g_seq=5 stack=0
+GoUnblock dt=9 g=51 g_seq=3 stack=0
+GoStart dt=162 g=51 g_seq=4
+UserTaskEnd dt=35 task=9 stack=36
+UserRegionEnd dt=16 task=8 name_string=31 stack=28
+GoDestroy dt=2
+GoStart dt=20 g=1 g_seq=6
+UserTaskEnd dt=14 task=8 stack=54
+UserLog dt=26 task=3 key_string=24 value_string=51 stack=55
+UserTaskBegin dt=14 task=10 parent_task=3 name_string=26 stack=56
+UserLog dt=42 task=10 key_string=27 value_string=52 stack=57
+UserRegionBegin dt=12 task=10 name_string=29 stack=58
+GoCreate dt=36 new_g=35 new_stack=17 stack=59
+GoCreate dt=11 new_g=36 new_stack=17 stack=59
+GoCreate dt=18 new_g=37 new_stack=17 stack=59
+GoCreate dt=10 new_g=38 new_stack=17 stack=59
+GoCreate dt=6 new_g=39 new_stack=17 stack=59
+GoCreate dt=8 new_g=40 new_stack=17 stack=59
+UserRegionEnd dt=7 task=10 name_string=29 stack=60
+GoBlock dt=9 reason_string=19 stack=61
+GoStart dt=15 g=40 g_seq=1
+UserRegionBegin dt=110 task=10 name_string=53 stack=26
+UserLog dt=16 task=10 key_string=24 value_string=54 stack=27
+UserRegionEnd dt=2 task=10 name_string=53 stack=28
+GoDestroy dt=2
+GoStart dt=6 g=38 g_seq=1
+UserRegionBegin dt=31 task=10 name_string=30 stack=26
+UserLog dt=5 task=10 key_string=24 value_string=55 stack=27
+UserRegionEnd dt=2 task=10 name_string=30 stack=28
+GoDestroy dt=1
+GoStart dt=2 g=39 g_seq=1
+UserRegionBegin dt=23 task=10 name_string=56 stack=26
+UserLog dt=6 task=10 key_string=24 value_string=57 stack=27
+UserRegionEnd dt=1 task=10 name_string=56 stack=28
+GoDestroy dt=1
+GoStart dt=8 g=35 g_seq=1
+UserRegionBegin dt=17 task=10 name_string=33 stack=26
+UserLog dt=4 task=10 key_string=24 value_string=58 stack=27
+UserRegionEnd dt=2 task=10 name_string=33 stack=28
+GoDestroy dt=1
+GoStart dt=3 g=36 g_seq=1
+UserRegionBegin dt=19 task=10 name_string=35 stack=26
+UserLog dt=4 task=10 key_string=24 value_string=59 stack=27
+UserRegionEnd dt=2 task=10 name_string=35 stack=28
+GoDestroy dt=1
+ProcStop dt=11
+ProcStart dt=142205 p=0 p_seq=9
+ProcStop dt=19
+ProcStart dt=16811 p=0 p_seq=10
+GoUnblock dt=26 g=1 g_seq=7 stack=0
+GoStart dt=201 g=1 g_seq=8
+UserTaskEnd dt=24 task=10 stack=62
+UserLog dt=18 task=4 key_string=24 value_string=63 stack=63
+UserTaskBegin dt=11 task=12 parent_task=4 name_string=26 stack=64
+UserLog dt=21 task=12 key_string=27 value_string=64 stack=65
+UserRegionBegin dt=7 task=12 name_string=29 stack=66
+GoCreate dt=33 new_g=5 new_stack=17 stack=67
+GoCreate dt=12 new_g=6 new_stack=17 stack=67
+GoCreate dt=9 new_g=7 new_stack=17 stack=67
+GoCreate dt=8 new_g=8 new_stack=17 stack=67
+GoCreate dt=19 new_g=9 new_stack=17 stack=67
+UserRegionEnd dt=14 task=12 name_string=29 stack=68
+GoBlock dt=11 reason_string=19 stack=69
+GoStart dt=13 g=9 g_seq=1
+UserRegionBegin dt=70 task=12 name_string=56 stack=26
+UserLog dt=11 task=12 key_string=24 value_string=65 stack=27
+UserRegionEnd dt=3 task=12 name_string=56 stack=28
+GoDestroy dt=2
+GoStart dt=7 g=5 g_seq=1
+UserRegionBegin dt=24 task=12 name_string=33 stack=26
+UserLog dt=5 task=12 key_string=24 value_string=66 stack=27
+UserRegionEnd dt=2 task=12 name_string=33 stack=28
+GoDestroy dt=2
+GoStart dt=8 g=6 g_seq=1
+UserRegionBegin dt=15 task=12 name_string=35 stack=26
+UserLog dt=7 task=12 key_string=24 value_string=67 stack=27
+UserRegionEnd dt=2 task=12 name_string=35 stack=28
+GoDestroy dt=1
+GoStart dt=2 g=7 g_seq=1
+UserRegionBegin dt=13 task=12 name_string=31 stack=26
+UserLog dt=5 task=12 key_string=24 value_string=68 stack=27
+UserLog dt=6 task=12 key_string=24 value_string=69 stack=30
+UserTaskBegin dt=5 task=13 parent_task=12 name_string=26 stack=31
+UserLog dt=7 task=13 key_string=27 value_string=70 stack=32
+UserRegionBegin dt=4 task=13 name_string=29 stack=33
+UserRegionEnd dt=6 task=13 name_string=29 stack=34
+GoBlock dt=18 reason_string=19 stack=35
+GoStart dt=12 g=8 g_seq=1
+UserRegionBegin dt=22 task=12 name_string=30 stack=26
+UserLog dt=5 task=12 key_string=24 value_string=71 stack=27
+UserRegionEnd dt=2 task=12 name_string=30 stack=28
+GoDestroy dt=1
+ProcStop dt=20
+ProcStart dt=141838 p=4 p_seq=8
+ProcStop dt=16
+ProcStart dt=17652 p=4 p_seq=9
+GoUnblock dt=48 g=1 g_seq=9 stack=0
+GoUnblock dt=8 g=7 g_seq=2 stack=0
+GoStart dt=271 g=7 g_seq=3
+UserTaskEnd dt=25 task=13 stack=36
+UserRegionEnd dt=15 task=12 name_string=31 stack=28
+GoDestroy dt=4
+GoStart dt=19 g=1 g_seq=10
+UserTaskEnd dt=19 task=12 stack=70
+UserLog dt=21 task=0 key_string=24 value_string=72 stack=13
+UserTaskBegin dt=19 task=14 parent_task=0 name_string=26 stack=14
+UserLog dt=37 task=14 key_string=27 value_string=73 stack=15
+UserRegionBegin dt=6 task=14 name_string=29 stack=16
+GoCreate dt=28 new_g=41 new_stack=17 stack=18
+GoCreate dt=14 new_g=42 new_stack=17 stack=18
+GoCreate dt=12 new_g=43 new_stack=17 stack=18
+GoCreate dt=10 new_g=44 new_stack=17 stack=18
+UserRegionEnd dt=5 task=14 name_string=29 stack=19
+GoBlock dt=9 reason_string=19 stack=20
+GoStart dt=16 g=44 g_seq=1
+UserRegionBegin dt=107 task=14 name_string=30 stack=26
+UserLog dt=16 task=14 key_string=24 value_string=74 stack=27
+UserRegionEnd dt=3 task=14 name_string=30 stack=28
+GoDestroy dt=2
+GoStart dt=7 g=41 g_seq=1
+UserRegionBegin dt=30 task=14 name_string=33 stack=26
+UserLog dt=7 task=14 key_string=24 value_string=75 stack=27
+UserRegionEnd dt=2 task=14 name_string=33 stack=28
+GoDestroy dt=2
+GoStart dt=7 g=42 g_seq=1
+UserRegionBegin dt=27 task=14 name_string=35 stack=26
+UserLog dt=7 task=14 key_string=24 value_string=76 stack=27
+UserRegionEnd dt=2 task=14 name_string=35 stack=28
+GoDestroy dt=2
+ProcStop dt=28
+ProcStart dt=141923 p=0 p_seq=12
+ProcStop dt=19
+ProcStart dt=16780 p=0 p_seq=13
+GoUnblock dt=22 g=43 g_seq=2 stack=0
+GoStart dt=162 g=43 g_seq=3
+UserTaskEnd dt=16 task=15 stack=36
+UserRegionEnd dt=12 task=14 name_string=31 stack=28
+GoDestroy dt=2
+ProcStop dt=8
+ProcStart dt=1532 p=2 p_seq=9
+ProcStop dt=12
+ProcStart dt=141906 p=4 p_seq=11
+ProcStop dt=16
+ProcStart dt=16784 p=4 p_seq=12
+GoUnblock dt=20 g=1 g_seq=13 stack=0
+GoStart dt=191 g=1 g_seq=14
+UserTaskEnd dt=15 task=16 stack=45
+UserLog dt=17 task=2 key_string=24 value_string=84 stack=46
+UserTaskBegin dt=8 task=17 parent_task=2 name_string=26 stack=47
+UserLog dt=20 task=17 key_string=27 value_string=85 stack=48
+UserRegionBegin dt=6 task=17 name_string=29 stack=49
+GoCreate dt=28 new_g=45 new_stack=17 stack=50
+GoCreate dt=9 new_g=46 new_stack=17 stack=50
+GoCreate dt=10 new_g=47 new_stack=17 stack=50
+UserRegionEnd dt=5 task=17 name_string=29 stack=51
+GoBlock dt=6 reason_string=19 stack=52
+GoStart dt=10 g=47 g_seq=1
+UserRegionBegin dt=69 task=17 name_string=31 stack=26
+UserLog dt=11 task=17 key_string=24 value_string=86 stack=27
+UserLog dt=7 task=17 key_string=24 value_string=87 stack=30
+UserTaskBegin dt=5 task=18 parent_task=17 name_string=26 stack=31
+UserLog dt=7 task=18 key_string=27 value_string=88 stack=32
+UserRegionBegin dt=5 task=18 name_string=29 stack=33
+UserRegionEnd dt=4 task=18 name_string=29 stack=34
+HeapAlloc dt=35 heapalloc_value=1818624
+GoBlock dt=14 reason_string=19 stack=35
+HeapAlloc dt=11 heapalloc_value=1826816
+GoStart dt=10 g=45 g_seq=1
+UserRegionBegin dt=29 task=17 name_string=33 stack=26
+UserLog dt=9 task=17 key_string=24 value_string=89 stack=27
+UserRegionEnd dt=3 task=17 name_string=33 stack=28
+GoDestroy dt=1
+GoStart dt=5 g=46 g_seq=1
+UserRegionBegin dt=15 task=17 name_string=35 stack=26
+UserLog dt=8 task=17 key_string=24 value_string=90 stack=27
+UserRegionEnd dt=2 task=17 name_string=35 stack=28
+GoDestroy dt=1
+ProcStop dt=3
+ProcStart dt=141981 p=0 p_seq=16
+ProcStop dt=19
+ProcStart dt=17153 p=0 p_seq=17
+GoUnblock dt=44 g=1 g_seq=15 stack=0
+GoUnblock dt=11 g=47 g_seq=2 stack=0
+GoStart dt=215 g=47 g_seq=3
+UserTaskEnd dt=22 task=18 stack=36
+UserRegionEnd dt=9 task=17 name_string=31 stack=28
+GoDestroy dt=3
+GoStart dt=19 g=1 g_seq=16
+UserTaskEnd dt=13 task=17 stack=54
+UserLog dt=18 task=3 key_string=24 value_string=91 stack=55
+UserTaskBegin dt=7 task=19 parent_task=3 name_string=26 stack=56
+UserLog dt=27 task=19 key_string=27 value_string=92 stack=57
+UserRegionBegin dt=8 task=19 name_string=29 stack=58
+GoCreate dt=30 new_g=10 new_stack=17 stack=59
+GoCreate dt=9 new_g=11 new_stack=17 stack=59
+GoCreate dt=11 new_g=12 new_stack=17 stack=59
+GoCreate dt=7 new_g=13 new_stack=17 stack=59
+GoCreate dt=7 new_g=14 new_stack=17 stack=59
+GoCreate dt=9 new_g=15 new_stack=17 stack=59
+UserRegionEnd dt=5 task=19 name_string=29 stack=60
+GoBlock dt=7 reason_string=19 stack=61
+GoStart dt=17 g=15 g_seq=1
+UserRegionBegin dt=61 task=19 name_string=53 stack=26
+UserLog dt=10 task=19 key_string=24 value_string=93 stack=27
+UserRegionEnd dt=3 task=19 name_string=53 stack=28
+GoDestroy dt=1
+GoStart dt=4 g=10 g_seq=1
+UserRegionBegin dt=26 task=19 name_string=33 stack=26
+UserLog dt=7 task=19 key_string=24 value_string=94 stack=27
+UserRegionEnd dt=2 task=19 name_string=33 stack=28
+GoDestroy dt=1
+GoStart dt=4 g=11 g_seq=1
+UserRegionBegin dt=20 task=19 name_string=35 stack=26
+UserLog dt=5 task=19 key_string=24 value_string=95 stack=27
+UserRegionEnd dt=2 task=19 name_string=35 stack=28
+GoDestroy dt=1
+GoStart dt=7 g=12 g_seq=1
+UserRegionBegin dt=14 task=19 name_string=31 stack=26
+UserLog dt=4 task=19 key_string=24 value_string=96 stack=27
+UserLog dt=4 task=19 key_string=24 value_string=97 stack=30
+UserTaskBegin dt=7 task=20 parent_task=19 name_string=26 stack=31
+UserLog dt=5 task=20 key_string=27 value_string=98 stack=32
+UserRegionBegin dt=4 task=20 name_string=29 stack=33
+UserRegionEnd dt=5 task=20 name_string=29 stack=34
+GoBlock dt=9 reason_string=19 stack=35
+GoStart dt=9 g=14 g_seq=1
+UserRegionBegin dt=28 task=19 name_string=56 stack=26
+UserLog dt=7 task=19 key_string=24 value_string=99 stack=27
+UserRegionEnd dt=2 task=19 name_string=56 stack=28
+GoDestroy dt=2
+ProcStop dt=17
+ProcStart dt=141933 p=2 p_seq=11
+ProcStop dt=13
+ProcStart dt=16744 p=2 p_seq=12
+GoUnblock dt=29 g=1 g_seq=17 stack=0
+GoUnblock dt=7 g=12 g_seq=2 stack=0
+GoStart dt=172 g=12 g_seq=3
+UserTaskEnd dt=15 task=20 stack=36
+UserRegionEnd dt=8 task=19 name_string=31 stack=28
+GoDestroy dt=2
+GoStart dt=11 g=1 g_seq=18
+UserTaskEnd dt=14 task=19 stack=62
+UserLog dt=16 task=4 key_string=24 value_string=101 stack=63
+UserTaskBegin dt=6 task=21 parent_task=4 name_string=26 stack=64
+UserLog dt=25 task=21 key_string=27 value_string=102 stack=65
+UserRegionBegin dt=7 task=21 name_string=29 stack=66
+GoCreate dt=23 new_g=54 new_stack=17 stack=67
+GoCreate dt=8 new_g=55 new_stack=17 stack=67
+GoCreate dt=17 new_g=56 new_stack=17 stack=67
+GoCreate dt=8 new_g=57 new_stack=17 stack=67
+GoCreate dt=7 new_g=58 new_stack=17 stack=67
+UserRegionEnd dt=4 task=21 name_string=29 stack=68
+GoBlock dt=9 reason_string=19 stack=69
+GoStart dt=7 g=58 g_seq=1
+UserRegionBegin dt=46 task=21 name_string=56 stack=26
+UserLog dt=8 task=21 key_string=24 value_string=103 stack=27
+UserRegionEnd dt=4 task=21 name_string=56 stack=28
+GoDestroy dt=1
+GoStart dt=3 g=54 g_seq=1
+UserRegionBegin dt=19 task=21 name_string=33 stack=26
+UserLog dt=7 task=21 key_string=24 value_string=104 stack=27
+UserRegionEnd dt=2 task=21 name_string=33 stack=28
+GoDestroy dt=1
+GoStart dt=2 g=55 g_seq=1
+UserRegionBegin dt=17 task=21 name_string=35 stack=26
+UserLog dt=4 task=21 key_string=24 value_string=105 stack=27
+UserRegionEnd dt=2 task=21 name_string=35 stack=28
+GoDestroy dt=1
+GoStart dt=5 g=56 g_seq=1
+UserRegionBegin dt=16 task=21 name_string=31 stack=26
+UserLog dt=4 task=21 key_string=24 value_string=106 stack=27
+UserLog dt=3 task=21 key_string=24 value_string=107 stack=30
+UserTaskBegin dt=4 task=22 parent_task=21 name_string=26 stack=31
+UserLog dt=6 task=22 key_string=27 value_string=108 stack=32
+UserRegionBegin dt=4 task=22 name_string=29 stack=33
+UserRegionEnd dt=7 task=22 name_string=29 stack=34
+GoBlock dt=14 reason_string=19 stack=35
+GoStart dt=3 g=57 g_seq=1
+UserRegionBegin dt=22 task=21 name_string=30 stack=26
+UserLog dt=6 task=21 key_string=24 value_string=109 stack=27
+UserRegionEnd dt=2 task=21 name_string=30 stack=28
+GoDestroy dt=2
+ProcStop dt=10
+ProcStart dt=128031 p=4 p_seq=15
+ProcStop dt=16
+ProcStart dt=33758 p=2 p_seq=15
+ProcStop dt=18
+EventBatch gen=1 m=1986496 time=2753925246280 size=267
+ProcStart dt=549 p=0 p_seq=1
+GoStart dt=211 g=18 g_seq=1
+GoBlock dt=3533 reason_string=12 stack=21
+GoStart dt=41 g=21 g_seq=1
+GoBlock dt=150 reason_string=10 stack=22
+GoStart dt=93 g=20 g_seq=1
+GoSyscallBegin dt=51 p_seq=2 stack=23
+GoSyscallEnd dt=400
+GoBlock dt=582 reason_string=15 stack=25
+GoStart dt=26 g=23 g_seq=1
+HeapAlloc dt=50 heapalloc_value=1646592
+UserRegionBegin dt=2921 task=5 name_string=31 stack=26
+UserLog dt=28 task=5 key_string=24 value_string=37 stack=27
+UserLog dt=13 task=5 key_string=24 value_string=38 stack=30
+UserTaskBegin dt=15 task=6 parent_task=5 name_string=26 stack=31
+HeapAlloc dt=26 heapalloc_value=1687552
+UserLog dt=14 task=6 key_string=27 value_string=39 stack=32
+UserRegionBegin dt=9 task=6 name_string=29 stack=33
+UserRegionEnd dt=6 task=6 name_string=29 stack=34
+GoBlock dt=15 reason_string=19 stack=35
+ProcStop dt=30
+ProcStart dt=156949 p=4 p_seq=2
+GoUnblock dt=46 g=1 g_seq=1 stack=0
+GoStart dt=253 g=1 g_seq=2
+UserTaskEnd dt=27 task=5 stack=37
+UserLog dt=23 task=1 key_string=24 value_string=40 stack=38
+UserTaskBegin dt=14 task=7 parent_task=1 name_string=26 stack=39
+HeapAlloc dt=596 heapalloc_value=1695744
+HeapAlloc dt=18 heapalloc_value=1703936
+UserLog dt=17 task=7 key_string=27 value_string=41 stack=40
+UserRegionBegin dt=14 task=7 name_string=29 stack=41
+HeapAlloc dt=10 heapalloc_value=1712128
+HeapAlloc dt=17 heapalloc_value=1720320
+GoCreate dt=44 new_g=33 new_stack=17 stack=42
+GoCreate dt=175 new_g=34 new_stack=17 stack=42
+UserRegionEnd dt=50 task=7 name_string=29 stack=43
+GoBlock dt=9 reason_string=19 stack=44
+HeapAlloc dt=16 heapalloc_value=1728512
+GoStart dt=239 g=34 g_seq=1
+HeapAlloc dt=21 heapalloc_value=1736704
+UserRegionBegin dt=92 task=7 name_string=35 stack=26
+UserLog dt=15 task=7 key_string=24 value_string=42 stack=27
+UserRegionEnd dt=4 task=7 name_string=35 stack=28
+GoDestroy dt=2
+ProcStop dt=21
+ProcStart dt=800974 p=4 p_seq=10
+ProcStop dt=39
+ProcStart dt=158775 p=0 p_seq=15
+ProcStop dt=24
+ProcStart dt=159722 p=4 p_seq=13
+GoStart dt=254 g=13 g_seq=1
+UserRegionBegin dt=239 task=19 name_string=30 stack=26
+UserLog dt=23 task=19 key_string=24 value_string=100 stack=27
+UserRegionEnd dt=6 task=19 name_string=30 stack=28
+GoDestroy dt=7
+ProcStop dt=22
+EventBatch gen=1 m=1986495 time=2753925251756 size=320
+ProcStart dt=705 p=4 p_seq=1
+ProcStop dt=1279
+ProcStart dt=158975 p=0 p_seq=5
+ProcStop dt=23
+ProcStart dt=792 p=0 p_seq=6
+GoStart dt=187 g=33 g_seq=1
+UserRegionBegin dt=244 task=7 name_string=33 stack=26
+UserLog dt=32 task=7 key_string=24 value_string=43 stack=27
+UserRegionEnd dt=7 task=7 name_string=33 stack=28
+GoDestroy dt=5
+ProcStop dt=24
+ProcStart dt=160255 p=4 p_seq=4
+ProcStop dt=27
+ProcStart dt=159067 p=2 p_seq=5
+GoStart dt=222 g=37 g_seq=1
+UserRegionBegin dt=114 task=10 name_string=31 stack=26
+UserLog dt=16 task=10 key_string=24 value_string=60 stack=27
+UserLog dt=8 task=10 key_string=24 value_string=61 stack=30
+UserTaskBegin dt=8 task=11 parent_task=10 name_string=26 stack=31
+UserLog dt=19 task=11 key_string=27 value_string=62 stack=32
+UserRegionBegin dt=6 task=11 name_string=29 stack=33
+UserRegionEnd dt=7 task=11 name_string=29 stack=34
+GoBlock dt=15 reason_string=19 stack=35
+ProcStop dt=11
+ProcStart dt=160101 p=4 p_seq=7
+ProcStop dt=21
+ProcStart dt=159647 p=2 p_seq=7
+GoStart dt=277 g=43 g_seq=1
+UserRegionBegin dt=126 task=14 name_string=31 stack=26
+UserLog dt=21 task=14 key_string=24 value_string=77 stack=27
+UserLog dt=9 task=14 key_string=24 value_string=78 stack=30
+UserTaskBegin dt=8 task=15 parent_task=14 name_string=26 stack=31
+UserLog dt=17 task=15 key_string=27 value_string=79 stack=32
+UserRegionBegin dt=6 task=15 name_string=29 stack=33
+UserRegionEnd dt=8 task=15 name_string=29 stack=34
+GoBlock dt=23 reason_string=19 stack=35
+ProcStop dt=17
+ProcStart dt=159706 p=0 p_seq=14
+GoStart dt=229 g=52 g_seq=1
+UserRegionBegin dt=103 task=16 name_string=33 stack=26
+UserLog dt=20 task=16 key_string=24 value_string=83 stack=27
+UserRegionEnd dt=4 task=16 name_string=33 stack=28
+GoDestroy dt=3
+ProcStop dt=17
+ProcStart dt=319699 p=2 p_seq=10
+ProcStop dt=20
+ProcStart dt=158728 p=4 p_seq=14
+ProcStop dt=17
+ProcStart dt=110606 p=2 p_seq=13
+ProcStop dt=10
+ProcStart dt=16732 p=2 p_seq=14
+GoUnblock dt=45 g=18 g_seq=2 stack=0
+GoStart dt=184 g=18 g_seq=3
+GoBlock dt=114 reason_string=12 stack=21
+ProcStop dt=8
+ProcStart dt=16779 p=4 p_seq=16
+ProcStop dt=11
+ProcStart dt=16790 p=4 p_seq=17
+GoUnblock dt=23 g=1 g_seq=19 stack=0
+GoUnblock dt=8 g=56 g_seq=2 stack=0
+GoStart dt=142 g=56 g_seq=3
+UserTaskEnd dt=14 task=22 stack=36
+UserRegionEnd dt=8 task=21 name_string=31 stack=28
+GoDestroy dt=5
+GoStart dt=18 g=1 g_seq=20
+UserTaskEnd dt=17 task=21 stack=70
+UserTaskEnd dt=12 task=4 stack=71
+HeapAlloc dt=802 heapalloc_value=1835008
+HeapAlloc dt=41 heapalloc_value=1843200
+HeapAlloc dt=13 heapalloc_value=1851392
+EventBatch gen=1 m=1986494 time=2753925248778 size=47
+ProcStart dt=390 p=3 p_seq=1
+GoStart dt=1718 g=22 g_seq=1
+HeapAlloc dt=1807 heapalloc_value=1654784
+HeapAlloc dt=406 heapalloc_value=1671168
+HeapAlloc dt=15 heapalloc_value=1679360
+UserRegionBegin dt=49 task=5 name_string=35 stack=26
+UserLog dt=30 task=5 key_string=24 value_string=36 stack=27
+UserRegionEnd dt=5 task=5 name_string=35 stack=28
+GoDestroy dt=5
+ProcStop dt=42
+EventBatch gen=1 m=1986492 time=2753925244400 size=582
+ProcStatus dt=67 p=1 pstatus=1
+GoStatus dt=4 g=1 m=1986492 gstatus=2
+ProcsChange dt=220 procs_value=8 stack=1
+STWBegin dt=127 kind_string=21 stack=2
+HeapGoal dt=3 heapgoal_value=4194304
+ProcStatus dt=2 p=0 pstatus=2
+ProcStatus dt=2 p=2 pstatus=2
+ProcStatus dt=1 p=3 pstatus=2
+ProcStatus dt=1 p=4 pstatus=2
+ProcStatus dt=1 p=5 pstatus=2
+ProcStatus dt=1 p=6 pstatus=2
+ProcStatus dt=1 p=7 pstatus=2
+ProcsChange dt=353 procs_value=8 stack=3
+STWEnd dt=277
+HeapAlloc dt=243 heapalloc_value=1605632
+HeapAlloc dt=24 heapalloc_value=1613824
+GoCreate dt=209 new_g=18 new_stack=4 stack=5
+GoCreate dt=561 new_g=19 new_stack=6 stack=7
+GoCreate dt=25 new_g=20 new_stack=8 stack=9
+UserTaskEnd dt=309 task=2 stack=10
+UserTaskBegin dt=26 task=3 parent_task=1 name_string=22 stack=11
+UserTaskBegin dt=918 task=4 parent_task=0 name_string=23 stack=12
+UserLog dt=461 task=0 key_string=24 value_string=25 stack=13
+UserTaskBegin dt=420 task=5 parent_task=0 name_string=26 stack=14
+UserLog dt=673 task=5 key_string=27 value_string=28 stack=15
+UserRegionBegin dt=15 task=5 name_string=29 stack=16
+HeapAlloc dt=51 heapalloc_value=1630208
+GoCreate dt=24 new_g=21 new_stack=17 stack=18
+GoCreate dt=17 new_g=22 new_stack=17 stack=18
+GoCreate dt=10 new_g=23 new_stack=17 stack=18
+GoCreate dt=9 new_g=24 new_stack=17 stack=18
+UserRegionEnd dt=549 task=5 name_string=29 stack=19
+GoBlock dt=14 reason_string=19 stack=20
+GoStart dt=378 g=24 g_seq=1
+HeapAlloc dt=65 heapalloc_value=1638400
+GoUnblock dt=559 g=21 g_seq=2 stack=24
+UserRegionBegin dt=1498 task=5 name_string=30 stack=26
+UserLog dt=35 task=5 key_string=24 value_string=32 stack=27
+UserRegionEnd dt=8 task=5 name_string=30 stack=28
+GoDestroy dt=5
+GoStart dt=24 g=21 g_seq=3
+UserRegionBegin dt=60 task=5 name_string=33 stack=26
+UserLog dt=7 task=5 key_string=24 value_string=34 stack=27
+UserRegionEnd dt=2 task=5 name_string=33 stack=28
+GoDestroy dt=2
+ProcStop dt=34
+ProcStart dt=141874 p=0 p_seq=3
+ProcStop dt=21
+ProcStart dt=16770 p=0 p_seq=4
+GoUnblock dt=29 g=23 g_seq=2 stack=0
+GoStart dt=176 g=23 g_seq=3
+UserTaskEnd dt=19 task=6 stack=36
+UserRegionEnd dt=14 task=5 name_string=31 stack=28
+GoDestroy dt=2
+ProcStop dt=12
+ProcStart dt=2251 p=4 p_seq=3
+ProcStop dt=22
+ProcStart dt=141952 p=2 p_seq=3
+ProcStop dt=27
+ProcStart dt=16789 p=2 p_seq=4
+GoUnblock dt=35 g=1 g_seq=3 stack=0
+GoStart dt=214 g=1 g_seq=4
+UserTaskEnd dt=26 task=7 stack=45
+UserLog dt=27 task=2 key_string=24 value_string=44 stack=46
+UserTaskBegin dt=10 task=8 parent_task=2 name_string=26 stack=47
+HeapAlloc dt=52 heapalloc_value=1744896
+HeapAlloc dt=22 heapalloc_value=1753088
+UserLog dt=13 task=8 key_string=27 value_string=45 stack=48
+UserRegionBegin dt=11 task=8 name_string=29 stack=49
+HeapAlloc dt=7 heapalloc_value=1761280
+HeapAlloc dt=18 heapalloc_value=1769472
+GoCreate dt=52 new_g=49 new_stack=17 stack=50
+GoCreate dt=12 new_g=50 new_stack=17 stack=50
+HeapAlloc dt=11 heapalloc_value=1777664
+GoCreate dt=9 new_g=51 new_stack=17 stack=50
+UserRegionEnd dt=9 task=8 name_string=29 stack=51
+GoBlock dt=11 reason_string=19 stack=52
+HeapAlloc dt=12 heapalloc_value=1785856
+GoStart dt=14 g=51 g_seq=1
+HeapAlloc dt=18 heapalloc_value=1794048
+UserRegionBegin dt=95 task=8 name_string=31 stack=26
+UserLog dt=22 task=8 key_string=24 value_string=46 stack=27
+UserLog dt=8 task=8 key_string=24 value_string=47 stack=30
+UserTaskBegin dt=5 task=9 parent_task=8 name_string=26 stack=31
+UserLog dt=7 task=9 key_string=27 value_string=48 stack=32
+UserRegionBegin dt=4 task=9 name_string=29 stack=33
+UserRegionEnd dt=7 task=9 name_string=29 stack=34
+HeapAlloc dt=11 heapalloc_value=1802240
+GoStop dt=674 reason_string=16 stack=53
+GoStart dt=12 g=51 g_seq=2
+GoBlock dt=8 reason_string=19 stack=35
+HeapAlloc dt=16 heapalloc_value=1810432
+ProcStop dt=8
+ProcStart dt=159907 p=0 p_seq=8
+ProcStop dt=25
+ProcStart dt=159186 p=2 p_seq=6
+GoUnblock dt=22 g=37 g_seq=2 stack=0
+GoStart dt=217 g=37 g_seq=3
+UserTaskEnd dt=19 task=11 stack=36
+UserRegionEnd dt=15 task=10 name_string=31 stack=28
+GoDestroy dt=5
+ProcStop dt=16
+ProcStart dt=160988 p=0 p_seq=11
+ProcStop dt=29
+ProcStart dt=158554 p=2 p_seq=8
+GoUnblock dt=38 g=1 g_seq=11 stack=0
+GoStart dt=240 g=1 g_seq=12
+UserTaskEnd dt=25 task=14 stack=37
+UserLog dt=23 task=1 key_string=24 value_string=80 stack=38
+UserTaskBegin dt=11 task=16 parent_task=1 name_string=26 stack=39
+UserLog dt=36 task=16 key_string=27 value_string=81 stack=40
+UserRegionBegin dt=13 task=16 name_string=29 stack=41
+GoCreate dt=39 new_g=52 new_stack=17 stack=42
+GoCreate dt=23 new_g=53 new_stack=17 stack=42
+UserRegionEnd dt=11 task=16 name_string=29 stack=43
+GoBlock dt=9 reason_string=19 stack=44
+GoStart dt=244 g=53 g_seq=1
+UserRegionBegin dt=101 task=16 name_string=35 stack=26
+UserLog dt=17 task=16 key_string=24 value_string=82 stack=27
+UserRegionEnd dt=4 task=16 name_string=35 stack=28
+GoDestroy dt=3
+ProcStop dt=28
+EventBatch gen=1 m=18446744073709551615 time=2753926855140 size=56
+GoStatus dt=74 g=2 m=18446744073709551615 gstatus=4
+GoStatus dt=3 g=3 m=18446744073709551615 gstatus=4
+GoStatus dt=1 g=4 m=18446744073709551615 gstatus=4
+GoStatus dt=1 g=17 m=18446744073709551615 gstatus=4
+EventBatch gen=1 m=18446744073709551615 time=2753926855560 size=1759
+Stacks
+Stack id=45 nframes=3
+	pc=4804964 func=110 file=111 line=80
+	pc=4804052 func=112 file=113 line=84
+	pc=4803566 func=114 file=113 line=44
+Stack id=22 nframes=7
+	pc=4633935 func=115 file=116 line=90
+	pc=4633896 func=117 file=118 line=223
+	pc=4633765 func=119 file=118 line=216
+	pc=4633083 func=120 file=118 line=131
+	pc=4764601 func=121 file=122 line=152
+	pc=4765335 func=123 file=122 line=238
+	pc=4804612 func=124 file=113 line=70
+Stack id=9 nframes=2
+	pc=4802543 func=125 file=126 line=128
+	pc=4803332 func=114 file=113 line=30
+Stack id=71 nframes=2
+	pc=4803671 func=110 file=111 line=80
+	pc=4803666 func=114 file=113 line=51
+Stack id=10 nframes=2
+	pc=4803415 func=110 file=111 line=80
+	pc=4803410 func=114 file=113 line=33
+Stack id=18 nframes=4
+	pc=4804196 func=127 file=113 line=69
+	pc=4802140 func=128 file=111 line=141
+	pc=4804022 func=112 file=113 line=67
+	pc=4803543 func=114 file=113 line=43
+Stack id=37 nframes=3
+	pc=4804964 func=110 file=111 line=80
+	pc=4804052 func=112 file=113 line=84
+	pc=4803543 func=114 file=113 line=43
+Stack id=31 nframes=4
+	pc=4803865 func=112 file=113 line=61
+	pc=4804890 func=129 file=113 line=73
+	pc=4802140 func=128 file=111 line=141
+	pc=4804691 func=124 file=113 line=70
+Stack id=55 nframes=2
+	pc=4803832 func=112 file=113 line=58
+	pc=4803609 func=114 file=113 line=46
+Stack id=47 nframes=2
+	pc=4803865 func=112 file=113 line=61
+	pc=4803589 func=114 file=113 line=45
+Stack id=38 nframes=2
+	pc=4803832 func=112 file=113 line=58
+	pc=4803566 func=114 file=113 line=44
+Stack id=56 nframes=2
+	pc=4803865 func=112 file=113 line=61
+	pc=4803609 func=114 file=113 line=46
+Stack id=33 nframes=4
+	pc=4804022 func=112 file=113 line=67
+	pc=4804890 func=129 file=113 line=73
+	pc=4802140 func=128 file=111 line=141
+	pc=4804691 func=124 file=113 line=70
+Stack id=44 nframes=3
+	pc=4599892 func=130 file=131 line=195
+	pc=4804036 func=112 file=113 line=83
+	pc=4803566 func=114 file=113 line=44
+Stack id=3 nframes=4
+	pc=4421707 func=132 file=133 line=1382
+	pc=4533555 func=134 file=135 line=255
+	pc=4802469 func=125 file=126 line=125
+	pc=4803332 func=114 file=113 line=30
+Stack id=6 nframes=1
+	pc=4539520 func=136 file=135 line=868
+Stack id=58 nframes=2
+	pc=4804022 func=112 file=113 line=67
+	pc=4803609 func=114 file=113 line=46
+Stack id=64 nframes=2
+	pc=4803865 func=112 file=113 line=61
+	pc=4803629 func=114 file=113 line=47
+Stack id=62 nframes=3
+	pc=4804964 func=110 file=111 line=80
+	pc=4804052 func=112 file=113 line=84
+	pc=4803609 func=114 file=113 line=46
+Stack id=34 nframes=4
+	pc=4804022 func=112 file=113 line=67
+	pc=4804890 func=129 file=113 line=73
+	pc=4802140 func=128 file=111 line=141
+	pc=4804691 func=124 file=113 line=70
+Stack id=30 nframes=4
+	pc=4803832 func=112 file=113 line=58
+	pc=4804890 func=129 file=113 line=73
+	pc=4802140 func=128 file=111 line=141
+	pc=4804691 func=124 file=113 line=70
+Stack id=32 nframes=4
+	pc=4803943 func=112 file=113 line=64
+	pc=4804890 func=129 file=113 line=73
+	pc=4802140 func=128 file=111 line=141
+	pc=4804691 func=124 file=113 line=70
+Stack id=26 nframes=1
+	pc=4804691 func=124 file=113 line=70
+Stack id=46 nframes=2
+	pc=4803832 func=112 file=113 line=58
+	pc=4803589 func=114 file=113 line=45
+Stack id=50 nframes=4
+	pc=4804196 func=127 file=113 line=69
+	pc=4802140 func=128 file=111 line=141
+	pc=4804022 func=112 file=113 line=67
+	pc=4803589 func=114 file=113 line=45
+Stack id=59 nframes=4
+	pc=4804196 func=127 file=113 line=69
+	pc=4802140 func=128 file=111 line=141
+	pc=4804022 func=112 file=113 line=67
+	pc=4803609 func=114 file=113 line=46
+Stack id=7 nframes=4
+	pc=4539492 func=137 file=135 line=868
+	pc=4533572 func=134 file=135 line=258
+	pc=4802469 func=125 file=126 line=125
+	pc=4803332 func=114 file=113 line=30
+Stack id=17 nframes=1
+	pc=4804512 func=124 file=113 line=69
+Stack id=57 nframes=2
+	pc=4803943 func=112 file=113 line=64
+	pc=4803609 func=114 file=113 line=46
+Stack id=41 nframes=2
+	pc=4804022 func=112 file=113 line=67
+	pc=4803566 func=114 file=113 line=44
+Stack id=63 nframes=2
+	pc=4803832 func=112 file=113 line=58
+	pc=4803629 func=114 file=113 line=47
+Stack id=60 nframes=2
+	pc=4804022 func=112 file=113 line=67
+	pc=4803609 func=114 file=113 line=46
+Stack id=5 nframes=4
+	pc=4542549 func=138 file=139 line=42
+	pc=4533560 func=134 file=135 line=257
+	pc=4802469 func=125 file=126 line=125
+	pc=4803332 func=114 file=113 line=30
+Stack id=40 nframes=2
+	pc=4803943 func=112 file=113 line=64
+	pc=4803566 func=114 file=113 line=44
+Stack id=21 nframes=3
+	pc=4217905 func=140 file=141 line=442
+	pc=4539946 func=142 file=135 line=928
+	pc=4542714 func=143 file=139 line=54
+Stack id=2 nframes=3
+	pc=4533284 func=134 file=135 line=238
+	pc=4802469 func=125 file=126 line=125
+	pc=4803332 func=114 file=113 line=30
+Stack id=53 nframes=6
+	pc=4247492 func=144 file=145 line=1374
+	pc=4599676 func=130 file=131 line=186
+	pc=4804036 func=112 file=113 line=83
+	pc=4804890 func=129 file=113 line=73
+	pc=4802140 func=128 file=111 line=141
+	pc=4804691 func=124 file=113 line=70
+Stack id=20 nframes=3
+	pc=4599892 func=130 file=131 line=195
+	pc=4804036 func=112 file=113 line=83
+	pc=4803543 func=114 file=113 line=43
+Stack id=70 nframes=3
+	pc=4804964 func=110 file=111 line=80
+	pc=4804052 func=112 file=113 line=84
+	pc=4803629 func=114 file=113 line=47
+Stack id=15 nframes=2
+	pc=4803943 func=112 file=113 line=64
+	pc=4803543 func=114 file=113 line=43
+Stack id=65 nframes=2
+	pc=4803943 func=112 file=113 line=64
+	pc=4803629 func=114 file=113 line=47
+Stack id=28 nframes=1
+	pc=4804691 func=124 file=113 line=70
+Stack id=48 nframes=2
+	pc=4803943 func=112 file=113 line=64
+	pc=4803589 func=114 file=113 line=45
+Stack id=61 nframes=3
+	pc=4599892 func=130 file=131 line=195
+	pc=4804036 func=112 file=113 line=83
+	pc=4803609 func=114 file=113 line=46
+Stack id=13 nframes=2
+	pc=4803832 func=112 file=113 line=58
+	pc=4803543 func=114 file=113 line=43
+Stack id=29 nframes=3
+	pc=4217905 func=140 file=141 line=442
+	pc=4539946 func=142 file=135 line=928
+	pc=4539559 func=136 file=135 line=871
+Stack id=51 nframes=2
+	pc=4804022 func=112 file=113 line=67
+	pc=4803589 func=114 file=113 line=45
+Stack id=42 nframes=4
+	pc=4804196 func=127 file=113 line=69
+	pc=4802140 func=128 file=111 line=141
+	pc=4804022 func=112 file=113 line=67
+	pc=4803566 func=114 file=113 line=44
+Stack id=14 nframes=2
+	pc=4803865 func=112 file=113 line=61
+	pc=4803543 func=114 file=113 line=43
+Stack id=39 nframes=2
+	pc=4803865 func=112 file=113 line=61
+	pc=4803566 func=114 file=113 line=44
+Stack id=49 nframes=2
+	pc=4804022 func=112 file=113 line=67
+	pc=4803589 func=114 file=113 line=45
+Stack id=52 nframes=3
+	pc=4599892 func=130 file=131 line=195
+	pc=4804036 func=112 file=113 line=83
+	pc=4803589 func=114 file=113 line=45
+Stack id=24 nframes=7
+	pc=4634510 func=146 file=116 line=223
+	pc=4634311 func=117 file=118 line=240
+	pc=4633765 func=119 file=118 line=216
+	pc=4633083 func=120 file=118 line=131
+	pc=4764601 func=121 file=122 line=152
+	pc=4765335 func=123 file=122 line=238
+	pc=4804612 func=124 file=113 line=70
+Stack id=43 nframes=2
+	pc=4804022 func=112 file=113 line=67
+	pc=4803566 func=114 file=113 line=44
+Stack id=19 nframes=2
+	pc=4804022 func=112 file=113 line=67
+	pc=4803543 func=114 file=113 line=43
+Stack id=69 nframes=3
+	pc=4599892 func=130 file=131 line=195
+	pc=4804036 func=112 file=113 line=83
+	pc=4803629 func=114 file=113 line=47
+Stack id=16 nframes=2
+	pc=4804022 func=112 file=113 line=67
+	pc=4803543 func=114 file=113 line=43
+Stack id=54 nframes=3
+	pc=4804964 func=110 file=111 line=80
+	pc=4804052 func=112 file=113 line=84
+	pc=4803589 func=114 file=113 line=45
+Stack id=35 nframes=5
+	pc=4599892 func=130 file=131 line=195
+	pc=4804036 func=112 file=113 line=83
+	pc=4804890 func=129 file=113 line=73
+	pc=4802140 func=128 file=111 line=141
+	pc=4804691 func=124 file=113 line=70
+Stack id=27 nframes=3
+	pc=4804862 func=129 file=113 line=71
+	pc=4802140 func=128 file=111 line=141
+	pc=4804691 func=124 file=113 line=70
+Stack id=4 nframes=1
+	pc=4542656 func=143 file=139 line=42
+Stack id=8 nframes=1
+	pc=4802720 func=147 file=126 line=128
+Stack id=66 nframes=2
+	pc=4804022 func=112 file=113 line=67
+	pc=4803629 func=114 file=113 line=47
+Stack id=1 nframes=4
+	pc=4548715 func=148 file=149 line=255
+	pc=4533263 func=134 file=135 line=237
+	pc=4802469 func=125 file=126 line=125
+	pc=4803332 func=114 file=113 line=30
+Stack id=67 nframes=4
+	pc=4804196 func=127 file=113 line=69
+	pc=4802140 func=128 file=111 line=141
+	pc=4804022 func=112 file=113 line=67
+	pc=4803629 func=114 file=113 line=47
+Stack id=23 nframes=7
+	pc=4641050 func=150 file=151 line=964
+	pc=4751591 func=152 file=153 line=209
+	pc=4751583 func=154 file=155 line=736
+	pc=4751136 func=156 file=155 line=380
+	pc=4753008 func=157 file=158 line=46
+	pc=4753000 func=159 file=160 line=183
+	pc=4802778 func=147 file=126 line=134
+Stack id=11 nframes=1
+	pc=4803445 func=114 file=113 line=36
+Stack id=68 nframes=2
+	pc=4804022 func=112 file=113 line=67
+	pc=4803629 func=114 file=113 line=47
+Stack id=36 nframes=5
+	pc=4804964 func=110 file=111 line=80
+	pc=4804052 func=112 file=113 line=84
+	pc=4804890 func=129 file=113 line=73
+	pc=4802140 func=128 file=111 line=141
+	pc=4804691 func=124 file=113 line=70
+Stack id=12 nframes=1
+	pc=4803492 func=114 file=113 line=39
+Stack id=25 nframes=1
+	pc=4802788 func=147 file=126 line=130
+EventBatch gen=1 m=18446744073709551615 time=2753925243266 size=3466
+Strings
+String id=1
+	data="Not worker"
+String id=2
+	data="GC (dedicated)"
+String id=3
+	data="GC (fractional)"
+String id=4
+	data="GC (idle)"
+String id=5
+	data="unspecified"
+String id=6
+	data="forever"
+String id=7
+	data="network"
+String id=8
+	data="select"
+String id=9
+	data="sync.(*Cond).Wait"
+String id=10
+	data="sync"
+String id=11
+	data="chan send"
+String id=12
+	data="chan receive"
+String id=13
+	data="GC mark assist wait for work"
+String id=14
+	data="GC background sweeper wait"
+String id=15
+	data="system goroutine wait"
+String id=16
+	data="preempted"
+String id=17
+	data="wait for debug call"
+String id=18
+	data="wait until GC ends"
+String id=19
+	data="sleep"
+String id=20
+	data="runtime.GoSched"
+String id=21
+	data="start trace"
+String id=22
+	data="type2"
+String id=23
+	data="type3"
+String id=24
+	data="log"
+String id=25
+	data="before do"
+String id=26
+	data="do"
+String id=27
+	data="log2"
+String id=28
+	data="do"
+String id=29
+	data="fanout"
+String id=30
+	data="region3"
+String id=31
+	data="region2"
+String id=32
+	data="fanout region3"
+String id=33
+	data="region0"
+String id=34
+	data="fanout region0"
+String id=35
+	data="region1"
+String id=36
+	data="fanout region1"
+String id=37
+	data="fanout region2"
+String id=38
+	data="before do"
+String id=39
+	data="do"
+String id=40
+	data="before do"
+String id=41
+	data="do"
+String id=42
+	data="fanout region1"
+String id=43
+	data="fanout region0"
+String id=44
+	data="before do"
+String id=45
+	data="do"
+String id=46
+	data="fanout region2"
+String id=47
+	data="before do"
+String id=48
+	data="do"
+String id=49
+	data="fanout region0"
+String id=50
+	data="fanout region1"
+String id=51
+	data="before do"
+String id=52
+	data="do"
+String id=53
+	data="region5"
+String id=54
+	data="fanout region5"
+String id=55
+	data="fanout region3"
+String id=56
+	data="region4"
+String id=57
+	data="fanout region4"
+String id=58
+	data="fanout region0"
+String id=59
+	data="fanout region1"
+String id=60
+	data="fanout region2"
+String id=61
+	data="before do"
+String id=62
+	data="do"
+String id=63
+	data="before do"
+String id=64
+	data="do"
+String id=65
+	data="fanout region4"
+String id=66
+	data="fanout region0"
+String id=67
+	data="fanout region1"
+String id=68
+	data="fanout region2"
+String id=69
+	data="before do"
+String id=70
+	data="do"
+String id=71
+	data="fanout region3"
+String id=72
+	data="before do"
+String id=73
+	data="do"
+String id=74
+	data="fanout region3"
+String id=75
+	data="fanout region0"
+String id=76
+	data="fanout region1"
+String id=77
+	data="fanout region2"
+String id=78
+	data="before do"
+String id=79
+	data="do"
+String id=80
+	data="before do"
+String id=81
+	data="do"
+String id=82
+	data="fanout region1"
+String id=83
+	data="fanout region0"
+String id=84
+	data="before do"
+String id=85
+	data="do"
+String id=86
+	data="fanout region2"
+String id=87
+	data="before do"
+String id=88
+	data="do"
+String id=89
+	data="fanout region0"
+String id=90
+	data="fanout region1"
+String id=91
+	data="before do"
+String id=92
+	data="do"
+String id=93
+	data="fanout region5"
+String id=94
+	data="fanout region0"
+String id=95
+	data="fanout region1"
+String id=96
+	data="fanout region2"
+String id=97
+	data="before do"
+String id=98
+	data="do"
+String id=99
+	data="fanout region4"
+String id=100
+	data="fanout region3"
+String id=101
+	data="before do"
+String id=102
+	data="do"
+String id=103
+	data="fanout region4"
+String id=104
+	data="fanout region0"
+String id=105
+	data="fanout region1"
+String id=106
+	data="fanout region2"
+String id=107
+	data="before do"
+String id=108
+	data="do"
+String id=109
+	data="fanout region3"
+String id=110
+	data="runtime/trace.(*Task).End"
+String id=111
+	data="/usr/local/google/home/mknyszek/work/go-1/src/runtime/trace/annotation.go"
+String id=112
+	data="main.do"
+String id=113
+	data="/usr/local/google/home/mknyszek/work/go-1/src/internal/trace/v2/testdata/testprog/annotations-stress.go"
+String id=114
+	data="main.main"
+String id=115
+	data="sync.(*Mutex).Lock"
+String id=116
+	data="/usr/local/google/home/mknyszek/work/go-1/src/sync/mutex.go"
+String id=117
+	data="sync.(*Pool).pinSlow"
+String id=118
+	data="/usr/local/google/home/mknyszek/work/go-1/src/sync/pool.go"
+String id=119
+	data="sync.(*Pool).pin"
+String id=120
+	data="sync.(*Pool).Get"
+String id=121
+	data="fmt.newPrinter"
+String id=122
+	data="/usr/local/google/home/mknyszek/work/go-1/src/fmt/print.go"
+String id=123
+	data="fmt.Sprintf"
+String id=124
+	data="main.do.func1.1"
+String id=125
+	data="runtime/trace.Start"
+String id=126
+	data="/usr/local/google/home/mknyszek/work/go-1/src/runtime/trace/trace.go"
+String id=127
+	data="main.do.func1"
+String id=128
+	data="runtime/trace.WithRegion"
+String id=129
+	data="main.do.func1.1.1"
+String id=130
+	data="time.Sleep"
+String id=131
+	data="/usr/local/google/home/mknyszek/work/go-1/src/runtime/time.go"
+String id=132
+	data="runtime.startTheWorld"
+String id=133
+	data="/usr/local/google/home/mknyszek/work/go-1/src/runtime/proc.go"
+String id=134
+	data="runtime.StartTrace"
+String id=135
+	data="/usr/local/google/home/mknyszek/work/go-1/src/runtime/trace2.go"
+String id=136
+	data="runtime.(*traceAdvancerState).start.func1"
+String id=137
+	data="runtime.(*traceAdvancerState).start"
+String id=138
+	data="runtime.traceStartReadCPU"
+String id=139
+	data="/usr/local/google/home/mknyszek/work/go-1/src/runtime/trace2cpu.go"
+String id=140
+	data="runtime.chanrecv1"
+String id=141
+	data="/usr/local/google/home/mknyszek/work/go-1/src/runtime/chan.go"
+String id=142
+	data="runtime.(*wakeableSleep).sleep"
+String id=143
+	data="runtime.traceStartReadCPU.func1"
+String id=144
+	data="runtime.newobject"
+String id=145
+	data="/usr/local/google/home/mknyszek/work/go-1/src/runtime/malloc.go"
+String id=146
+	data="sync.(*Mutex).Unlock"
+String id=147
+	data="runtime/trace.Start.func1"
+String id=148
+	data="runtime.traceLocker.Gomaxprocs"
+String id=149
+	data="/usr/local/google/home/mknyszek/work/go-1/src/runtime/trace2runtime.go"
+String id=150
+	data="syscall.write"
+String id=151
+	data="/usr/local/google/home/mknyszek/work/go-1/src/syscall/zsyscall_linux_amd64.go"
+String id=152
+	data="syscall.Write"
+String id=153
+	data="/usr/local/google/home/mknyszek/work/go-1/src/syscall/syscall_unix.go"
+String id=154
+	data="internal/poll.ignoringEINTRIO"
+String id=155
+	data="/usr/local/google/home/mknyszek/work/go-1/src/internal/poll/fd_unix.go"
+String id=156
+	data="internal/poll.(*FD).Write"
+String id=157
+	data="os.(*File).write"
+String id=158
+	data="/usr/local/google/home/mknyszek/work/go-1/src/os/file_posix.go"
+String id=159
+	data="os.(*File).Write"
+String id=160
+	data="/usr/local/google/home/mknyszek/work/go-1/src/os/file.go"
diff --git a/trace/testdata/tests/go122-annotations.test b/trace/testdata/tests/go122-annotations.test
new file mode 100644
index 0000000..4749d82
--- /dev/null
+++ b/trace/testdata/tests/go122-annotations.test
@@ -0,0 +1,299 @@
+-- expect --
+SUCCESS
+-- trace --
+Trace Go1.22
+EventBatch gen=1 m=18446744073709551615 time=28113086279559 size=5
+Frequency freq=15625000
+EventBatch gen=1 m=167930 time=28113086277797 size=41
+ProcStart dt=505 p=1 p_seq=1
+GoStart dt=303 g=7 g_seq=1
+HeapAlloc dt=646 heapalloc_value=1892352
+HeapAlloc dt=149 heapalloc_value=1900544
+GoBlock dt=146 reason_string=12 stack=24
+GoStart dt=14 g=6 g_seq=1
+HeapAlloc dt=16 heapalloc_value=1908736
+GoBlock dt=347 reason_string=12 stack=25
+EventBatch gen=1 m=167928 time=28113086279032 size=10
+ProcStart dt=451 p=2 p_seq=1
+GoStart dt=188 g=8 g_seq=1
+EventBatch gen=1 m=167926 time=28113086275999 size=324
+ProcStatus dt=295 p=0 pstatus=1
+GoStatus dt=5 g=1 m=167926 gstatus=2
+ProcsChange dt=405 procs_value=48 stack=1
+STWBegin dt=65 kind_string=21 stack=2
+HeapGoal dt=2 heapgoal_value=4194304
+ProcStatus dt=4 p=1 pstatus=2
+ProcStatus dt=1 p=2 pstatus=2
+ProcStatus dt=1 p=3 pstatus=2
+ProcStatus dt=1 p=4 pstatus=2
+ProcStatus dt=1 p=5 pstatus=2
+ProcStatus dt=1 p=6 pstatus=2
+ProcStatus dt=1 p=7 pstatus=2
+ProcStatus dt=1 p=8 pstatus=2
+ProcStatus dt=1 p=9 pstatus=2
+ProcStatus dt=1 p=10 pstatus=2
+ProcStatus dt=1 p=11 pstatus=2
+ProcStatus dt=1 p=12 pstatus=2
+ProcStatus dt=1 p=13 pstatus=2
+ProcStatus dt=1 p=14 pstatus=2
+ProcStatus dt=1 p=15 pstatus=2
+ProcStatus dt=1 p=16 pstatus=2
+ProcStatus dt=1 p=17 pstatus=2
+ProcStatus dt=1 p=18 pstatus=2
+ProcStatus dt=1 p=19 pstatus=2
+ProcStatus dt=1 p=20 pstatus=2
+ProcStatus dt=1 p=21 pstatus=2
+ProcStatus dt=1 p=22 pstatus=2
+ProcStatus dt=1 p=23 pstatus=2
+ProcStatus dt=1 p=24 pstatus=2
+ProcStatus dt=1 p=25 pstatus=2
+ProcStatus dt=1 p=26 pstatus=2
+ProcStatus dt=1 p=27 pstatus=2
+ProcStatus dt=1 p=28 pstatus=2
+ProcStatus dt=1 p=29 pstatus=2
+ProcStatus dt=1 p=30 pstatus=2
+ProcStatus dt=1 p=31 pstatus=2
+ProcStatus dt=1 p=32 pstatus=2
+ProcStatus dt=1 p=33 pstatus=2
+ProcStatus dt=1 p=34 pstatus=2
+ProcStatus dt=1 p=35 pstatus=2
+ProcStatus dt=1 p=36 pstatus=2
+ProcStatus dt=1 p=37 pstatus=2
+ProcStatus dt=1 p=38 pstatus=2
+ProcStatus dt=1 p=39 pstatus=2
+ProcStatus dt=1 p=40 pstatus=2
+ProcStatus dt=1 p=41 pstatus=2
+ProcStatus dt=1 p=42 pstatus=2
+ProcStatus dt=1 p=43 pstatus=2
+ProcStatus dt=1 p=44 pstatus=2
+ProcStatus dt=1 p=45 pstatus=2
+ProcStatus dt=1 p=46 pstatus=2
+ProcStatus dt=1 p=47 pstatus=2
+ProcsChange dt=1 procs_value=48 stack=3
+STWEnd dt=184
+GoCreate dt=252 new_g=6 new_stack=4 stack=5
+GoCreate dt=78 new_g=7 new_stack=6 stack=7
+GoCreate dt=73 new_g=8 new_stack=8 stack=9
+UserTaskBegin dt=71 task=1 parent_task=0 name_string=22 stack=10
+UserRegionBegin dt=535 task=1 name_string=23 stack=11
+HeapAlloc dt=26 heapalloc_value=1884160
+GoCreate dt=8 new_g=9 new_stack=12 stack=13
+GoBlock dt=249 reason_string=10 stack=14
+GoStart dt=8 g=9 g_seq=1
+UserRegionBegin dt=286 task=1 name_string=24 stack=15
+UserRegionBegin dt=244 task=1 name_string=25 stack=16
+UserRegionBegin dt=6 task=1 name_string=26 stack=17
+UserLog dt=6 task=1 key_string=27 value_string=28 stack=18
+UserRegionEnd dt=4 task=1 name_string=26 stack=19
+UserRegionEnd dt=315 task=1 name_string=25 stack=20
+UserTaskEnd dt=5 task=1 stack=21
+GoUnblock dt=11 g=1 g_seq=1 stack=22
+GoDestroy dt=6
+GoStart dt=10 g=1 g_seq=2
+UserRegionBegin dt=278 task=0 name_string=29 stack=23
+EventBatch gen=1 m=18446744073709551615 time=28113086280061 size=57
+GoStatus dt=318 g=2 m=18446744073709551615 gstatus=4
+GoStatus dt=3 g=3 m=18446744073709551615 gstatus=4
+GoStatus dt=1 g=4 m=18446744073709551615 gstatus=4
+GoStatus dt=1 g=5 m=18446744073709551615 gstatus=4
+EventBatch gen=1 m=18446744073709551615 time=28113086280852 size=488
+Stacks
+Stack id=17 nframes=3
+	pc=4816080 func=30 file=31 line=45
+	pc=4813660 func=32 file=33 line=141
+	pc=4815908 func=34 file=31 line=43
+Stack id=8 nframes=1
+	pc=4814528 func=35 file=36 line=128
+Stack id=9 nframes=2
+	pc=4814351 func=37 file=36 line=128
+	pc=4815228 func=38 file=31 line=27
+Stack id=24 nframes=3
+	pc=4217457 func=39 file=40 line=442
+	pc=4544973 func=41 file=42 line=918
+	pc=4544806 func=43 file=42 line=871
+Stack id=7 nframes=4
+	pc=4544740 func=44 file=42 line=868
+	pc=4538792 func=45 file=42 line=258
+	pc=4814277 func=37 file=36 line=125
+	pc=4815228 func=38 file=31 line=27
+Stack id=22 nframes=3
+	pc=4642148 func=46 file=47 line=81
+	pc=4816326 func=48 file=47 line=87
+	pc=4815941 func=34 file=31 line=50
+Stack id=11 nframes=1
+	pc=4815364 func=38 file=31 line=34
+Stack id=5 nframes=4
+	pc=4547349 func=49 file=50 line=42
+	pc=4538780 func=45 file=42 line=257
+	pc=4814277 func=37 file=36 line=125
+	pc=4815228 func=38 file=31 line=27
+Stack id=23 nframes=1
+	pc=4815568 func=38 file=31 line=54
+Stack id=3 nframes=4
+	pc=4421860 func=51 file=52 line=1360
+	pc=4538775 func=45 file=42 line=255
+	pc=4814277 func=37 file=36 line=125
+	pc=4815228 func=38 file=31 line=27
+Stack id=21 nframes=2
+	pc=4816228 func=53 file=33 line=80
+	pc=4815926 func=34 file=31 line=50
+Stack id=1 nframes=4
+	pc=4553515 func=54 file=55 line=255
+	pc=4538503 func=45 file=42 line=237
+	pc=4814277 func=37 file=36 line=125
+	pc=4815228 func=38 file=31 line=27
+Stack id=12 nframes=1
+	pc=4815680 func=34 file=31 line=37
+Stack id=6 nframes=1
+	pc=4544768 func=43 file=42 line=868
+Stack id=2 nframes=3
+	pc=4538523 func=45 file=42 line=238
+	pc=4814277 func=37 file=36 line=125
+	pc=4815228 func=38 file=31 line=27
+Stack id=13 nframes=1
+	pc=4815492 func=38 file=31 line=37
+Stack id=4 nframes=1
+	pc=4547456 func=56 file=50 line=42
+Stack id=14 nframes=2
+	pc=4642407 func=57 file=47 line=116
+	pc=4815502 func=38 file=31 line=51
+Stack id=18 nframes=5
+	pc=4816147 func=58 file=31 line=46
+	pc=4813660 func=32 file=33 line=141
+	pc=4816080 func=30 file=31 line=45
+	pc=4813660 func=32 file=33 line=141
+	pc=4815908 func=34 file=31 line=43
+Stack id=20 nframes=1
+	pc=4815908 func=34 file=31 line=43
+Stack id=25 nframes=3
+	pc=4217457 func=39 file=40 line=442
+	pc=4544973 func=41 file=42 line=918
+	pc=4547514 func=56 file=50 line=54
+Stack id=16 nframes=1
+	pc=4815908 func=34 file=31 line=43
+Stack id=15 nframes=1
+	pc=4815838 func=34 file=31 line=41
+Stack id=19 nframes=3
+	pc=4816080 func=30 file=31 line=45
+	pc=4813660 func=32 file=33 line=141
+	pc=4815908 func=34 file=31 line=43
+Stack id=10 nframes=1
+	pc=4815332 func=38 file=31 line=33
+EventBatch gen=1 m=18446744073709551615 time=28113086274600 size=1620
+Strings
+String id=1
+	data="Not worker"
+String id=2
+	data="GC (dedicated)"
+String id=3
+	data="GC (fractional)"
+String id=4
+	data="GC (idle)"
+String id=5
+	data="unspecified"
+String id=6
+	data="forever"
+String id=7
+	data="network"
+String id=8
+	data="select"
+String id=9
+	data="sync.(*Cond).Wait"
+String id=10
+	data="sync"
+String id=11
+	data="chan send"
+String id=12
+	data="chan receive"
+String id=13
+	data="GC mark assist wait for work"
+String id=14
+	data="GC background sweeper wait"
+String id=15
+	data="system goroutine wait"
+String id=16
+	data="preempted"
+String id=17
+	data="wait for debug call"
+String id=18
+	data="wait until GC ends"
+String id=19
+	data="sleep"
+String id=20
+	data="runtime.GoSched"
+String id=21
+	data="start trace"
+String id=22
+	data="task0"
+String id=23
+	data="task0 region"
+String id=24
+	data="unended region"
+String id=25
+	data="region0"
+String id=26
+	data="region1"
+String id=27
+	data="key0"
+String id=28
+	data="0123456789abcdef"
+String id=29
+	data="post-existing region"
+String id=30
+	data="main.main.func1.1"
+String id=31
+	data="/usr/local/google/home/mknyszek/work/go-1/src/internal/trace/v2/testdata/testprog/annotations.go"
+String id=32
+	data="runtime/trace.WithRegion"
+String id=33
+	data="/usr/local/google/home/mknyszek/work/go-1/src/runtime/trace/annotation.go"
+String id=34
+	data="main.main.func1"
+String id=35
+	data="runtime/trace.Start.func1"
+String id=36
+	data="/usr/local/google/home/mknyszek/work/go-1/src/runtime/trace/trace.go"
+String id=37
+	data="runtime/trace.Start"
+String id=38
+	data="main.main"
+String id=39
+	data="runtime.chanrecv1"
+String id=40
+	data="/usr/local/google/home/mknyszek/work/go-1/src/runtime/chan.go"
+String id=41
+	data="runtime.(*wakeableSleep).sleep"
+String id=42
+	data="/usr/local/google/home/mknyszek/work/go-1/src/runtime/trace2.go"
+String id=43
+	data="runtime.(*traceAdvancerState).start.func1"
+String id=44
+	data="runtime.(*traceAdvancerState).start"
+String id=45
+	data="runtime.StartTrace"
+String id=46
+	data="sync.(*WaitGroup).Add"
+String id=47
+	data="/usr/local/google/home/mknyszek/work/go-1/src/sync/waitgroup.go"
+String id=48
+	data="sync.(*WaitGroup).Done"
+String id=49
+	data="runtime.traceStartReadCPU"
+String id=50
+	data="/usr/local/google/home/mknyszek/work/go-1/src/runtime/trace2cpu.go"
+String id=51
+	data="runtime.startTheWorld"
+String id=52
+	data="/usr/local/google/home/mknyszek/work/go-1/src/runtime/proc.go"
+String id=53
+	data="runtime/trace.(*Task).End"
+String id=54
+	data="runtime.traceLocker.Gomaxprocs"
+String id=55
+	data="/usr/local/google/home/mknyszek/work/go-1/src/runtime/trace2runtime.go"
+String id=56
+	data="runtime.traceStartReadCPU.func1"
+String id=57
+	data="sync.(*WaitGroup).Wait"
+String id=58
+	data="main.main.func1.1.1"
diff --git a/trace/testdata/tests/go122-confuse-seq-across-generations.test b/trace/testdata/tests/go122-confuse-seq-across-generations.test
new file mode 100644
index 0000000..c0d6f0d
--- /dev/null
+++ b/trace/testdata/tests/go122-confuse-seq-across-generations.test
@@ -0,0 +1,36 @@
+-- expect --
+SUCCESS
+-- trace --
+Trace Go1.22
+EventBatch gen=1 m=0 time=0 size=13
+ProcStatus dt=1 p=0 pstatus=1
+GoStatus dt=1 g=1 m=0 gstatus=2
+GoStop dt=1 reason_string=1 stack=0
+EventBatch gen=1 m=1 time=0 size=12
+ProcStatus dt=1 p=1 pstatus=1
+GoStart dt=1 g=1 g_seq=1
+GoStop dt=1 reason_string=1 stack=0
+EventBatch gen=1 m=18446744073709551615 time=0 size=5
+Frequency freq=15625000
+EventBatch gen=1 m=18446744073709551615 time=0 size=1
+Stacks
+EventBatch gen=1 m=18446744073709551615 time=0 size=12
+Strings
+String id=1
+	data="whatever"
+EventBatch gen=2 m=1 time=3 size=8
+ProcStatus dt=1 p=1 pstatus=1
+GoStart dt=1 g=1 g_seq=2
+EventBatch gen=2 m=0 time=5 size=17
+ProcStatus dt=1 p=0 pstatus=1
+GoStatus dt=1 g=1 m=0 gstatus=1
+GoStart dt=1 g=1 g_seq=1
+GoStop dt=1 reason_string=1 stack=0
+EventBatch gen=2 m=18446744073709551615 time=0 size=5
+Frequency freq=15625000
+EventBatch gen=2 m=18446744073709551615 time=0 size=1
+Stacks
+EventBatch gen=2 m=18446744073709551615 time=0 size=12
+Strings
+String id=1
+	data="whatever"
diff --git a/trace/testdata/tests/go122-create-syscall-reuse-thread-id.test b/trace/testdata/tests/go122-create-syscall-reuse-thread-id.test
new file mode 100644
index 0000000..1820738
--- /dev/null
+++ b/trace/testdata/tests/go122-create-syscall-reuse-thread-id.test
@@ -0,0 +1,23 @@
+-- expect --
+SUCCESS
+-- trace --
+Trace Go1.22
+EventBatch gen=1 m=0 time=0 size=37
+GoCreateSyscall dt=1 new_g=4
+GoSyscallEndBlocked dt=1
+ProcStatus dt=1 p=0 pstatus=2
+ProcStart dt=1 p=0 p_seq=1
+GoStatus dt=1 g=4 m=18446744073709551615 gstatus=1
+GoStart dt=1 g=4 g_seq=1
+GoSyscallBegin dt=1 p_seq=2 stack=0
+GoDestroySyscall dt=1
+EventBatch gen=1 m=0 time=0 size=13
+ProcStatus dt=1 p=1 pstatus=2
+ProcStart dt=1 p=1 p_seq=1
+ProcSteal dt=1 p=0 p_seq=3 m=0
+EventBatch gen=1 m=18446744073709551615 time=0 size=5
+Frequency freq=15625000
+EventBatch gen=1 m=18446744073709551615 time=0 size=1
+Stacks
+EventBatch gen=1 m=18446744073709551615 time=0 size=1
+Strings
diff --git a/trace/testdata/tests/go122-create-syscall-with-p.test b/trace/testdata/tests/go122-create-syscall-with-p.test
new file mode 100644
index 0000000..9b329b8
--- /dev/null
+++ b/trace/testdata/tests/go122-create-syscall-with-p.test
@@ -0,0 +1,22 @@
+-- expect --
+FAILURE ".*expected a proc but didn't have one.*"
+-- trace --
+Trace Go1.22
+EventBatch gen=1 m=0 time=0 size=34
+GoCreateSyscall dt=1 new_g=4
+ProcStatus dt=1 p=0 pstatus=2
+ProcStart dt=1 p=0 p_seq=1
+GoSyscallEndBlocked dt=1
+GoStart dt=1 g=4 g_seq=1
+GoSyscallBegin dt=1 p_seq=2 stack=0
+GoDestroySyscall dt=1
+GoCreateSyscall dt=1 new_g=4
+GoSyscallEnd dt=1
+GoSyscallBegin dt=1 p_seq=3 stack=0
+GoDestroySyscall dt=1
+EventBatch gen=1 m=18446744073709551615 time=0 size=5
+Frequency freq=15625000
+EventBatch gen=1 m=18446744073709551615 time=0 size=1
+Stacks
+EventBatch gen=1 m=18446744073709551615 time=0 size=1
+Strings
diff --git a/trace/testdata/tests/go122-gc-stress.test b/trace/testdata/tests/go122-gc-stress.test
new file mode 100644
index 0000000..8d77fe1
--- /dev/null
+++ b/trace/testdata/tests/go122-gc-stress.test
@@ -0,0 +1,4207 @@
+-- expect --
+SUCCESS
+-- trace --
+Trace Go1.22
+EventBatch gen=3 m=18446744073709551615 time=28114950954550 size=5
+Frequency freq=15625000
+EventBatch gen=3 m=169438 time=28114950899454 size=615
+ProcStatus dt=2 p=47 pstatus=1
+GoStatus dt=1 g=111 m=169438 gstatus=2
+GCMarkAssistActive dt=1 g=111
+GCMarkAssistEnd dt=1
+HeapAlloc dt=38 heapalloc_value=191159744
+HeapAlloc dt=134 heapalloc_value=191192512
+GCMarkAssistBegin dt=60 stack=3
+GoStop dt=2288 reason_string=20 stack=9
+GoStart dt=15 g=111 g_seq=1
+GCMarkAssistEnd dt=1860
+HeapAlloc dt=46 heapalloc_value=191585728
+GCMarkAssistBegin dt=35 stack=3
+GoBlock dt=32 reason_string=13 stack=11
+GoUnblock dt=14 g=57 g_seq=5 stack=0
+GoStart dt=9 g=57 g_seq=6
+GoLabel dt=3 label_string=2
+GoBlock dt=2925 reason_string=15 stack=5
+GoUnblock dt=12 g=57 g_seq=7 stack=0
+GoStart dt=5 g=57 g_seq=8
+GoLabel dt=1 label_string=2
+GoBlock dt=391 reason_string=15 stack=5
+GoUnblock dt=15 g=57 g_seq=9 stack=0
+GoStart dt=7 g=57 g_seq=10
+GoLabel dt=1 label_string=2
+GoBlock dt=307 reason_string=15 stack=5
+GoUnblock dt=7 g=57 g_seq=11 stack=0
+GoStart dt=3 g=57 g_seq=12
+GoLabel dt=2 label_string=2
+GoBlock dt=1049 reason_string=15 stack=5
+GoUnblock dt=23 g=58 g_seq=7 stack=0
+GoStart dt=8 g=58 g_seq=8
+GoLabel dt=1 label_string=2
+GoBlock dt=1126 reason_string=15 stack=5
+GoUnblock dt=12 g=53 g_seq=3 stack=0
+GoStart dt=5 g=53 g_seq=4
+GoLabel dt=1 label_string=2
+GoBlock dt=1751 reason_string=15 stack=5
+GoUnblock dt=12 g=53 g_seq=5 stack=0
+GoStart dt=6 g=53 g_seq=6
+GoLabel dt=3 label_string=2
+GoBlock dt=119 reason_string=15 stack=5
+GoStart dt=15 g=88 g_seq=4
+GoBlock dt=50 reason_string=13 stack=11
+GoUnblock dt=1212 g=54 g_seq=15 stack=0
+GoStart dt=6 g=54 g_seq=16
+GoLabel dt=1 label_string=4
+GoBlock dt=2984 reason_string=15 stack=5
+GoUnblock dt=2696 g=52 g_seq=21 stack=0
+GoStart dt=3 g=52 g_seq=22
+GoLabel dt=1 label_string=4
+GoBlock dt=2013 reason_string=15 stack=5
+GoStart dt=18 g=98 g_seq=6
+GCMarkAssistEnd dt=6
+HeapAlloc dt=44 heapalloc_value=192003520
+GCMarkAssistBegin dt=54 stack=3
+GoBlock dt=481 reason_string=13 stack=11
+GoUnblock dt=51 g=14 g_seq=17 stack=0
+GoStart dt=4 g=14 g_seq=18
+GoLabel dt=1 label_string=4
+GoBlock dt=3954 reason_string=15 stack=5
+GoUnblock dt=59 g=57 g_seq=41 stack=0
+GoStart dt=8 g=57 g_seq=42
+GoLabel dt=1 label_string=4
+GoBlock dt=63 reason_string=15 stack=5
+GoUnblock dt=11 g=57 g_seq=43 stack=0
+GoStart dt=4 g=57 g_seq=44
+GoLabel dt=1 label_string=2
+GoBlock dt=3186 reason_string=15 stack=5
+GoUnblock dt=11 g=57 g_seq=45 stack=0
+GoStart dt=3 g=57 g_seq=46
+GoLabel dt=1 label_string=2
+GoBlock dt=9 reason_string=15 stack=5
+ProcStop dt=60
+ProcStart dt=50 p=47 p_seq=1
+GoUnblock dt=9 g=22 g_seq=33 stack=0
+GoStart dt=4 g=22 g_seq=34
+GoLabel dt=1 label_string=4
+GoBlock dt=97 reason_string=15 stack=5
+GoUnblock dt=9 g=22 g_seq=35 stack=0
+GoStart dt=5 g=22 g_seq=36
+GoLabel dt=1 label_string=2
+GoBlock dt=2605 reason_string=15 stack=5
+GoUnblock dt=10 g=22 g_seq=37 stack=0
+GoStart dt=4 g=22 g_seq=38
+GoLabel dt=1 label_string=2
+GoBlock dt=13 reason_string=15 stack=5
+ProcStop dt=37
+ProcStart dt=582 p=47 p_seq=2
+GoStart dt=504 g=97 g_seq=4
+GCMarkAssistEnd dt=5
+GCMarkAssistBegin dt=34 stack=3
+GoBlock dt=279 reason_string=13 stack=11
+ProcStop dt=30
+ProcStart dt=3780 p=47 p_seq=3
+GoUnblock dt=9 g=71 g_seq=25 stack=0
+GoStart dt=128 g=71 g_seq=26
+GoLabel dt=1 label_string=2
+GoBlock dt=210 reason_string=15 stack=5
+GoUnblock dt=8 g=71 g_seq=27 stack=0
+GoStart dt=1 g=71 g_seq=28
+GoLabel dt=1 label_string=2
+GoBlock dt=1627 reason_string=15 stack=5
+GoStart dt=27 g=105 g_seq=6
+GCMarkAssistEnd dt=3
+HeapAlloc dt=44 heapalloc_value=192477912
+GCMarkAssistBegin dt=77 stack=3
+GoStop dt=873 reason_string=20 stack=9
+GoUnblock dt=12 g=23 g_seq=47 stack=0
+GoStart dt=3 g=23 g_seq=48
+GoLabel dt=1 label_string=2
+GoBlock dt=36 reason_string=15 stack=5
+GoUnblock dt=6 g=23 g_seq=49 stack=0
+GoStart dt=1 g=23 g_seq=50
+GoLabel dt=1 label_string=2
+GoBlock dt=9 reason_string=15 stack=5
+GoUnblock dt=8 g=23 g_seq=51 stack=0
+GoStart dt=3 g=23 g_seq=52
+GoLabel dt=1 label_string=2
+GoBlock dt=15 reason_string=15 stack=5
+GoStart dt=10 g=105 g_seq=7
+GoStop dt=16 reason_string=20 stack=9
+GoUnblock dt=7 g=23 g_seq=53 stack=0
+GoStart dt=3 g=23 g_seq=54
+GoLabel dt=1 label_string=2
+GoBlock dt=10 reason_string=15 stack=5
+GoUnblock dt=12 g=23 g_seq=55 stack=0
+GoStart dt=3 g=23 g_seq=56
+GoLabel dt=1 label_string=2
+GoBlock dt=9 reason_string=15 stack=5
+GoUnblock dt=4 g=23 g_seq=57 stack=0
+GoStart dt=1 g=23 g_seq=58
+GoLabel dt=1 label_string=2
+GoBlock dt=4554 reason_string=15 stack=5
+GoStart dt=14 g=105 g_seq=10
+GCMarkAssistEnd dt=5
+HeapAlloc dt=65 heapalloc_value=193682136
+GCMarkAssistBegin dt=16 stack=3
+GoBlock dt=44 reason_string=13 stack=11
+GoStart dt=15 g=83 g_seq=8
+HeapAlloc dt=221 heapalloc_value=194173656
+HeapAlloc dt=1927 heapalloc_value=195443416
+GoStop dt=5838 reason_string=16 stack=6
+GoStart dt=51 g=83 g_seq=9
+GCMarkAssistBegin dt=12 stack=3
+GoBlock dt=35 reason_string=10 stack=18
+GoStart dt=70 g=87 g_seq=6
+GCMarkAssistBegin dt=14 stack=3
+GoBlock dt=35 reason_string=13 stack=11
+ProcStop dt=77
+EventBatch gen=3 m=169436 time=28114950894898 size=160
+ProcStatus dt=2 p=34 pstatus=1
+GoStatus dt=3 g=107 m=169436 gstatus=2
+GCMarkAssistBegin dt=15 stack=3
+GoBlock dt=4050 reason_string=13 stack=11
+GoStatus dt=20 g=23 m=18446744073709551615 gstatus=4
+GoUnblock dt=3 g=23 g_seq=1 stack=0
+GoStart dt=8 g=23 g_seq=2
+GoLabel dt=1 label_string=2
+GoUnblock dt=2316 g=81 g_seq=1 stack=12
+GoBlock dt=626 reason_string=15 stack=5
+GoUnblock dt=9 g=23 g_seq=3 stack=0
+GoStart dt=9 g=23 g_seq=4
+GoLabel dt=1 label_string=2
+GoBlock dt=3975 reason_string=15 stack=5
+GoUnblock dt=35 g=23 g_seq=5 stack=0
+GoStart dt=6 g=23 g_seq=6
+GoLabel dt=1 label_string=2
+GoBlock dt=142 reason_string=15 stack=5
+GoUnblock dt=9 g=23 g_seq=7 stack=0
+GoStart dt=4 g=23 g_seq=8
+GoLabel dt=1 label_string=2
+GoBlock dt=3815 reason_string=15 stack=5
+GoUnblock dt=10 g=23 g_seq=9 stack=0
+GoStart dt=6 g=23 g_seq=10
+GoLabel dt=1 label_string=2
+GoBlock dt=3560 reason_string=15 stack=5
+GoUnblock dt=8 g=23 g_seq=11 stack=0
+GoStart dt=4 g=23 g_seq=12
+GoLabel dt=3 label_string=2
+GoBlock dt=2781 reason_string=15 stack=5
+GoUnblock dt=13 g=23 g_seq=13 stack=0
+GoStart dt=4 g=23 g_seq=14
+GoLabel dt=1 label_string=2
+GoBlock dt=1277 reason_string=15 stack=5
+ProcStop dt=16
+EventBatch gen=3 m=169435 time=28114950897148 size=522
+ProcStatus dt=2 p=24 pstatus=1
+GoStatus dt=2 g=122 m=169435 gstatus=2
+GCMarkAssistActive dt=1 g=122
+GCMarkAssistEnd dt=3
+HeapAlloc dt=24 heapalloc_value=190602688
+GCMarkAssistBegin dt=95 stack=3
+GCMarkAssistEnd dt=4651
+GCMarkAssistBegin dt=50 stack=3
+GoBlock dt=2931 reason_string=13 stack=11
+ProcStop dt=1401
+ProcStart dt=18 p=24 p_seq=1
+GoUnblock dt=3524 g=28 g_seq=5 stack=0
+GoStart dt=10 g=28 g_seq=6
+GoLabel dt=1 label_string=4
+GoBlock dt=42 reason_string=15 stack=5
+GoUnblock dt=1162 g=24 g_seq=11 stack=0
+GoStart dt=7 g=24 g_seq=12
+GoLabel dt=1 label_string=4
+GoBlock dt=3050 reason_string=15 stack=5
+GoUnblock dt=5301 g=67 g_seq=15 stack=0
+GoStart dt=4 g=67 g_seq=16
+GoLabel dt=1 label_string=4
+GoBlock dt=40 reason_string=15 stack=5
+ProcStop dt=64
+ProcStart dt=841 p=24 p_seq=2
+GoStatus dt=58 g=16 m=18446744073709551615 gstatus=4
+GoUnblock dt=3 g=16 g_seq=1 stack=0
+GoStart dt=273 g=16 g_seq=2
+GoLabel dt=1 label_string=4
+GoBlock dt=139 reason_string=15 stack=5
+ProcStop dt=52
+ProcStart dt=97 p=24 p_seq=3
+GoUnblock dt=5 g=16 g_seq=3 stack=0
+GoStart dt=2 g=16 g_seq=4
+GoLabel dt=1 label_string=4
+GoBlock dt=471 reason_string=15 stack=5
+GoUnblock dt=58 g=16 g_seq=5 stack=0
+GoStart dt=6 g=16 g_seq=6
+GoLabel dt=3 label_string=4
+GoBlock dt=912 reason_string=15 stack=5
+GoUnblock dt=9 g=16 g_seq=7 stack=0
+GoStart dt=6 g=16 g_seq=8
+GoLabel dt=1 label_string=2
+GoUnblock dt=6571 g=113 g_seq=5 stack=12
+GoBlock dt=22 reason_string=15 stack=5
+ProcStop dt=73
+ProcStart dt=22914 p=30 p_seq=16
+GoStart dt=342 g=117 g_seq=4
+GCMarkAssistEnd dt=8
+HeapAlloc dt=67 heapalloc_value=196467152
+GoStop dt=5253 reason_string=16 stack=6
+GoStart dt=44 g=128 g_seq=7
+GCMarkAssistBegin dt=21 stack=3
+GoBlock dt=37 reason_string=10 stack=18
+GoStart dt=7 g=130 g_seq=5
+GoBlock dt=182 reason_string=10 stack=20
+ProcStop dt=81
+ProcStart dt=8287 p=2 p_seq=2
+GoStart dt=164 g=82 g_seq=11
+GCMarkAssistEnd dt=8
+HeapAlloc dt=169 heapalloc_value=104038048
+HeapAlloc dt=135 heapalloc_value=104189856
+HeapAlloc dt=126 heapalloc_value=104287136
+HeapAlloc dt=24 heapalloc_value=104308256
+HeapAlloc dt=28 heapalloc_value=104313888
+HeapAlloc dt=14 heapalloc_value=104399904
+GCSweepBegin dt=43 stack=28
+GCSweepEnd dt=8 swept_value=8192 reclaimed_value=8192
+HeapAlloc dt=4 heapalloc_value=104473632
+HeapAlloc dt=58 heapalloc_value=104510496
+HeapAlloc dt=22 heapalloc_value=104534432
+HeapAlloc dt=51 heapalloc_value=104654624
+GCSweepBegin dt=146 stack=28
+GCSweepEnd dt=8 swept_value=24576 reclaimed_value=24576
+HeapAlloc dt=4 heapalloc_value=104878624
+HeapAlloc dt=42 heapalloc_value=105007648
+HeapAlloc dt=29 heapalloc_value=105077280
+HeapAlloc dt=36 heapalloc_value=105105952
+HeapAlloc dt=44 heapalloc_value=105242784
+HeapAlloc dt=58 heapalloc_value=105431200
+HeapAlloc dt=128 heapalloc_value=105593760
+HeapAlloc dt=199 heapalloc_value=106209440
+GCSweepBegin dt=155 stack=28
+GCSweepEnd dt=13 swept_value=32768 reclaimed_value=32768
+HeapAlloc dt=3 heapalloc_value=106666272
+HeapAlloc dt=77 heapalloc_value=106901152
+HeapAlloc dt=64 heapalloc_value=107211808
+HeapAlloc dt=133 heapalloc_value=107661088
+HeapAlloc dt=34 heapalloc_value=107722528
+HeapAlloc dt=108 heapalloc_value=108207392
+GCSweepBegin dt=202 stack=28
+GCSweepEnd dt=13 swept_value=32768 reclaimed_value=32768
+HeapAlloc dt=3 heapalloc_value=108742816
+HeapAlloc dt=112 heapalloc_value=109093664
+HeapAlloc dt=207 heapalloc_value=109913120
+HeapAlloc dt=271 heapalloc_value=110834560
+HeapAlloc dt=212 heapalloc_value=111566720
+HeapAlloc dt=148 heapalloc_value=112190720
+HeapAlloc dt=74 heapalloc_value=112528128
+HeapAlloc dt=143 heapalloc_value=113050240
+HeapAlloc dt=19 heapalloc_value=113194368
+HeapAlloc dt=135 heapalloc_value=113615232
+GCSweepBegin dt=251 stack=27
+EventBatch gen=3 m=169434 time=28114950909315 size=660
+ProcStatus dt=2 p=7 pstatus=1
+GoStatus dt=2 g=71 m=169434 gstatus=2
+GoBlock dt=6 reason_string=15 stack=5
+GoUnblock dt=2633 g=53 g_seq=7 stack=0
+GoStart dt=7 g=53 g_seq=8
+GoLabel dt=3 label_string=4
+GoBlock dt=127 reason_string=15 stack=5
+GoUnblock dt=1358 g=52 g_seq=15 stack=0
+GoStart dt=7 g=52 g_seq=16
+GoLabel dt=1 label_string=4
+GoBlock dt=27 reason_string=15 stack=5
+GoStart dt=1150 g=93 g_seq=4
+GCMarkAssistEnd dt=7
+HeapAlloc dt=39 heapalloc_value=191897024
+GCMarkAssistBegin dt=27 stack=3
+GoStop dt=894 reason_string=20 stack=9
+GoStart dt=13 g=93 g_seq=5
+GoBlock dt=150 reason_string=13 stack=11
+ProcStop dt=57
+ProcStart dt=14 p=7 p_seq=1
+ProcStop dt=4205
+ProcStart dt=18 p=7 p_seq=2
+GoUnblock dt=4 g=22 g_seq=17 stack=0
+GoStart dt=172 g=22 g_seq=18
+GoLabel dt=1 label_string=4
+GoBlock dt=1298 reason_string=15 stack=5
+GoUnblock dt=12 g=22 g_seq=19 stack=0
+GoStart dt=7 g=22 g_seq=20
+GoLabel dt=1 label_string=2
+GoBlock dt=108 reason_string=15 stack=5
+GoUnblock dt=9 g=22 g_seq=21 stack=0
+GoStart dt=4 g=22 g_seq=22
+GoLabel dt=1 label_string=2
+GoBlock dt=309 reason_string=15 stack=5
+GoUnblock dt=19 g=57 g_seq=35 stack=0
+GoStart dt=6 g=57 g_seq=36
+GoLabel dt=1 label_string=2
+GoBlock dt=26 reason_string=15 stack=5
+GoUnblock dt=12 g=30 g_seq=15 stack=0
+GoStart dt=4 g=30 g_seq=16
+GoLabel dt=1 label_string=2
+GoBlock dt=410 reason_string=15 stack=5
+GoUnblock dt=2384 g=23 g_seq=37 stack=0
+GoStart dt=7 g=23 g_seq=38
+GoLabel dt=1 label_string=4
+GoBlock dt=119 reason_string=15 stack=5
+GoUnblock dt=58 g=25 g_seq=21 stack=0
+GoStart dt=4 g=25 g_seq=22
+GoLabel dt=1 label_string=4
+GoBlock dt=1875 reason_string=15 stack=5
+GoUnblock dt=53 g=29 g_seq=15 stack=0
+GoStart dt=3 g=29 g_seq=16
+GoLabel dt=1 label_string=4
+GoBlock dt=133 reason_string=15 stack=5
+GoUnblock dt=51 g=25 g_seq=25 stack=0
+GoStart dt=5 g=25 g_seq=26
+GoLabel dt=1 label_string=4
+GoBlock dt=14 reason_string=15 stack=5
+GoUnblock dt=42 g=25 g_seq=27 stack=0
+GoStart dt=3 g=25 g_seq=28
+GoLabel dt=1 label_string=4
+GoBlock dt=56 reason_string=15 stack=5
+GoUnblock dt=1741 g=24 g_seq=41 stack=0
+GoStart dt=4 g=24 g_seq=42
+GoLabel dt=3 label_string=2
+GoBlock dt=15 reason_string=15 stack=5
+GoUnblock dt=26 g=25 g_seq=31 stack=0
+GoStart dt=4 g=25 g_seq=32
+GoLabel dt=1 label_string=2
+GoBlock dt=2653 reason_string=15 stack=5
+GoUnblock dt=10 g=25 g_seq=33 stack=0
+GoStart dt=6 g=25 g_seq=34
+GoLabel dt=1 label_string=2
+GoBlock dt=151 reason_string=15 stack=5
+GoUnblock dt=37 g=25 g_seq=35 stack=0
+GoStart dt=3 g=25 g_seq=36
+GoLabel dt=1 label_string=4
+GoBlock dt=12 reason_string=15 stack=5
+GoUnblock dt=8 g=25 g_seq=37 stack=0
+GoStart dt=3 g=25 g_seq=38
+GoLabel dt=1 label_string=2
+GoBlock dt=1197 reason_string=15 stack=5
+GoUnblock dt=38 g=22 g_seq=43 stack=0
+GoStart dt=7 g=22 g_seq=44
+GoLabel dt=1 label_string=4
+GoBlock dt=16 reason_string=15 stack=5
+ProcStop dt=28
+ProcStart dt=2728 p=7 p_seq=3
+GoUnblock dt=10 g=25 g_seq=39 stack=0
+GoStart dt=162 g=25 g_seq=40
+GoLabel dt=2 label_string=2
+GoBlock dt=36 reason_string=15 stack=5
+GoUnblock dt=10 g=25 g_seq=41 stack=0
+GoStart dt=4 g=25 g_seq=42
+GoLabel dt=1 label_string=2
+GoBlock dt=19 reason_string=15 stack=5
+GoUnblock dt=7 g=25 g_seq=43 stack=0
+GoStart dt=1 g=25 g_seq=44
+GoLabel dt=1 label_string=2
+GoUnblock dt=616 g=81 g_seq=6 stack=12
+GoBlock dt=1549 reason_string=15 stack=5
+GoStart dt=12 g=112 g_seq=5
+GoBlock dt=22 reason_string=13 stack=11
+GoStart dt=8 g=90 g_seq=4
+GCMarkAssistEnd dt=3
+HeapAlloc dt=2613 heapalloc_value=192625368
+GoStop dt=48 reason_string=16 stack=6
+GoUnblock dt=13 g=54 g_seq=35 stack=0
+GoStart dt=4 g=54 g_seq=36
+GoLabel dt=1 label_string=2
+GoBlock dt=269 reason_string=15 stack=5
+GoUnblock dt=6 g=54 g_seq=37 stack=0
+GoStart dt=5 g=54 g_seq=38
+GoLabel dt=1 label_string=2
+GoBlock dt=856 reason_string=15 stack=5
+GoUnblock dt=23 g=52 g_seq=61 stack=0
+GoStart dt=4 g=52 g_seq=62
+GoLabel dt=1 label_string=2
+GoBlock dt=33 reason_string=15 stack=5
+GoUnblock dt=13 g=52 g_seq=63 stack=0
+GoStart dt=2 g=52 g_seq=64
+GoLabel dt=1 label_string=2
+GoBlock dt=38 reason_string=15 stack=5
+GoUnblock dt=17 g=52 g_seq=65 stack=0
+GoStart dt=3 g=52 g_seq=66
+GoLabel dt=1 label_string=2
+GoBlock dt=37 reason_string=15 stack=5
+GoUnblock dt=11 g=52 g_seq=67 stack=0
+GoStart dt=4 g=52 g_seq=68
+GoLabel dt=1 label_string=2
+GoBlock dt=2457 reason_string=15 stack=5
+GoUnblock dt=11 g=52 g_seq=69 stack=0
+GoStart dt=4 g=52 g_seq=70
+GoLabel dt=1 label_string=2
+GoBlock dt=9 reason_string=15 stack=5
+GoStart dt=23 g=114 g_seq=4
+GCMarkAssistEnd dt=457
+HeapAlloc dt=223 heapalloc_value=194968280
+GoStop dt=6900 reason_string=16 stack=4
+GoStart dt=24 g=114 g_seq=5
+GCMarkAssistBegin dt=86 stack=3
+GoBlock dt=43 reason_string=10 stack=18
+ProcStop dt=49
+ProcStart dt=475 p=7 p_seq=4
+ProcStop dt=40
+ProcStart dt=1388 p=7 p_seq=5
+GoUnblock dt=9 g=131 g_seq=8 stack=0
+GoStart dt=169 g=131 g_seq=9
+GoSyscallBegin dt=24 p_seq=6 stack=7
+GoSyscallEnd dt=184
+GoBlock dt=11 reason_string=15 stack=2
+ProcStop dt=42
+ProcStart dt=18109 p=16 p_seq=2
+GoStart dt=176 g=91 g_seq=4
+GCMarkAssistEnd dt=8
+HeapAlloc dt=22 heapalloc_value=114837120
+HeapAlloc dt=88 heapalloc_value=114853504
+GCSweepBegin dt=145 stack=27
+EventBatch gen=3 m=169433 time=28114950897465 size=806
+ProcStatus dt=2 p=2 pstatus=1
+GoStatus dt=1 g=24 m=169433 gstatus=2
+GoBlock dt=9 reason_string=15 stack=5
+GoUnblock dt=19 g=24 g_seq=1 stack=0
+GoStart dt=5 g=24 g_seq=2
+GoLabel dt=2 label_string=2
+GoBlock dt=4044 reason_string=15 stack=5
+GoUnblock dt=17 g=24 g_seq=3 stack=0
+GoStart dt=4 g=24 g_seq=4
+GoLabel dt=1 label_string=2
+GoBlock dt=4262 reason_string=15 stack=5
+GoUnblock dt=19 g=28 g_seq=3 stack=0
+GoStart dt=4 g=28 g_seq=4
+GoLabel dt=1 label_string=2
+GoBlock dt=461 reason_string=15 stack=5
+GoUnblock dt=4544 g=72 g_seq=15 stack=0
+GoStart dt=9 g=72 g_seq=16
+GoLabel dt=3 label_string=4
+GoBlock dt=32 reason_string=15 stack=5
+GoUnblock dt=9 g=72 g_seq=17 stack=0
+GoStart dt=2 g=72 g_seq=18
+GoLabel dt=2 label_string=2
+GoBlock dt=13 reason_string=15 stack=5
+GoUnblock dt=3 g=72 g_seq=19 stack=0
+GoStart dt=1 g=72 g_seq=20
+GoLabel dt=1 label_string=2
+GoBlock dt=237 reason_string=15 stack=5
+GoUnblock dt=8 g=72 g_seq=21 stack=0
+GoStart dt=3 g=72 g_seq=22
+GoLabel dt=1 label_string=2
+GoBlock dt=151 reason_string=15 stack=5
+GoUnblock dt=11 g=72 g_seq=23 stack=0
+GoStart dt=6 g=72 g_seq=24
+GoLabel dt=1 label_string=2
+GoBlock dt=3418 reason_string=15 stack=5
+ProcStop dt=1573
+ProcStart dt=17 p=2 p_seq=1
+ProcStop dt=1102
+ProcStart dt=21668 p=19 p_seq=4
+GoUnblock dt=16 g=51 g_seq=47 stack=0
+GoStart dt=7 g=51 g_seq=48
+GoLabel dt=1 label_string=2
+GoBlock dt=60 reason_string=15 stack=5
+GoUnblock dt=6 g=51 g_seq=49 stack=0
+GoStart dt=1 g=51 g_seq=50
+GoLabel dt=3 label_string=2
+GoBlock dt=5166 reason_string=15 stack=5
+GoStart dt=18 g=106 g_seq=5
+GCMarkAssistEnd dt=10
+HeapAlloc dt=56 heapalloc_value=193452760
+GCMarkAssistBegin dt=116 stack=3
+GCMarkAssistEnd dt=58
+HeapAlloc dt=47 heapalloc_value=193714904
+GoStop dt=54 reason_string=16 stack=6
+GoUnblock dt=18 g=54 g_seq=41 stack=0
+GoStart dt=4 g=54 g_seq=42
+GoLabel dt=2 label_string=2
+GoUnblock dt=16 g=105 g_seq=11 stack=12
+GoBlock dt=21 reason_string=15 stack=5
+GoStart dt=8 g=105 g_seq=12
+GCMarkAssistEnd dt=7
+HeapAlloc dt=33 heapalloc_value=193919704
+GCMarkAssistBegin dt=13 stack=3
+GCMarkAssistEnd dt=91
+HeapAlloc dt=173 heapalloc_value=194378456
+GCMarkAssistBegin dt=26 stack=3
+GoBlock dt=37 reason_string=13 stack=11
+GoStart dt=33 g=104 g_seq=2
+GCMarkAssistEnd dt=5
+HeapAlloc dt=81 heapalloc_value=194673368
+GoStop dt=2248 reason_string=16 stack=6
+GoStart dt=2855 g=104 g_seq=3
+GCMarkAssistBegin dt=16 stack=3
+GoBlock dt=27 reason_string=10 stack=18
+GoStart dt=16 g=103 g_seq=5
+GCMarkAssistEnd dt=6
+HeapAlloc dt=6180 heapalloc_value=196655568
+GoStop dt=14 reason_string=16 stack=6
+GoStart dt=146 g=102 g_seq=5
+GCMarkAssistBegin dt=10 stack=3
+HeapAlloc dt=38 heapalloc_value=196663760
+GoBlock dt=16 reason_string=10 stack=18
+ProcStop dt=41
+ProcStart dt=1317 p=19 p_seq=5
+ProcStop dt=24
+ProcStart dt=2117 p=0 p_seq=5
+GoStart dt=5190 g=115 g_seq=10
+GCMarkAssistEnd dt=6
+GCSweepBegin dt=22 stack=27
+GCSweepEnd dt=727 swept_value=71303168 reclaimed_value=1302272
+HeapAlloc dt=37 heapalloc_value=103898784
+HeapAlloc dt=200 heapalloc_value=103947936
+HeapAlloc dt=63 heapalloc_value=103960224
+HeapAlloc dt=27 heapalloc_value=103997088
+HeapAlloc dt=65 heapalloc_value=104103584
+HeapAlloc dt=87 heapalloc_value=104132512
+HeapAlloc dt=63 heapalloc_value=104255392
+HeapAlloc dt=87 heapalloc_value=104267680
+HeapAlloc dt=73 heapalloc_value=104379424
+HeapAlloc dt=79 heapalloc_value=104494112
+GCSweepBegin dt=40 stack=28
+GCSweepEnd dt=7 swept_value=16384 reclaimed_value=16384
+HeapAlloc dt=8 heapalloc_value=104526880
+HeapAlloc dt=27 heapalloc_value=104589088
+HeapAlloc dt=42 heapalloc_value=104711968
+HeapAlloc dt=83 heapalloc_value=104821280
+GCSweepBegin dt=21 stack=28
+GCSweepEnd dt=4 swept_value=32768 reclaimed_value=32768
+HeapAlloc dt=2 heapalloc_value=104854048
+HeapAlloc dt=105 heapalloc_value=105064992
+GCSweepBegin dt=94 stack=28
+GCSweepEnd dt=9 swept_value=8192 reclaimed_value=8192
+HeapAlloc dt=4 heapalloc_value=105250976
+GCSweepBegin dt=29 stack=28
+GCSweepEnd dt=10 swept_value=16384 reclaimed_value=16384
+HeapAlloc dt=4 heapalloc_value=105447584
+HeapAlloc dt=30 heapalloc_value=105476256
+HeapAlloc dt=57 heapalloc_value=105566368
+GCSweepBegin dt=74 stack=28
+GCSweepEnd dt=5 swept_value=32768 reclaimed_value=32768
+HeapAlloc dt=3 heapalloc_value=105741216
+HeapAlloc dt=77 heapalloc_value=105921440
+HeapAlloc dt=76 heapalloc_value=106143904
+HeapAlloc dt=50 heapalloc_value=106274976
+HeapAlloc dt=113 heapalloc_value=106633504
+HeapAlloc dt=110 heapalloc_value=107036320
+HeapAlloc dt=95 heapalloc_value=107351072
+HeapAlloc dt=80 heapalloc_value=107702048
+GCSweepBegin dt=78 stack=28
+GCSweepEnd dt=6 swept_value=24576 reclaimed_value=24576
+HeapAlloc dt=2 heapalloc_value=107835936
+HeapAlloc dt=39 heapalloc_value=107904288
+HeapAlloc dt=82 heapalloc_value=108390432
+HeapAlloc dt=230 heapalloc_value=108955808
+HeapAlloc dt=126 heapalloc_value=109421344
+GCSweepBegin dt=131 stack=28
+GCSweepEnd dt=5 swept_value=16384 reclaimed_value=16384
+HeapAlloc dt=3 heapalloc_value=109929504
+GCSweepBegin dt=29 stack=28
+GCSweepEnd dt=4 swept_value=8192 reclaimed_value=8192
+HeapAlloc dt=3 heapalloc_value=110038816
+HeapAlloc dt=28 heapalloc_value=110109472
+HeapAlloc dt=93 heapalloc_value=110412672
+HeapAlloc dt=33 heapalloc_value=110547840
+HeapAlloc dt=123 heapalloc_value=111070848
+GCSweepBegin dt=155 stack=28
+GCSweepEnd dt=10 swept_value=16384 reclaimed_value=16384
+HeapAlloc dt=3 heapalloc_value=111648640
+GCSweepBegin dt=61 stack=28
+GCSweepEnd dt=8 swept_value=24576 reclaimed_value=24576
+HeapAlloc dt=3 heapalloc_value=111996800
+GCSweepBegin dt=37 stack=28
+GCSweepEnd dt=5 swept_value=16384 reclaimed_value=16384
+HeapAlloc dt=8 heapalloc_value=112149760
+HeapAlloc dt=32 heapalloc_value=112342272
+GCSweepBegin dt=75 stack=28
+GCSweepEnd dt=7 swept_value=16384 reclaimed_value=16384
+HeapAlloc dt=5 heapalloc_value=112601856
+HeapAlloc dt=61 heapalloc_value=112923264
+HeapAlloc dt=90 heapalloc_value=113262720
+HeapAlloc dt=88 heapalloc_value=113522304
+HeapAlloc dt=119 heapalloc_value=113967488
+HeapAlloc dt=59 heapalloc_value=114201216
+GCSweepBegin dt=130 stack=27
+EventBatch gen=3 m=169431 time=28114950897743 size=407
+ProcStatus dt=2 p=11 pstatus=1
+GoStatus dt=4 g=51 m=169431 gstatus=2
+GoBlock dt=6 reason_string=15 stack=5
+GoUnblock dt=13 g=51 g_seq=1 stack=0
+GoStart dt=6 g=51 g_seq=2
+GoLabel dt=1 label_string=2
+GoBlock dt=4143 reason_string=15 stack=5
+GoStatus dt=1425 g=28 m=18446744073709551615 gstatus=4
+GoUnblock dt=2 g=28 g_seq=1 stack=0
+GoStart dt=7 g=28 g_seq=2
+GoLabel dt=1 label_string=4
+GoBlock dt=1758 reason_string=15 stack=5
+GoUnblock dt=3904 g=25 g_seq=9 stack=0
+GoStart dt=9 g=25 g_seq=10
+GoLabel dt=1 label_string=4
+GoBlock dt=41 reason_string=15 stack=5
+ProcStop dt=1189
+ProcStart dt=16 p=11 p_seq=1
+GoUnblock dt=1157 g=57 g_seq=21 stack=0
+GoStart dt=6 g=57 g_seq=22
+GoLabel dt=1 label_string=4
+GoBlock dt=25 reason_string=15 stack=5
+GoUnblock dt=1614 g=52 g_seq=13 stack=0
+GoStart dt=11 g=52 g_seq=14
+GoLabel dt=4 label_string=4
+GoBlock dt=86 reason_string=15 stack=5
+GoUnblock dt=4771 g=22 g_seq=11 stack=0
+GoStart dt=12 g=22 g_seq=12
+GoLabel dt=1 label_string=4
+GoBlock dt=1413 reason_string=15 stack=5
+GoUnblock dt=10 g=22 g_seq=13 stack=0
+GoStart dt=4 g=22 g_seq=14
+GoLabel dt=1 label_string=2
+GoBlock dt=39 reason_string=15 stack=5
+ProcStop dt=67
+ProcStart dt=2286 p=11 p_seq=2
+ProcStop dt=95
+ProcStart dt=53 p=0 p_seq=2
+GoUnblock dt=9 g=57 g_seq=33 stack=0
+GoStart dt=8 g=57 g_seq=34
+GoLabel dt=1 label_string=4
+GoBlock dt=37 reason_string=15 stack=5
+GoUnblock dt=20 g=22 g_seq=23 stack=0
+GoStart dt=3 g=22 g_seq=24
+GoLabel dt=1 label_string=2
+GoBlock dt=1036 reason_string=15 stack=5
+GoUnblock dt=11 g=22 g_seq=25 stack=0
+GoStart dt=6 g=22 g_seq=26
+GoLabel dt=1 label_string=2
+GoBlock dt=2130 reason_string=15 stack=5
+GoUnblock dt=11 g=22 g_seq=27 stack=0
+GoStart dt=7 g=22 g_seq=28
+GoLabel dt=2 label_string=2
+GoBlock dt=1227 reason_string=15 stack=5
+GoUnblock dt=12 g=22 g_seq=29 stack=0
+GoStart dt=6 g=22 g_seq=30
+GoLabel dt=1 label_string=2
+GoBlock dt=31 reason_string=15 stack=5
+GoUnblock dt=7 g=22 g_seq=31 stack=0
+GoStart dt=2 g=22 g_seq=32
+GoLabel dt=1 label_string=2
+GoBlock dt=2282 reason_string=15 stack=5
+GoUnblock dt=71 g=29 g_seq=33 stack=0
+GoStart dt=4 g=29 g_seq=34
+GoLabel dt=1 label_string=4
+GoBlock dt=1234 reason_string=15 stack=5
+GoUnblock dt=8 g=29 g_seq=35 stack=0
+GoStart dt=8 g=29 g_seq=36
+GoLabel dt=1 label_string=2
+GoBlock dt=18 reason_string=15 stack=5
+ProcStop dt=49
+ProcStart dt=10623 p=11 p_seq=5
+ProcStop dt=54
+ProcStart dt=686 p=11 p_seq=6
+GoStart dt=185 g=127 g_seq=5
+GCMarkAssistBegin dt=71 stack=3
+GoStop dt=67 reason_string=20 stack=9
+GoUnblock dt=15 g=53 g_seq=47 stack=0
+GoStart dt=3 g=53 g_seq=48
+GoLabel dt=1 label_string=2
+GoUnblock dt=661 g=121 g_seq=10 stack=12
+GoUnblock dt=7 g=88 g_seq=5 stack=12
+GoUnblock dt=8 g=87 g_seq=4 stack=12
+GoUnblock dt=2751 g=94 g_seq=10 stack=12
+GoUnblock dt=8 g=106 g_seq=7 stack=12
+GoUnblock dt=8 g=98 g_seq=9 stack=12
+GoBlock dt=18 reason_string=15 stack=5
+GoStart dt=17 g=87 g_seq=5
+GCMarkAssistEnd dt=5
+HeapAlloc dt=202 heapalloc_value=194796248
+GoStop dt=7327 reason_string=16 stack=6
+GoStart dt=68 g=84 g_seq=8
+GCMarkAssistBegin dt=16 stack=3
+GoBlock dt=29 reason_string=13 stack=11
+ProcStop dt=88
+EventBatch gen=3 m=169428 time=28114950899204 size=756
+ProcStatus dt=2 p=31 pstatus=1
+GoStatus dt=5 g=104 m=169428 gstatus=2
+GCMarkAssistActive dt=1 g=104
+GCMarkAssistEnd dt=2
+HeapAlloc dt=37 heapalloc_value=191110592
+GCMarkAssistBegin dt=21 stack=3
+GoBlock dt=2670 reason_string=13 stack=11
+GoStatus dt=1400 g=22 m=18446744073709551615 gstatus=4
+GoUnblock dt=3 g=22 g_seq=1 stack=0
+GoStart dt=7 g=22 g_seq=2
+GoLabel dt=1 label_string=4
+GoBlock dt=43 reason_string=15 stack=5
+GoUnblock dt=2567 g=70 g_seq=3 stack=0
+GoStart dt=9 g=70 g_seq=4
+GoLabel dt=1 label_string=4
+GoBlock dt=329 reason_string=15 stack=5
+GoUnblock dt=97 g=70 g_seq=5 stack=0
+GoStart dt=5 g=70 g_seq=6
+GoLabel dt=3 label_string=2
+GoUnblock dt=1728 g=84 g_seq=3 stack=12
+GoBlock dt=3527 reason_string=15 stack=5
+GoStart dt=4132 g=114 g_seq=2
+GoStatus dt=28 g=115 m=18446744073709551615 gstatus=4
+GoUnblock dt=8 g=115 g_seq=1 stack=10
+GCMarkAssistBegin dt=18 stack=3
+GoBlock dt=196 reason_string=13 stack=11
+GoStart dt=14 g=115 g_seq=2
+GoStatus dt=18 g=102 m=18446744073709551615 gstatus=4
+GoUnblock dt=3 g=102 g_seq=1 stack=10
+GCMarkAssistBegin dt=13 stack=3
+GoBlock dt=371 reason_string=13 stack=11
+GoUnblock dt=9 g=30 g_seq=11 stack=0
+GoStart dt=6 g=30 g_seq=12
+GoLabel dt=1 label_string=2
+GoBlock dt=5520 reason_string=15 stack=5
+GoUnblock dt=8 g=30 g_seq=13 stack=0
+GoStart dt=4 g=30 g_seq=14
+GoLabel dt=1 label_string=2
+GoBlock dt=28 reason_string=15 stack=5
+GoUnblock dt=10 g=57 g_seq=37 stack=0
+GoStart dt=3 g=57 g_seq=38
+GoLabel dt=1 label_string=2
+GoBlock dt=157 reason_string=15 stack=5
+GoUnblock dt=7 g=57 g_seq=39 stack=0
+GoStart dt=4 g=57 g_seq=40
+GoLabel dt=1 label_string=2
+GoBlock dt=140 reason_string=15 stack=5
+GoUnblock dt=10 g=53 g_seq=25 stack=0
+GoStart dt=3 g=53 g_seq=26
+GoLabel dt=1 label_string=2
+GoBlock dt=90 reason_string=15 stack=5
+GoUnblock dt=62 g=53 g_seq=27 stack=0
+GoStart dt=4 g=53 g_seq=28
+GoLabel dt=1 label_string=4
+GoBlock dt=11 reason_string=15 stack=5
+GoUnblock dt=46 g=53 g_seq=29 stack=0
+GoStart dt=7 g=53 g_seq=30
+GoLabel dt=1 label_string=4
+GoBlock dt=51 reason_string=15 stack=5
+ProcStop dt=2236
+ProcStart dt=966 p=35 p_seq=2
+GoStart dt=19 g=81 g_seq=5
+GCMarkAssistEnd dt=7
+HeapAlloc dt=67 heapalloc_value=192133920
+GCMarkAssistBegin dt=46 stack=3
+GoBlock dt=32 reason_string=13 stack=11
+ProcStop dt=57
+ProcStart dt=15 p=35 p_seq=3
+GoUnblock dt=2 g=69 g_seq=23 stack=0
+GoStart dt=2 g=69 g_seq=24
+GoLabel dt=1 label_string=4
+GoBlock dt=224 reason_string=15 stack=5
+GoUnblock dt=52 g=69 g_seq=25 stack=0
+GoStart dt=3 g=69 g_seq=26
+GoLabel dt=1 label_string=4
+GoBlock dt=289 reason_string=15 stack=5
+GoStart dt=23 g=118 g_seq=2
+GCMarkAssistEnd dt=7
+HeapAlloc dt=21 heapalloc_value=192207648
+GCMarkAssistBegin dt=103 stack=3
+GoBlock dt=18 reason_string=13 stack=11
+GoUnblock dt=48 g=29 g_seq=13 stack=0
+GoStart dt=1 g=29 g_seq=14
+GoLabel dt=1 label_string=4
+GoBlock dt=19 reason_string=15 stack=5
+GoUnblock dt=44 g=25 g_seq=23 stack=0
+GoStart dt=6 g=25 g_seq=24
+GoLabel dt=1 label_string=4
+GoBlock dt=144 reason_string=15 stack=5
+GoUnblock dt=49 g=29 g_seq=17 stack=0
+GoStart dt=1 g=29 g_seq=18
+GoLabel dt=1 label_string=4
+GoBlock dt=777 reason_string=15 stack=5
+GoUnblock dt=56 g=52 g_seq=31 stack=0
+GoStart dt=3 g=52 g_seq=32
+GoLabel dt=1 label_string=4
+GoBlock dt=21 reason_string=15 stack=5
+GoUnblock dt=27 g=51 g_seq=33 stack=0
+GoStart dt=5 g=51 g_seq=34
+GoLabel dt=1 label_string=2
+GoBlock dt=12 reason_string=15 stack=5
+GoUnblock dt=13 g=51 g_seq=35 stack=0
+GoStart dt=4 g=51 g_seq=36
+GoLabel dt=1 label_string=2
+GoBlock dt=226 reason_string=15 stack=5
+GoUnblock dt=7 g=51 g_seq=37 stack=0
+GoStart dt=4 g=51 g_seq=38
+GoLabel dt=1 label_string=2
+GoBlock dt=3928 reason_string=15 stack=5
+GoUnblock dt=14 g=51 g_seq=39 stack=0
+GoStart dt=3 g=51 g_seq=40
+GoLabel dt=3 label_string=2
+GoBlock dt=214 reason_string=15 stack=5
+GoUnblock dt=5 g=51 g_seq=41 stack=0
+GoStart dt=1 g=51 g_seq=42
+GoLabel dt=1 label_string=2
+GoBlock dt=305 reason_string=15 stack=5
+GoUnblock dt=8 g=51 g_seq=43 stack=0
+GoStart dt=5 g=51 g_seq=44
+GoLabel dt=1 label_string=2
+GoBlock dt=9 reason_string=15 stack=5
+ProcStop dt=47
+ProcStart dt=5058 p=35 p_seq=4
+GoUnblock dt=20 g=52 g_seq=51 stack=0
+GoStart dt=188 g=52 g_seq=52
+GoLabel dt=1 label_string=2
+GoBlock dt=33 reason_string=15 stack=5
+GoUnblock dt=9 g=52 g_seq=53 stack=0
+GoStart dt=4 g=52 g_seq=54
+GoLabel dt=1 label_string=2
+GoBlock dt=12 reason_string=15 stack=5
+GoStart dt=14 g=126 g_seq=3
+GCMarkAssistEnd dt=7
+HeapAlloc dt=2068 heapalloc_value=192592600
+GoStop dt=31 reason_string=16 stack=4
+GoUnblock dt=10 g=30 g_seq=39 stack=0
+GoStart dt=4 g=30 g_seq=40
+GoLabel dt=1 label_string=2
+GoBlock dt=54 reason_string=15 stack=5
+GoStart dt=708 g=121 g_seq=9
+GoBlock dt=49 reason_string=13 stack=11
+GoStart dt=18 g=90 g_seq=5
+GCMarkAssistBegin dt=12 stack=3
+GoBlock dt=39 reason_string=13 stack=11
+GoUnblock dt=15 g=71 g_seq=31 stack=0
+GoStart dt=4 g=71 g_seq=32
+GoLabel dt=2 label_string=2
+GoBlock dt=1101 reason_string=15 stack=5
+GoUnblock dt=13 g=71 g_seq=33 stack=0
+GoStart dt=4 g=71 g_seq=34
+GoLabel dt=1 label_string=2
+GoBlock dt=27 reason_string=15 stack=5
+GoUnblock dt=18 g=14 g_seq=54 stack=0
+GoStart dt=4 g=14 g_seq=55
+GoLabel dt=2 label_string=2
+GoUnblock dt=2171 g=94 g_seq=8 stack=12
+GoBlock dt=28 reason_string=15 stack=5
+GoStart dt=11 g=94 g_seq=9
+GCMarkAssistEnd dt=6
+HeapAlloc dt=42 heapalloc_value=193665752
+GCMarkAssistBegin dt=100 stack=3
+GoBlock dt=30 reason_string=13 stack=11
+GoStart dt=13 g=106 g_seq=6
+HeapAlloc dt=99 heapalloc_value=193977048
+GCMarkAssistBegin dt=21 stack=3
+GoBlock dt=30 reason_string=13 stack=11
+GoStart dt=16 g=92 g_seq=4
+GCMarkAssistEnd dt=6
+HeapAlloc dt=884 heapalloc_value=195205848
+GoStop dt=3270 reason_string=16 stack=4
+GoStart dt=29 g=97 g_seq=6
+GCMarkAssistEnd dt=6
+HeapAlloc dt=42 heapalloc_value=195795408
+GCMarkAssistBegin dt=3026 stack=3
+GoBlock dt=85 reason_string=10 stack=18
+ProcStop dt=99
+EventBatch gen=3 m=169426 time=28114950897488 size=116
+ProcStatus dt=1 p=32 pstatus=1
+GoStatus dt=2 g=90 m=169426 gstatus=2
+GCMarkAssistActive dt=1 g=90
+GCMarkAssistEnd dt=3
+HeapAlloc dt=47 heapalloc_value=190627264
+GCMarkAssistBegin dt=51 stack=3
+GoBlock dt=2393 reason_string=13 stack=11
+GoStart dt=1449 g=125 g_seq=2
+GoStatus dt=26 g=127 m=18446744073709551615 gstatus=4
+GoUnblock dt=16 g=127 g_seq=1 stack=10
+GCMarkAssistBegin dt=17 stack=3
+GoStop dt=6909 reason_string=20 stack=9
+GoStart dt=20 g=125 g_seq=3
+GoBlock dt=2101 reason_string=13 stack=11
+GoUnblock dt=2575 g=71 g_seq=11 stack=0
+GoStart dt=8 g=71 g_seq=12
+GoLabel dt=3 label_string=4
+GoBlock dt=44 reason_string=15 stack=5
+GoStart dt=20 g=82 g_seq=7
+GoBlock dt=367 reason_string=13 stack=11
+GoUnblock dt=11 g=22 g_seq=9 stack=0
+GoStart dt=4 g=22 g_seq=10
+GoLabel dt=1 label_string=2
+GoBlock dt=3492 reason_string=15 stack=5
+ProcStop dt=9
+EventBatch gen=3 m=169425 time=28114950900302 size=349
+ProcStatus dt=2 p=10 pstatus=1
+GoStatus dt=2 g=70 m=169425 gstatus=2
+GoBlock dt=8 reason_string=15 stack=5
+GoUnblock dt=15 g=70 g_seq=1 stack=0
+GoStart dt=5 g=70 g_seq=2
+GoLabel dt=1 label_string=2
+GoBlock dt=5604 reason_string=15 stack=5
+GoUnblock dt=33 g=29 g_seq=3 stack=0
+GoStart dt=5 g=29 g_seq=4
+GoLabel dt=1 label_string=2
+GoBlock dt=1191 reason_string=15 stack=5
+GoUnblock dt=9 g=29 g_seq=5 stack=0
+GoStart dt=5 g=29 g_seq=6
+GoLabel dt=2 label_string=2
+GoBlock dt=1935 reason_string=15 stack=5
+GoUnblock dt=15 g=51 g_seq=11 stack=0
+GoStart dt=5 g=51 g_seq=12
+GoLabel dt=1 label_string=2
+GoBlock dt=307 reason_string=15 stack=5
+ProcStop dt=4189
+ProcStart dt=15 p=10 p_seq=1
+GoUnblock dt=10 g=69 g_seq=17 stack=0
+GoStart dt=4 g=69 g_seq=18
+GoLabel dt=1 label_string=2
+GoUnblock dt=780 g=93 g_seq=3 stack=12
+GoBlock dt=6076 reason_string=15 stack=5
+GoUnblock dt=11 g=69 g_seq=19 stack=0
+GoStart dt=4 g=69 g_seq=20
+GoLabel dt=3 label_string=2
+GoUnblock dt=93 g=98 g_seq=5 stack=12
+GoBlock dt=5034 reason_string=15 stack=5
+GoUnblock dt=14 g=58 g_seq=25 stack=0
+GoStart dt=5 g=58 g_seq=26
+GoLabel dt=2 label_string=2
+GoBlock dt=1253 reason_string=15 stack=5
+GoUnblock dt=6 g=58 g_seq=27 stack=0
+GoStart dt=4 g=58 g_seq=28
+GoLabel dt=1 label_string=2
+GoBlock dt=1031 reason_string=15 stack=5
+GoUnblock dt=6 g=58 g_seq=29 stack=0
+GoStart dt=4 g=58 g_seq=30
+GoLabel dt=1 label_string=2
+GoBlock dt=17 reason_string=15 stack=5
+GoUnblock dt=24 g=52 g_seq=33 stack=0
+GoStart dt=6 g=52 g_seq=34
+GoLabel dt=1 label_string=2
+GoBlock dt=321 reason_string=15 stack=5
+GoUnblock dt=75 g=29 g_seq=27 stack=0
+GoStart dt=4 g=29 g_seq=28
+GoLabel dt=1 label_string=4
+GoBlock dt=248 reason_string=15 stack=5
+GoUnblock dt=61 g=57 g_seq=47 stack=0
+GoStart dt=4 g=57 g_seq=48
+GoLabel dt=1 label_string=4
+GoBlock dt=794 reason_string=15 stack=5
+ProcStop dt=41
+ProcStart dt=15678 p=21 p_seq=3
+GoStart dt=22 g=88 g_seq=6
+GCMarkAssistEnd dt=9
+HeapAlloc dt=84 heapalloc_value=194730712
+GoStop dt=2177 reason_string=16 stack=6
+GoStart dt=2495 g=88 g_seq=7
+GCMarkAssistBegin dt=19 stack=3
+GoBlock dt=37 reason_string=10 stack=18
+GoStart dt=15 g=126 g_seq=6
+GCMarkAssistEnd dt=5
+HeapAlloc dt=27 heapalloc_value=196114896
+GCMarkAssistBegin dt=18 stack=3
+GoBlock dt=30 reason_string=10 stack=18
+GoStart dt=15 g=98 g_seq=10
+GCMarkAssistEnd dt=6
+HeapAlloc dt=48 heapalloc_value=196155856
+GoStop dt=6168 reason_string=16 stack=6
+GoStart dt=156 g=98 g_seq=11
+GCMarkAssistBegin dt=9 stack=3
+GoBlock dt=27 reason_string=10 stack=18
+GoStart dt=27 g=94 g_seq=12
+GCMarkAssistBegin dt=13 stack=3
+GoBlock dt=35 reason_string=10 stack=18
+ProcStop dt=55
+ProcStart dt=14725 p=13 p_seq=1
+GoStart dt=171 g=112 g_seq=9
+GCMarkAssistEnd dt=6
+GCSweepBegin dt=222 stack=27
+EventBatch gen=3 m=169424 time=28114950894869 size=176
+ProcStatus dt=1 p=23 pstatus=3
+GoStatus dt=2 g=131 m=169424 gstatus=3
+GoSyscallEnd dt=1
+GoBlock dt=64 reason_string=15 stack=2
+GoUnblock dt=2260 g=67 g_seq=1 stack=0
+GoStart dt=6 g=67 g_seq=2
+GoLabel dt=2 label_string=4
+GoBlock dt=530 reason_string=15 stack=5
+GoUnblock dt=12 g=69 g_seq=3 stack=0
+GoStart dt=5 g=69 g_seq=4
+GoLabel dt=1 label_string=2
+GoUnblock dt=2455 g=90 g_seq=1 stack=12
+GoBlock dt=20 reason_string=15 stack=5
+GoUnblock dt=16 g=69 g_seq=5 stack=0
+GoStart dt=7 g=69 g_seq=6
+GoLabel dt=1 label_string=2
+GoUnblock dt=493 g=120 g_seq=2 stack=12
+GoBlock dt=1777 reason_string=15 stack=5
+GoUnblock dt=832 g=69 g_seq=7 stack=0
+GoStart dt=9 g=69 g_seq=8
+GoLabel dt=2 label_string=2
+GoBlock dt=5425 reason_string=15 stack=5
+GoUnblock dt=15 g=69 g_seq=9 stack=0
+GoStart dt=4 g=69 g_seq=10
+GoLabel dt=1 label_string=2
+GoBlock dt=1370 reason_string=15 stack=5
+ProcStop dt=2533
+ProcStart dt=11 p=23 p_seq=1
+GoUnblock dt=3354 g=54 g_seq=17 stack=0
+GoStart dt=7 g=54 g_seq=18
+GoLabel dt=1 label_string=4
+GoBlock dt=29 reason_string=15 stack=5
+GoUnblock dt=25 g=54 g_seq=19 stack=0
+GoStart dt=5 g=54 g_seq=20
+GoLabel dt=2 label_string=2
+GoBlock dt=232 reason_string=15 stack=5
+GoUnblock dt=11 g=54 g_seq=21 stack=0
+GoStart dt=7 g=54 g_seq=22
+GoLabel dt=1 label_string=2
+GoBlock dt=293 reason_string=15 stack=5
+ProcStop dt=11
+EventBatch gen=3 m=169423 time=28114950894865 size=525
+ProcStatus dt=2 p=30 pstatus=1
+GoStatus dt=4 g=87 m=169423 gstatus=2
+GCMarkAssistActive dt=1 g=87
+GCMarkAssistEnd dt=2
+HeapAlloc dt=98 heapalloc_value=189963712
+GoStop dt=56 reason_string=16 stack=6
+GoUnblock dt=20 g=131 g_seq=1 stack=0
+GoStart dt=7 g=131 g_seq=2
+GoSyscallBegin dt=39 p_seq=1 stack=7
+GoSyscallEnd dt=304
+GoSyscallBegin dt=19 p_seq=2 stack=7
+GoSyscallEnd dt=59
+GoSyscallBegin dt=15 p_seq=3 stack=7
+GoSyscallEnd dt=52
+GoSyscallBegin dt=11 p_seq=4 stack=7
+GoSyscallEnd dt=50
+GoSyscallBegin dt=8 p_seq=5 stack=7
+GoSyscallEnd dt=48
+GoSyscallBegin dt=10 p_seq=6 stack=7
+GoSyscallEnd dt=54
+GoSyscallBegin dt=13 p_seq=7 stack=7
+GoSyscallEnd dt=51
+GoSyscallBegin dt=12 p_seq=8 stack=7
+GoSyscallEnd dt=49
+GoSyscallBegin dt=16 p_seq=9 stack=7
+GoSyscallEnd dt=245
+GoSyscallBegin dt=12 p_seq=10 stack=7
+GoSyscallEnd dt=49
+GoSyscallBegin dt=10 p_seq=11 stack=7
+GoSyscallEnd dt=49
+GoSyscallBegin dt=10 p_seq=12 stack=7
+GoSyscallEnd dt=48
+GoSyscallBegin dt=6 p_seq=13 stack=7
+GoSyscallEnd dt=52
+GoStop dt=24 reason_string=16 stack=8
+GoUnblock dt=9 g=14 g_seq=1 stack=0
+GoStart dt=5 g=14 g_seq=2
+GoLabel dt=1 label_string=2
+GoUnblock dt=2948 g=107 g_seq=1 stack=12
+GoBlock dt=2891 reason_string=15 stack=5
+GoUnblock dt=11 g=14 g_seq=3 stack=0
+GoStart dt=5 g=14 g_seq=4
+GoLabel dt=1 label_string=2
+GoBlock dt=1138 reason_string=15 stack=5
+GoUnblock dt=22 g=51 g_seq=5 stack=0
+GoStart dt=5 g=51 g_seq=6
+GoLabel dt=1 label_string=2
+GoUnblock dt=451 g=82 g_seq=3 stack=12
+GoBlock dt=460 reason_string=15 stack=5
+GoUnblock dt=4052 g=54 g_seq=5 stack=0
+GoStart dt=11 g=54 g_seq=6
+GoLabel dt=1 label_string=4
+GoBlock dt=72 reason_string=15 stack=5
+GoUnblock dt=1333 g=57 g_seq=15 stack=0
+GoStart dt=8 g=57 g_seq=16
+GoLabel dt=1 label_string=4
+GoBlock dt=283 reason_string=15 stack=5
+GoUnblock dt=1185 g=57 g_seq=19 stack=0
+GoStart dt=7 g=57 g_seq=20
+GoLabel dt=1 label_string=4
+GoBlock dt=134 reason_string=15 stack=5
+GoUnblock dt=1144 g=53 g_seq=11 stack=0
+GoStart dt=6 g=53 g_seq=12
+GoLabel dt=1 label_string=4
+GoBlock dt=372 reason_string=15 stack=5
+GoUnblock dt=16 g=53 g_seq=13 stack=0
+GoStart dt=7 g=53 g_seq=14
+GoLabel dt=1 label_string=2
+GoBlock dt=8581 reason_string=15 stack=5
+ProcStop dt=76
+ProcStart dt=22 p=30 p_seq=14
+GoUnblock dt=3 g=72 g_seq=31 stack=0
+GoStart dt=7 g=72 g_seq=32
+GoLabel dt=1 label_string=4
+GoBlock dt=46 reason_string=15 stack=5
+GoUnblock dt=63 g=23 g_seq=31 stack=0
+GoStart dt=7 g=23 g_seq=32
+GoLabel dt=1 label_string=4
+GoBlock dt=34 reason_string=15 stack=5
+GoUnblock dt=14 g=23 g_seq=33 stack=0
+GoStart dt=4 g=23 g_seq=34
+GoLabel dt=2 label_string=2
+GoBlock dt=47 reason_string=15 stack=5
+GoUnblock dt=74 g=53 g_seq=19 stack=0
+GoStart dt=6 g=53 g_seq=20
+GoLabel dt=1 label_string=4
+GoBlock dt=154 reason_string=15 stack=5
+GoStatus dt=91 g=56 m=18446744073709551615 gstatus=4
+GoUnblock dt=2 g=56 g_seq=1 stack=0
+GoStart dt=43 g=56 g_seq=2
+GoLabel dt=1 label_string=4
+GoBlock dt=45 reason_string=15 stack=5
+GoUnblock dt=65 g=53 g_seq=23 stack=0
+GoStart dt=8 g=53 g_seq=24
+GoLabel dt=1 label_string=4
+GoBlock dt=16 reason_string=15 stack=5
+ProcStop dt=2526
+ProcStart dt=208 p=30 p_seq=15
+GoUnblock dt=8 g=53 g_seq=37 stack=0
+GoStart dt=5 g=53 g_seq=38
+GoLabel dt=1 label_string=4
+GoBlock dt=694 reason_string=15 stack=5
+GoUnblock dt=14 g=53 g_seq=39 stack=0
+GoStart dt=4 g=53 g_seq=40
+GoLabel dt=3 label_string=2
+GoBlock dt=336 reason_string=15 stack=5
+GoUnblock dt=52 g=53 g_seq=41 stack=0
+GoStart dt=4 g=53 g_seq=42
+GoLabel dt=1 label_string=4
+GoUnblock dt=449 g=118 g_seq=1 stack=12
+GoBlock dt=17 reason_string=15 stack=5
+GoUnblock dt=65 g=24 g_seq=31 stack=0
+GoStart dt=6 g=24 g_seq=32
+GoLabel dt=2 label_string=4
+GoBlock dt=56 reason_string=15 stack=5
+GoUnblock dt=54 g=24 g_seq=33 stack=0
+GoStart dt=5 g=24 g_seq=34
+GoLabel dt=1 label_string=4
+GoBlock dt=489 reason_string=15 stack=5
+GoUnblock dt=9 g=24 g_seq=35 stack=0
+GoStart dt=4 g=24 g_seq=36
+GoLabel dt=1 label_string=2
+GoBlock dt=1307 reason_string=15 stack=5
+ProcStop dt=84
+ProcStart dt=23944 p=15 p_seq=1
+GoStart dt=174 g=108 g_seq=3
+GCMarkAssistBegin dt=25 stack=3
+GoBlock dt=59 reason_string=10 stack=18
+ProcStop dt=71
+EventBatch gen=3 m=169421 time=28114950900230 size=330
+ProcStatus dt=1 p=33 pstatus=1
+GoStatus dt=5 g=81 m=169421 gstatus=2
+GCMarkAssistActive dt=3 g=81
+GoBlock dt=7 reason_string=13 stack=11
+GoStatus dt=1543 g=57 m=18446744073709551615 gstatus=4
+GoUnblock dt=3 g=57 g_seq=1 stack=0
+GoStart dt=10 g=57 g_seq=2
+GoLabel dt=1 label_string=4
+GoBlock dt=123 reason_string=15 stack=5
+GoStatus dt=1345 g=58 m=18446744073709551615 gstatus=4
+GoUnblock dt=3 g=58 g_seq=1 stack=0
+GoStart dt=5 g=58 g_seq=2
+GoLabel dt=1 label_string=4
+GoBlock dt=154 reason_string=15 stack=5
+GoUnblock dt=5938 g=54 g_seq=7 stack=0
+GoStart dt=7 g=54 g_seq=8
+GoLabel dt=1 label_string=4
+GoBlock dt=93 reason_string=15 stack=5
+GoStart dt=1331 g=97 g_seq=2
+GoStatus dt=26 g=93 m=18446744073709551615 gstatus=4
+GoUnblock dt=6 g=93 g_seq=1 stack=10
+GCMarkAssistBegin dt=18 stack=3
+GCMarkAssistEnd dt=1894
+HeapAlloc dt=57 heapalloc_value=191872448
+GCMarkAssistBegin dt=26 stack=3
+GoBlock dt=46 reason_string=13 stack=11
+GoUnblock dt=2442 g=52 g_seq=19 stack=0
+GoStart dt=14 g=52 g_seq=20
+GoLabel dt=1 label_string=4
+GoBlock dt=767 reason_string=15 stack=5
+ProcStop dt=2248
+ProcStart dt=24 p=33 p_seq=1
+GoUnblock dt=8 g=72 g_seq=27 stack=0
+GoStart dt=7 g=72 g_seq=28
+GoLabel dt=1 label_string=4
+GoUnblock dt=172 g=119 g_seq=3 stack=12
+GoBlock dt=1629 reason_string=15 stack=5
+GoUnblock dt=71 g=28 g_seq=9 stack=0
+GoStart dt=7 g=28 g_seq=10
+GoLabel dt=1 label_string=4
+GoBlock dt=276 reason_string=15 stack=5
+GoUnblock dt=72 g=28 g_seq=11 stack=0
+GoStart dt=4 g=28 g_seq=12
+GoLabel dt=1 label_string=4
+GoBlock dt=2016 reason_string=15 stack=5
+GoUnblock dt=16 g=28 g_seq=13 stack=0
+GoStart dt=7 g=28 g_seq=14
+GoLabel dt=1 label_string=2
+GoBlock dt=6712 reason_string=15 stack=5
+ProcStop dt=63
+ProcStart dt=20808 p=14 p_seq=1
+GoStart dt=205 g=89 g_seq=7
+GCMarkAssistEnd dt=10
+HeapAlloc dt=64 heapalloc_value=196245968
+GoStop dt=6073 reason_string=16 stack=6
+GoStart dt=21 g=89 g_seq=8
+GCMarkAssistBegin dt=15 stack=3
+GoBlock dt=38 reason_string=10 stack=18
+ProcStop dt=129
+ProcStart dt=13557 p=11 p_seq=7
+GoStart dt=202 g=116 g_seq=12
+GCMarkAssistEnd dt=10
+GCSweepBegin dt=25 stack=28
+GCSweepEnd dt=12 swept_value=32768 reclaimed_value=32768
+HeapAlloc dt=3 heapalloc_value=114760576
+GCSweepBegin dt=70 stack=28
+GCSweepEnd dt=5 swept_value=24576 reclaimed_value=24576
+HeapAlloc dt=1 heapalloc_value=114785152
+GCSweepBegin dt=353 stack=27
+EventBatch gen=3 m=169420 time=28114950896337 size=112
+ProcStatus dt=2 p=17 pstatus=1
+GoStatus dt=1 g=84 m=169420 gstatus=2
+GCMarkAssistActive dt=1 g=84
+GCMarkAssistEnd dt=3
+HeapAlloc dt=20 heapalloc_value=190365120
+GCMarkAssistBegin dt=42 stack=3
+GoStop dt=861 reason_string=20 stack=9
+GoStart dt=142 g=126 g_seq=1
+GoBlock dt=2538 reason_string=13 stack=11
+GoUnblock dt=1653 g=30 g_seq=1 stack=0
+GoStart dt=7 g=30 g_seq=2
+GoLabel dt=2 label_string=4
+GoBlock dt=6064 reason_string=15 stack=5
+GoUnblock dt=1633 g=25 g_seq=11 stack=0
+GoStart dt=8 g=25 g_seq=12
+GoLabel dt=1 label_string=4
+GoBlock dt=4927 reason_string=15 stack=5
+GoUnblock dt=3569 g=67 g_seq=11 stack=0
+GoStart dt=7 g=67 g_seq=12
+GoLabel dt=1 label_string=4
+GoBlock dt=1289 reason_string=15 stack=5
+GoUnblock dt=73 g=67 g_seq=13 stack=0
+GoStart dt=4 g=67 g_seq=14
+GoLabel dt=1 label_string=4
+GoBlock dt=46 reason_string=15 stack=5
+ProcStop dt=52
+EventBatch gen=3 m=169419 time=28114950898971 size=132
+ProcStatus dt=2 p=13 pstatus=1
+GoStatus dt=2 g=30 m=169419 gstatus=2
+GoBlock dt=7 reason_string=15 stack=5
+GoUnblock dt=2697 g=72 g_seq=1 stack=0
+GoStart dt=8 g=72 g_seq=2
+GoLabel dt=1 label_string=4
+GoBlock dt=969 reason_string=15 stack=5
+GoStart dt=2978 g=95 g_seq=2
+GoStatus dt=32 g=88 m=18446744073709551615 gstatus=4
+GoUnblock dt=7 g=88 g_seq=1 stack=10
+GCMarkAssistBegin dt=18 stack=3
+GoStop dt=1258 reason_string=20 stack=9
+GoStart dt=17 g=88 g_seq=2
+GoStatus dt=27 g=113 m=18446744073709551615 gstatus=4
+GoUnblock dt=5 g=113 g_seq=1 stack=10
+GCMarkAssistBegin dt=12 stack=3
+GoStop dt=1797 reason_string=20 stack=9
+GoStart dt=18 g=88 g_seq=3
+GoStop dt=2883 reason_string=20 stack=9
+GoUnblock dt=14 g=70 g_seq=7 stack=0
+GoStart dt=5 g=70 g_seq=8
+GoLabel dt=3 label_string=2
+GoBlock dt=5294 reason_string=15 stack=5
+GoStart dt=14 g=123 g_seq=5
+GoBlock dt=18 reason_string=13 stack=11
+ProcStop dt=16
+EventBatch gen=3 m=169418 time=28114950895095 size=398
+ProcStatus dt=1 p=35 pstatus=2
+ProcStart dt=2 p=35 p_seq=1
+GoStart dt=38 g=87 g_seq=1
+HeapAlloc dt=103 heapalloc_value=190086592
+GCMarkAssistBegin dt=64 stack=3
+GCMarkAssistEnd dt=3228
+HeapAlloc dt=76 heapalloc_value=190995904
+GCMarkAssistBegin dt=149 stack=3
+GoBlock dt=3823 reason_string=13 stack=11
+GoStart dt=1406 g=82 g_seq=4
+GCMarkAssistEnd dt=12
+HeapAlloc dt=82 heapalloc_value=191618496
+GCMarkAssistBegin dt=75 stack=3
+GoStop dt=4342 reason_string=20 stack=9
+GoStart dt=17 g=82 g_seq=5
+GoStop dt=987 reason_string=20 stack=9
+GoStart dt=26 g=82 g_seq=6
+GoStop dt=3601 reason_string=20 stack=9
+GoUnblock dt=14 g=58 g_seq=17 stack=0
+GoStart dt=3 g=58 g_seq=18
+GoLabel dt=3 label_string=2
+GoBlock dt=1524 reason_string=15 stack=5
+GoUnblock dt=23 g=25 g_seq=15 stack=0
+GoStart dt=8 g=25 g_seq=16
+GoLabel dt=3 label_string=2
+GoBlock dt=7942 reason_string=15 stack=5
+ProcStop dt=2920
+ProcStart dt=69 p=31 p_seq=1
+GoUnblock dt=7 g=67 g_seq=25 stack=0
+GoStart dt=5 g=67 g_seq=26
+GoLabel dt=1 label_string=4
+GoBlock dt=1990 reason_string=15 stack=5
+GoUnblock dt=110 g=67 g_seq=29 stack=0
+GoStart dt=6 g=67 g_seq=30
+GoLabel dt=1 label_string=4
+GoBlock dt=39 reason_string=15 stack=5
+GoUnblock dt=64 g=52 g_seq=29 stack=0
+GoStart dt=1 g=52 g_seq=30
+GoLabel dt=1 label_string=4
+GoBlock dt=40 reason_string=15 stack=5
+GoUnblock dt=72 g=29 g_seq=19 stack=0
+GoStart dt=7 g=29 g_seq=20
+GoLabel dt=1 label_string=4
+GoBlock dt=65 reason_string=15 stack=5
+GoUnblock dt=1007 g=23 g_seq=43 stack=0
+GoStart dt=8 g=23 g_seq=44
+GoLabel dt=1 label_string=4
+GoBlock dt=1633 reason_string=15 stack=5
+GoUnblock dt=7 g=23 g_seq=45 stack=0
+GoStart dt=160 g=23 g_seq=46
+GoLabel dt=1 label_string=2
+GoBlock dt=16 reason_string=15 stack=5
+ProcStop dt=31
+ProcStart dt=8279 p=26 p_seq=2
+GoStart dt=216 g=103 g_seq=3
+GCMarkAssistBegin dt=19 stack=3
+GoBlock dt=41 reason_string=13 stack=11
+GoUnblock dt=11 g=25 g_seq=47 stack=0
+GoStart dt=3 g=25 g_seq=48
+GoLabel dt=1 label_string=2
+GoBlock dt=1274 reason_string=15 stack=5
+ProcStop dt=46
+ProcStart dt=1294 p=26 p_seq=3
+GoStart dt=164 g=127 g_seq=6
+GoStop dt=45 reason_string=20 stack=9
+GoStart dt=17 g=127 g_seq=7
+GCMarkAssistEnd dt=1921
+GoStop dt=49 reason_string=16 stack=17
+GoUnblock dt=17 g=22 g_seq=59 stack=0
+GoStart dt=8 g=22 g_seq=60
+GoLabel dt=1 label_string=2
+GoBlock dt=75 reason_string=15 stack=5
+GoStart dt=44 g=83 g_seq=7
+GCMarkAssistEnd dt=4
+GCMarkAssistBegin dt=50 stack=3
+GCMarkAssistEnd dt=27
+HeapAlloc dt=55 heapalloc_value=193551064
+GoStop dt=47 reason_string=16 stack=4
+GoStart dt=30 g=84 g_seq=7
+HeapAlloc dt=82 heapalloc_value=193772248
+HeapAlloc dt=291 heapalloc_value=194239192
+HeapAlloc dt=198 heapalloc_value=194493144
+HeapAlloc dt=7678 heapalloc_value=196524496
+GoStop dt=18 reason_string=16 stack=6
+ProcStop dt=218
+ProcStart dt=2082 p=26 p_seq=4
+ProcStop dt=68
+ProcStart dt=16818 p=14 p_seq=2
+GoStart dt=242 g=118 g_seq=7
+GCMarkAssistEnd dt=8
+GCSweepBegin dt=32 stack=28
+GCSweepEnd dt=11 swept_value=24576 reclaimed_value=24576
+HeapAlloc dt=3 heapalloc_value=114809728
+GCSweepBegin dt=279 stack=27
+EventBatch gen=3 m=169417 time=28114950894785 size=650
+ProcStatus dt=2 p=18 pstatus=1
+GoStatus dt=2 g=120 m=169417 gstatus=2
+GCMarkAssistActive dt=1 g=120
+GCMarkAssistEnd dt=2
+HeapAlloc dt=26 heapalloc_value=189767104
+GoStop dt=131 reason_string=16 stack=4
+GoStart dt=59 g=120 g_seq=1
+HeapAlloc dt=138 heapalloc_value=190045632
+GCMarkAssistBegin dt=31 stack=3
+GCMarkAssistEnd dt=3339
+HeapAlloc dt=63 heapalloc_value=190938560
+GCMarkAssistBegin dt=150 stack=3
+GoBlock dt=270 reason_string=13 stack=11
+GoUnblock dt=4058 g=57 g_seq=3 stack=0
+GoStart dt=7 g=57 g_seq=4
+GoLabel dt=1 label_string=4
+GoBlock dt=902 reason_string=15 stack=5
+GoUnblock dt=4049 g=30 g_seq=3 stack=0
+GoStart dt=8 g=30 g_seq=4
+GoLabel dt=1 label_string=4
+GoBlock dt=521 reason_string=15 stack=5
+GoUnblock dt=1581 g=57 g_seq=17 stack=0
+GoStart dt=11 g=57 g_seq=18
+GoLabel dt=3 label_string=4
+GoBlock dt=37 reason_string=15 stack=5
+GoUnblock dt=14 g=69 g_seq=11 stack=0
+GoStart dt=4 g=69 g_seq=12
+GoLabel dt=3 label_string=2
+GoBlock dt=543 reason_string=15 stack=5
+GoUnblock dt=10 g=69 g_seq=13 stack=0
+GoStart dt=6 g=69 g_seq=14
+GoLabel dt=1 label_string=2
+GoBlock dt=1813 reason_string=15 stack=5
+ProcStop dt=2875
+ProcStart dt=28 p=18 p_seq=1
+GoUnblock dt=1296 g=54 g_seq=23 stack=0
+GoStart dt=7 g=54 g_seq=24
+GoLabel dt=1 label_string=4
+GoBlock dt=1516 reason_string=15 stack=5
+GoUnblock dt=7 g=54 g_seq=25 stack=0
+GoStart dt=5 g=54 g_seq=26
+GoLabel dt=1 label_string=2
+GoBlock dt=6851 reason_string=15 stack=5
+GoUnblock dt=71 g=72 g_seq=41 stack=0
+GoStart dt=5 g=72 g_seq=42
+GoLabel dt=1 label_string=4
+GoBlock dt=21 reason_string=15 stack=5
+GoUnblock dt=5 g=72 g_seq=43 stack=0
+GoStart dt=3 g=72 g_seq=44
+GoLabel dt=1 label_string=2
+GoBlock dt=62 reason_string=15 stack=5
+GoUnblock dt=19 g=72 g_seq=45 stack=0
+GoStart dt=4 g=72 g_seq=46
+GoLabel dt=1 label_string=2
+GoBlock dt=3727 reason_string=15 stack=5
+ProcStop dt=69
+ProcStart dt=21 p=18 p_seq=2
+GoUnblock dt=10 g=70 g_seq=15 stack=0
+GoStart dt=3 g=70 g_seq=16
+GoLabel dt=1 label_string=4
+GoBlock dt=14 reason_string=15 stack=5
+GoUnblock dt=49 g=70 g_seq=17 stack=0
+GoStart dt=3 g=70 g_seq=18
+GoLabel dt=1 label_string=4
+GoBlock dt=2314 reason_string=15 stack=5
+ProcStop dt=46
+ProcStart dt=1398 p=18 p_seq=3
+ProcStop dt=38
+ProcStart dt=4183 p=18 p_seq=4
+GoStart dt=183 g=96 g_seq=4
+GCMarkAssistEnd dt=9
+HeapAlloc dt=36 heapalloc_value=192305952
+GCMarkAssistBegin dt=28 stack=3
+GoBlock dt=1320 reason_string=13 stack=11
+GoUnblock dt=15 g=25 g_seq=45 stack=0
+GoStart dt=7 g=25 g_seq=46
+GoLabel dt=1 label_string=2
+GoBlock dt=600 reason_string=15 stack=5
+GoStart dt=13 g=89 g_seq=5
+GCMarkAssistBegin dt=11 stack=3
+GoBlock dt=112 reason_string=13 stack=11
+GoStart dt=14 g=121 g_seq=8
+GoStop dt=1488 reason_string=20 stack=9
+GoUnblock dt=16 g=25 g_seq=49 stack=0
+GoStart dt=7 g=25 g_seq=50
+GoLabel dt=2 label_string=2
+GoUnblock dt=1803 g=115 g_seq=6 stack=12
+GoUnblock dt=5 g=93 g_seq=6 stack=12
+GoUnblock dt=6 g=85 g_seq=5 stack=12
+GoUnblock dt=3 g=104 g_seq=1 stack=12
+GoUnblock dt=6 g=108 g_seq=1 stack=12
+GoUnblock dt=4 g=120 g_seq=4 stack=12
+GoUnblock dt=4 g=126 g_seq=5 stack=12
+GoUnblock dt=7 g=114 g_seq=3 stack=12
+GoUnblock dt=5 g=86 g_seq=4 stack=12
+GoUnblock dt=4 g=110 g_seq=3 stack=12
+GoBlock dt=14 reason_string=15 stack=5
+GoUnblock dt=7 g=25 g_seq=51 stack=0
+GoStart dt=1 g=25 g_seq=52
+GoLabel dt=1 label_string=2
+GoBlock dt=12 reason_string=15 stack=5
+GoStart dt=8 g=115 g_seq=7
+GCMarkAssistEnd dt=6
+HeapAlloc dt=32 heapalloc_value=192838360
+GCMarkAssistBegin dt=55 stack=3
+GoStop dt=1501 reason_string=20 stack=9
+GoUnblock dt=18 g=51 g_seq=51 stack=0
+GoStart dt=6 g=51 g_seq=52
+GoLabel dt=1 label_string=2
+GoUnblock dt=1117 g=105 g_seq=13 stack=12
+GoBlock dt=8 reason_string=15 stack=5
+GoStart dt=8 g=105 g_seq=14
+GCMarkAssistEnd dt=6
+GCMarkAssistBegin dt=27 stack=3
+GoBlock dt=13 reason_string=13 stack=11
+GoStart dt=7 g=86 g_seq=5
+GCMarkAssistEnd dt=6
+HeapAlloc dt=12 heapalloc_value=195148504
+GCMarkAssistBegin dt=65 stack=3
+HeapAlloc dt=22 heapalloc_value=195214040
+GoBlock dt=17 reason_string=10 stack=18
+GoStart dt=2881 g=124 g_seq=5
+HeapAlloc dt=35 heapalloc_value=195517144
+HeapAlloc dt=15 heapalloc_value=195566296
+HeapAlloc dt=61 heapalloc_value=195574224
+HeapAlloc dt=16 heapalloc_value=195631568
+GCMarkAssistBegin dt=23 stack=3
+GoBlock dt=34 reason_string=10 stack=18
+GoStart dt=14 g=90 g_seq=7
+GCMarkAssistEnd dt=5
+HeapAlloc dt=4 heapalloc_value=195697104
+GCMarkAssistBegin dt=58 stack=3
+GoBlock dt=15 reason_string=10 stack=18
+GoStart dt=10 g=96 g_seq=6
+GCMarkAssistEnd dt=3
+GCMarkAssistBegin dt=37 stack=3
+GoBlock dt=16 reason_string=13 stack=11
+GoStart dt=14 g=92 g_seq=5
+GCMarkAssistBegin dt=75 stack=3
+GoBlock dt=25 reason_string=10 stack=18
+GoStart dt=9 g=119 g_seq=6
+GCMarkAssistEnd dt=5
+HeapAlloc dt=20 heapalloc_value=195926480
+GCMarkAssistBegin dt=19 stack=3
+GoBlock dt=14 reason_string=10 stack=18
+GoStart dt=9 g=85 g_seq=6
+GCMarkAssistEnd dt=3
+HeapAlloc dt=38 heapalloc_value=195983824
+GoStop dt=5763 reason_string=16 stack=6
+GoStart dt=15 g=85 g_seq=7
+GCMarkAssistBegin dt=6 stack=3
+GoBlock dt=21 reason_string=10 stack=18
+ProcStop dt=46
+ProcStart dt=17429 p=15 p_seq=2
+GoStart dt=180 g=3 g_seq=2
+EventBatch gen=3 m=169416 time=28114950894874 size=516
+ProcStatus dt=2 p=26 pstatus=1
+GoStatus dt=1 g=98 m=169416 gstatus=2
+GCMarkAssistActive dt=1 g=98
+GCMarkAssistEnd dt=2
+HeapAlloc dt=136 heapalloc_value=190004672
+GoStop dt=29 reason_string=16 stack=4
+GoStart dt=29 g=86 g_seq=1
+GCMarkAssistBegin dt=75 stack=3
+GCMarkAssistEnd dt=8456
+HeapAlloc dt=48 heapalloc_value=191569344
+GoStop dt=32 reason_string=16 stack=4
+GoStart dt=19 g=86 g_seq=2
+GCMarkAssistBegin dt=73 stack=3
+GoStop dt=324 reason_string=20 stack=9
+GoStart dt=11 g=116 g_seq=3
+GoStop dt=270 reason_string=20 stack=9
+GoUnblock dt=14 g=51 g_seq=7 stack=0
+GoStart dt=4 g=51 g_seq=8
+GoLabel dt=3 label_string=2
+GoBlock dt=4139 reason_string=15 stack=5
+GoUnblock dt=9 g=51 g_seq=9 stack=0
+GoStart dt=6 g=51 g_seq=10
+GoLabel dt=1 label_string=2
+GoBlock dt=564 reason_string=15 stack=5
+GoUnblock dt=12 g=29 g_seq=7 stack=0
+GoStart dt=4 g=29 g_seq=8
+GoLabel dt=1 label_string=2
+GoBlock dt=13475 reason_string=15 stack=5
+ProcStop dt=61
+ProcStart dt=17 p=26 p_seq=1
+GoUnblock dt=6 g=53 g_seq=31 stack=0
+GoStart dt=3 g=53 g_seq=32
+GoLabel dt=1 label_string=4
+GoBlock dt=18 reason_string=15 stack=5
+GoUnblock dt=6 g=53 g_seq=33 stack=0
+GoStart dt=4 g=53 g_seq=34
+GoLabel dt=1 label_string=2
+GoBlock dt=2291 reason_string=15 stack=5
+GoUnblock dt=8 g=53 g_seq=35 stack=0
+GoStart dt=4 g=53 g_seq=36
+GoLabel dt=1 label_string=2
+GoBlock dt=32 reason_string=15 stack=5
+GoUnblock dt=68 g=29 g_seq=9 stack=0
+GoStart dt=4 g=29 g_seq=10
+GoLabel dt=1 label_string=4
+GoBlock dt=796 reason_string=15 stack=5
+GoUnblock dt=60 g=29 g_seq=11 stack=0
+GoStart dt=4 g=29 g_seq=12
+GoLabel dt=1 label_string=4
+GoBlock dt=643 reason_string=15 stack=5
+GoUnblock dt=61 g=53 g_seq=43 stack=0
+GoStart dt=4 g=53 g_seq=44
+GoLabel dt=1 label_string=4
+GoBlock dt=3485 reason_string=15 stack=5
+GoUnblock dt=10 g=53 g_seq=45 stack=0
+GoStart dt=5 g=53 g_seq=46
+GoLabel dt=1 label_string=2
+GoBlock dt=14 reason_string=15 stack=5
+ProcStop dt=38
+ProcStart dt=9443 p=0 p_seq=3
+GoStart dt=226 g=115 g_seq=5
+GoBlock dt=168 reason_string=13 stack=11
+GoUnblock dt=11 g=30 g_seq=37 stack=0
+GoStart dt=6 g=30 g_seq=38
+GoLabel dt=1 label_string=2
+GoBlock dt=67 reason_string=15 stack=5
+ProcStop dt=46
+ProcStart dt=1842 p=25 p_seq=6
+GoUnblock dt=12 g=29 g_seq=37 stack=0
+GoStart dt=5 g=29 g_seq=38
+GoLabel dt=1 label_string=2
+GoBlock dt=2260 reason_string=15 stack=5
+GoUnblock dt=16 g=29 g_seq=39 stack=0
+GoStart dt=4 g=29 g_seq=40
+GoLabel dt=1 label_string=2
+GoBlock dt=19 reason_string=15 stack=5
+GoStart dt=34 g=99 g_seq=4
+GCMarkAssistEnd dt=7
+HeapAlloc dt=55 heapalloc_value=193501912
+GoStop dt=29 reason_string=16 stack=4
+GoUnblock dt=18 g=29 g_seq=41 stack=0
+GoStart dt=7 g=29 g_seq=42
+GoLabel dt=1 label_string=2
+GoBlock dt=10 reason_string=15 stack=5
+GoUnblock dt=14 g=29 g_seq=43 stack=0
+GoStart dt=4 g=29 g_seq=44
+GoLabel dt=1 label_string=2
+GoBlock dt=40 reason_string=15 stack=5
+GoStart dt=16 g=111 g_seq=6
+GoBlock dt=37 reason_string=13 stack=11
+GoStart dt=13 g=125 g_seq=6
+GCMarkAssistBegin dt=13 stack=3
+GoBlock dt=34 reason_string=13 stack=11
+GoStart dt=23 g=115 g_seq=8
+GoBlock dt=61 reason_string=13 stack=11
+GoStart dt=27 g=120 g_seq=5
+GCMarkAssistEnd dt=12
+HeapAlloc dt=82 heapalloc_value=194067160
+GoStop dt=22 reason_string=16 stack=4
+GoStart dt=10 g=93 g_seq=7
+GCMarkAssistEnd dt=4
+HeapAlloc dt=663 heapalloc_value=194992856
+GCMarkAssistBegin dt=23 stack=3
+GoBlock dt=12 reason_string=13 stack=11
+GoStart dt=11 g=99 g_seq=7
+GCMarkAssistEnd dt=5
+HeapAlloc dt=4741 heapalloc_value=196180432
+GoStop dt=10 reason_string=16 stack=6
+GoStart dt=19 g=99 g_seq=8
+GCMarkAssistBegin dt=8 stack=3
+GoBlock dt=18 reason_string=10 stack=18
+GoStart dt=9 g=100 g_seq=4
+GCMarkAssistEnd dt=5
+HeapAlloc dt=101 heapalloc_value=196295120
+GoStop dt=6074 reason_string=16 stack=6
+GoStart dt=49 g=100 g_seq=5
+GCMarkAssistBegin dt=10 stack=3
+GoBlock dt=32 reason_string=13 stack=11
+ProcStop dt=67
+ProcStart dt=12947 p=10 p_seq=3
+GoStart dt=200 g=86 g_seq=7
+GoUnblock dt=38 g=124 g_seq=6 stack=30
+GCMarkAssistEnd dt=5
+HeapAlloc dt=90 heapalloc_value=113809792
+HeapAlloc dt=112 heapalloc_value=114160256
+GCSweepBegin dt=694 stack=31
+EventBatch gen=3 m=169415 time=28114950903030 size=633
+ProcStatus dt=1 p=28 pstatus=1
+GoStatus dt=3 g=91 m=169415 gstatus=2
+GCMarkAssistActive dt=1 g=91
+GCMarkAssistEnd dt=2
+HeapAlloc dt=29 heapalloc_value=191479232
+GCMarkAssistBegin dt=84 stack=3
+GoBlock dt=82 reason_string=13 stack=11
+GoStart dt=4920 g=113 g_seq=2
+GoStatus dt=31 g=123 m=18446744073709551615 gstatus=4
+GoUnblock dt=10 g=123 g_seq=1 stack=10
+GCMarkAssistBegin dt=14 stack=3
+GoStop dt=1855 reason_string=20 stack=9
+GoStart dt=15 g=113 g_seq=3
+GoStop dt=352 reason_string=20 stack=9
+GoStart dt=13 g=113 g_seq=4
+GoBlock dt=261 reason_string=13 stack=11
+GoUnblock dt=3404 g=52 g_seq=17 stack=0
+GoStart dt=7 g=52 g_seq=18
+GoLabel dt=1 label_string=4
+GoBlock dt=1025 reason_string=15 stack=5
+GoUnblock dt=4703 g=67 g_seq=17 stack=0
+GoStart dt=8 g=67 g_seq=18
+GoLabel dt=1 label_string=4
+GoBlock dt=1418 reason_string=15 stack=5
+GoUnblock dt=72 g=23 g_seq=29 stack=0
+GoStart dt=4 g=23 g_seq=30
+GoLabel dt=1 label_string=4
+GoBlock dt=307 reason_string=15 stack=5
+GoUnblock dt=85 g=72 g_seq=33 stack=0
+GoStart dt=5 g=72 g_seq=34
+GoLabel dt=3 label_string=4
+GoBlock dt=30 reason_string=15 stack=5
+GoStatus dt=168 g=68 m=18446744073709551615 gstatus=4
+GoUnblock dt=2 g=68 g_seq=1 stack=0
+GoStart dt=64 g=68 g_seq=2
+GoLabel dt=1 label_string=4
+GoBlock dt=55 reason_string=15 stack=5
+GoUnblock dt=10 g=68 g_seq=3 stack=0
+GoStart dt=3 g=68 g_seq=4
+GoLabel dt=2 label_string=2
+GoBlock dt=327 reason_string=15 stack=5
+ProcStop dt=80
+ProcStart dt=25 p=28 p_seq=1
+GoUnblock dt=7 g=30 g_seq=17 stack=0
+GoStart dt=4 g=30 g_seq=18
+GoLabel dt=3 label_string=4
+GoBlock dt=2630 reason_string=15 stack=5
+GoUnblock dt=28 g=72 g_seq=39 stack=0
+GoStart dt=12 g=72 g_seq=40
+GoLabel dt=1 label_string=2
+GoBlock dt=21 reason_string=15 stack=5
+GoUnblock dt=77 g=30 g_seq=19 stack=0
+GoStart dt=10 g=30 g_seq=20
+GoLabel dt=1 label_string=4
+GoBlock dt=3781 reason_string=15 stack=5
+GoUnblock dt=15 g=30 g_seq=21 stack=0
+GoStart dt=5 g=30 g_seq=22
+GoLabel dt=1 label_string=2
+GoBlock dt=2537 reason_string=15 stack=5
+GoUnblock dt=55 g=30 g_seq=23 stack=0
+GoStart dt=5 g=30 g_seq=24
+GoLabel dt=1 label_string=4
+GoBlock dt=478 reason_string=15 stack=5
+GoUnblock dt=8 g=30 g_seq=25 stack=0
+GoStart dt=4 g=30 g_seq=26
+GoLabel dt=1 label_string=2
+GoBlock dt=1039 reason_string=15 stack=5
+GoStart dt=26 g=14 g_seq=37
+GoBlock dt=1631 reason_string=15 stack=5
+GoUnblock dt=22 g=52 g_seq=43 stack=0
+GoStart dt=8 g=52 g_seq=44
+GoLabel dt=3 label_string=2
+GoBlock dt=21 reason_string=15 stack=5
+GoUnblock dt=9 g=52 g_seq=45 stack=0
+GoStart dt=3 g=52 g_seq=46
+GoLabel dt=1 label_string=2
+GoBlock dt=17 reason_string=15 stack=5
+GoUnblock dt=6 g=52 g_seq=47 stack=0
+GoStart dt=3 g=52 g_seq=48
+GoLabel dt=1 label_string=2
+GoUnblock dt=217 g=112 g_seq=3 stack=12
+GoBlock dt=298 reason_string=15 stack=5
+GoUnblock dt=8 g=52 g_seq=49 stack=0
+GoStart dt=3 g=52 g_seq=50
+GoLabel dt=1 label_string=2
+GoBlock dt=1919 reason_string=15 stack=5
+GoStart dt=16 g=121 g_seq=6
+GCMarkAssistEnd dt=6
+HeapAlloc dt=1354 heapalloc_value=192363224
+GoStop dt=25 reason_string=16 stack=4
+GoStart dt=16 g=121 g_seq=7
+GCMarkAssistBegin dt=74 stack=3
+GoStop dt=496 reason_string=20 stack=9
+GoUnblock dt=11 g=52 g_seq=55 stack=0
+GoStart dt=4 g=52 g_seq=56
+GoLabel dt=1 label_string=2
+GoUnblock dt=1666 g=94 g_seq=5 stack=12
+GoBlock dt=18 reason_string=15 stack=5
+GoUnblock dt=18 g=30 g_seq=41 stack=0
+GoStart dt=4 g=30 g_seq=42
+GoLabel dt=1 label_string=2
+GoUnblock dt=1362 g=84 g_seq=5 stack=12
+GoUnblock dt=6 g=125 g_seq=4 stack=12
+GoUnblock dt=5 g=118 g_seq=3 stack=12
+GoBlock dt=9 reason_string=15 stack=5
+GoUnblock dt=10 g=30 g_seq=43 stack=0
+GoStart dt=3 g=30 g_seq=44
+GoLabel dt=1 label_string=2
+GoBlock dt=9 reason_string=15 stack=5
+GoStart dt=6 g=84 g_seq=6
+GCMarkAssistEnd dt=5
+HeapAlloc dt=24 heapalloc_value=192748248
+GCMarkAssistBegin dt=83 stack=3
+GCMarkAssistEnd dt=1516
+HeapAlloc dt=28 heapalloc_value=193231576
+GoStop dt=27 reason_string=16 stack=6
+GoUnblock dt=14 g=22 g_seq=57 stack=0
+GoStart dt=3 g=22 g_seq=58
+GoLabel dt=1 label_string=2
+GoUnblock dt=16 g=81 g_seq=8 stack=12
+GoBlock dt=10 reason_string=15 stack=5
+GoStart dt=11 g=125 g_seq=5
+GCMarkAssistEnd dt=5
+HeapAlloc dt=16 heapalloc_value=193354456
+GoStop dt=95 reason_string=16 stack=6
+GoUnblock dt=34 g=22 g_seq=61 stack=0
+GoStart dt=1 g=22 g_seq=62
+GoLabel dt=1 label_string=2
+GoUnblock dt=1090 g=99 g_seq=6 stack=12
+GoBlock dt=10 reason_string=15 stack=5
+GoStart dt=8 g=81 g_seq=9
+GCMarkAssistEnd dt=5
+HeapAlloc dt=3528 heapalloc_value=195729872
+GoStop dt=10 reason_string=16 stack=6
+GoStart dt=17 g=81 g_seq=10
+GCMarkAssistBegin dt=9 stack=3
+GoBlock dt=34 reason_string=10 stack=18
+GoStart dt=20 g=121 g_seq=11
+GCMarkAssistEnd dt=4
+HeapAlloc dt=44 heapalloc_value=195852752
+GoStop dt=7425 reason_string=16 stack=6
+ProcStop dt=134
+ProcStart dt=14156 p=12 p_seq=2
+GoStart dt=200 g=84 g_seq=10
+GCMarkAssistEnd dt=6
+GCSweepBegin dt=35 stack=27
+EventBatch gen=3 m=169414 time=28114950903409 size=415
+ProcStatus dt=1 p=19 pstatus=1
+GoStatus dt=1 g=54 m=169414 gstatus=2
+GoBlock dt=7 reason_string=15 stack=5
+GoUnblock dt=2586 g=25 g_seq=5 stack=0
+GoStart dt=8 g=25 g_seq=6
+GoLabel dt=1 label_string=4
+GoBlock dt=2605 reason_string=15 stack=5
+GoUnblock dt=1216 g=71 g_seq=3 stack=0
+GoStart dt=7 g=71 g_seq=4
+GoLabel dt=1 label_string=4
+GoBlock dt=672 reason_string=15 stack=5
+GoUnblock dt=7231 g=23 g_seq=15 stack=0
+GoStart dt=8 g=23 g_seq=16
+GoLabel dt=1 label_string=4
+GoBlock dt=1212 reason_string=15 stack=5
+GoUnblock dt=11 g=23 g_seq=17 stack=0
+GoStart dt=7 g=23 g_seq=18
+GoLabel dt=3 label_string=2
+GoBlock dt=82 reason_string=15 stack=5
+GoUnblock dt=9 g=23 g_seq=19 stack=0
+GoStart dt=6 g=23 g_seq=20
+GoLabel dt=1 label_string=2
+GoBlock dt=162 reason_string=15 stack=5
+ProcStop dt=99
+ProcStart dt=3257 p=19 p_seq=1
+GoUnblock dt=13 g=68 g_seq=5 stack=0
+GoStart dt=10 g=68 g_seq=6
+GoLabel dt=1 label_string=2
+GoBlock dt=43 reason_string=15 stack=5
+GoUnblock dt=12 g=68 g_seq=7 stack=0
+GoStart dt=2 g=68 g_seq=8
+GoLabel dt=1 label_string=2
+GoBlock dt=133 reason_string=15 stack=5
+GoUnblock dt=23 g=58 g_seq=23 stack=0
+GoStart dt=6 g=58 g_seq=24
+GoLabel dt=1 label_string=2
+GoBlock dt=2822 reason_string=15 stack=5
+GoUnblock dt=11 g=69 g_seq=21 stack=0
+GoStart dt=7 g=69 g_seq=22
+GoLabel dt=2 label_string=2
+GoBlock dt=25 reason_string=15 stack=5
+GoUnblock dt=2937 g=58 g_seq=31 stack=0
+GoStart dt=6 g=58 g_seq=32
+GoLabel dt=1 label_string=4
+GoBlock dt=20 reason_string=15 stack=5
+ProcStop dt=60
+ProcStart dt=31 p=19 p_seq=2
+GoUnblock dt=9 g=56 g_seq=7 stack=0
+GoStart dt=6 g=56 g_seq=8
+GoLabel dt=3 label_string=4
+GoBlock dt=949 reason_string=15 stack=5
+ProcStop dt=41
+ProcStart dt=433 p=19 p_seq=3
+ProcStop dt=43
+ProcStart dt=9942 p=11 p_seq=4
+ProcStop dt=50
+ProcStart dt=2351 p=22 p_seq=6
+GoUnblock dt=15 g=30 g_seq=45 stack=0
+GoStart dt=205 g=30 g_seq=46
+GoLabel dt=1 label_string=2
+GoUnblock dt=145 g=113 g_seq=7 stack=12
+GoBlock dt=21 reason_string=15 stack=5
+GoStart dt=10 g=113 g_seq=8
+GCMarkAssistEnd dt=8
+HeapAlloc dt=48 heapalloc_value=192895704
+GCMarkAssistBegin dt=118 stack=3
+GCMarkAssistEnd dt=272
+HeapAlloc dt=20 heapalloc_value=192936664
+HeapAlloc dt=89 heapalloc_value=192953048
+HeapAlloc dt=41 heapalloc_value=192994008
+HeapAlloc dt=92 heapalloc_value=193059544
+HeapAlloc dt=102 heapalloc_value=193108696
+HeapAlloc dt=94 heapalloc_value=193133272
+HeapAlloc dt=42 heapalloc_value=193141464
+HeapAlloc dt=31 heapalloc_value=193207000
+GCMarkAssistBegin dt=142 stack=3
+GoBlock dt=114 reason_string=13 stack=11
+GoStart dt=179 g=109 g_seq=5
+GCMarkAssistEnd dt=8
+GCMarkAssistBegin dt=54 stack=3
+GCMarkAssistEnd dt=720
+HeapAlloc dt=23 heapalloc_value=194427608
+HeapAlloc dt=456 heapalloc_value=195001048
+GCMarkAssistBegin dt=18 stack=3
+GoBlock dt=22 reason_string=13 stack=11
+GoStart dt=23 g=113 g_seq=10
+GCMarkAssistEnd dt=3
+HeapAlloc dt=54 heapalloc_value=195099352
+GoStop dt=6390 reason_string=16 stack=6
+GoStart dt=23 g=113 g_seq=11
+GCMarkAssistBegin dt=6 stack=3
+GoBlock dt=21 reason_string=10 stack=18
+GoStart dt=33 g=101 g_seq=6
+GCMarkAssistEnd dt=6
+HeapAlloc dt=29 heapalloc_value=196409808
+GCMarkAssistBegin dt=22 stack=3
+GoBlock dt=52 reason_string=10 stack=18
+ProcStop dt=102
+EventBatch gen=3 m=169413 time=28114950897164 size=752
+ProcStatus dt=1 p=0 pstatus=1
+GoStatus dt=6 g=67 m=169413 gstatus=2
+GoBlock dt=11 reason_string=15 stack=5
+GoUnblock dt=18 g=25 g_seq=1 stack=0
+GoStart dt=7 g=25 g_seq=2
+GoLabel dt=1 label_string=2
+GoBlock dt=1315 reason_string=15 stack=5
+GoUnblock dt=11 g=25 g_seq=3 stack=0
+GoStart dt=6 g=25 g_seq=4
+GoLabel dt=1 label_string=2
+GoUnblock dt=4173 g=106 g_seq=1 stack=12
+GoBlock dt=1258 reason_string=15 stack=5
+GoUnblock dt=4804 g=30 g_seq=5 stack=0
+GoStart dt=7 g=30 g_seq=6
+GoLabel dt=1 label_string=4
+GoBlock dt=541 reason_string=15 stack=5
+GoUnblock dt=30 g=30 g_seq=7 stack=0
+GoStart dt=6 g=30 g_seq=8
+GoLabel dt=3 label_string=2
+GoBlock dt=3873 reason_string=15 stack=5
+GoUnblock dt=10 g=30 g_seq=9 stack=0
+GoStart dt=5 g=30 g_seq=10
+GoLabel dt=3 label_string=2
+GoBlock dt=3107 reason_string=15 stack=5
+GoUnblock dt=3672 g=14 g_seq=15 stack=0
+GoStart dt=6 g=14 g_seq=16
+GoLabel dt=1 label_string=4
+GoBlock dt=442 reason_string=15 stack=5
+GoStart dt=32 g=83 g_seq=4
+GCMarkAssistEnd dt=7
+HeapAlloc dt=49 heapalloc_value=191962560
+GCMarkAssistBegin dt=108 stack=3
+GoStop dt=885 reason_string=20 stack=9
+GoStart dt=14 g=83 g_seq=5
+GoBlock dt=21 reason_string=13 stack=11
+ProcStop dt=93
+ProcStart dt=38 p=0 p_seq=1
+GoUnblock dt=7 g=53 g_seq=17 stack=0
+GoStart dt=2 g=53 g_seq=18
+GoLabel dt=1 label_string=4
+GoBlock dt=31 reason_string=15 stack=5
+ProcStop dt=89
+ProcStart dt=45 p=11 p_seq=3
+GoUnblock dt=6 g=23 g_seq=35 stack=0
+GoStart dt=14 g=23 g_seq=36
+GoLabel dt=3 label_string=4
+GoBlock dt=2881 reason_string=15 stack=5
+GoUnblock dt=72 g=25 g_seq=17 stack=0
+GoStart dt=6 g=25 g_seq=18
+GoLabel dt=1 label_string=4
+GoBlock dt=19 reason_string=15 stack=5
+GoUnblock dt=58 g=25 g_seq=19 stack=0
+GoStart dt=3 g=25 g_seq=20
+GoLabel dt=1 label_string=4
+GoBlock dt=13 reason_string=15 stack=5
+GoStart dt=16 g=94 g_seq=4
+GoBlock dt=356 reason_string=13 stack=11
+GoUnblock dt=80 g=52 g_seq=27 stack=0
+GoStart dt=9 g=52 g_seq=28
+GoLabel dt=1 label_string=4
+GoBlock dt=2325 reason_string=15 stack=5
+GoUnblock dt=57 g=67 g_seq=31 stack=0
+GoStart dt=4 g=67 g_seq=32
+GoLabel dt=1 label_string=4
+GoBlock dt=2043 reason_string=15 stack=5
+GoUnblock dt=9 g=67 g_seq=33 stack=0
+GoStart dt=171 g=67 g_seq=34
+GoLabel dt=5 label_string=2
+GoBlock dt=21 reason_string=15 stack=5
+ProcStop dt=60
+ProcStart dt=1735 p=25 p_seq=4
+GoUnblock dt=61 g=22 g_seq=39 stack=0
+GoStart dt=178 g=22 g_seq=40
+GoLabel dt=1 label_string=4
+GoBlock dt=66 reason_string=15 stack=5
+GoUnblock dt=8 g=22 g_seq=41 stack=0
+GoStart dt=4 g=22 g_seq=42
+GoLabel dt=1 label_string=2
+GoBlock dt=975 reason_string=15 stack=5
+ProcStop dt=1192
+ProcStart dt=347 p=25 p_seq=5
+GoUnblock dt=11 g=131 g_seq=6 stack=0
+GoStart dt=145 g=131 g_seq=7
+GoBlock dt=21 reason_string=15 stack=2
+GoUnblock dt=30 g=14 g_seq=38 stack=0
+GoStart dt=4 g=14 g_seq=39
+GoLabel dt=1 label_string=2
+GoBlock dt=65 reason_string=15 stack=5
+GoStart dt=26 g=130 g_seq=1
+ProcStatus dt=380 p=38 pstatus=2
+ProcStatus dt=4 p=39 pstatus=2
+ProcStatus dt=4 p=40 pstatus=2
+ProcStatus dt=3 p=41 pstatus=2
+ProcStatus dt=5 p=42 pstatus=2
+ProcStatus dt=5 p=43 pstatus=2
+ProcStatus dt=2 p=44 pstatus=2
+ProcStatus dt=3 p=45 pstatus=2
+ProcStatus dt=4 p=46 pstatus=2
+GoStop dt=1488 reason_string=16 stack=15
+GoUnblock dt=17 g=51 g_seq=45 stack=0
+GoStart dt=3 g=51 g_seq=46
+GoLabel dt=3 label_string=2
+GoBlock dt=1337 reason_string=15 stack=5
+GoStart dt=13 g=81 g_seq=7
+GCMarkAssistEnd dt=6
+GCMarkAssistBegin dt=31 stack=3
+GoBlock dt=20 reason_string=13 stack=11
+GoStart dt=5 g=130 g_seq=2
+HeapAlloc dt=98 heapalloc_value=192314072
+GoBlock dt=348 reason_string=12 stack=16
+GoStart dt=31 g=103 g_seq=2
+GCMarkAssistEnd dt=7
+HeapAlloc dt=53 heapalloc_value=192428760
+GoStop dt=173 reason_string=16 stack=6
+GoUnblock dt=18 g=71 g_seq=29 stack=0
+GoStart dt=4 g=71 g_seq=30
+GoLabel dt=3 label_string=2
+GoBlock dt=1289 reason_string=15 stack=5
+GoStart dt=17 g=126 g_seq=4
+GCMarkAssistBegin dt=125 stack=3
+GoBlock dt=23 reason_string=13 stack=11
+ProcStop dt=76
+ProcStart dt=2523 p=0 p_seq=4
+GoUnblock dt=16 g=30 g_seq=47 stack=0
+GoStart dt=196 g=30 g_seq=48
+GoLabel dt=2 label_string=2
+GoUnblock dt=1834 g=125 g_seq=7 stack=12
+GoBlock dt=17 reason_string=15 stack=5
+GoStart dt=14 g=125 g_seq=8
+GCMarkAssistEnd dt=5
+HeapAlloc dt=69 heapalloc_value=194566872
+GoStop dt=2253 reason_string=16 stack=6
+GoStart dt=2080 g=125 g_seq=9
+GCMarkAssistBegin dt=14 stack=3
+GoBlock dt=41 reason_string=10 stack=18
+GoStart dt=13 g=106 g_seq=8
+GCMarkAssistEnd dt=6
+HeapAlloc dt=53 heapalloc_value=196106704
+GoStop dt=6900 reason_string=16 stack=6
+GoStart dt=57 g=121 g_seq=12
+GCMarkAssistBegin dt=16 stack=3
+GoBlock dt=47 reason_string=10 stack=18
+ProcStop dt=83
+ProcStart dt=11930 p=7 p_seq=7
+GoStart dt=191 g=96 g_seq=8
+GCMarkAssistEnd dt=10
+HeapAlloc dt=59 heapalloc_value=109727392
+HeapAlloc dt=159 heapalloc_value=110336128
+HeapAlloc dt=109 heapalloc_value=110662528
+GCSweepBegin dt=144 stack=28
+GCSweepEnd dt=18 swept_value=16384 reclaimed_value=16384
+HeapAlloc dt=3 heapalloc_value=111288448
+GCSweepBegin dt=49 stack=28
+GCSweepEnd dt=14 swept_value=24576 reclaimed_value=24576
+HeapAlloc dt=5 heapalloc_value=111591296
+HeapAlloc dt=65 heapalloc_value=111888256
+HeapAlloc dt=228 heapalloc_value=112797056
+HeapAlloc dt=134 heapalloc_value=113322880
+HeapAlloc dt=83 heapalloc_value=113549696
+GCSweepBegin dt=35 stack=28
+GCSweepEnd dt=16 swept_value=32768 reclaimed_value=32768
+HeapAlloc dt=3 heapalloc_value=113842560
+HeapAlloc dt=75 heapalloc_value=114080128
+HeapAlloc dt=64 heapalloc_value=114307712
+HeapAlloc dt=134 heapalloc_value=114580608
+HeapAlloc dt=77 heapalloc_value=114670464
+GCSweepBegin dt=33 stack=28
+GCSweepEnd dt=6 swept_value=24576 reclaimed_value=24576
+HeapAlloc dt=3 heapalloc_value=114727808
+GCSweepBegin dt=90 stack=27
+EventBatch gen=3 m=169412 time=28114950898429 size=583
+ProcStatus dt=1 p=36 pstatus=2
+ProcStart dt=2 p=36 p_seq=1
+GoStart dt=401 g=83 g_seq=2
+GoBlock dt=1477 reason_string=13 stack=11
+GoStart dt=1208 g=81 g_seq=2
+GCMarkAssistEnd dt=9
+HeapAlloc dt=57 heapalloc_value=191348160
+GoStop dt=42 reason_string=16 stack=4
+GoStart dt=25 g=81 g_seq=3
+GCMarkAssistBegin dt=394 stack=3
+GoBlock dt=1177 reason_string=13 stack=11
+GoStart dt=28 g=106 g_seq=2
+GCMarkAssistEnd dt=10
+HeapAlloc dt=52 heapalloc_value=191503808
+GCMarkAssistBegin dt=52 stack=3
+GoStop dt=60 reason_string=20 stack=9
+GoUnblock dt=73 g=58 g_seq=3 stack=0
+GoStart dt=6 g=58 g_seq=4
+GoLabel dt=3 label_string=4
+GoBlock dt=2860 reason_string=15 stack=5
+GoUnblock dt=3777 g=24 g_seq=9 stack=0
+GoStart dt=6 g=24 g_seq=10
+GoLabel dt=1 label_string=4
+GoBlock dt=41 reason_string=15 stack=5
+GoUnblock dt=1167 g=71 g_seq=9 stack=0
+GoStart dt=7 g=71 g_seq=10
+GoLabel dt=1 label_string=4
+GoBlock dt=1396 reason_string=15 stack=5
+GoUnblock dt=1371 g=57 g_seq=23 stack=0
+GoStart dt=7 g=57 g_seq=24
+GoLabel dt=1 label_string=4
+GoBlock dt=584 reason_string=15 stack=5
+GoUnblock dt=4657 g=23 g_seq=23 stack=0
+GoStart dt=7 g=23 g_seq=24
+GoLabel dt=1 label_string=4
+GoBlock dt=40 reason_string=15 stack=5
+ProcStop dt=82
+ProcStart dt=1505 p=36 p_seq=2
+ProcStop dt=74
+ProcStart dt=19 p=36 p_seq=3
+GoUnblock dt=7 g=23 g_seq=27 stack=0
+GoStart dt=7 g=23 g_seq=28
+GoLabel dt=1 label_string=4
+GoBlock dt=122 reason_string=15 stack=5
+GoUnblock dt=58 g=52 g_seq=25 stack=0
+GoStart dt=6 g=52 g_seq=26
+GoLabel dt=1 label_string=4
+GoBlock dt=4034 reason_string=15 stack=5
+GoUnblock dt=75 g=14 g_seq=19 stack=0
+GoStart dt=6 g=14 g_seq=20
+GoLabel dt=1 label_string=4
+GoBlock dt=2059 reason_string=15 stack=5
+GoUnblock dt=63 g=14 g_seq=21 stack=0
+GoStart dt=4 g=14 g_seq=22
+GoLabel dt=1 label_string=4
+GoBlock dt=56 reason_string=15 stack=5
+ProcStop dt=49
+ProcStart dt=20 p=36 p_seq=4
+GoUnblock dt=6 g=67 g_seq=27 stack=0
+GoStart dt=2 g=67 g_seq=28
+GoLabel dt=1 label_string=4
+GoBlock dt=13 reason_string=15 stack=5
+ProcStop dt=1721
+ProcStart dt=20316 p=36 p_seq=5
+GoStart dt=197 g=94 g_seq=11
+GCMarkAssistEnd dt=7
+HeapAlloc dt=6672 heapalloc_value=196598224
+GoStop dt=15 reason_string=16 stack=6
+GoStart dt=54 g=106 g_seq=9
+GCMarkAssistBegin dt=16 stack=3
+GoBlock dt=32 reason_string=10 stack=18
+GoStart dt=41 g=103 g_seq=6
+GCMarkAssistBegin dt=15 stack=3
+GoBlock dt=84 reason_string=10 stack=18
+ProcStop dt=43
+ProcStart dt=10888 p=5 p_seq=1
+GoStart dt=189 g=120 g_seq=8
+GCMarkAssistEnd dt=7
+HeapAlloc dt=54 heapalloc_value=106433440
+HeapAlloc dt=94 heapalloc_value=106861728
+GCSweepBegin dt=92 stack=28
+GCSweepEnd dt=13 swept_value=24576 reclaimed_value=24576
+HeapAlloc dt=4 heapalloc_value=107301920
+HeapAlloc dt=65 heapalloc_value=107394848
+GCSweepBegin dt=32 stack=28
+GCSweepEnd dt=11 swept_value=32768 reclaimed_value=32768
+HeapAlloc dt=2 heapalloc_value=107616032
+HeapAlloc dt=60 heapalloc_value=107763488
+HeapAlloc dt=78 heapalloc_value=107953440
+HeapAlloc dt=65 heapalloc_value=108333088
+GCSweepBegin dt=38 stack=28
+GCSweepEnd dt=5 swept_value=32768 reclaimed_value=32768
+HeapAlloc dt=1 heapalloc_value=108423200
+GCSweepBegin dt=80 stack=28
+GCSweepEnd dt=9 swept_value=32768 reclaimed_value=32768
+HeapAlloc dt=3 heapalloc_value=108682656
+GCSweepBegin dt=61 stack=28
+GCSweepEnd dt=10 swept_value=8192 reclaimed_value=8192
+HeapAlloc dt=4 heapalloc_value=108816544
+HeapAlloc dt=32 heapalloc_value=108994080
+HeapAlloc dt=50 heapalloc_value=109290272
+HeapAlloc dt=112 heapalloc_value=109566240
+HeapAlloc dt=104 heapalloc_value=109973280
+GCSweepBegin dt=66 stack=29
+GCSweepEnd dt=17 swept_value=8192 reclaimed_value=0
+HeapAlloc dt=3 heapalloc_value=110183040
+HeapAlloc dt=86 heapalloc_value=110506880
+HeapAlloc dt=149 heapalloc_value=111151232
+HeapAlloc dt=24 heapalloc_value=111272064
+HeapAlloc dt=53 heapalloc_value=111368064
+HeapAlloc dt=68 heapalloc_value=111632256
+HeapAlloc dt=103 heapalloc_value=112078720
+GCSweepBegin dt=120 stack=28
+GCSweepEnd dt=7 swept_value=24576 reclaimed_value=24576
+HeapAlloc dt=3 heapalloc_value=112585472
+HeapAlloc dt=34 heapalloc_value=112616832
+HeapAlloc dt=39 heapalloc_value=112882304
+HeapAlloc dt=141 heapalloc_value=113391232
+HeapAlloc dt=80 heapalloc_value=113664384
+HeapAlloc dt=152 heapalloc_value=114242176
+HeapAlloc dt=104 heapalloc_value=114415616
+HeapAlloc dt=38 heapalloc_value=114527360
+HeapAlloc dt=28 heapalloc_value=114592896
+GCSweepBegin dt=227 stack=27
+EventBatch gen=3 m=169411 time=28114950895719 size=370
+ProcStatus dt=1 p=21 pstatus=1
+GoStatus dt=5 g=85 m=169411 gstatus=2
+GCMarkAssistActive dt=1 g=85
+GCMarkAssistEnd dt=3
+HeapAlloc dt=44 heapalloc_value=190299584
+GoStop dt=38 reason_string=16 stack=4
+GoStart dt=20 g=85 g_seq=1
+GCMarkAssistBegin dt=119 stack=3
+GoStop dt=4468 reason_string=20 stack=9
+GoStart dt=15 g=85 g_seq=2
+GoStop dt=1589 reason_string=20 stack=9
+GoStart dt=8 g=85 g_seq=3
+GCMarkAssistEnd dt=2892
+HeapAlloc dt=33 heapalloc_value=191733184
+GCMarkAssistBegin dt=98 stack=3
+GoStop dt=2309 reason_string=20 stack=9
+GoStart dt=10 g=95 g_seq=3
+GoBlock dt=153 reason_string=13 stack=11
+GoStart dt=5 g=85 g_seq=4
+GoBlock dt=18 reason_string=13 stack=11
+GoUnblock dt=3925 g=58 g_seq=13 stack=0
+GoStart dt=8 g=58 g_seq=14
+GoLabel dt=3 label_string=4
+GoBlock dt=106 reason_string=15 stack=5
+ProcStop dt=1275
+ProcStart dt=21 p=21 p_seq=1
+ProcStop dt=1335
+ProcStart dt=14 p=21 p_seq=2
+GoUnblock dt=1349 g=14 g_seq=9 stack=0
+GoStart dt=8 g=14 g_seq=10
+GoLabel dt=1 label_string=4
+GoBlock dt=255 reason_string=15 stack=5
+GoUnblock dt=2226 g=70 g_seq=9 stack=0
+GoStart dt=8 g=70 g_seq=10
+GoLabel dt=1 label_string=4
+GoBlock dt=398 reason_string=15 stack=5
+GoUnblock dt=8 g=70 g_seq=11 stack=0
+GoStart dt=6 g=70 g_seq=12
+GoLabel dt=1 label_string=2
+GoBlock dt=8210 reason_string=15 stack=5
+GoUnblock dt=12 g=70 g_seq=13 stack=0
+GoStart dt=5 g=70 g_seq=14
+GoLabel dt=2 label_string=2
+GoBlock dt=2354 reason_string=15 stack=5
+GoUnblock dt=93 g=72 g_seq=47 stack=0
+GoStart dt=9 g=72 g_seq=48
+GoLabel dt=1 label_string=4
+GoBlock dt=27 reason_string=15 stack=5
+GoUnblock dt=220 g=72 g_seq=49 stack=0
+GoStart dt=7 g=72 g_seq=50
+GoLabel dt=1 label_string=2
+GoBlock dt=20 reason_string=15 stack=5
+ProcStop dt=61
+ProcStart dt=16474 p=33 p_seq=2
+GoStart dt=3475 g=107 g_seq=4
+GCMarkAssistEnd dt=9
+HeapAlloc dt=52 heapalloc_value=196041168
+GoStop dt=5585 reason_string=16 stack=6
+GoStart dt=15 g=107 g_seq=5
+GCMarkAssistBegin dt=91 stack=3
+GoBlock dt=34 reason_string=10 stack=18
+ProcStop dt=55
+ProcStart dt=1514 p=33 p_seq=3
+ProcStop dt=41
+ProcStart dt=12390 p=8 p_seq=1
+GoStart dt=166 g=100 g_seq=7
+GCMarkAssistEnd dt=5
+HeapAlloc dt=51 heapalloc_value=111353984
+GCSweepBegin dt=133 stack=28
+GCSweepEnd dt=18 swept_value=32768 reclaimed_value=32768
+HeapAlloc dt=3 heapalloc_value=112029568
+HeapAlloc dt=68 heapalloc_value=112301312
+HeapAlloc dt=120 heapalloc_value=112739712
+HeapAlloc dt=116 heapalloc_value=113221760
+HeapAlloc dt=53 heapalloc_value=113380224
+HeapAlloc dt=115 heapalloc_value=113768832
+HeapAlloc dt=66 heapalloc_value=114026880
+HeapAlloc dt=127 heapalloc_value=114403328
+GCSweepBegin dt=47 stack=28
+GCSweepEnd dt=10 swept_value=32768 reclaimed_value=32768
+HeapAlloc dt=3 heapalloc_value=114503936
+HeapAlloc dt=67 heapalloc_value=114651264
+GCSweepBegin dt=299 stack=27
+EventBatch gen=3 m=169409 time=28114950894853 size=224
+ProcStatus dt=2 p=29 pstatus=1
+GoStatus dt=3 g=126 m=169409 gstatus=2
+HeapAlloc dt=3 heapalloc_value=189824448
+GCMarkAssistBegin dt=163 stack=3
+GoStop dt=1609 reason_string=20 stack=9
+GoStart dt=26 g=98 g_seq=2
+GCMarkAssistBegin dt=17 stack=3
+GCMarkAssistEnd dt=7751
+HeapAlloc dt=77 heapalloc_value=191675840
+GoStop dt=39 reason_string=16 stack=6
+GoStart dt=20 g=116 g_seq=4
+GoBlock dt=302 reason_string=13 stack=11
+GoUnblock dt=4886 g=51 g_seq=13 stack=0
+GoStart dt=8 g=51 g_seq=14
+GoLabel dt=1 label_string=4
+GoBlock dt=2058 reason_string=15 stack=5
+GoUnblock dt=11 g=51 g_seq=15 stack=0
+GoStart dt=6 g=51 g_seq=16
+GoLabel dt=3 label_string=2
+GoBlock dt=2936 reason_string=15 stack=5
+GoUnblock dt=35 g=58 g_seq=21 stack=0
+GoStart dt=6 g=58 g_seq=22
+GoLabel dt=3 label_string=2
+GoBlock dt=7995 reason_string=15 stack=5
+GoUnblock dt=20 g=68 g_seq=9 stack=0
+GoStart dt=6 g=68 g_seq=10
+GoLabel dt=3 label_string=2
+GoBlock dt=92 reason_string=15 stack=5
+GoUnblock dt=8 g=68 g_seq=11 stack=0
+GoStart dt=1 g=68 g_seq=12
+GoLabel dt=1 label_string=2
+GoBlock dt=7039 reason_string=15 stack=5
+ProcStop dt=54
+ProcStart dt=14204 p=3 p_seq=1
+GoStart dt=213 g=94 g_seq=7
+GCMarkAssistBegin dt=29 stack=3
+GoBlock dt=62 reason_string=13 stack=11
+GoStart dt=20 g=124 g_seq=4
+GCMarkAssistEnd dt=6
+GCMarkAssistBegin dt=38 stack=3
+GCMarkAssistEnd dt=98
+HeapAlloc dt=118 heapalloc_value=193911512
+HeapAlloc dt=123 heapalloc_value=194116312
+HeapAlloc dt=352 heapalloc_value=194616024
+GoStop dt=3095 reason_string=16 stack=6
+GoStart dt=26 g=110 g_seq=4
+GCMarkAssistEnd dt=6
+HeapAlloc dt=30 heapalloc_value=195508952
+GoStop dt=4300 reason_string=16 stack=6
+GoStart dt=65 g=110 g_seq=5
+GCMarkAssistBegin dt=10 stack=3
+GoBlock dt=46 reason_string=10 stack=18
+ProcStop dt=124
+EventBatch gen=3 m=169408 time=28114950896863 size=856
+ProcStatus dt=1 p=22 pstatus=1
+GoStatus dt=2 g=105 m=169408 gstatus=2
+GCMarkAssistActive dt=1 g=105
+GCMarkAssistEnd dt=2
+HeapAlloc dt=22 heapalloc_value=190512576
+HeapAlloc dt=94 heapalloc_value=190537152
+GCMarkAssistBegin dt=18 stack=3
+GCMarkAssistEnd dt=1243
+HeapAlloc dt=34 heapalloc_value=190741952
+GCMarkAssistBegin dt=36 stack=3
+GCMarkAssistEnd dt=4423
+HeapAlloc dt=22 heapalloc_value=191413696
+GoStop dt=23 reason_string=16 stack=4
+GoStart dt=15 g=105 g_seq=1
+GCMarkAssistBegin dt=57 stack=3
+GoStop dt=662 reason_string=20 stack=9
+GoStart dt=12 g=105 g_seq=2
+GoStop dt=4139 reason_string=20 stack=9
+GoStart dt=11 g=105 g_seq=3
+GoStop dt=4306 reason_string=20 stack=9
+GoStart dt=15 g=105 g_seq=4
+GoBlock dt=21 reason_string=13 stack=11
+GoUnblock dt=2669 g=58 g_seq=19 stack=0
+GoStart dt=5 g=58 g_seq=20
+GoLabel dt=1 label_string=4
+GoBlock dt=90 reason_string=15 stack=5
+GoUnblock dt=28 g=51 g_seq=17 stack=0
+GoStart dt=5 g=51 g_seq=18
+GoLabel dt=1 label_string=2
+GoBlock dt=5245 reason_string=15 stack=5
+GoUnblock dt=68 g=51 g_seq=19 stack=0
+GoStart dt=8 g=51 g_seq=20
+GoLabel dt=1 label_string=4
+GoBlock dt=14 reason_string=15 stack=5
+GoUnblock dt=6 g=51 g_seq=21 stack=0
+GoStart dt=1 g=51 g_seq=22
+GoLabel dt=1 label_string=2
+GoBlock dt=7035 reason_string=15 stack=5
+GoUnblock dt=13 g=51 g_seq=23 stack=0
+GoStart dt=4 g=51 g_seq=24
+GoLabel dt=2 label_string=2
+GoUnblock dt=188 g=116 g_seq=5 stack=12
+GoBlock dt=65 reason_string=15 stack=5
+GoUnblock dt=9 g=51 g_seq=25 stack=0
+GoStart dt=2 g=51 g_seq=26
+GoLabel dt=1 label_string=2
+GoBlock dt=170 reason_string=15 stack=5
+GoUnblock dt=15 g=51 g_seq=27 stack=0
+GoStart dt=6 g=51 g_seq=28
+GoLabel dt=1 label_string=2
+GoBlock dt=33 reason_string=15 stack=5
+GoUnblock dt=7 g=51 g_seq=29 stack=0
+GoStart dt=6 g=51 g_seq=30
+GoLabel dt=1 label_string=2
+GoBlock dt=159 reason_string=15 stack=5
+GoUnblock dt=8 g=51 g_seq=31 stack=0
+GoStart dt=3 g=51 g_seq=32
+GoLabel dt=1 label_string=2
+GoBlock dt=124 reason_string=15 stack=5
+ProcStop dt=79
+ProcStart dt=18 p=22 p_seq=1
+GoUnblock dt=4 g=29 g_seq=21 stack=0
+GoStart dt=4 g=29 g_seq=22
+GoLabel dt=1 label_string=4
+GoBlock dt=28 reason_string=15 stack=5
+ProcStop dt=45
+ProcStart dt=12 p=22 p_seq=2
+GoUnblock dt=2 g=29 g_seq=23 stack=0
+GoStart dt=1 g=29 g_seq=24
+GoLabel dt=1 label_string=4
+GoBlock dt=19 reason_string=15 stack=5
+GoUnblock dt=45 g=29 g_seq=25 stack=0
+GoStart dt=1 g=29 g_seq=26
+GoLabel dt=1 label_string=4
+GoBlock dt=151 reason_string=15 stack=5
+GoUnblock dt=14 g=52 g_seq=35 stack=0
+GoStart dt=6 g=52 g_seq=36
+GoLabel dt=1 label_string=2
+GoBlock dt=13 reason_string=15 stack=5
+GoUnblock dt=4 g=52 g_seq=37 stack=0
+GoStart dt=3 g=52 g_seq=38
+GoLabel dt=1 label_string=2
+GoBlock dt=127 reason_string=15 stack=5
+GoUnblock dt=7 g=52 g_seq=39 stack=0
+GoStart dt=1 g=52 g_seq=40
+GoLabel dt=1 label_string=2
+GoBlock dt=11 reason_string=15 stack=5
+GoUnblock dt=6 g=52 g_seq=41 stack=0
+GoStart dt=2 g=52 g_seq=42
+GoLabel dt=1 label_string=2
+GoBlock dt=4594 reason_string=15 stack=5
+ProcStop dt=42
+ProcStart dt=1703 p=27 p_seq=42
+GoUnblock dt=17 g=22 g_seq=45 stack=0
+GoStart dt=283 g=22 g_seq=46
+GoLabel dt=2 label_string=2
+GoUnblock dt=103 g=96 g_seq=3 stack=12
+GoUnblock dt=95 g=121 g_seq=5 stack=12
+GoUnblock dt=5 g=126 g_seq=2 stack=12
+GoUnblock dt=529 g=115 g_seq=3 stack=12
+GoBlock dt=552 reason_string=15 stack=5
+GoUnblock dt=31 g=22 g_seq=47 stack=0
+GoStart dt=4 g=22 g_seq=48
+GoLabel dt=1 label_string=2
+GoUnblock dt=763 g=90 g_seq=3 stack=12
+GoBlock dt=39 reason_string=15 stack=5
+GoUnblock dt=12 g=22 g_seq=49 stack=0
+GoStart dt=4 g=22 g_seq=50
+GoLabel dt=1 label_string=2
+GoBlock dt=806 reason_string=15 stack=5
+GoStart dt=18 g=115 g_seq=4
+GCMarkAssistEnd dt=8
+HeapAlloc dt=834 heapalloc_value=192494296
+GCMarkAssistBegin dt=33 stack=3
+GoStop dt=622 reason_string=20 stack=9
+GoUnblock dt=15 g=14 g_seq=44 stack=0
+GoStart dt=5 g=14 g_seq=45
+GoLabel dt=1 label_string=2
+GoBlock dt=1768 reason_string=15 stack=5
+GoUnblock dt=11 g=14 g_seq=46 stack=0
+GoStart dt=4 g=14 g_seq=47
+GoLabel dt=1 label_string=2
+GoBlock dt=20 reason_string=15 stack=5
+GoUnblock dt=10 g=14 g_seq=48 stack=0
+GoStart dt=636 g=14 g_seq=49
+GoLabel dt=1 label_string=2
+GoBlock dt=55 reason_string=15 stack=5
+GoUnblock dt=18 g=14 g_seq=50 stack=0
+GoStart dt=3 g=14 g_seq=51
+GoLabel dt=1 label_string=2
+GoBlock dt=46 reason_string=15 stack=5
+GoUnblock dt=15 g=14 g_seq=52 stack=0
+GoStart dt=4 g=14 g_seq=53
+GoLabel dt=1 label_string=2
+GoBlock dt=26 reason_string=15 stack=5
+GoUnblock dt=29 g=70 g_seq=23 stack=0
+GoStart dt=5 g=70 g_seq=24
+GoLabel dt=1 label_string=2
+GoBlock dt=15 reason_string=15 stack=5
+GoStart dt=30 g=94 g_seq=6
+GCMarkAssistEnd dt=5
+HeapAlloc dt=37 heapalloc_value=192699096
+GoStop dt=34 reason_string=16 stack=6
+GoUnblock dt=9 g=70 g_seq=25 stack=0
+GoStart dt=3 g=70 g_seq=26
+GoLabel dt=1 label_string=2
+GoUnblock dt=190 g=98 g_seq=7 stack=12
+GoUnblock dt=6 g=91 g_seq=1 stack=12
+GoUnblock dt=7 g=123 g_seq=6 stack=12
+GoUnblock dt=5 g=100 g_seq=3 stack=12
+GoUnblock dt=3 g=102 g_seq=3 stack=12
+GoUnblock dt=3 g=103 g_seq=4 stack=12
+GoUnblock dt=5 g=117 g_seq=3 stack=12
+GoBlock dt=45 reason_string=15 stack=5
+GoUnblock dt=8 g=70 g_seq=27 stack=0
+GoStart dt=1 g=70 g_seq=28
+GoLabel dt=1 label_string=2
+GoUnblock dt=1939 g=111 g_seq=7 stack=12
+GoUnblock dt=10 g=101 g_seq=5 stack=12
+GoBlock dt=23 reason_string=15 stack=5
+GoStart dt=15 g=98 g_seq=8
+GCMarkAssistEnd dt=8
+HeapAlloc dt=57 heapalloc_value=193960664
+GCMarkAssistBegin dt=83 stack=3
+GoBlock dt=26 reason_string=13 stack=11
+GoStart dt=7 g=91 g_seq=2
+GCMarkAssistEnd dt=6
+HeapAlloc dt=47 heapalloc_value=194296536
+GCMarkAssistBegin dt=103 stack=3
+GoBlock dt=118 reason_string=13 stack=11
+GoStart dt=20 g=123 g_seq=7
+GCMarkAssistEnd dt=4
+HeapAlloc dt=448 heapalloc_value=195058392
+GoStop dt=6487 reason_string=16 stack=6
+GoStart dt=27 g=123 g_seq=8
+GCMarkAssistBegin dt=10 stack=3
+GoBlock dt=32 reason_string=10 stack=18
+ProcStop dt=78
+ProcStart dt=16845 p=9 p_seq=1
+GoStart dt=21 g=127 g_seq=10
+GCMarkAssistEnd dt=11
+GCSweepBegin dt=37 stack=28
+GCSweepEnd dt=17 swept_value=24576 reclaimed_value=24576
+HeapAlloc dt=7 heapalloc_value=110613376
+HeapAlloc dt=77 heapalloc_value=110956160
+HeapAlloc dt=127 heapalloc_value=111501184
+HeapAlloc dt=150 heapalloc_value=112133376
+HeapAlloc dt=103 heapalloc_value=112487168
+HeapAlloc dt=158 heapalloc_value=113166976
+GCSweepBegin dt=50 stack=28
+GCSweepEnd dt=32 swept_value=16384 reclaimed_value=16384
+HeapAlloc dt=6 heapalloc_value=113407616
+HeapAlloc dt=173 heapalloc_value=114067840
+HeapAlloc dt=153 heapalloc_value=114430208
+GCSweepBegin dt=35 stack=28
+GCSweepEnd dt=4 swept_value=24576 reclaimed_value=24576
+HeapAlloc dt=4 heapalloc_value=114551936
+GCSweepBegin dt=1034 stack=27
+EventBatch gen=3 m=169407 time=28114950901555 size=528
+ProcStatus dt=2 p=4 pstatus=1
+GoStatus dt=1 g=72 m=169407 gstatus=2
+GoBlock dt=7 reason_string=15 stack=5
+GoUnblock dt=1446 g=72 g_seq=3 stack=0
+GoStart dt=9 g=72 g_seq=4
+GoLabel dt=1 label_string=4
+GoBlock dt=394 reason_string=15 stack=5
+GoStart dt=26 g=106 g_seq=3
+GoBlock dt=149 reason_string=13 stack=11
+GoUnblock dt=2557 g=72 g_seq=5 stack=0
+GoStart dt=8 g=72 g_seq=6
+GoLabel dt=1 label_string=4
+GoBlock dt=44 reason_string=15 stack=5
+GoUnblock dt=13 g=72 g_seq=7 stack=0
+GoStart dt=6 g=72 g_seq=8
+GoLabel dt=5 label_string=2
+GoBlock dt=1622 reason_string=15 stack=5
+GoUnblock dt=9 g=72 g_seq=9 stack=0
+GoStart dt=6 g=72 g_seq=10
+GoLabel dt=1 label_string=2
+GoUnblock dt=165 g=87 g_seq=2 stack=12
+GoBlock dt=854 reason_string=15 stack=5
+GoUnblock dt=9 g=72 g_seq=11 stack=0
+GoStart dt=4 g=72 g_seq=12
+GoLabel dt=1 label_string=2
+GoBlock dt=398 reason_string=15 stack=5
+GoUnblock dt=20 g=72 g_seq=13 stack=0
+GoStart dt=5 g=72 g_seq=14
+GoLabel dt=1 label_string=2
+GoBlock dt=1475 reason_string=15 stack=5
+GoStart dt=1158 g=93 g_seq=2
+GoStatus dt=24 g=94 m=18446744073709551615 gstatus=4
+GoUnblock dt=5 g=94 g_seq=1 stack=10
+GCMarkAssistBegin dt=19 stack=3
+GoBlock dt=235 reason_string=13 stack=11
+GoStart dt=9 g=94 g_seq=2
+GoStatus dt=18 g=100 m=18446744073709551615 gstatus=4
+GoUnblock dt=3 g=100 g_seq=1 stack=10
+GCMarkAssistBegin dt=16 stack=3
+GoStop dt=7669 reason_string=20 stack=9
+GoStart dt=9 g=94 g_seq=3
+GoStop dt=5028 reason_string=20 stack=9
+GoUnblock dt=76 g=23 g_seq=39 stack=0
+GoStart dt=4 g=23 g_seq=40
+GoLabel dt=1 label_string=4
+GoBlock dt=464 reason_string=15 stack=5
+GoUnblock dt=67 g=23 g_seq=41 stack=0
+GoStart dt=151 g=23 g_seq=42
+GoLabel dt=2 label_string=4
+GoBlock dt=3280 reason_string=15 stack=5
+GoStart dt=35 g=113 g_seq=6
+GCMarkAssistEnd dt=7
+GCMarkAssistBegin dt=65 stack=3
+GoBlock dt=63 reason_string=13 stack=11
+ProcStop dt=162
+ProcStart dt=22113 p=24 p_seq=4
+GoStart dt=228 g=111 g_seq=8
+GCMarkAssistEnd dt=11
+HeapAlloc dt=64 heapalloc_value=196401616
+GoStop dt=6120 reason_string=16 stack=6
+GoStart dt=26 g=111 g_seq=9
+GCMarkAssistBegin dt=15 stack=3
+GoBlock dt=35 reason_string=10 stack=18
+ProcStop dt=128
+ProcStart dt=7783 p=1 p_seq=3
+GoStart dt=191 g=87 g_seq=8
+GCMarkAssistEnd dt=9
+GCSweepBegin dt=33 stack=28
+GCSweepEnd dt=16 swept_value=16384 reclaimed_value=16384
+HeapAlloc dt=4 heapalloc_value=103833248
+GCSweepBegin dt=56 stack=27
+GCSweepEnd dt=1508 swept_value=4194304 reclaimed_value=3072000
+HeapAlloc dt=33 heapalloc_value=105692064
+HeapAlloc dt=115 heapalloc_value=105976736
+HeapAlloc dt=44 heapalloc_value=106034080
+HeapAlloc dt=109 heapalloc_value=106332320
+HeapAlloc dt=95 heapalloc_value=106715424
+HeapAlloc dt=80 heapalloc_value=106958496
+HeapAlloc dt=97 heapalloc_value=107330592
+HeapAlloc dt=56 heapalloc_value=107460384
+HeapAlloc dt=117 heapalloc_value=107811360
+HeapAlloc dt=62 heapalloc_value=108141856
+HeapAlloc dt=115 heapalloc_value=108472352
+HeapAlloc dt=103 heapalloc_value=108710048
+GCSweepBegin dt=51 stack=28
+GCSweepEnd dt=11 swept_value=16384 reclaimed_value=16384
+HeapAlloc dt=4 heapalloc_value=108832928
+HeapAlloc dt=51 heapalloc_value=109134624
+HeapAlloc dt=100 heapalloc_value=109470496
+HeapAlloc dt=98 heapalloc_value=109831200
+HeapAlloc dt=69 heapalloc_value=110087968
+HeapAlloc dt=117 heapalloc_value=110388096
+HeapAlloc dt=150 heapalloc_value=111005312
+HeapAlloc dt=140 heapalloc_value=111509376
+HeapAlloc dt=55 heapalloc_value=111773568
+HeapAlloc dt=105 heapalloc_value=112162048
+GCSweepBegin dt=85 stack=28
+GCSweepEnd dt=8 swept_value=32768 reclaimed_value=32768
+HeapAlloc dt=3 heapalloc_value=112560896
+HeapAlloc dt=68 heapalloc_value=112816768
+HeapAlloc dt=47 heapalloc_value=112988800
+HeapAlloc dt=122 heapalloc_value=113464960
+HeapAlloc dt=150 heapalloc_value=114008448
+GCSweepBegin dt=885 stack=27
+EventBatch gen=3 m=169406 time=28114950897134 size=117
+ProcStatus dt=3 p=6 pstatus=1
+GoStatus dt=5 g=52 m=169406 gstatus=2
+GoBlock dt=14 reason_string=15 stack=5
+GoUnblock dt=16 g=52 g_seq=1 stack=0
+GoStart dt=5 g=52 g_seq=2
+GoLabel dt=1 label_string=2
+GoBlock dt=3752 reason_string=15 stack=5
+GoUnblock dt=21 g=52 g_seq=3 stack=0
+GoStart dt=7 g=52 g_seq=4
+GoLabel dt=1 label_string=2
+GoBlock dt=4444 reason_string=15 stack=5
+GoUnblock dt=12 g=52 g_seq=5 stack=0
+GoStart dt=7 g=52 g_seq=6
+GoLabel dt=1 label_string=2
+GoBlock dt=5071 reason_string=15 stack=5
+GoUnblock dt=15 g=52 g_seq=7 stack=0
+GoStart dt=6 g=52 g_seq=8
+GoLabel dt=2 label_string=2
+GoBlock dt=2302 reason_string=15 stack=5
+GoUnblock dt=14 g=52 g_seq=9 stack=0
+GoStart dt=6 g=52 g_seq=10
+GoLabel dt=1 label_string=2
+GoBlock dt=32 reason_string=15 stack=5
+GoUnblock dt=9 g=52 g_seq=11 stack=0
+GoStart dt=6 g=52 g_seq=12
+GoLabel dt=1 label_string=2
+GoBlock dt=22 reason_string=15 stack=5
+ProcStop dt=35
+EventBatch gen=3 m=169405 time=28114950903578 size=119
+ProcStatus dt=2 p=15 pstatus=1
+GoStatus dt=4 g=53 m=169405 gstatus=2
+GoBlock dt=8 reason_string=15 stack=5
+GoUnblock dt=5238 g=25 g_seq=7 stack=0
+GoStart dt=7 g=25 g_seq=8
+GoLabel dt=1 label_string=4
+GoBlock dt=49 reason_string=15 stack=5
+GoUnblock dt=1111 g=58 g_seq=11 stack=0
+GoStart dt=6 g=58 g_seq=12
+GoLabel dt=1 label_string=4
+GoBlock dt=158 reason_string=15 stack=5
+GoStart dt=3143 g=100 g_seq=2
+GoStatus dt=20 g=109 m=18446744073709551615 gstatus=4
+GoUnblock dt=7 g=109 g_seq=1 stack=10
+GCMarkAssistBegin dt=17 stack=3
+GoBlock dt=2307 reason_string=13 stack=11
+GoUnblock dt=2192 g=14 g_seq=13 stack=0
+GoStart dt=4 g=14 g_seq=14
+GoLabel dt=1 label_string=4
+GoBlock dt=1366 reason_string=15 stack=5
+GoUnblock dt=68 g=23 g_seq=21 stack=0
+GoStart dt=4 g=23 g_seq=22
+GoLabel dt=1 label_string=4
+GoBlock dt=21 reason_string=15 stack=5
+ProcStop dt=3159
+EventBatch gen=3 m=169404 time=28114950896316 size=116
+ProcStatus dt=1 p=5 pstatus=1
+GoStatus dt=2 g=14 m=169404 gstatus=2
+GoBlock dt=5 reason_string=15 stack=5
+GoUnblock dt=1436 g=67 g_seq=3 stack=0
+GoStart dt=217 g=67 g_seq=4
+GoLabel dt=3 label_string=4
+GoBlock dt=1945 reason_string=15 stack=5
+GoStart dt=23 g=121 g_seq=3
+GoStop dt=570 reason_string=20 stack=9
+GoStart dt=14 g=121 g_seq=4
+GoBlock dt=1389 reason_string=13 stack=11
+GoUnblock dt=13 g=51 g_seq=3 stack=0
+GoStart dt=7 g=51 g_seq=4
+GoLabel dt=1 label_string=2
+GoBlock dt=1439 reason_string=15 stack=5
+GoUnblock dt=17 g=14 g_seq=5 stack=0
+GoStart dt=5 g=14 g_seq=6
+GoLabel dt=2 label_string=2
+GoBlock dt=11474 reason_string=15 stack=5
+GoStart dt=4166 g=109 g_seq=3
+GoBlock dt=39 reason_string=13 stack=11
+GoStart dt=20 g=119 g_seq=4
+GCMarkAssistEnd dt=7
+HeapAlloc dt=68 heapalloc_value=191921600
+GCMarkAssistBegin dt=69 stack=3
+GoBlock dt=23 reason_string=13 stack=11
+ProcStop dt=59
+EventBatch gen=3 m=169402 time=28114950895074 size=135
+ProcStatus dt=2 p=9 pstatus=1
+GoStatus dt=2 g=25 m=169402 gstatus=2
+GoBlock dt=14 reason_string=15 stack=5
+GoStart dt=54 g=98 g_seq=1
+GCMarkAssistBegin dt=99 stack=3
+GCMarkAssistEnd dt=1187
+HeapAlloc dt=68 heapalloc_value=190463424
+GoStop dt=53 reason_string=16 stack=6
+GoStart dt=10 g=82 g_seq=1
+GCMarkAssistBegin dt=82 stack=3
+GoStop dt=2699 reason_string=20 stack=9
+GoStart dt=13 g=107 g_seq=2
+GCMarkAssistEnd dt=7
+GCMarkAssistBegin dt=49 stack=3
+GoBlock dt=852 reason_string=13 stack=11
+GoStart dt=29 g=90 g_seq=2
+GCMarkAssistEnd dt=3
+HeapAlloc dt=36 heapalloc_value=191233472
+GCMarkAssistBegin dt=825 stack=3
+GoBlock dt=392 reason_string=13 stack=11
+GoUnblock dt=21 g=67 g_seq=5 stack=0
+GoStart dt=5 g=67 g_seq=6
+GoLabel dt=1 label_string=2
+GoBlock dt=8638 reason_string=15 stack=5
+GoUnblock dt=9 g=67 g_seq=7 stack=0
+GoStart dt=4 g=67 g_seq=8
+GoLabel dt=1 label_string=2
+GoBlock dt=145 reason_string=15 stack=5
+GoUnblock dt=14 g=67 g_seq=9 stack=0
+GoStart dt=5 g=67 g_seq=10
+GoLabel dt=1 label_string=2
+GoBlock dt=7067 reason_string=15 stack=5
+ProcStop dt=23
+EventBatch gen=3 m=169401 time=28114950894770 size=505
+ProcStatus dt=1 p=8 pstatus=1
+GoStatus dt=1 g=130 m=169401 gstatus=2
+ProcsChange dt=124 procs_value=48 stack=1
+GCActive dt=3 gc_seq=4
+HeapAlloc dt=600 heapalloc_value=190152128
+HeapAlloc dt=16 heapalloc_value=190160320
+HeapAlloc dt=11095 heapalloc_value=191741376
+HeapAlloc dt=179 heapalloc_value=191749568
+HeapAlloc dt=14244 heapalloc_value=192011712
+HeapAlloc dt=292 heapalloc_value=192019904
+HeapAlloc dt=244 heapalloc_value=192028096
+HeapAlloc dt=3225 heapalloc_value=192036288
+HeapAlloc dt=39 heapalloc_value=192044192
+HeapAlloc dt=60 heapalloc_value=192052000
+HeapAlloc dt=462 heapalloc_value=192060192
+HeapAlloc dt=85 heapalloc_value=192068384
+HeapAlloc dt=341 heapalloc_value=192076576
+HeapAlloc dt=314 heapalloc_value=192142112
+GoStop dt=8367 reason_string=16 stack=14
+GoUnblock dt=274 g=30 g_seq=27 stack=0
+GoStart dt=6 g=30 g_seq=28
+GoLabel dt=1 label_string=2
+GoBlock dt=312 reason_string=15 stack=5
+GoUnblock dt=403 g=30 g_seq=29 stack=0
+GoStart dt=4 g=30 g_seq=30
+GoLabel dt=1 label_string=2
+GoBlock dt=773 reason_string=15 stack=5
+GoUnblock dt=7 g=30 g_seq=31 stack=0
+GoStart dt=3 g=30 g_seq=32
+GoLabel dt=1 label_string=2
+GoBlock dt=8 reason_string=15 stack=5
+GoStart dt=14 g=112 g_seq=4
+GCMarkAssistEnd dt=6
+HeapAlloc dt=45 heapalloc_value=192297760
+GCMarkAssistBegin dt=107 stack=3
+GoStop dt=897 reason_string=20 stack=9
+GoUnblock dt=15 g=70 g_seq=19 stack=0
+GoStart dt=5 g=70 g_seq=20
+GoLabel dt=1 label_string=2
+GoUnblock dt=1479 g=105 g_seq=5 stack=12
+GoBlock dt=2280 reason_string=15 stack=5
+GoUnblock dt=12 g=70 g_seq=21 stack=0
+GoStart dt=5 g=70 g_seq=22
+GoLabel dt=2 label_string=2
+GoBlock dt=1253 reason_string=15 stack=5
+GoUnblock dt=23 g=71 g_seq=35 stack=0
+GoStart dt=8 g=71 g_seq=36
+GoLabel dt=2 label_string=2
+GoBlock dt=26 reason_string=15 stack=5
+GoUnblock dt=6 g=71 g_seq=37 stack=0
+GoStart dt=3 g=71 g_seq=38
+GoLabel dt=1 label_string=2
+GoBlock dt=9 reason_string=15 stack=5
+GoUnblock dt=3 g=71 g_seq=39 stack=0
+GoStart dt=2 g=71 g_seq=40
+GoLabel dt=1 label_string=2
+GoBlock dt=21 reason_string=15 stack=5
+GoUnblock dt=3 g=71 g_seq=41 stack=0
+GoStart dt=1 g=71 g_seq=42
+GoLabel dt=1 label_string=2
+GoUnblock dt=82 g=109 g_seq=4 stack=12
+GoUnblock dt=6 g=106 g_seq=4 stack=12
+GoUnblock dt=103 g=111 g_seq=4 stack=12
+GoUnblock dt=5 g=112 g_seq=6 stack=12
+GoUnblock dt=6 g=96 g_seq=5 stack=12
+GoUnblock dt=4 g=119 g_seq=5 stack=12
+GoUnblock dt=6 g=122 g_seq=1 stack=12
+GoUnblock dt=11 g=97 g_seq=5 stack=12
+GoUnblock dt=4 g=107 g_seq=3 stack=12
+GoUnblock dt=106 g=92 g_seq=3 stack=12
+GoUnblock dt=4 g=116 g_seq=9 stack=12
+GoUnblock dt=5 g=82 g_seq=8 stack=12
+GoBlock dt=9 reason_string=15 stack=5
+GoStart dt=12 g=111 g_seq=5
+GCMarkAssistEnd dt=5
+HeapAlloc dt=22 heapalloc_value=192797400
+GCMarkAssistBegin dt=75 stack=3
+GoStop dt=22 reason_string=20 stack=9
+GoUnblock dt=11 g=25 g_seq=53 stack=0
+GoStart dt=4 g=25 g_seq=54
+GoLabel dt=1 label_string=2
+GoUnblock dt=1354 g=95 g_seq=4 stack=12
+GoUnblock dt=9 g=90 g_seq=6 stack=12
+GoUnblock dt=6 g=113 g_seq=9 stack=12
+GoUnblock dt=3 g=89 g_seq=6 stack=12
+GoBlock dt=30 reason_string=15 stack=5
+GoStart dt=10 g=112 g_seq=7
+GCMarkAssistEnd dt=5
+GCMarkAssistBegin dt=28 stack=3
+GoBlock dt=587 reason_string=13 stack=11
+GoStart dt=6 g=116 g_seq=10
+GCMarkAssistEnd dt=5
+HeapAlloc dt=54 heapalloc_value=194337496
+GCMarkAssistBegin dt=51 stack=3
+GoBlock dt=21 reason_string=13 stack=11
+GoStart dt=8 g=82 g_seq=9
+GCMarkAssistEnd dt=6
+HeapAlloc dt=63 heapalloc_value=194525912
+GCMarkAssistBegin dt=51 stack=3
+GoBlock dt=45 reason_string=13 stack=11
+GoStart dt=22 g=95 g_seq=5
+GCMarkAssistEnd dt=6
+HeapAlloc dt=1508 heapalloc_value=195394264
+GoStop dt=6034 reason_string=16 stack=6
+GoStart dt=48 g=95 g_seq=6
+GCMarkAssistBegin dt=18 stack=3
+GoBlock dt=48 reason_string=10 stack=18
+ProcStop dt=85
+ProcStart dt=20619 p=17 p_seq=1
+GoStart dt=1507 g=130 g_seq=7
+EventBatch gen=3 m=169400 time=28114950894819 size=671
+ProcStatus dt=1 p=12 pstatus=1
+GoStatus dt=2 g=112 m=169400 gstatus=2
+GCMarkAssistBegin dt=120 stack=3
+GCMarkAssistEnd dt=3298
+HeapAlloc dt=41 heapalloc_value=190758336
+GCMarkAssistBegin dt=29 stack=3
+GoStop dt=2271 reason_string=20 stack=9
+GoStart dt=14 g=112 g_seq=1
+GoStop dt=569 reason_string=20 stack=9
+GoUnblock dt=2436 g=54 g_seq=1 stack=0
+GoStart dt=18 g=54 g_seq=2
+GoLabel dt=1 label_string=4
+GoBlock dt=31 reason_string=15 stack=5
+GoUnblock dt=5090 g=57 g_seq=13 stack=0
+GoStart dt=6 g=57 g_seq=14
+GoLabel dt=1 label_string=4
+GoBlock dt=734 reason_string=15 stack=5
+GoUnblock dt=4144 g=71 g_seq=15 stack=0
+GoStart dt=5 g=71 g_seq=16
+GoLabel dt=1 label_string=4
+GoUnblock dt=415 g=111 g_seq=2 stack=12
+GoBlock dt=5674 reason_string=15 stack=5
+GoUnblock dt=9 g=71 g_seq=17 stack=0
+GoStart dt=5 g=71 g_seq=18
+GoLabel dt=1 label_string=2
+GoUnblock dt=693 g=83 g_seq=3 stack=12
+GoBlock dt=4708 reason_string=15 stack=5
+GoUnblock dt=14 g=71 g_seq=19 stack=0
+GoStart dt=6 g=71 g_seq=20
+GoLabel dt=3 label_string=2
+GoBlock dt=1294 reason_string=15 stack=5
+GoUnblock dt=11 g=71 g_seq=21 stack=0
+GoStart dt=4 g=71 g_seq=22
+GoLabel dt=1 label_string=2
+GoBlock dt=2434 reason_string=15 stack=5
+GoUnblock dt=8 g=71 g_seq=23 stack=0
+GoStart dt=3 g=71 g_seq=24
+GoLabel dt=1 label_string=2
+GoBlock dt=4227 reason_string=15 stack=5
+ProcStop dt=41
+ProcStart dt=3260 p=12 p_seq=1
+GoUnblock dt=16 g=30 g_seq=33 stack=0
+GoStart dt=143 g=30 g_seq=34
+GoLabel dt=1 label_string=2
+GoUnblock dt=553 g=89 g_seq=3 stack=12
+GoUnblock dt=971 g=127 g_seq=3 stack=12
+GoBlock dt=39 reason_string=15 stack=5
+GoStart dt=21 g=89 g_seq=4
+GCMarkAssistEnd dt=10
+HeapAlloc dt=1100 heapalloc_value=192510680
+GoStop dt=24 reason_string=16 stack=6
+GoUnblock dt=12 g=22 g_seq=51 stack=0
+GoStart dt=5 g=22 g_seq=52
+GoLabel dt=3 label_string=2
+GoBlock dt=1678 reason_string=15 stack=5
+GoUnblock dt=13 g=22 g_seq=53 stack=0
+GoStart dt=277 g=22 g_seq=54
+GoLabel dt=3 label_string=2
+GoBlock dt=960 reason_string=15 stack=5
+GoUnblock dt=8 g=22 g_seq=55 stack=0
+GoStart dt=4 g=22 g_seq=56
+GoLabel dt=1 label_string=2
+GoUnblock dt=583 g=99 g_seq=3 stack=12
+GoUnblock dt=5 g=83 g_seq=6 stack=12
+GoUnblock dt=5 g=124 g_seq=3 stack=12
+GoUnblock dt=6 g=105 g_seq=9 stack=12
+GoUnblock dt=1280 g=128 g_seq=3 stack=12
+GoUnblock dt=8 g=101 g_seq=3 stack=12
+GoBlock dt=7 reason_string=15 stack=5
+GoStart dt=11 g=128 g_seq=4
+GCMarkAssistEnd dt=7
+HeapAlloc dt=38 heapalloc_value=193297112
+GCMarkAssistBegin dt=118 stack=3
+GCMarkAssistEnd dt=44
+HeapAlloc dt=21 heapalloc_value=193403608
+GoStop dt=87 reason_string=16 stack=6
+GoStart dt=15 g=101 g_seq=4
+GCMarkAssistEnd dt=5
+HeapAlloc dt=58 heapalloc_value=193608408
+GCMarkAssistBegin dt=92 stack=3
+GoBlock dt=22 reason_string=13 stack=11
+GoStart dt=10 g=128 g_seq=5
+HeapAlloc dt=34 heapalloc_value=193829592
+HeapAlloc dt=166 heapalloc_value=194026200
+HeapAlloc dt=236 heapalloc_value=194419416
+HeapAlloc dt=885 heapalloc_value=195279576
+GoStop dt=6734 reason_string=16 stack=6
+GoUnblock dt=1628 g=130 g_seq=3 stack=0
+GoStart dt=136 g=130 g_seq=4
+HeapAlloc dt=62 heapalloc_value=196532688
+HeapAlloc dt=28 heapalloc_value=196540880
+HeapAlloc dt=22 heapalloc_value=196549072
+HeapAlloc dt=26 heapalloc_value=196557264
+HeapAlloc dt=38 heapalloc_value=196565456
+HeapAlloc dt=51 heapalloc_value=196573648
+GoStop dt=3032 reason_string=16 stack=19
+GoStart dt=10 g=117 g_seq=5
+GCMarkAssistBegin dt=16 stack=3
+GoBlock dt=51 reason_string=10 stack=18
+ProcStop dt=29
+ProcStart dt=9381 p=4 p_seq=2
+GoStart dt=190 g=105 g_seq=16
+GCMarkAssistEnd dt=4
+HeapAlloc dt=76 heapalloc_value=105214112
+HeapAlloc dt=103 heapalloc_value=105517216
+HeapAlloc dt=84 heapalloc_value=105642912
+HeapAlloc dt=85 heapalloc_value=105864096
+GCSweepBegin dt=188 stack=28
+GCSweepEnd dt=17 swept_value=16384 reclaimed_value=16384
+HeapAlloc dt=2 heapalloc_value=106376096
+HeapAlloc dt=43 heapalloc_value=106518816
+HeapAlloc dt=43 heapalloc_value=106756384
+HeapAlloc dt=82 heapalloc_value=106978976
+HeapAlloc dt=42 heapalloc_value=107091616
+GCSweepBegin dt=23 stack=28
+GCSweepEnd dt=8 swept_value=8192 reclaimed_value=8192
+HeapAlloc dt=3 heapalloc_value=107310112
+HeapAlloc dt=35 heapalloc_value=107372960
+HeapAlloc dt=65 heapalloc_value=107583264
+HeapAlloc dt=141 heapalloc_value=108018976
+HeapAlloc dt=161 heapalloc_value=108567968
+GCSweepBegin dt=85 stack=28
+GCSweepEnd dt=9 swept_value=24576 reclaimed_value=24576
+HeapAlloc dt=4 heapalloc_value=108808352
+HeapAlloc dt=90 heapalloc_value=109241120
+HeapAlloc dt=139 heapalloc_value=109623584
+HeapAlloc dt=162 heapalloc_value=110175008
+HeapAlloc dt=164 heapalloc_value=110769024
+HeapAlloc dt=246 heapalloc_value=111705984
+HeapAlloc dt=187 heapalloc_value=112446208
+HeapAlloc dt=161 heapalloc_value=113148544
+HeapAlloc dt=295 heapalloc_value=114145664
+GCSweepBegin dt=159 stack=28
+GCSweepEnd dt=5 swept_value=8192 reclaimed_value=8192
+HeapAlloc dt=7 heapalloc_value=114588800
+GCSweepBegin dt=48 stack=27
+EventBatch gen=3 m=169398 time=28114950899192 size=165
+ProcStatus dt=1 p=37 pstatus=2
+ProcStart dt=2 p=37 p_seq=1
+GoStatus dt=3261 g=29 m=18446744073709551615 gstatus=4
+GoUnblock dt=6 g=29 g_seq=1 stack=0
+GoStart dt=10 g=29 g_seq=2
+GoLabel dt=1 label_string=4
+GoBlock dt=1840 reason_string=15 stack=5
+GoStart dt=16 g=86 g_seq=3
+GoBlock dt=1090 reason_string=13 stack=11
+ProcStop dt=1389
+ProcStart dt=16 p=37 p_seq=2
+GoStart dt=1537 g=84 g_seq=4
+GCMarkAssistEnd dt=7
+HeapAlloc dt=55 heapalloc_value=191847872
+GCMarkAssistBegin dt=85 stack=3
+GoBlock dt=249 reason_string=13 stack=11
+GoUnblock dt=1134 g=58 g_seq=9 stack=0
+GoStart dt=7 g=58 g_seq=10
+GoLabel dt=1 label_string=4
+GoBlock dt=27 reason_string=15 stack=5
+GoUnblock dt=2190 g=53 g_seq=9 stack=0
+GoStart dt=8 g=53 g_seq=10
+GoLabel dt=1 label_string=4
+GoBlock dt=21 reason_string=15 stack=5
+GoUnblock dt=2156 g=25 g_seq=13 stack=0
+GoStart dt=4 g=25 g_seq=14
+GoLabel dt=1 label_string=4
+GoBlock dt=20 reason_string=15 stack=5
+GoUnblock dt=1089 g=14 g_seq=7 stack=0
+GoStart dt=4 g=14 g_seq=8
+GoLabel dt=1 label_string=4
+GoBlock dt=107 reason_string=15 stack=5
+GoUnblock dt=1081 g=24 g_seq=15 stack=0
+GoStart dt=6 g=24 g_seq=16
+GoLabel dt=1 label_string=4
+GoBlock dt=19 reason_string=15 stack=5
+ProcStop dt=1075
+EventBatch gen=3 m=169397 time=28114950897533 size=734
+ProcStatus dt=1 p=25 pstatus=1
+GoStatus dt=2 g=118 m=169397 gstatus=2
+GCMarkAssistActive dt=1 g=118
+GCMarkAssistEnd dt=2
+HeapAlloc dt=37 heapalloc_value=190684608
+GCMarkAssistBegin dt=79 stack=3
+GoBlock dt=1327 reason_string=13 stack=11
+ProcStop dt=4643
+ProcStart dt=23 p=25 p_seq=1
+GoUnblock dt=20 g=53 g_seq=1 stack=0
+GoStart dt=9 g=53 g_seq=2
+GoLabel dt=1 label_string=2
+GoBlock dt=2529 reason_string=15 stack=5
+GoStart dt=3244 g=123 g_seq=2
+GoStatus dt=30 g=97 m=18446744073709551615 gstatus=4
+GoUnblock dt=13 g=97 g_seq=1 stack=10
+GCMarkAssistBegin dt=20 stack=3
+GoStop dt=1976 reason_string=20 stack=9
+GoStart dt=15 g=123 g_seq=3
+GoStop dt=2654 reason_string=20 stack=9
+GoStart dt=12 g=123 g_seq=4
+GoStop dt=2704 reason_string=20 stack=9
+GoUnblock dt=9 g=24 g_seq=17 stack=0
+GoStart dt=4 g=24 g_seq=18
+GoLabel dt=1 label_string=2
+GoBlock dt=4029 reason_string=15 stack=5
+GoUnblock dt=14 g=24 g_seq=19 stack=0
+GoStart dt=4 g=24 g_seq=20
+GoLabel dt=1 label_string=2
+GoBlock dt=534 reason_string=15 stack=5
+GoUnblock dt=4 g=24 g_seq=21 stack=0
+GoStart dt=4 g=24 g_seq=22
+GoLabel dt=1 label_string=2
+GoBlock dt=250 reason_string=15 stack=5
+GoUnblock dt=12 g=24 g_seq=23 stack=0
+GoStart dt=4 g=24 g_seq=24
+GoLabel dt=1 label_string=2
+GoBlock dt=22 reason_string=15 stack=5
+ProcStop dt=71
+ProcStart dt=244 p=25 p_seq=2
+ProcStop dt=54
+ProcStart dt=25 p=25 p_seq=3
+GoUnblock dt=8 g=53 g_seq=21 stack=0
+GoStart dt=7 g=53 g_seq=22
+GoLabel dt=1 label_string=4
+GoBlock dt=86 reason_string=15 stack=5
+GoUnblock dt=59 g=56 g_seq=3 stack=0
+GoStart dt=4 g=56 g_seq=4
+GoLabel dt=1 label_string=4
+GoBlock dt=6219 reason_string=15 stack=5
+GoUnblock dt=52 g=56 g_seq=5 stack=0
+GoStart dt=4 g=56 g_seq=6
+GoLabel dt=1 label_string=4
+GoBlock dt=98 reason_string=15 stack=5
+GoUnblock dt=61 g=14 g_seq=27 stack=0
+GoStart dt=4 g=14 g_seq=28
+GoLabel dt=1 label_string=4
+GoBlock dt=32 reason_string=15 stack=5
+GoUnblock dt=13 g=14 g_seq=29 stack=0
+GoStart dt=5 g=14 g_seq=30
+GoLabel dt=1 label_string=2
+GoBlock dt=2423 reason_string=15 stack=5
+ProcStop dt=36
+ProcStart dt=7135 p=31 p_seq=2
+GoStart dt=228 g=127 g_seq=4
+GCMarkAssistEnd dt=9
+HeapAlloc dt=2440 heapalloc_value=192666328
+GoStop dt=28 reason_string=16 stack=4
+GoUnblock dt=19 g=52 g_seq=57 stack=0
+GoStart dt=6 g=52 g_seq=58
+GoLabel dt=1 label_string=2
+GoBlock dt=1072 reason_string=15 stack=5
+GoUnblock dt=16 g=52 g_seq=59 stack=0
+GoStart dt=6 g=52 g_seq=60
+GoLabel dt=1 label_string=2
+GoBlock dt=19 reason_string=15 stack=5
+GoUnblock dt=17 g=54 g_seq=39 stack=0
+GoStart dt=4 g=54 g_seq=40
+GoLabel dt=1 label_string=2
+GoBlock dt=2352 reason_string=15 stack=5
+GoStart dt=22 g=127 g_seq=8
+GCMarkAssistBegin dt=127 stack=3
+GoBlock dt=42 reason_string=13 stack=11
+GoStart dt=766 g=122 g_seq=2
+GCMarkAssistEnd dt=2
+HeapAlloc dt=19 heapalloc_value=194902744
+GCMarkAssistBegin dt=66 stack=3
+STWBegin dt=12586 kind_string=21 stack=21
+GoUnblock dt=699 g=91 g_seq=3 stack=22
+GoUnblock dt=5 g=127 g_seq=9 stack=22
+GoUnblock dt=3 g=112 g_seq=8 stack=22
+GoUnblock dt=4 g=82 g_seq=10 stack=22
+GoUnblock dt=3 g=116 g_seq=11 stack=22
+GoUnblock dt=3 g=93 g_seq=8 stack=22
+GoUnblock dt=4 g=109 g_seq=6 stack=22
+GoUnblock dt=5 g=115 g_seq=9 stack=22
+GoUnblock dt=7 g=120 g_seq=7 stack=22
+GoUnblock dt=7 g=105 g_seq=15 stack=22
+GoUnblock dt=6 g=96 g_seq=7 stack=22
+GoUnblock dt=3 g=118 g_seq=6 stack=22
+GoUnblock dt=4 g=87 g_seq=7 stack=22
+GoUnblock dt=4 g=84 g_seq=9 stack=22
+GoUnblock dt=6 g=100 g_seq=6 stack=22
+GoUnblock dt=29 g=86 g_seq=6 stack=23
+HeapAlloc dt=53 heapalloc_value=103773088
+GoStatus dt=10 g=3 m=18446744073709551615 gstatus=4
+GoUnblock dt=7 g=3 g_seq=1 stack=24
+GCEnd dt=3 gc_seq=5
+HeapGoal dt=6 heapgoal_value=207987496
+ProcsChange dt=45 procs_value=48 stack=25
+STWEnd dt=399
+GoUnblock dt=5992 g=130 g_seq=6 stack=26
+GCMarkAssistEnd dt=9
+HeapAlloc dt=11 heapalloc_value=103816864
+GCSweepBegin dt=79 stack=27
+GCSweepEnd dt=1631 swept_value=8388608 reclaimed_value=3260416
+HeapAlloc dt=14 heapalloc_value=104810272
+HeapAlloc dt=104 heapalloc_value=105001504
+HeapAlloc dt=107 heapalloc_value=105164960
+HeapAlloc dt=55 heapalloc_value=105308320
+HeapAlloc dt=200 heapalloc_value=105798560
+HeapAlloc dt=119 heapalloc_value=106091424
+HeapAlloc dt=118 heapalloc_value=106359712
+HeapAlloc dt=47 heapalloc_value=106488096
+HeapAlloc dt=44 heapalloc_value=106763424
+HeapAlloc dt=26 heapalloc_value=106820768
+HeapAlloc dt=106 heapalloc_value=107277344
+HeapAlloc dt=131 heapalloc_value=107656992
+HeapAlloc dt=71 heapalloc_value=107790880
+GCSweepBegin dt=42 stack=28
+GCSweepEnd dt=6 swept_value=24576 reclaimed_value=24576
+HeapAlloc dt=3 heapalloc_value=107860512
+HeapAlloc dt=71 heapalloc_value=108305696
+HeapAlloc dt=113 heapalloc_value=108608928
+HeapAlloc dt=129 heapalloc_value=108890272
+HeapAlloc dt=147 heapalloc_value=109508896
+HeapAlloc dt=88 heapalloc_value=109776544
+HeapAlloc dt=140 heapalloc_value=110286976
+HeapAlloc dt=151 heapalloc_value=110900096
+HeapAlloc dt=152 heapalloc_value=111433600
+HeapAlloc dt=136 heapalloc_value=111931264
+HeapAlloc dt=67 heapalloc_value=112248064
+HeapAlloc dt=209 heapalloc_value=113046144
+HeapAlloc dt=213 heapalloc_value=113949056
+HeapAlloc dt=236 heapalloc_value=114471168
+HeapAlloc dt=90 heapalloc_value=114663552
+GCSweepBegin dt=45 stack=28
+GCSweepEnd dt=10 swept_value=32768 reclaimed_value=32768
+HeapAlloc dt=3 heapalloc_value=114703232
+GCSweepBegin dt=54 stack=27
+EventBatch gen=3 m=169396 time=28114950894859 size=148
+ProcStatus dt=2 p=1 pstatus=1
+GoStatus dt=4 g=86 m=169396 gstatus=2
+GCMarkAssistActive dt=2 g=86
+GCMarkAssistEnd dt=2
+HeapAlloc dt=42 heapalloc_value=189889984
+GoStop dt=32 reason_string=16 stack=4
+GoUnblock dt=117 g=69 g_seq=1 stack=0
+GoStart dt=6 g=69 g_seq=2
+GoLabel dt=1 label_string=2
+GoBlock dt=2672 reason_string=15 stack=5
+GoStart dt=16 g=84 g_seq=1
+GoStop dt=2565 reason_string=20 stack=9
+GoStart dt=17 g=84 g_seq=2
+GoBlock dt=886 reason_string=13 stack=11
+ProcStop dt=2581
+ProcStart dt=17 p=1 p_seq=1
+ProcStop dt=4400
+ProcStart dt=16 p=1 p_seq=2
+GoStart dt=24 g=87 g_seq=3
+GCMarkAssistEnd dt=8
+HeapAlloc dt=70 heapalloc_value=191782336
+GCMarkAssistBegin dt=85 stack=3
+GoBlock dt=1055 reason_string=13 stack=11
+GoUnblock dt=20 g=54 g_seq=9 stack=0
+GoStart dt=7 g=54 g_seq=10
+GoLabel dt=3 label_string=2
+GoBlock dt=230 reason_string=15 stack=5
+GoUnblock dt=12 g=54 g_seq=11 stack=0
+GoStart dt=6 g=54 g_seq=12
+GoLabel dt=1 label_string=2
+GoBlock dt=1754 reason_string=15 stack=5
+GoUnblock dt=12 g=54 g_seq=13 stack=0
+GoStart dt=8 g=54 g_seq=14
+GoLabel dt=3 label_string=2
+GoBlock dt=1379 reason_string=15 stack=5
+ProcStop dt=15
+EventBatch gen=3 m=169395 time=28114950898507 size=532
+ProcStatus dt=2 p=14 pstatus=1
+GoStatus dt=2 g=103 m=169395 gstatus=2
+GCMarkAssistActive dt=1 g=103
+GCMarkAssistEnd dt=3
+HeapAlloc dt=40 heapalloc_value=190873024
+HeapAlloc dt=75 heapalloc_value=191036864
+GCMarkAssistBegin dt=65 stack=3
+GoBlock dt=6142 reason_string=13 stack=11
+GoStart dt=19 g=98 g_seq=3
+GCMarkAssistBegin dt=20 stack=3
+GoStop dt=1738 reason_string=20 stack=9
+GoStart dt=16 g=98 g_seq=4
+GoBlock dt=2102 reason_string=13 stack=11
+GoUnblock dt=2317 g=71 g_seq=5 stack=0
+GoStart dt=5 g=71 g_seq=6
+GoLabel dt=2 label_string=4
+GoBlock dt=128 reason_string=15 stack=5
+GoUnblock dt=2283 g=71 g_seq=13 stack=0
+GoStart dt=7 g=71 g_seq=14
+GoLabel dt=1 label_string=4
+GoBlock dt=97 reason_string=15 stack=5
+GoUnblock dt=1168 g=24 g_seq=13 stack=0
+GoStart dt=7 g=24 g_seq=14
+GoLabel dt=1 label_string=4
+GoBlock dt=1399 reason_string=15 stack=5
+GoUnblock dt=3752 g=23 g_seq=25 stack=0
+GoStart dt=6 g=23 g_seq=26
+GoLabel dt=3 label_string=4
+GoBlock dt=1167 reason_string=15 stack=5
+GoUnblock dt=99 g=52 g_seq=23 stack=0
+GoStart dt=35 g=52 g_seq=24
+GoLabel dt=1 label_string=4
+GoBlock dt=47 reason_string=15 stack=5
+GoUnblock dt=81 g=67 g_seq=19 stack=0
+GoStart dt=8 g=67 g_seq=20
+GoLabel dt=3 label_string=4
+GoBlock dt=3975 reason_string=15 stack=5
+GoUnblock dt=18 g=67 g_seq=21 stack=0
+GoStart dt=6 g=67 g_seq=22
+GoLabel dt=1 label_string=2
+GoBlock dt=80 reason_string=15 stack=5
+GoUnblock dt=18 g=67 g_seq=23 stack=0
+GoStart dt=6 g=67 g_seq=24
+GoLabel dt=1 label_string=2
+GoBlock dt=22 reason_string=15 stack=5
+GoUnblock dt=3174 g=14 g_seq=23 stack=0
+GoStart dt=7 g=14 g_seq=24
+GoLabel dt=1 label_string=4
+GoBlock dt=22 reason_string=15 stack=5
+GoUnblock dt=9 g=14 g_seq=25 stack=0
+GoStart dt=2 g=14 g_seq=26
+GoLabel dt=1 label_string=2
+GoBlock dt=13 reason_string=15 stack=5
+GoUnblock dt=65 g=29 g_seq=29 stack=0
+GoStart dt=8 g=29 g_seq=30
+GoLabel dt=1 label_string=4
+GoBlock dt=18 reason_string=15 stack=5
+GoUnblock dt=13 g=29 g_seq=31 stack=0
+GoStart dt=6 g=29 g_seq=32
+GoLabel dt=2 label_string=2
+GoBlock dt=21 reason_string=15 stack=5
+GoUnblock dt=19 g=24 g_seq=37 stack=0
+GoStart dt=4 g=24 g_seq=38
+GoLabel dt=2 label_string=2
+GoBlock dt=33 reason_string=15 stack=5
+GoUnblock dt=8 g=24 g_seq=39 stack=0
+GoStart dt=3 g=24 g_seq=40
+GoLabel dt=1 label_string=2
+GoBlock dt=32 reason_string=15 stack=5
+GoUnblock dt=80 g=25 g_seq=29 stack=0
+GoStart dt=9 g=25 g_seq=30
+GoLabel dt=1 label_string=4
+GoBlock dt=20 reason_string=15 stack=5
+GoUnblock dt=27 g=24 g_seq=43 stack=0
+GoStart dt=6 g=24 g_seq=44
+GoLabel dt=1 label_string=2
+GoBlock dt=185 reason_string=15 stack=5
+GoUnblock dt=9 g=24 g_seq=45 stack=0
+GoStart dt=6 g=24 g_seq=46
+GoLabel dt=3 label_string=2
+GoBlock dt=10 reason_string=15 stack=5
+GoUnblock dt=6 g=24 g_seq=47 stack=0
+GoStart dt=1 g=24 g_seq=48
+GoLabel dt=1 label_string=2
+GoBlock dt=41 reason_string=15 stack=5
+ProcStop dt=59
+ProcStart dt=21430 p=4 p_seq=1
+GoStart dt=238 g=102 g_seq=4
+GCMarkAssistEnd dt=10
+HeapAlloc dt=38 heapalloc_value=196352464
+GoStop dt=5526 reason_string=16 stack=6
+ProcStop dt=240
+ProcStart dt=11401 p=6 p_seq=1
+GoStart dt=196 g=109 g_seq=7
+GCMarkAssistEnd dt=5
+HeapAlloc dt=54 heapalloc_value=108264736
+HeapAlloc dt=117 heapalloc_value=108527008
+HeapAlloc dt=77 heapalloc_value=108783776
+HeapAlloc dt=90 heapalloc_value=109036320
+HeapAlloc dt=77 heapalloc_value=109355808
+HeapAlloc dt=106 heapalloc_value=109678240
+HeapAlloc dt=70 heapalloc_value=110030624
+HeapAlloc dt=90 heapalloc_value=110205056
+HeapAlloc dt=51 heapalloc_value=110347136
+HeapAlloc dt=63 heapalloc_value=110588800
+HeapAlloc dt=69 heapalloc_value=110912384
+HeapAlloc dt=42 heapalloc_value=111111808
+HeapAlloc dt=105 heapalloc_value=111452032
+HeapAlloc dt=89 heapalloc_value=111822720
+HeapAlloc dt=106 heapalloc_value=112260352
+HeapAlloc dt=55 heapalloc_value=112397056
+HeapAlloc dt=62 heapalloc_value=112682368
+HeapAlloc dt=137 heapalloc_value=113281920
+GCSweepBegin dt=50 stack=28
+GCSweepEnd dt=8 swept_value=16384 reclaimed_value=16384
+HeapAlloc dt=4 heapalloc_value=113424000
+HeapAlloc dt=92 heapalloc_value=113908096
+GCSweepBegin dt=145 stack=31
+EventBatch gen=3 m=169394 time=28114950898962 size=373
+ProcStatus dt=1 p=20 pstatus=1
+GoStatus dt=4 g=108 m=169394 gstatus=2
+GCMarkAssistActive dt=1 g=108
+GCMarkAssistEnd dt=2
+HeapAlloc dt=25 heapalloc_value=191102400
+GCMarkAssistBegin dt=104 stack=3
+GCMarkAssistEnd dt=2445
+HeapAlloc dt=47 heapalloc_value=191372736
+GCMarkAssistBegin dt=11 stack=3
+GoBlock dt=1789 reason_string=13 stack=11
+GoUnblock dt=19 g=22 g_seq=3 stack=0
+GoStart dt=7 g=22 g_seq=4
+GoLabel dt=1 label_string=2
+GoBlock dt=3342 reason_string=15 stack=5
+GoUnblock dt=2752 g=71 g_seq=1 stack=0
+GoStart dt=7 g=71 g_seq=2
+GoLabel dt=1 label_string=4
+GoBlock dt=269 reason_string=15 stack=5
+GoStart dt=4308 g=111 g_seq=3
+GCMarkAssistEnd dt=7
+HeapAlloc dt=58 heapalloc_value=191888832
+GCMarkAssistBegin dt=42 stack=3
+GoBlock dt=148 reason_string=13 stack=11
+GoUnblock dt=1120 g=72 g_seq=25 stack=0
+GoStart dt=5 g=72 g_seq=26
+GoLabel dt=1 label_string=4
+GoBlock dt=640 reason_string=15 stack=5
+GoStart dt=1105 g=102 g_seq=2
+GoStatus dt=19 g=117 m=18446744073709551615 gstatus=4
+GoUnblock dt=4 g=117 g_seq=1 stack=10
+GCMarkAssistBegin dt=13 stack=3
+GoBlock dt=32 reason_string=13 stack=11
+GoStart dt=8 g=117 g_seq=2
+GoStatus dt=19 g=128 m=18446744073709551615 gstatus=4
+GoUnblock dt=2 g=128 g_seq=1 stack=10
+GCMarkAssistBegin dt=5 stack=3
+GoBlock dt=15 reason_string=13 stack=11
+GoStart dt=5 g=128 g_seq=2
+GoStatus dt=12 g=92 m=18446744073709551615 gstatus=4
+GoUnblock dt=1 g=92 g_seq=1 stack=10
+GCMarkAssistBegin dt=9 stack=3
+GoBlock dt=14 reason_string=13 stack=11
+GoStart dt=7 g=92 g_seq=2
+GoStatus dt=17 g=101 m=18446744073709551615 gstatus=4
+GoUnblock dt=1 g=101 g_seq=1 stack=10
+GCMarkAssistBegin dt=7 stack=3
+GoBlock dt=10 reason_string=13 stack=11
+GoStart dt=5 g=101 g_seq=2
+GoStatus dt=11 g=99 m=18446744073709551615 gstatus=4
+GoUnblock dt=1 g=99 g_seq=1 stack=10
+GCMarkAssistBegin dt=8 stack=3
+GoBlock dt=15 reason_string=13 stack=11
+GoStart dt=6 g=99 g_seq=2
+GoStatus dt=11 g=89 m=18446744073709551615 gstatus=4
+GoUnblock dt=1 g=89 g_seq=1 stack=10
+GCMarkAssistBegin dt=10 stack=3
+GoBlock dt=15 reason_string=13 stack=11
+GoStart dt=4 g=89 g_seq=2
+GoStatus dt=11 g=124 m=18446744073709551615 gstatus=4
+GoUnblock dt=2 g=124 g_seq=1 stack=10
+GCMarkAssistBegin dt=8 stack=3
+GoBlock dt=34 reason_string=13 stack=11
+GoStart dt=5 g=124 g_seq=2
+GoStatus dt=10 g=96 m=18446744073709551615 gstatus=4
+GoUnblock dt=1 g=96 g_seq=1 stack=10
+GCMarkAssistBegin dt=4 stack=3
+GoBlock dt=14 reason_string=13 stack=11
+GoStart dt=4 g=96 g_seq=2
+GCMarkAssistBegin dt=8 stack=3
+GoBlock dt=22 reason_string=13 stack=11
+ProcStop dt=16
+EventBatch gen=3 m=169393 time=28114950894837 size=271
+ProcStatus dt=2 p=16 pstatus=1
+GoStatus dt=2 g=69 m=169393 gstatus=2
+GoBlock dt=122 reason_string=15 stack=5
+GoStatus dt=2224 g=83 m=169393 gstatus=1
+GoStart dt=1 g=83 g_seq=1
+GoStatus dt=33 g=121 m=18446744073709551615 gstatus=4
+GoUnblock dt=10 g=121 g_seq=1 stack=10
+GCMarkAssistBegin dt=16 stack=3
+GoStop dt=620 reason_string=20 stack=9
+GoStart dt=11 g=121 g_seq=2
+GoStatus dt=18 g=110 m=18446744073709551615 gstatus=4
+GoUnblock dt=3 g=110 g_seq=1 stack=10
+GCMarkAssistBegin dt=12 stack=3
+GoStop dt=1840 reason_string=20 stack=9
+GoStart dt=16 g=110 g_seq=2
+GoStatus dt=19 g=125 m=18446744073709551615 gstatus=4
+GoUnblock dt=3 g=125 g_seq=1 stack=10
+GCMarkAssistBegin dt=10 stack=3
+GoBlock dt=1799 reason_string=13 stack=11
+GoStart dt=1317 g=127 g_seq=2
+GoStatus dt=21 g=116 m=18446744073709551615 gstatus=4
+GoUnblock dt=9 g=116 g_seq=1 stack=10
+GCMarkAssistBegin dt=16 stack=3
+GoBlock dt=473 reason_string=13 stack=11
+GoStart dt=28 g=116 g_seq=2
+GoStatus dt=14 g=119 m=18446744073709551615 gstatus=4
+GoUnblock dt=3 g=119 g_seq=1 stack=10
+GCMarkAssistBegin dt=12 stack=3
+GoStop dt=570 reason_string=20 stack=9
+GoStart dt=24 g=119 g_seq=2
+GoStatus dt=18 g=95 m=18446744073709551615 gstatus=4
+GoUnblock dt=3 g=95 g_seq=1 stack=10
+GCMarkAssistBegin dt=11 stack=3
+GoBlock dt=5206 reason_string=13 stack=11
+ProcStop dt=2547
+ProcStart dt=26 p=16 p_seq=1
+GoUnblock dt=87 g=58 g_seq=15 stack=0
+GoStart dt=8 g=58 g_seq=16
+GoLabel dt=1 label_string=4
+GoBlock dt=579 reason_string=15 stack=5
+GoUnblock dt=23 g=69 g_seq=15 stack=0
+GoStart dt=5 g=69 g_seq=16
+GoLabel dt=1 label_string=2
+GoBlock dt=1028 reason_string=15 stack=5
+GoUnblock dt=2356 g=14 g_seq=11 stack=0
+GoStart dt=6 g=14 g_seq=12
+GoLabel dt=1 label_string=4
+GoBlock dt=1282 reason_string=15 stack=5
+ProcStop dt=8
+EventBatch gen=3 m=169392 time=28114950898262 size=651
+ProcStatus dt=1 p=3 pstatus=1
+GoStatus dt=1 g=106 m=169392 gstatus=2
+GCMarkAssistActive dt=1 g=106
+GCMarkAssistEnd dt=3
+HeapAlloc dt=34 heapalloc_value=190807488
+HeapAlloc dt=125 heapalloc_value=190832064
+GCMarkAssistBegin dt=46 stack=3
+GoBlock dt=1002 reason_string=13 stack=11
+GoStart dt=28 g=82 g_seq=2
+GoBlock dt=1446 reason_string=13 stack=11
+GoStart dt=34 g=120 g_seq=3
+GCMarkAssistEnd dt=2
+HeapAlloc dt=32 heapalloc_value=191282624
+GCMarkAssistBegin dt=115 stack=3
+GoBlock dt=25 reason_string=13 stack=11
+GoStart dt=17 g=112 g_seq=2
+GoBlock dt=2074 reason_string=13 stack=11
+GoUnblock dt=2604 g=24 g_seq=5 stack=0
+GoStart dt=7 g=24 g_seq=6
+GoLabel dt=2 label_string=4
+GoBlock dt=278 reason_string=15 stack=5
+GoUnblock dt=2267 g=58 g_seq=5 stack=0
+GoStart dt=9 g=58 g_seq=6
+GoLabel dt=1 label_string=4
+GoBlock dt=316 reason_string=15 stack=5
+GoUnblock dt=1167 g=24 g_seq=7 stack=0
+GoStart dt=6 g=24 g_seq=8
+GoLabel dt=1 label_string=4
+GoBlock dt=171 reason_string=15 stack=5
+GoUnblock dt=1155 g=71 g_seq=7 stack=0
+GoStart dt=6 g=71 g_seq=8
+GoLabel dt=1 label_string=4
+GoBlock dt=32 reason_string=15 stack=5
+GoStart dt=3316 g=109 g_seq=2
+GoStatus dt=28 g=114 m=18446744073709551615 gstatus=4
+GoUnblock dt=8 g=114 g_seq=1 stack=10
+GCMarkAssistBegin dt=18 stack=3
+GoStop dt=3860 reason_string=20 stack=9
+GoUnblock dt=14 g=57 g_seq=31 stack=0
+GoStart dt=5 g=57 g_seq=32
+GoLabel dt=3 label_string=2
+GoBlock dt=3324 reason_string=15 stack=5
+GoUnblock dt=97 g=24 g_seq=25 stack=0
+GoStart dt=6 g=24 g_seq=26
+GoLabel dt=1 label_string=4
+GoBlock dt=1146 reason_string=15 stack=5
+GoUnblock dt=73 g=24 g_seq=27 stack=0
+GoStart dt=4 g=24 g_seq=28
+GoLabel dt=1 label_string=4
+GoUnblock dt=2655 g=81 g_seq=4 stack=12
+GoBlock dt=402 reason_string=15 stack=5
+GoUnblock dt=9 g=24 g_seq=29 stack=0
+GoStart dt=7 g=24 g_seq=30
+GoLabel dt=1 label_string=2
+GoBlock dt=492 reason_string=15 stack=5
+GoUnblock dt=21 g=69 g_seq=27 stack=0
+GoStart dt=6 g=69 g_seq=28
+GoLabel dt=1 label_string=2
+GoBlock dt=20 reason_string=15 stack=5
+GoUnblock dt=11 g=69 g_seq=29 stack=0
+GoStart dt=3 g=69 g_seq=30
+GoLabel dt=1 label_string=2
+GoBlock dt=459 reason_string=15 stack=5
+GoStart dt=168 g=116 g_seq=6
+GCMarkAssistEnd dt=8
+HeapAlloc dt=61 heapalloc_value=192232224
+GCMarkAssistBegin dt=39 stack=3
+GoBlock dt=2360 reason_string=13 stack=11
+ProcStop dt=53
+ProcStart dt=14760 p=10 p_seq=2
+GoStart dt=211 g=99 g_seq=5
+GCMarkAssistBegin dt=93 stack=3
+GoBlock dt=33 reason_string=13 stack=11
+GoStart dt=9 g=120 g_seq=6
+GCMarkAssistBegin dt=78 stack=3
+GoBlock dt=102 reason_string=13 stack=11
+GoStart dt=31 g=108 g_seq=2
+GCMarkAssistEnd dt=6
+HeapAlloc dt=307 heapalloc_value=194853592
+GoStop dt=7166 reason_string=16 stack=6
+GoStart dt=86 g=128 g_seq=6
+HeapAlloc dt=4873 heapalloc_value=196688336
+GoStop dt=12 reason_string=16 stack=6
+ProcStop dt=395
+ProcStart dt=8670 p=3 p_seq=2
+GoStart dt=193 g=93 g_seq=9
+GCMarkAssistEnd dt=7
+HeapAlloc dt=78 heapalloc_value=104465440
+HeapAlloc dt=122 heapalloc_value=104583584
+HeapAlloc dt=92 heapalloc_value=104769312
+HeapAlloc dt=127 heapalloc_value=104935968
+GCSweepBegin dt=109 stack=28
+GCSweepEnd dt=9 swept_value=32768 reclaimed_value=32768
+HeapAlloc dt=2 heapalloc_value=105138720
+HeapAlloc dt=77 heapalloc_value=105373856
+GCSweepBegin dt=157 stack=28
+GCSweepEnd dt=8 swept_value=16384 reclaimed_value=16384
+HeapAlloc dt=3 heapalloc_value=105708448
+GCSweepBegin dt=56 stack=28
+GCSweepEnd dt=11 swept_value=16384 reclaimed_value=16384
+HeapAlloc dt=4 heapalloc_value=105880480
+GCSweepBegin dt=48 stack=28
+GCSweepEnd dt=10 swept_value=32768 reclaimed_value=32768
+HeapAlloc dt=4 heapalloc_value=106124192
+GCSweepBegin dt=79 stack=28
+GCSweepEnd dt=7 swept_value=8192 reclaimed_value=8192
+HeapAlloc dt=2 heapalloc_value=106283168
+HeapAlloc dt=98 heapalloc_value=106567968
+HeapAlloc dt=116 heapalloc_value=107070496
+HeapAlloc dt=30 heapalloc_value=107146272
+HeapAlloc dt=105 heapalloc_value=107517728
+HeapAlloc dt=169 heapalloc_value=108084512
+HeapAlloc dt=187 heapalloc_value=108649888
+HeapAlloc dt=158 heapalloc_value=109200160
+HeapAlloc dt=200 heapalloc_value=109872160
+GCSweepBegin dt=116 stack=28
+GCSweepEnd dt=9 swept_value=24576 reclaimed_value=24576
+HeapAlloc dt=3 heapalloc_value=110229632
+HeapAlloc dt=54 heapalloc_value=110441344
+HeapAlloc dt=76 heapalloc_value=110711680
+HeapAlloc dt=100 heapalloc_value=111216768
+HeapAlloc dt=156 heapalloc_value=111708032
+HeapAlloc dt=55 heapalloc_value=111972224
+HeapAlloc dt=122 heapalloc_value=112391424
+HeapAlloc dt=160 heapalloc_value=113099392
+HeapAlloc dt=191 heapalloc_value=113713536
+HeapAlloc dt=158 heapalloc_value=114362368
+GCSweepBegin dt=88 stack=28
+GCSweepEnd dt=14 swept_value=16384 reclaimed_value=16384
+HeapAlloc dt=9 heapalloc_value=114520320
+HeapAlloc dt=56 heapalloc_value=114636672
+GCSweepBegin dt=180 stack=27
+EventBatch gen=3 m=169390 time=28114950895313 size=834
+ProcStatus dt=1 p=27 pstatus=1
+GoStatus dt=3 g=82 m=169390 gstatus=2
+GCMarkAssistActive dt=1 g=82
+GCMarkAssistEnd dt=2
+HeapAlloc dt=28 heapalloc_value=190143936
+HeapAlloc dt=270 heapalloc_value=190201280
+HeapAlloc dt=96 heapalloc_value=190209472
+HeapAlloc dt=29 heapalloc_value=190258624
+HeapAlloc dt=107 heapalloc_value=190356928
+GCMarkAssistBegin dt=57 stack=3
+GCMarkAssistEnd dt=502
+HeapAlloc dt=27 heapalloc_value=190430656
+GoStop dt=26 reason_string=16 stack=4
+GoStart dt=12 g=131 g_seq=3
+GoSyscallBegin dt=17 p_seq=1 stack=7
+GoSyscallEnd dt=205
+GoSyscallBegin dt=19 p_seq=2 stack=7
+GoSyscallEnd dt=2580
+GoSyscallBegin dt=16 p_seq=3 stack=7
+GoSyscallEnd dt=71
+GoSyscallBegin dt=15 p_seq=4 stack=7
+GoSyscallEnd dt=72
+GoSyscallBegin dt=25 p_seq=5 stack=7
+GoSyscallEnd dt=76
+GoSyscallBegin dt=12 p_seq=6 stack=7
+GoSyscallEnd dt=69
+GoSyscallBegin dt=11 p_seq=7 stack=7
+GoSyscallEnd dt=62
+GoSyscallBegin dt=13 p_seq=8 stack=7
+GoSyscallEnd dt=67
+GoSyscallBegin dt=16 p_seq=9 stack=7
+GoSyscallEnd dt=64
+GoSyscallBegin dt=12 p_seq=10 stack=7
+GoSyscallEnd dt=65
+GoSyscallBegin dt=14 p_seq=11 stack=7
+GoSyscallEnd dt=226
+GoSyscallBegin dt=14 p_seq=12 stack=7
+GoSyscallEnd dt=69
+GoSyscallBegin dt=17 p_seq=13 stack=7
+GoSyscallEnd dt=72
+GoSyscallBegin dt=15 p_seq=14 stack=7
+GoSyscallEnd dt=66
+GoSyscallBegin dt=18 p_seq=15 stack=7
+GoSyscallEnd dt=63
+GoSyscallBegin dt=13 p_seq=16 stack=7
+GoSyscallEnd dt=69
+GoSyscallBegin dt=17 p_seq=17 stack=7
+GoSyscallEnd dt=66
+GoSyscallBegin dt=109 p_seq=18 stack=7
+GoSyscallEnd dt=73
+GoSyscallBegin dt=13 p_seq=19 stack=7
+GoSyscallEnd dt=68
+GoSyscallBegin dt=16 p_seq=20 stack=7
+GoSyscallEnd dt=63
+GoSyscallBegin dt=15 p_seq=21 stack=7
+GoSyscallEnd dt=82
+GoSyscallBegin dt=11 p_seq=22 stack=7
+GoSyscallEnd dt=177
+GoSyscallBegin dt=14 p_seq=23 stack=7
+GoSyscallEnd dt=62
+GoSyscallBegin dt=13 p_seq=24 stack=7
+GoSyscallEnd dt=90
+GoSyscallBegin dt=11 p_seq=25 stack=7
+GoSyscallEnd dt=69
+GoSyscallBegin dt=13 p_seq=26 stack=7
+GoSyscallEnd dt=65
+GoSyscallBegin dt=15 p_seq=27 stack=7
+GoSyscallEnd dt=72
+GoSyscallBegin dt=15 p_seq=28 stack=7
+GoSyscallEnd dt=73
+GoSyscallBegin dt=18 p_seq=29 stack=7
+GoSyscallEnd dt=80
+GoSyscallBegin dt=21 p_seq=30 stack=7
+GoSyscallEnd dt=72
+GoSyscallBegin dt=17 p_seq=31 stack=7
+GoSyscallEnd dt=67
+GoSyscallBegin dt=12 p_seq=32 stack=7
+GoSyscallEnd dt=171
+GoSyscallBegin dt=16 p_seq=33 stack=7
+GoSyscallEnd dt=76
+GoSyscallBegin dt=18 p_seq=34 stack=7
+GoSyscallEnd dt=78
+GoSyscallBegin dt=13 p_seq=35 stack=7
+GoSyscallEnd dt=77
+GoSyscallBegin dt=20 p_seq=36 stack=7
+GoSyscallEnd dt=77
+GoBlock dt=16 reason_string=15 stack=2
+GoUnblock dt=1400 g=54 g_seq=3 stack=0
+GoStart dt=8 g=54 g_seq=4
+GoLabel dt=1 label_string=4
+GoBlock dt=2659 reason_string=15 stack=5
+GoUnblock dt=13 g=22 g_seq=5 stack=0
+GoStart dt=5 g=22 g_seq=6
+GoLabel dt=1 label_string=2
+GoBlock dt=2498 reason_string=15 stack=5
+GoUnblock dt=10 g=22 g_seq=7 stack=0
+GoStart dt=7 g=22 g_seq=8
+GoLabel dt=2 label_string=2
+GoBlock dt=4213 reason_string=15 stack=5
+GoUnblock dt=1324 g=57 g_seq=25 stack=0
+GoStart dt=11 g=57 g_seq=26
+GoLabel dt=1 label_string=4
+GoBlock dt=256 reason_string=15 stack=5
+GoUnblock dt=8 g=57 g_seq=27 stack=0
+GoStart dt=5 g=57 g_seq=28
+GoLabel dt=1 label_string=2
+GoBlock dt=485 reason_string=15 stack=5
+GoUnblock dt=8 g=57 g_seq=29 stack=0
+GoStart dt=6 g=57 g_seq=30
+GoLabel dt=3 label_string=2
+GoBlock dt=504 reason_string=15 stack=5
+ProcStop dt=3771
+ProcStart dt=29 p=27 p_seq=37
+GoUnblock dt=9 g=22 g_seq=15 stack=0
+GoStart dt=5 g=22 g_seq=16
+GoLabel dt=1 label_string=4
+GoBlock dt=123 reason_string=15 stack=5
+GoUnblock dt=19 g=28 g_seq=7 stack=0
+GoStart dt=2 g=28 g_seq=8
+GoLabel dt=1 label_string=2
+GoBlock dt=67 reason_string=15 stack=5
+GoUnblock dt=73 g=72 g_seq=29 stack=0
+GoStart dt=8 g=72 g_seq=30
+GoLabel dt=1 label_string=4
+GoBlock dt=1357 reason_string=15 stack=5
+GoUnblock dt=71 g=53 g_seq=15 stack=0
+GoStart dt=5 g=53 g_seq=16
+GoLabel dt=2 label_string=4
+GoBlock dt=53 reason_string=15 stack=5
+ProcStop dt=61
+ProcStart dt=29 p=27 p_seq=38
+GoUnblock dt=4 g=72 g_seq=35 stack=0
+GoStart dt=4 g=72 g_seq=36
+GoLabel dt=1 label_string=4
+GoBlock dt=775 reason_string=15 stack=5
+GoUnblock dt=11 g=72 g_seq=37 stack=0
+GoStart dt=5 g=72 g_seq=38
+GoLabel dt=3 label_string=2
+GoBlock dt=2553 reason_string=15 stack=5
+GoUnblock dt=23 g=54 g_seq=27 stack=0
+GoStart dt=7 g=54 g_seq=28
+GoLabel dt=1 label_string=2
+GoBlock dt=5185 reason_string=15 stack=5
+ProcStop dt=46
+ProcStart dt=1102 p=27 p_seq=39
+GoUnblock dt=17 g=14 g_seq=31 stack=0
+GoStart dt=191 g=14 g_seq=32
+GoLabel dt=5 label_string=2
+GoBlock dt=26 reason_string=15 stack=5
+GoUnblock dt=7 g=14 g_seq=33 stack=0
+GoStart dt=2 g=14 g_seq=34
+GoLabel dt=1 label_string=2
+GoBlock dt=81 reason_string=15 stack=5
+GoUnblock dt=11 g=14 g_seq=35 stack=0
+GoStart dt=6 g=14 g_seq=36
+GoLabel dt=1 label_string=2
+GoUnblock dt=257 g=97 g_seq=3 stack=12
+GoStop dt=1123 reason_string=16 stack=13
+GoUnblock dt=612 g=131 g_seq=4 stack=0
+GoStart dt=5 g=131 g_seq=5
+GoSyscallBegin dt=23 p_seq=40 stack=7
+GoSyscallEnd dt=200
+GoSyscallBegin dt=13 p_seq=41 stack=7
+GoSyscallEnd dt=179
+GoBlock dt=6 reason_string=15 stack=2
+ProcStop dt=31
+ProcStart dt=1232 p=22 p_seq=3
+GoUnblock dt=16 g=14 g_seq=40 stack=0
+GoStart dt=157 g=14 g_seq=41
+GoLabel dt=2 label_string=2
+GoUnblock dt=343 g=103 g_seq=1 stack=12
+GoBlock dt=2805 reason_string=15 stack=5
+ProcStop dt=68
+ProcStart dt=17 p=22 p_seq=4
+GoUnblock dt=3 g=14 g_seq=42 stack=0
+GoStart dt=4 g=14 g_seq=43
+GoLabel dt=1 label_string=4
+GoUnblock dt=609 g=116 g_seq=7 stack=12
+GoBlock dt=9 reason_string=15 stack=5
+GoStart dt=10 g=116 g_seq=8
+GCMarkAssistEnd dt=7
+HeapAlloc dt=60 heapalloc_value=192527064
+GCMarkAssistBegin dt=41 stack=3
+GoBlock dt=47 reason_string=13 stack=11
+GoUnblock dt=13 g=30 g_seq=35 stack=0
+GoStart dt=4 g=30 g_seq=36
+GoLabel dt=2 label_string=2
+GoBlock dt=266 reason_string=15 stack=5
+GoStart dt=16 g=105 g_seq=8
+GoBlock dt=18 reason_string=13 stack=11
+GoUnblock dt=55 g=54 g_seq=29 stack=0
+GoStart dt=8 g=54 g_seq=30
+GoLabel dt=1 label_string=4
+GoBlock dt=13 reason_string=15 stack=5
+GoUnblock dt=10 g=54 g_seq=31 stack=0
+GoStart dt=1 g=54 g_seq=32
+GoLabel dt=1 label_string=2
+GoBlock dt=46 reason_string=15 stack=5
+ProcStop dt=57
+ProcStart dt=14 p=22 p_seq=5
+GoUnblock dt=4 g=54 g_seq=33 stack=0
+GoStart dt=159 g=54 g_seq=34
+GoLabel dt=1 label_string=4
+GoBlock dt=8 reason_string=15 stack=5
+ProcStop dt=32
+ProcStart dt=3156 p=29 p_seq=1
+GoUnblock dt=15 g=71 g_seq=43 stack=0
+GoStart dt=165 g=71 g_seq=44
+GoLabel dt=1 label_string=2
+GoBlock dt=1463 reason_string=15 stack=5
+GoStart dt=22 g=118 g_seq=4
+GCMarkAssistEnd dt=6
+HeapAlloc dt=903 heapalloc_value=195328728
+GoStop dt=6525 reason_string=16 stack=6
+GoStart dt=46 g=118 g_seq=5
+GCMarkAssistBegin dt=12 stack=3
+GoBlock dt=31 reason_string=13 stack=11
+ProcStop dt=194
+EventBatch gen=3 m=18446744073709551615 time=28114950975784 size=435
+GoStatus dt=1 g=1 m=18446744073709551615 gstatus=4
+GoStatus dt=3 g=2 m=18446744073709551615 gstatus=4
+GoStatus dt=6 g=4 m=18446744073709551615 gstatus=4
+GoStatus dt=5 g=5 m=18446744073709551615 gstatus=4
+GoStatus dt=4 g=6 m=18446744073709551615 gstatus=4
+GoStatus dt=3 g=7 m=18446744073709551615 gstatus=4
+GoStatus dt=3 g=17 m=18446744073709551615 gstatus=4
+GoStatus dt=3 g=33 m=18446744073709551615 gstatus=4
+GoStatus dt=3 g=8 m=18446744073709551615 gstatus=4
+GoStatus dt=3 g=9 m=18446744073709551615 gstatus=4
+GoStatus dt=3 g=10 m=18446744073709551615 gstatus=4
+GoStatus dt=3 g=18 m=18446744073709551615 gstatus=4
+GoStatus dt=3 g=11 m=18446744073709551615 gstatus=4
+GoStatus dt=4 g=34 m=18446744073709551615 gstatus=4
+GoStatus dt=3 g=19 m=18446744073709551615 gstatus=4
+GoStatus dt=3 g=12 m=18446744073709551615 gstatus=4
+GoStatus dt=2 g=20 m=18446744073709551615 gstatus=4
+GoStatus dt=4 g=35 m=18446744073709551615 gstatus=4
+GoStatus dt=3 g=13 m=18446744073709551615 gstatus=4
+GoStatus dt=3 g=21 m=18446744073709551615 gstatus=4
+GoStatus dt=3 g=36 m=18446744073709551615 gstatus=4
+GoStatus dt=3 g=49 m=18446744073709551615 gstatus=4
+GoStatus dt=3 g=50 m=18446744073709551615 gstatus=4
+GoStatus dt=3 g=15 m=18446744073709551615 gstatus=4
+GoStatus dt=4 g=65 m=18446744073709551615 gstatus=4
+GoStatus dt=2 g=66 m=18446744073709551615 gstatus=4
+GoStatus dt=3 g=26 m=18446744073709551615 gstatus=4
+GoStatus dt=4 g=55 m=18446744073709551615 gstatus=4
+GoStatus dt=3 g=27 m=18446744073709551615 gstatus=4
+GoStatus dt=3 g=37 m=18446744073709551615 gstatus=4
+GoStatus dt=3 g=129 m=18446744073709551615 gstatus=4
+EventBatch gen=3 m=18446744073709551615 time=28114950976078 size=1132
+Stacks
+Stack id=20 nframes=2
+	pc=4540421 func=22 file=23 line=363
+	pc=4546157 func=24 file=23 line=874
+Stack id=21 nframes=5
+	pc=4312466 func=25 file=26 line=564
+	pc=4247187 func=27 file=28 line=1333
+	pc=4245160 func=29 file=28 line=1021
+	pc=4502184 func=30 file=31 line=103
+	pc=4804475 func=32 file=33 line=60
+Stack id=18 nframes=6
+	pc=4296626 func=34 file=35 line=807
+	pc=4312466 func=25 file=26 line=564
+	pc=4247187 func=27 file=28 line=1333
+	pc=4245160 func=29 file=28 line=1021
+	pc=4502184 func=30 file=31 line=103
+	pc=4804475 func=32 file=33 line=60
+Stack id=26 nframes=7
+	pc=4300939 func=36 file=35 line=1196
+	pc=4297301 func=34 file=35 line=926
+	pc=4312466 func=25 file=26 line=564
+	pc=4247187 func=27 file=28 line=1333
+	pc=4245160 func=29 file=28 line=1021
+	pc=4502184 func=30 file=31 line=103
+	pc=4804475 func=32 file=33 line=60
+Stack id=7 nframes=7
+	pc=4709082 func=37 file=38 line=964
+	pc=4738119 func=39 file=40 line=209
+	pc=4738111 func=41 file=42 line=736
+	pc=4737664 func=43 file=42 line=380
+	pc=4739536 func=44 file=45 line=46
+	pc=4739528 func=46 file=47 line=183
+	pc=4803162 func=48 file=49 line=134
+Stack id=10 nframes=4
+	pc=4295522 func=50 file=35 line=627
+	pc=4246870 func=29 file=28 line=1288
+	pc=4502184 func=30 file=31 line=103
+	pc=4804475 func=32 file=33 line=60
+Stack id=29 nframes=8
+	pc=4556437 func=51 file=52 line=352
+	pc=4341796 func=53 file=54 line=521
+	pc=4279859 func=55 file=56 line=127
+	pc=4277746 func=57 file=58 line=182
+	pc=4244580 func=59 file=28 line=944
+	pc=4245653 func=29 file=28 line=1116
+	pc=4502184 func=30 file=31 line=103
+	pc=4804475 func=32 file=33 line=60
+Stack id=14 nframes=1
+	pc=4546157 func=24 file=23 line=874
+Stack id=17 nframes=1
+	pc=0 func=0 file=0 line=0
+Stack id=19 nframes=2
+	pc=4540420 func=22 file=23 line=353
+	pc=4546157 func=24 file=23 line=874
+Stack id=13 nframes=1
+	pc=0 func=0 file=0 line=0
+Stack id=5 nframes=2
+	pc=4418893 func=60 file=61 line=402
+	pc=4301860 func=62 file=35 line=1297
+Stack id=25 nframes=7
+	pc=4298957 func=36 file=35 line=1087
+	pc=4297301 func=34 file=35 line=926
+	pc=4312466 func=25 file=26 line=564
+	pc=4247187 func=27 file=28 line=1333
+	pc=4245160 func=29 file=28 line=1021
+	pc=4502184 func=30 file=31 line=103
+	pc=4804475 func=32 file=33 line=60
+Stack id=4 nframes=2
+	pc=4502184 func=30 file=31 line=103
+	pc=4804475 func=32 file=33 line=60
+Stack id=30 nframes=6
+	pc=4297308 func=34 file=35 line=817
+	pc=4312466 func=25 file=26 line=564
+	pc=4247187 func=27 file=28 line=1333
+	pc=4245160 func=29 file=28 line=1021
+	pc=4502184 func=30 file=31 line=103
+	pc=4804475 func=32 file=33 line=60
+Stack id=11 nframes=6
+	pc=4314276 func=63 file=26 line=749
+	pc=4312530 func=25 file=26 line=589
+	pc=4247187 func=27 file=28 line=1333
+	pc=4245160 func=29 file=28 line=1021
+	pc=4502184 func=30 file=31 line=103
+	pc=4804475 func=32 file=33 line=60
+Stack id=6 nframes=2
+	pc=4502184 func=30 file=31 line=103
+	pc=4804475 func=32 file=33 line=60
+Stack id=15 nframes=1
+	pc=4546157 func=24 file=23 line=874
+Stack id=8 nframes=1
+	pc=0 func=0 file=0 line=0
+Stack id=12 nframes=2
+	pc=4614055 func=64 file=65 line=474
+	pc=4302129 func=62 file=35 line=1357
+Stack id=3 nframes=6
+	pc=4556897 func=66 file=52 line=378
+	pc=4312252 func=25 file=26 line=536
+	pc=4247187 func=27 file=28 line=1333
+	pc=4245160 func=29 file=28 line=1021
+	pc=4502184 func=30 file=31 line=103
+	pc=4804475 func=32 file=33 line=60
+Stack id=9 nframes=5
+	pc=4312495 func=25 file=26 line=576
+	pc=4247187 func=27 file=28 line=1333
+	pc=4245160 func=29 file=28 line=1021
+	pc=4502184 func=30 file=31 line=103
+	pc=4804475 func=32 file=33 line=60
+Stack id=24 nframes=8
+	pc=4614055 func=64 file=65 line=474
+	pc=4298031 func=36 file=35 line=964
+	pc=4297301 func=34 file=35 line=926
+	pc=4312466 func=25 file=26 line=564
+	pc=4247187 func=27 file=28 line=1333
+	pc=4245160 func=29 file=28 line=1021
+	pc=4502184 func=30 file=31 line=103
+	pc=4804475 func=32 file=33 line=60
+Stack id=23 nframes=6
+	pc=4297239 func=34 file=35 line=914
+	pc=4312466 func=25 file=26 line=564
+	pc=4247187 func=27 file=28 line=1333
+	pc=4245160 func=29 file=28 line=1021
+	pc=4502184 func=30 file=31 line=103
+	pc=4804475 func=32 file=33 line=60
+Stack id=2 nframes=1
+	pc=4803172 func=48 file=49 line=130
+Stack id=28 nframes=8
+	pc=4556437 func=51 file=52 line=352
+	pc=4341796 func=53 file=54 line=521
+	pc=4280028 func=55 file=56 line=147
+	pc=4277746 func=57 file=58 line=182
+	pc=4244580 func=59 file=28 line=944
+	pc=4246070 func=29 file=28 line=1145
+	pc=4502184 func=30 file=31 line=103
+	pc=4804475 func=32 file=33 line=60
+Stack id=27 nframes=5
+	pc=4353658 func=67 file=68 line=958
+	pc=4278148 func=69 file=58 line=234
+	pc=4246244 func=29 file=28 line=1160
+	pc=4502184 func=30 file=31 line=103
+	pc=4804475 func=32 file=33 line=60
+Stack id=16 nframes=3
+	pc=4217457 func=70 file=71 line=442
+	pc=4546317 func=72 file=23 line=918
+	pc=4546150 func=24 file=23 line=871
+Stack id=31 nframes=8
+	pc=4353658 func=67 file=68 line=958
+	pc=4280657 func=73 file=56 line=254
+	pc=4280247 func=55 file=56 line=170
+	pc=4277746 func=57 file=58 line=182
+	pc=4244580 func=59 file=28 line=944
+	pc=4246070 func=29 file=28 line=1145
+	pc=4502184 func=30 file=31 line=103
+	pc=4804475 func=32 file=33 line=60
+Stack id=1 nframes=3
+	pc=4554859 func=74 file=52 line=255
+	pc=4540633 func=22 file=23 line=391
+	pc=4546157 func=24 file=23 line=874
+Stack id=22 nframes=10
+	pc=4558967 func=75 file=76 line=166
+	pc=4558898 func=77 file=52 line=445
+	pc=4447453 func=78 file=61 line=3712
+	pc=4314041 func=79 file=26 line=714
+	pc=4297238 func=34 file=35 line=909
+	pc=4312466 func=25 file=26 line=564
+	pc=4247187 func=27 file=28 line=1333
+	pc=4245160 func=29 file=28 line=1021
+	pc=4502184 func=30 file=31 line=103
+	pc=4804475 func=32 file=33 line=60
+EventBatch gen=3 m=18446744073709551615 time=28114950894688 size=2762
+Strings
+String id=1
+	data="Not worker"
+String id=2
+	data="GC (dedicated)"
+String id=3
+	data="GC (fractional)"
+String id=4
+	data="GC (idle)"
+String id=5
+	data="unspecified"
+String id=6
+	data="forever"
+String id=7
+	data="network"
+String id=8
+	data="select"
+String id=9
+	data="sync.(*Cond).Wait"
+String id=10
+	data="sync"
+String id=11
+	data="chan send"
+String id=12
+	data="chan receive"
+String id=13
+	data="GC mark assist wait for work"
+String id=14
+	data="GC background sweeper wait"
+String id=15
+	data="system goroutine wait"
+String id=16
+	data="preempted"
+String id=17
+	data="wait for debug call"
+String id=18
+	data="wait until GC ends"
+String id=19
+	data="sleep"
+String id=20
+	data="runtime.GoSched"
+String id=21
+	data="GC mark termination"
+String id=22
+	data="runtime.traceAdvance"
+String id=23
+	data="/usr/local/google/home/mknyszek/work/go-1/src/runtime/trace2.go"
+String id=24
+	data="runtime.(*traceAdvancerState).start.func1"
+String id=25
+	data="runtime.gcAssistAlloc"
+String id=26
+	data="/usr/local/google/home/mknyszek/work/go-1/src/runtime/mgcmark.go"
+String id=27
+	data="runtime.deductAssistCredit"
+String id=28
+	data="/usr/local/google/home/mknyszek/work/go-1/src/runtime/malloc.go"
+String id=29
+	data="runtime.mallocgc"
+String id=30
+	data="runtime.makeslice"
+String id=31
+	data="/usr/local/google/home/mknyszek/work/go-1/src/runtime/slice.go"
+String id=32
+	data="main.main.func1"
+String id=33
+	data="/usr/local/google/home/mknyszek/work/go-1/src/internal/trace/v2/testdata/testprog/gc-stress.go"
+String id=34
+	data="runtime.gcMarkDone"
+String id=35
+	data="/usr/local/google/home/mknyszek/work/go-1/src/runtime/mgc.go"
+String id=36
+	data="runtime.gcMarkTermination"
+String id=37
+	data="syscall.write"
+String id=38
+	data="/usr/local/google/home/mknyszek/work/go-1/src/syscall/zsyscall_linux_amd64.go"
+String id=39
+	data="syscall.Write"
+String id=40
+	data="/usr/local/google/home/mknyszek/work/go-1/src/syscall/syscall_unix.go"
+String id=41
+	data="internal/poll.ignoringEINTRIO"
+String id=42
+	data="/usr/local/google/home/mknyszek/work/go-1/src/internal/poll/fd_unix.go"
+String id=43
+	data="internal/poll.(*FD).Write"
+String id=44
+	data="os.(*File).write"
+String id=45
+	data="/usr/local/google/home/mknyszek/work/go-1/src/os/file_posix.go"
+String id=46
+	data="os.(*File).Write"
+String id=47
+	data="/usr/local/google/home/mknyszek/work/go-1/src/os/file.go"
+String id=48
+	data="runtime/trace.Start.func1"
+String id=49
+	data="/usr/local/google/home/mknyszek/work/go-1/src/runtime/trace/trace.go"
+String id=50
+	data="runtime.gcStart"
+String id=51
+	data="runtime.traceLocker.GCSweepSpan"
+String id=52
+	data="/usr/local/google/home/mknyszek/work/go-1/src/runtime/trace2runtime.go"
+String id=53
+	data="runtime.(*sweepLocked).sweep"
+String id=54
+	data="/usr/local/google/home/mknyszek/work/go-1/src/runtime/mgcsweep.go"
+String id=55
+	data="runtime.(*mcentral).cacheSpan"
+String id=56
+	data="/usr/local/google/home/mknyszek/work/go-1/src/runtime/mcentral.go"
+String id=57
+	data="runtime.(*mcache).refill"
+String id=58
+	data="/usr/local/google/home/mknyszek/work/go-1/src/runtime/mcache.go"
+String id=59
+	data="runtime.(*mcache).nextFree"
+String id=60
+	data="runtime.gopark"
+String id=61
+	data="/usr/local/google/home/mknyszek/work/go-1/src/runtime/proc.go"
+String id=62
+	data="runtime.gcBgMarkWorker"
+String id=63
+	data="runtime.gcParkAssist"
+String id=64
+	data="runtime.systemstack_switch"
+String id=65
+	data="/usr/local/google/home/mknyszek/work/go-1/src/runtime/asm_amd64.s"
+String id=66
+	data="runtime.traceLocker.GCMarkAssistStart"
+String id=67
+	data="runtime.(*mheap).alloc"
+String id=68
+	data="/usr/local/google/home/mknyszek/work/go-1/src/runtime/mheap.go"
+String id=69
+	data="runtime.(*mcache).allocLarge"
+String id=70
+	data="runtime.chanrecv1"
+String id=71
+	data="/usr/local/google/home/mknyszek/work/go-1/src/runtime/chan.go"
+String id=72
+	data="runtime.(*wakeableSleep).sleep"
+String id=73
+	data="runtime.(*mcentral).grow"
+String id=74
+	data="runtime.traceLocker.Gomaxprocs"
+String id=75
+	data="runtime.traceLocker.stack"
+String id=76
+	data="/usr/local/google/home/mknyszek/work/go-1/src/runtime/trace2event.go"
+String id=77
+	data="runtime.traceLocker.GoUnpark"
+String id=78
+	data="runtime.injectglist"
+String id=79
+	data="runtime.gcWakeAllAssists"
diff --git a/trace/testdata/tests/go122-go-create-without-running-g.test b/trace/testdata/tests/go122-go-create-without-running-g.test
new file mode 100644
index 0000000..494c444
--- /dev/null
+++ b/trace/testdata/tests/go122-go-create-without-running-g.test
@@ -0,0 +1,17 @@
+-- expect --
+SUCCESS
+-- trace --
+Trace Go1.22
+EventBatch gen=1 m=0 time=0 size=17
+ProcStatus dt=1 p=0 pstatus=1
+GoCreate dt=1 new_g=5 new_stack=0 stack=0
+GoStart dt=1 g=5 g_seq=1
+GoStop dt=1 reason_string=1 stack=0
+EventBatch gen=1 m=18446744073709551615 time=0 size=5
+Frequency freq=15625000
+EventBatch gen=1 m=18446744073709551615 time=0 size=1
+Stacks
+EventBatch gen=1 m=18446744073709551615 time=0 size=12
+Strings
+String id=1
+	data="whatever"
diff --git a/trace/testdata/tests/go122-syscall-steal-proc-ambiguous.test b/trace/testdata/tests/go122-syscall-steal-proc-ambiguous.test
new file mode 100644
index 0000000..0d88af4
--- /dev/null
+++ b/trace/testdata/tests/go122-syscall-steal-proc-ambiguous.test
@@ -0,0 +1,21 @@
+-- expect --
+SUCCESS
+-- trace --
+Trace Go1.22
+EventBatch gen=1 m=0 time=0 size=21
+ProcStatus dt=0 p=0 pstatus=1
+GoStatus dt=0 g=1 m=0 gstatus=2
+GoSyscallBegin dt=0 p_seq=1 stack=0
+GoSyscallEnd dt=0
+GoSyscallBegin dt=0 p_seq=2 stack=0
+GoSyscallEndBlocked dt=0
+EventBatch gen=1 m=1 time=0 size=14
+ProcStatus dt=0 p=2 pstatus=1
+GoStatus dt=0 g=2 m=1 gstatus=2
+ProcSteal dt=0 p=0 p_seq=3 m=0
+EventBatch gen=1 m=18446744073709551615 time=0 size=5
+Frequency freq=15625000
+EventBatch gen=1 m=18446744073709551615 time=0 size=1
+Stacks
+EventBatch gen=1 m=18446744073709551615 time=0 size=1
+Strings
diff --git a/trace/testdata/tests/go122-syscall-steal-proc-gen-boundary-bare-m.test b/trace/testdata/tests/go122-syscall-steal-proc-gen-boundary-bare-m.test
new file mode 100644
index 0000000..bbfc9cc
--- /dev/null
+++ b/trace/testdata/tests/go122-syscall-steal-proc-gen-boundary-bare-m.test
@@ -0,0 +1,17 @@
+-- expect --
+SUCCESS
+-- trace --
+Trace Go1.22
+EventBatch gen=1 m=0 time=0 size=11
+ProcStatus dt=1 p=1 pstatus=1
+GoStatus dt=1 g=1 m=0 gstatus=3
+GoSyscallEndBlocked dt=1
+EventBatch gen=1 m=1 time=0 size=9
+ProcStatus dt=1 p=0 pstatus=4
+ProcSteal dt=1 p=0 p_seq=1 m=0
+EventBatch gen=1 m=18446744073709551615 time=0 size=5
+Frequency freq=15625000
+EventBatch gen=1 m=18446744073709551615 time=0 size=1
+Stacks
+EventBatch gen=1 m=18446744073709551615 time=0 size=1
+Strings
diff --git a/trace/testdata/tests/go122-syscall-steal-proc-gen-boundary-reacquire-new-proc-bare-m.test b/trace/testdata/tests/go122-syscall-steal-proc-gen-boundary-reacquire-new-proc-bare-m.test
new file mode 100644
index 0000000..8e29132
--- /dev/null
+++ b/trace/testdata/tests/go122-syscall-steal-proc-gen-boundary-reacquire-new-proc-bare-m.test
@@ -0,0 +1,18 @@
+-- expect --
+SUCCESS
+-- trace --
+Trace Go1.22
+EventBatch gen=1 m=0 time=0 size=15
+GoStatus dt=1 g=1 m=0 gstatus=3
+ProcStatus dt=1 p=1 pstatus=2
+ProcStart dt=1 p=1 p_seq=1
+GoSyscallEndBlocked dt=1
+EventBatch gen=1 m=1 time=0 size=9
+ProcStatus dt=1 p=0 pstatus=4
+ProcSteal dt=1 p=0 p_seq=1 m=0
+EventBatch gen=1 m=18446744073709551615 time=0 size=5
+Frequency freq=15625000
+EventBatch gen=1 m=18446744073709551615 time=0 size=1
+Stacks
+EventBatch gen=1 m=18446744073709551615 time=0 size=1
+Strings
diff --git a/trace/testdata/tests/go122-syscall-steal-proc-gen-boundary-reacquire-new-proc.test b/trace/testdata/tests/go122-syscall-steal-proc-gen-boundary-reacquire-new-proc.test
new file mode 100644
index 0000000..3b26e8f
--- /dev/null
+++ b/trace/testdata/tests/go122-syscall-steal-proc-gen-boundary-reacquire-new-proc.test
@@ -0,0 +1,20 @@
+-- expect --
+SUCCESS
+-- trace --
+Trace Go1.22
+EventBatch gen=1 m=0 time=0 size=15
+GoStatus dt=1 g=1 m=0 gstatus=3
+ProcStatus dt=1 p=1 pstatus=2
+ProcStart dt=1 p=1 p_seq=1
+GoSyscallEndBlocked dt=1
+EventBatch gen=1 m=1 time=0 size=18
+ProcStatus dt=1 p=2 pstatus=1
+GoStatus dt=1 g=2 m=1 gstatus=2
+ProcStatus dt=1 p=0 pstatus=4
+ProcSteal dt=1 p=0 p_seq=1 m=0
+EventBatch gen=1 m=18446744073709551615 time=0 size=5
+Frequency freq=15625000
+EventBatch gen=1 m=18446744073709551615 time=0 size=1
+Stacks
+EventBatch gen=1 m=18446744073709551615 time=0 size=1
+Strings
diff --git a/trace/testdata/tests/go122-syscall-steal-proc-gen-boundary.test b/trace/testdata/tests/go122-syscall-steal-proc-gen-boundary.test
new file mode 100644
index 0000000..133d8a5
--- /dev/null
+++ b/trace/testdata/tests/go122-syscall-steal-proc-gen-boundary.test
@@ -0,0 +1,19 @@
+-- expect --
+SUCCESS
+-- trace --
+Trace Go1.22
+EventBatch gen=1 m=0 time=0 size=11
+ProcStatus dt=1 p=1 pstatus=1
+GoStatus dt=1 g=1 m=0 gstatus=3
+GoSyscallEndBlocked dt=1
+EventBatch gen=1 m=1 time=0 size=18
+ProcStatus dt=1 p=2 pstatus=1
+GoStatus dt=1 g=2 m=1 gstatus=2
+ProcStatus dt=1 p=0 pstatus=4
+ProcSteal dt=1 p=0 p_seq=1 m=0
+EventBatch gen=1 m=18446744073709551615 time=0 size=5
+Frequency freq=15625000
+EventBatch gen=1 m=18446744073709551615 time=0 size=1
+Stacks
+EventBatch gen=1 m=18446744073709551615 time=0 size=1
+Strings
diff --git a/trace/testdata/tests/go122-syscall-steal-proc-reacquire-new-proc-bare-m.test b/trace/testdata/tests/go122-syscall-steal-proc-reacquire-new-proc-bare-m.test
new file mode 100644
index 0000000..fa68c82
--- /dev/null
+++ b/trace/testdata/tests/go122-syscall-steal-proc-reacquire-new-proc-bare-m.test
@@ -0,0 +1,19 @@
+-- expect --
+SUCCESS
+-- trace --
+Trace Go1.22
+EventBatch gen=1 m=0 time=0 size=23
+ProcStatus dt=1 p=1 pstatus=2
+ProcStatus dt=1 p=0 pstatus=1
+GoStatus dt=1 g=1 m=0 gstatus=2
+GoSyscallBegin dt=1 p_seq=1 stack=0
+ProcStart dt=1 p=1 p_seq=1
+GoSyscallEndBlocked dt=1
+EventBatch gen=1 m=1 time=0 size=5
+ProcSteal dt=1 p=0 p_seq=2 m=0
+EventBatch gen=1 m=18446744073709551615 time=0 size=5
+Frequency freq=15625000
+EventBatch gen=1 m=18446744073709551615 time=0 size=1
+Stacks
+EventBatch gen=1 m=18446744073709551615 time=0 size=1
+Strings
diff --git a/trace/testdata/tests/go122-syscall-steal-proc-reacquire-new-proc.test b/trace/testdata/tests/go122-syscall-steal-proc-reacquire-new-proc.test
new file mode 100644
index 0000000..85c19fc
--- /dev/null
+++ b/trace/testdata/tests/go122-syscall-steal-proc-reacquire-new-proc.test
@@ -0,0 +1,21 @@
+-- expect --
+SUCCESS
+-- trace --
+Trace Go1.22
+EventBatch gen=1 m=0 time=0 size=23
+ProcStatus dt=1 p=1 pstatus=2
+ProcStatus dt=1 p=0 pstatus=1
+GoStatus dt=1 g=1 m=0 gstatus=2
+GoSyscallBegin dt=1 p_seq=1 stack=0
+ProcStart dt=1 p=1 p_seq=1
+GoSyscallEndBlocked dt=1
+EventBatch gen=1 m=1 time=0 size=14
+ProcStatus dt=1 p=2 pstatus=1
+GoStatus dt=1 g=2 m=1 gstatus=2
+ProcSteal dt=1 p=0 p_seq=2 m=0
+EventBatch gen=1 m=18446744073709551615 time=0 size=5
+Frequency freq=15625000
+EventBatch gen=1 m=18446744073709551615 time=0 size=1
+Stacks
+EventBatch gen=1 m=18446744073709551615 time=0 size=1
+Strings
diff --git a/trace/testdata/tests/go122-syscall-steal-proc-self.test b/trace/testdata/tests/go122-syscall-steal-proc-self.test
new file mode 100644
index 0000000..6484eb6
--- /dev/null
+++ b/trace/testdata/tests/go122-syscall-steal-proc-self.test
@@ -0,0 +1,17 @@
+-- expect --
+SUCCESS
+-- trace --
+Trace Go1.22
+EventBatch gen=1 m=0 time=0 size=24
+ProcStatus dt=0 p=0 pstatus=1
+GoStatus dt=0 g=1 m=0 gstatus=2
+GoSyscallBegin dt=0 p_seq=1 stack=0
+ProcSteal dt=0 p=0 p_seq=2 m=0
+ProcStart dt=0 p=0 p_seq=3
+GoSyscallEndBlocked dt=0
+EventBatch gen=1 m=18446744073709551615 time=0 size=5
+Frequency freq=15625000
+EventBatch gen=1 m=18446744073709551615 time=0 size=1
+Stacks
+EventBatch gen=1 m=18446744073709551615 time=0 size=1
+Strings
diff --git a/trace/testdata/tests/go122-syscall-steal-proc-simple-bare-m.test b/trace/testdata/tests/go122-syscall-steal-proc-simple-bare-m.test
new file mode 100644
index 0000000..d338722
--- /dev/null
+++ b/trace/testdata/tests/go122-syscall-steal-proc-simple-bare-m.test
@@ -0,0 +1,17 @@
+-- expect --
+SUCCESS
+-- trace --
+Trace Go1.22
+EventBatch gen=1 m=0 time=0 size=15
+ProcStatus dt=1 p=0 pstatus=1
+GoStatus dt=1 g=1 m=0 gstatus=2
+GoSyscallBegin dt=1 p_seq=1 stack=0
+GoSyscallEndBlocked dt=1
+EventBatch gen=1 m=1 time=0 size=5
+ProcSteal dt=1 p=0 p_seq=2 m=0
+EventBatch gen=1 m=18446744073709551615 time=0 size=5
+Frequency freq=15625000
+EventBatch gen=1 m=18446744073709551615 time=0 size=1
+Stacks
+EventBatch gen=1 m=18446744073709551615 time=0 size=1
+Strings
diff --git a/trace/testdata/tests/go122-syscall-steal-proc-simple.test b/trace/testdata/tests/go122-syscall-steal-proc-simple.test
new file mode 100644
index 0000000..a1f9db4
--- /dev/null
+++ b/trace/testdata/tests/go122-syscall-steal-proc-simple.test
@@ -0,0 +1,19 @@
+-- expect --
+SUCCESS
+-- trace --
+Trace Go1.22
+EventBatch gen=1 m=0 time=0 size=15
+ProcStatus dt=1 p=0 pstatus=1
+GoStatus dt=1 g=1 m=0 gstatus=2
+GoSyscallBegin dt=1 p_seq=1 stack=0
+GoSyscallEndBlocked dt=1
+EventBatch gen=1 m=1 time=0 size=14
+ProcStatus dt=1 p=2 pstatus=1
+GoStatus dt=1 g=2 m=1 gstatus=2
+ProcSteal dt=1 p=0 p_seq=2 m=0
+EventBatch gen=1 m=18446744073709551615 time=0 size=5
+Frequency freq=15625000
+EventBatch gen=1 m=18446744073709551615 time=0 size=1
+Stacks
+EventBatch gen=1 m=18446744073709551615 time=0 size=1
+Strings
diff --git a/trace/testdata/tests/go122-syscall-steal-proc-sitting-in-syscall.test b/trace/testdata/tests/go122-syscall-steal-proc-sitting-in-syscall.test
new file mode 100644
index 0000000..58c41c5
--- /dev/null
+++ b/trace/testdata/tests/go122-syscall-steal-proc-sitting-in-syscall.test
@@ -0,0 +1,15 @@
+-- expect --
+SUCCESS
+-- trace --
+Trace Go1.22
+EventBatch gen=1 m=0 time=0 size=9
+ProcStatus dt=1 p=0 pstatus=4
+ProcSteal dt=1 p=0 p_seq=1 m=1
+EventBatch gen=1 m=18446744073709551615 time=0 size=5
+GoStatus dt=1 g=1 m=1 gstatus=3
+EventBatch gen=1 m=18446744073709551615 time=0 size=5
+Frequency freq=15625000
+EventBatch gen=1 m=18446744073709551615 time=0 size=1
+Stacks
+EventBatch gen=1 m=18446744073709551615 time=0 size=1
+Strings
diff --git a/trace/testdata/tests/go122-task-across-generations.test b/trace/testdata/tests/go122-task-across-generations.test
new file mode 100644
index 0000000..0b8abd7
--- /dev/null
+++ b/trace/testdata/tests/go122-task-across-generations.test
@@ -0,0 +1,26 @@
+-- expect --
+SUCCESS
+-- trace --
+Trace Go1.22
+EventBatch gen=1 m=0 time=0 size=15
+ProcStatus dt=1 p=0 pstatus=1
+GoStatus dt=1 g=1 m=0 gstatus=2
+UserTaskBegin dt=1 task=2 parent_task=0 name_string=1 stack=0
+EventBatch gen=1 m=18446744073709551615 time=0 size=5
+Frequency freq=15625000
+EventBatch gen=1 m=18446744073709551615 time=0 size=1
+Stacks
+EventBatch gen=1 m=18446744073709551615 time=0 size=11
+Strings
+String id=1
+	data="my task"
+EventBatch gen=2 m=0 time=5 size=13
+ProcStatus dt=1 p=0 pstatus=1
+GoStatus dt=1 g=1 m=0 gstatus=2
+UserTaskEnd dt=1 task=2 stack=0
+EventBatch gen=2 m=18446744073709551615 time=0 size=5
+Frequency freq=15625000
+EventBatch gen=2 m=18446744073709551615 time=0 size=1
+Stacks
+EventBatch gen=2 m=18446744073709551615 time=0 size=1
+Strings
diff --git a/trace/value.go b/trace/value.go
new file mode 100644
index 0000000..629269a
--- /dev/null
+++ b/trace/value.go
@@ -0,0 +1,57 @@
+// Copyright 2023 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.
+
+// Code generated by "gen.bash" from internal/trace/v2; DO NOT EDIT.
+
+//go:build go1.21
+
+package trace
+
+import "fmt"
+
+// Value is a dynamically-typed value obtained from a trace.
+type Value struct {
+	kind   ValueKind
+	scalar uint64
+}
+
+// ValueKind is the type of a dynamically-typed value from a trace.
+type ValueKind uint8
+
+const (
+	ValueBad ValueKind = iota
+	ValueUint64
+)
+
+// Kind returns the ValueKind of the value.
+//
+// It represents the underlying structure of the value.
+//
+// New ValueKinds may be added in the future. Users of this type must be robust
+// to that possibility.
+func (v Value) Kind() ValueKind {
+	return v.kind
+}
+
+// Uint64 returns the uint64 value for a MetricSampleUint64.
+//
+// Panics if this metric sample's Kind is not MetricSampleUint64.
+func (v Value) Uint64() uint64 {
+	if v.kind != ValueUint64 {
+		panic("Uint64 called on Value of a different Kind")
+	}
+	return v.scalar
+}
+
+// valueAsString produces a debug string value.
+//
+// This isn't just Value.String because we may want to use that to store
+// string values in the future.
+func valueAsString(v Value) string {
+	switch v.Kind() {
+	case ValueUint64:
+		return fmt.Sprintf("Uint64(%d)", v.scalar)
+	}
+	return "Bad"
+}