]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/trace: add almost full support for v2 traces in the trace viewer
authorMichael Anthony Knyszek <mknyszek@google.com>
Tue, 14 Nov 2023 17:03:24 +0000 (17:03 +0000)
committerGopher Robot <gobot@golang.org>
Tue, 21 Nov 2023 20:45:06 +0000 (20:45 +0000)
This change refactors the cmd/trace package and adds most of the support
for v2 traces.

The following features of note are missing in this CL and will be
implemented in follow-up CLs:
- The focustask filter for the trace viewer
- The taskid filter for the trace viewer
- The goid filter for the trace viewer
- Pprof profiles
- The MMU graph
- The goroutine analysis pages
- The task analysis pages
- The region analysis pages

This CL makes one notable change to the trace CLI: it makes the -d flag
accept an integer to set the debug mode. For old traces -d != 0 works
just like -d. For new traces -d=1 means the high-level events and -d=2
means the low-level events.

Thanks to Felix Geisendörfer (felix.geisendoerfer@datadoghq.com) for
doing a lot of work on this CL; I picked this up from him and got a
massive headstart as a result.

For #60773.
For #63960.

Change-Id: I3626e22473227c5980134a85f1bb6a845f567b1b
Reviewed-on: https://go-review.googlesource.com/c/go/+/542218
Reviewed-by: Michael Pratt <mpratt@google.com>
Auto-Submit: Michael Knyszek <mknyszek@google.com>
TryBot-Bypass: Michael Knyszek <mknyszek@google.com>

26 files changed:
src/cmd/go/internal/trace/trace.go
src/cmd/trace/main.go
src/cmd/trace/mmu.go
src/cmd/trace/trace.go
src/cmd/trace/trace_test.go
src/cmd/trace/trace_unix_test.go
src/cmd/trace/v2/gen.go [new file with mode: 0644]
src/cmd/trace/v2/gstate.go [new file with mode: 0644]
src/cmd/trace/v2/jsontrace.go [new file with mode: 0644]
src/cmd/trace/v2/jsontrace_test.go [new file with mode: 0644]
src/cmd/trace/v2/main.go [new file with mode: 0644]
src/cmd/trace/v2/procgen.go [new file with mode: 0644]
src/cmd/trace/v2/testdata/generate.go [new file with mode: 0644]
src/cmd/trace/v2/testdata/go122.test [new file with mode: 0644]
src/cmd/trace/v2/testdata/mktests.go [new file with mode: 0644]
src/cmd/trace/v2/testdata/testprog/main.go [new file with mode: 0644]
src/cmd/trace/v2/viewer.go [new file with mode: 0644]
src/go/build/deps_test.go
src/internal/trace/parser.go
src/internal/trace/traceviewer/emitter.go [new file with mode: 0644]
src/internal/trace/traceviewer/format/format.go [moved from src/cmd/internal/traceviewer/format.go with 60% similarity]
src/internal/trace/traceviewer/http.go [new file with mode: 0644]
src/internal/trace/traceviewer/static/README.md [moved from src/cmd/trace/static/README.md with 100% similarity]
src/internal/trace/traceviewer/static/trace_viewer_full.html [moved from src/cmd/trace/static/trace_viewer_full.html with 100% similarity]
src/internal/trace/traceviewer/static/webcomponents.min.js [moved from src/cmd/trace/static/webcomponents.min.js with 100% similarity]
src/internal/trace/v2/version/version.go

index 17d3ee9e7fda99c2c244dbc46361e3857dedbbb2..f96aa40002e76f0769e5d4869c72a0bc1d05346f 100644 (file)
@@ -5,10 +5,10 @@
 package trace
 
 import (
-       "cmd/internal/traceviewer"
        "context"
        "encoding/json"
        "errors"
+       "internal/trace/traceviewer/format"
        "os"
        "strings"
        "sync/atomic"
@@ -47,7 +47,7 @@ func StartSpan(ctx context.Context, name string) (context.Context, *Span) {
                return ctx, nil
        }
        childSpan := &Span{t: tc.t, name: name, tid: tc.tid, start: time.Now()}
-       tc.t.writeEvent(&traceviewer.Event{
+       tc.t.writeEvent(&format.Event{
                Name:  childSpan.name,
                Time:  float64(childSpan.start.UnixNano()) / float64(time.Microsecond),
                TID:   childSpan.tid,
@@ -77,7 +77,7 @@ func Flow(ctx context.Context, from *Span, to *Span) {
        }
 
        id := tc.t.getNextFlowID()
-       tc.t.writeEvent(&traceviewer.Event{
+       tc.t.writeEvent(&format.Event{
                Name:     from.name + " -> " + to.name,
                Category: "flow",
                ID:       id,
@@ -85,7 +85,7 @@ func Flow(ctx context.Context, from *Span, to *Span) {
                Phase:    phaseFlowStart,
                TID:      from.tid,
        })
-       tc.t.writeEvent(&traceviewer.Event{
+       tc.t.writeEvent(&format.Event{
                Name:      from.name + " -> " + to.name,
                Category:  "flow", // TODO(matloob): Add Category to Flow?
                ID:        id,
@@ -110,7 +110,7 @@ func (s *Span) Done() {
                return
        }
        s.end = time.Now()
-       s.t.writeEvent(&traceviewer.Event{
+       s.t.writeEvent(&format.Event{
                Name:  s.name,
                Time:  float64(s.end.UnixNano()) / float64(time.Microsecond),
                TID:   s.tid,
@@ -125,7 +125,7 @@ type tracer struct {
        nextFlowID atomic.Uint64
 }
 
-func (t *tracer) writeEvent(ev *traceviewer.Event) error {
+func (t *tracer) writeEvent(ev *format.Event) error {
        f := <-t.file
        defer func() { t.file <- f }()
        var err error
index 9e9e7f3e49e0f431ea0ff57df8d2e7137b831605..b269050499c7db217f36db0bc7e6ad565d1e4705 100644 (file)
@@ -7,10 +7,11 @@ package main
 import (
        "bufio"
        "cmd/internal/browser"
+       cmdv2 "cmd/trace/v2"
        "flag"
        "fmt"
-       "html/template"
        "internal/trace"
+       "internal/trace/traceviewer"
        "io"
        "log"
        "net"
@@ -46,7 +47,7 @@ Supported profile types are:
 Flags:
        -http=addr: HTTP service address (e.g., ':6060')
        -pprof=type: print a pprof-like profile instead
-       -d: print debug info such as parsed events
+       -d=int: print debug info such as parsed events (1 for high-level, 2 for low-level)
 
 Note that while the various profiles available when launching
 'go tool trace' work on every browser, the trace viewer itself
@@ -57,7 +58,7 @@ and is only actively tested on that browser.
 var (
        httpFlag  = flag.String("http", "localhost:0", "HTTP service address (e.g., ':6060')")
        pprofFlag = flag.String("pprof", "", "print a pprof-like profile instead")
-       debugFlag = flag.Bool("d", false, "print debug information such as parsed events list")
+       debugFlag = flag.Int("d", 0, "print debug information (1 for basic debug info, 2 for lower-level info)")
 
        // The binary file name, left here for serveSVGProfile.
        programBinary string
@@ -83,6 +84,13 @@ func main() {
                flag.Usage()
        }
 
+       if isTraceV2(traceFile) {
+               if err := cmdv2.Main(traceFile, *httpFlag, *pprofFlag, *debugFlag); err != nil {
+                       dief("%s\n", err)
+               }
+               return
+       }
+
        var pprofFunc func(io.Writer, *http.Request) error
        switch *pprofFlag {
        case "net":
@@ -115,7 +123,7 @@ func main() {
                dief("%v\n", err)
        }
 
-       if *debugFlag {
+       if *debugFlag != 0 {
                trace.Print(res.Events)
                os.Exit(0)
        }
@@ -132,12 +140,27 @@ func main() {
        browser.Open(addr)
 
        // Start http server.
-       http.HandleFunc("/", httpMain)
+       http.Handle("/", traceviewer.MainHandler(ranges))
        err = http.Serve(ln, nil)
        dief("failed to start http server: %v\n", err)
 }
 
-var ranges []Range
+// isTraceV2 returns true if filename holds a v2 trace.
+func isTraceV2(filename string) bool {
+       file, err := os.Open(filename)
+       if err != nil {
+               return false
+       }
+       defer file.Close()
+
+       ver, _, err := trace.ReadVersion(file)
+       if err != nil {
+               return false
+       }
+       return ver >= 1022
+}
+
+var ranges []traceviewer.Range
 
 var loader struct {
        once sync.Once
@@ -175,209 +198,6 @@ func parseTrace() (trace.ParseResult, error) {
        return loader.res, loader.err
 }
 
-// httpMain serves the starting page.
-func httpMain(w http.ResponseWriter, r *http.Request) {
-       if err := templMain.Execute(w, ranges); err != nil {
-               http.Error(w, err.Error(), http.StatusInternalServerError)
-               return
-       }
-}
-
-var templMain = template.Must(template.New("").Parse(`
-<html>
-<style>
-/* See https://github.com/golang/pkgsite/blob/master/static/shared/typography/typography.css */
-body {
-  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji';
-  font-size:   1rem;
-  line-height: normal;
-  max-width:   9in;
-  margin:      1em;
-}
-h1 { font-size: 1.5rem; }
-h2 { font-size: 1.375rem; }
-h1,h2 {
-  font-weight: 600;
-  line-height: 1.25em;
-  word-break: break-word;
-}
-p  { color: grey85; font-size:85%; }
-</style>
-<body>
-<h1>cmd/trace: the Go trace event viewer</h1>
-<p>
-  This web server provides various visualizations of an event log gathered during
-  the execution of a Go program that uses the <a href='https://pkg.go.dev/runtime/trace'>runtime/trace</a> package.
-</p>
-
-<h2>Event timelines for running goroutines</h2>
-{{if $}}
-<p>
-  Large traces are split into multiple sections of equal data size
-  (not duration) to avoid overwhelming the visualizer.
-</p>
-<ul>
-       {{range $e := $}}
-               <li><a href="{{$e.URL}}">View trace ({{$e.Name}})</a></li>
-       {{end}}
-</ul>
-{{else}}
-<ul>
-       <li><a href="/trace">View trace</a></li>
-</ul>
-{{end}}
-<p>
-  This view displays a timeline for each of the GOMAXPROCS logical
-  processors, showing which goroutine (if any) was running on that
-  logical processor at each moment.
-
-  Each goroutine has an identifying number (e.g. G123), main function,
-  and color.
-
-  A colored bar represents an uninterrupted span of execution.
-
-  Execution of a goroutine may migrate from one logical processor to another,
-  causing a single colored bar to be horizontally continuous but
-  vertically displaced.
-</p>
-<p>
-  Clicking on a span reveals information about it, such as its
-  duration, its causal predecessors and successors, and the stack trace
-  at the final moment when it yielded the logical processor, for example
-  because it made a system call or tried to acquire a mutex.
-
-  Directly underneath each bar, a smaller bar or more commonly a fine
-  vertical line indicates an event occurring during its execution.
-  Some of these are related to garbage collection; most indicate that
-  a goroutine yielded its logical processor but then immediately resumed execution
-  on the same logical processor. Clicking on the event displays the stack trace
-  at the moment it occurred.
-</p>
-<p>
-  The causal relationships between spans of goroutine execution
-  can be displayed by clicking the Flow Events button at the top.
-</p>
-<p>
-  At the top ("STATS"), there are three additional timelines that
-  display statistical information.
-
-  "Goroutines" is a time series of the count of existing goroutines;
-  clicking on it displays their breakdown by state at that moment:
-  running, runnable, or waiting.
-
-  "Heap" is a time series of the amount of heap memory allocated (in orange)
-  and (in green) the allocation limit at which the next GC cycle will begin.
-
-  "Threads" shows the number of kernel threads in existence: there is
-  always one kernel thread per logical processor, and additional threads
-  are created for calls to non-Go code such as a system call or a
-  function written in C.
-</p>
-<p>
-  Above the event trace for the first logical processor are
-  traces for various runtime-internal events.
-
-  The "GC" bar shows when the garbage collector is running, and in which stage.
-  Garbage collection may temporarily affect all the logical processors
-  and the other metrics.
-
-  The "Network", "Timers", and "Syscalls" traces indicate events in
-  the runtime that cause goroutines to wake up.
-</p>
-<p>
-  The visualization allows you to navigate events at scales ranging from several
-  seconds to a handful of nanoseconds.
-
-  Consult the documentation for the Chromium <a href='https://www.chromium.org/developers/how-tos/trace-event-profiling-tool/'>Trace Event Profiling Tool<a/>
-  for help navigating the view.
-</p>
-
-<ul>
-<li><a href="/goroutines">Goroutine analysis</a></li>
-</ul>
-<p>
-  This view displays information about each set of goroutines that
-  shares the same main function.
-
-  Clicking on a main function shows links to the four types of
-  blocking profile (see below) applied to that subset of goroutines.
-
-  It also shows a table of specific goroutine instances, with various
-  execution statistics and a link to the event timeline for each one.
-
-  The timeline displays only the selected goroutine and any others it
-  interacts with via block/unblock events. (The timeline is
-  goroutine-oriented rather than logical processor-oriented.)
-</p>
-
-<h2>Profiles</h2>
-<p>
-  Each link below displays a global profile in zoomable graph form as
-  produced by <a href='https://go.dev/blog/pprof'>pprof</a>'s "web" command.
-
-  In addition there is a link to download the profile for offline
-  analysis with pprof.
-
-  All four profiles represent causes of delay that prevent a goroutine
-  from running on a logical processor: because it was waiting for the network,
-  for a synchronization operation on a mutex or channel, for a system call,
-  or for a logical processor to become available.
-</p>
-<ul>
-<li><a href="/io">Network blocking profile</a> (<a href="/io?raw=1" download="io.profile">⬇</a>)</li>
-<li><a href="/block">Synchronization blocking profile</a> (<a href="/block?raw=1" download="block.profile">⬇</a>)</li>
-<li><a href="/syscall">Syscall blocking profile</a> (<a href="/syscall?raw=1" download="syscall.profile">⬇</a>)</li>
-<li><a href="/sched">Scheduler latency profile</a> (<a href="/sche?raw=1" download="sched.profile">⬇</a>)</li>
-</ul>
-
-<h2>User-defined tasks and regions</h2>
-<p>
-  The trace API allows a target program to annotate a <a
-  href='https://pkg.go.dev/runtime/trace#Region'>region</a> of code
-  within a goroutine, such as a key function, so that its performance
-  can be analyzed.
-
-  <a href='https://pkg.go.dev/runtime/trace#Log'>Log events</a> may be
-  associated with a region to record progress and relevant values.
-
-  The API also allows annotation of higher-level
-  <a href='https://pkg.go.dev/runtime/trace#Task'>tasks</a>,
-  which may involve work across many goroutines.
-</p>
-<p>
-  The links below display, for each region and task, a histogram of its execution times.
-
-  Each histogram bucket contains a sample trace that records the
-  sequence of events such as goroutine creations, log events, and
-  subregion start/end times.
-
-  For each task, you can click through to a logical-processor or
-  goroutine-oriented view showing the tasks and regions on the
-  timeline.
-
-  Such information may help uncover which steps in a region are
-  unexpectedly slow, or reveal relationships between the data values
-  logged in a request and its running time.
-</p>
-<ul>
-<li><a href="/usertasks">User-defined tasks</a></li>
-<li><a href="/userregions">User-defined regions</a></li>
-</ul>
-
-<h2>Garbage collection metrics</h2>
-<ul>
-<li><a href="/mmu">Minimum mutator utilization</a></li>
-</ul>
-<p>
-  This chart indicates the maximum GC pause time (the largest x value
-  for which y is zero), and more generally, the fraction of time that
-  the processors are available to application goroutines ("mutators"),
-  for any time window of a specified size, in the worst case.
-</p>
-</body>
-</html>
-`))
-
 func dief(msg string, args ...any) {
        fmt.Fprintf(os.Stderr, msg, args...)
        os.Exit(1)
index b71dcd64110415369508a027f74f7b5c2e24a63b..43017c857ee97eea84559c7bfc389237acae8584 100644 (file)
@@ -29,6 +29,7 @@ import (
        "encoding/json"
        "fmt"
        "internal/trace"
+       "internal/trace/traceviewer"
        "log"
        "math"
        "net/http"
@@ -393,7 +394,7 @@ type linkedUtilWindow struct {
 
 func newLinkedUtilWindow(ui trace.UtilWindow, window time.Duration) linkedUtilWindow {
        // Find the range containing this window.
-       var r Range
+       var r traceviewer.Range
        for _, r = range ranges {
                if r.EndTime > ui.Time {
                        break
index 618df42033c61b13af8df1c9a5bd4964f3b0285d..865bc612a976d918986f5e491e8b148d6265f72f 100644 (file)
@@ -5,29 +5,24 @@
 package main
 
 import (
-       "cmd/internal/traceviewer"
-       "embed"
-       "encoding/json"
        "fmt"
        "internal/trace"
-       "io"
+       "internal/trace/traceviewer"
        "log"
        "math"
        "net/http"
        "runtime/debug"
        "sort"
        "strconv"
-       "strings"
        "time"
-)
 
-//go:embed static/trace_viewer_full.html static/webcomponents.min.js
-var staticContent embed.FS
+       "internal/trace/traceviewer/format"
+)
 
 func init() {
        http.HandleFunc("/trace", httpTrace)
        http.HandleFunc("/jsontrace", httpJsonTrace)
-       http.Handle("/static/", http.FileServer(http.FS(staticContent)))
+       http.Handle("/static/", traceviewer.StaticHandler())
 }
 
 // httpTrace serves either whole trace (goid==0) or trace for goid goroutine.
@@ -37,142 +32,8 @@ func httpTrace(w http.ResponseWriter, r *http.Request) {
                http.Error(w, err.Error(), http.StatusInternalServerError)
                return
        }
-       if err := r.ParseForm(); err != nil {
-               http.Error(w, err.Error(), http.StatusInternalServerError)
-               return
-       }
-       html := strings.ReplaceAll(templTrace, "{{PARAMS}}", r.Form.Encode())
-       w.Write([]byte(html))
-
-}
-
-// https://chromium.googlesource.com/catapult/+/9508452e18f130c98499cb4c4f1e1efaedee8962/tracing/docs/embedding-trace-viewer.md
-// This is almost verbatim copy of https://chromium-review.googlesource.com/c/catapult/+/2062938/2/tracing/bin/index.html
-var templTrace = `
-<html>
-<head>
-<script src="/static/webcomponents.min.js"></script>
-<script>
-'use strict';
-
-function onTraceViewerImportFail() {
-  document.addEventListener('DOMContentLoaded', function() {
-    document.body.textContent =
-    '/static/trace_viewer_full.html is missing. File a bug in https://golang.org/issue';
-  });
+       traceviewer.TraceHandler().ServeHTTP(w, r)
 }
-</script>
-
-<link rel="import" href="/static/trace_viewer_full.html"
-      onerror="onTraceViewerImportFail(event)">
-
-<style type="text/css">
-  html, body {
-    box-sizing: border-box;
-    overflow: hidden;
-    margin: 0px;
-    padding: 0;
-    width: 100%;
-    height: 100%;
-  }
-  #trace-viewer {
-    width: 100%;
-    height: 100%;
-  }
-  #trace-viewer:focus {
-    outline: none;
-  }
-</style>
-<script>
-'use strict';
-(function() {
-  var viewer;
-  var url;
-  var model;
-
-  function load() {
-    var req = new XMLHttpRequest();
-    var isBinary = /[.]gz$/.test(url) || /[.]zip$/.test(url);
-    req.overrideMimeType('text/plain; charset=x-user-defined');
-    req.open('GET', url, true);
-    if (isBinary)
-      req.responseType = 'arraybuffer';
-
-    req.onreadystatechange = function(event) {
-      if (req.readyState !== 4)
-        return;
-
-      window.setTimeout(function() {
-        if (req.status === 200)
-          onResult(isBinary ? req.response : req.responseText);
-        else
-          onResultFail(req.status);
-      }, 0);
-    };
-    req.send(null);
-  }
-
-  function onResultFail(err) {
-    var overlay = new tr.ui.b.Overlay();
-    overlay.textContent = err + ': ' + url + ' could not be loaded';
-    overlay.title = 'Failed to fetch data';
-    overlay.visible = true;
-  }
-
-  function onResult(result) {
-    model = new tr.Model();
-    var opts = new tr.importer.ImportOptions();
-    opts.shiftWorldToZero = false;
-    var i = new tr.importer.Import(model, opts);
-    var p = i.importTracesWithProgressDialog([result]);
-    p.then(onModelLoaded, onImportFail);
-  }
-
-  function onModelLoaded() {
-    viewer.model = model;
-    viewer.viewTitle = "trace";
-
-    if (!model || model.bounds.isEmpty)
-      return;
-    var sel = window.location.hash.substr(1);
-    if (sel === '')
-      return;
-    var parts = sel.split(':');
-    var range = new (tr.b.Range || tr.b.math.Range)();
-    range.addValue(parseFloat(parts[0]));
-    range.addValue(parseFloat(parts[1]));
-    viewer.trackView.viewport.interestRange.set(range);
-  }
-
-  function onImportFail(err) {
-    var overlay = new tr.ui.b.Overlay();
-    overlay.textContent = tr.b.normalizeException(err).message;
-    overlay.title = 'Import error';
-    overlay.visible = true;
-  }
-
-  document.addEventListener('WebComponentsReady', function() {
-    var container = document.createElement('track-view-container');
-    container.id = 'track_view_container';
-
-    viewer = document.createElement('tr-ui-timeline-view');
-    viewer.track_view_container = container;
-    Polymer.dom(viewer).appendChild(container);
-
-    viewer.id = 'trace-viewer';
-    viewer.globalMode = true;
-    Polymer.dom(document.body).appendChild(viewer);
-
-    url = '/jsontrace?{{PARAMS}}';
-    load();
-  });
-}());
-</script>
-</head>
-<body>
-</body>
-</html>
-`
 
 // httpJsonTrace serves json trace, requested from within templTrace HTML.
 func httpJsonTrace(w http.ResponseWriter, r *http.Request) {
@@ -203,7 +64,7 @@ func httpJsonTrace(w http.ResponseWriter, r *http.Request) {
                        log.Printf("failed to find goroutine %d", goid)
                        return
                }
-               params.mode = modeGoroutineOriented
+               params.mode = traceviewer.ModeGoroutineOriented
                params.startTime = g.StartTime
                if g.EndTime != 0 {
                        params.endTime = g.EndTime
@@ -225,7 +86,7 @@ func httpJsonTrace(w http.ResponseWriter, r *http.Request) {
                        return
                }
                goid := task.events[0].G
-               params.mode = modeGoroutineOriented | modeTaskOriented
+               params.mode = traceviewer.ModeGoroutineOriented | traceviewer.ModeTaskOriented
                params.startTime = task.firstTimestamp() - 1
                params.endTime = task.lastTimestamp() + 1
                params.maing = goid
@@ -250,7 +111,7 @@ func httpJsonTrace(w http.ResponseWriter, r *http.Request) {
                        log.Printf("failed to find task with id %d", taskid)
                        return
                }
-               params.mode = modeTaskOriented
+               params.mode = traceviewer.ModeTaskOriented
                params.startTime = task.firstTimestamp() - 1
                params.endTime = task.lastTimestamp() + 1
                params.tasks = task.descendants()
@@ -272,247 +133,31 @@ func httpJsonTrace(w http.ResponseWriter, r *http.Request) {
                }
        }
 
-       c := viewerDataTraceConsumer(w, start, end)
+       c := traceviewer.ViewerDataTraceConsumer(w, start, end)
        if err := generateTrace(params, c); err != nil {
                log.Printf("failed to generate trace: %v", err)
                return
        }
 }
 
-type Range struct {
-       Name      string
-       Start     int
-       End       int
-       StartTime int64
-       EndTime   int64
-}
-
-func (r Range) URL() string {
-       return fmt.Sprintf("/trace?start=%d&end=%d", r.Start, r.End)
-}
-
 // splitTrace splits the trace into a number of ranges,
 // each resulting in approx 100MB of json output
 // (trace viewer can hardly handle more).
-func splitTrace(res trace.ParseResult) []Range {
+func splitTrace(res trace.ParseResult) []traceviewer.Range {
        params := &traceParams{
                parsed:  res,
                endTime: math.MaxInt64,
        }
-       s, c := splittingTraceConsumer(100 << 20) // 100M
+       s, c := traceviewer.SplittingTraceConsumer(100 << 20) // 100M
        if err := generateTrace(params, c); err != nil {
                dief("%v\n", err)
        }
        return s.Ranges
 }
 
-type splitter struct {
-       Ranges []Range
-}
-
-// walkStackFrames calls fn for id and all of its parent frames from allFrames.
-func walkStackFrames(allFrames map[string]traceviewer.Frame, id int, fn func(id int)) {
-       for id != 0 {
-               f, ok := allFrames[strconv.Itoa(id)]
-               if !ok {
-                       break
-               }
-               fn(id)
-               id = f.Parent
-       }
-}
-
-func stackFrameEncodedSize(id uint, f traceviewer.Frame) int {
-       // We want to know the marginal size of traceviewer.Data.Frames for
-       // each event. Running full JSON encoding of the map for each event is
-       // far too slow.
-       //
-       // Since the format is fixed, we can easily compute the size without
-       // encoding.
-       //
-       // A single entry looks like one of the following:
-       //
-       //   "1":{"name":"main.main:30"},
-       //   "10":{"name":"pkg.NewSession:173","parent":9},
-       //
-       // The parent is omitted if 0. The trailing comma is omitted from the
-       // last entry, but we don't need that much precision.
-       const (
-               baseSize = len(`"`) + len(`":{"name":"`) + len(`"},`)
-
-               // Don't count the trailing quote on the name, as that is
-               // counted in baseSize.
-               parentBaseSize = len(`,"parent":`)
-       )
-
-       size := baseSize
-
-       size += len(f.Name)
-
-       // Bytes for id (always positive).
-       for id > 0 {
-               size += 1
-               id /= 10
-       }
-
-       if f.Parent > 0 {
-               size += parentBaseSize
-               // Bytes for parent (always positive).
-               for f.Parent > 0 {
-                       size += 1
-                       f.Parent /= 10
-               }
-       }
-
-       return size
-}
-
-func splittingTraceConsumer(max int) (*splitter, traceConsumer) {
-       type eventSz struct {
-               Time   float64
-               Sz     int
-               Frames []int
-       }
-
-       var (
-               // data.Frames contains only the frames for required events.
-               data = traceviewer.Data{Frames: make(map[string]traceviewer.Frame)}
-
-               allFrames = make(map[string]traceviewer.Frame)
-
-               sizes []eventSz
-               cw    countingWriter
-       )
-
-       s := new(splitter)
-
-       return s, traceConsumer{
-               consumeTimeUnit: func(unit string) {
-                       data.TimeUnit = unit
-               },
-               consumeViewerEvent: func(v *traceviewer.Event, required bool) {
-                       if required {
-                               // Store required events inside data so flush
-                               // can include them in the required part of the
-                               // trace.
-                               data.Events = append(data.Events, v)
-                               walkStackFrames(allFrames, v.Stack, func(id int) {
-                                       s := strconv.Itoa(id)
-                                       data.Frames[s] = allFrames[s]
-                               })
-                               walkStackFrames(allFrames, v.EndStack, func(id int) {
-                                       s := strconv.Itoa(id)
-                                       data.Frames[s] = allFrames[s]
-                               })
-                               return
-                       }
-                       enc := json.NewEncoder(&cw)
-                       enc.Encode(v)
-                       size := eventSz{Time: v.Time, Sz: cw.size + 1} // +1 for ",".
-                       // Add referenced stack frames. Their size is computed
-                       // in flush, where we can dedup across events.
-                       walkStackFrames(allFrames, v.Stack, func(id int) {
-                               size.Frames = append(size.Frames, id)
-                       })
-                       walkStackFrames(allFrames, v.EndStack, func(id int) {
-                               size.Frames = append(size.Frames, id) // This may add duplicates. We'll dedup later.
-                       })
-                       sizes = append(sizes, size)
-                       cw.size = 0
-               },
-               consumeViewerFrame: func(k string, v traceviewer.Frame) {
-                       allFrames[k] = v
-               },
-               flush: func() {
-                       // Calculate size of the mandatory part of the trace.
-                       // This includes thread names and stack frames for
-                       // required events.
-                       cw.size = 0
-                       enc := json.NewEncoder(&cw)
-                       enc.Encode(data)
-                       requiredSize := cw.size
-
-                       // Then calculate size of each individual event and
-                       // their stack frames, grouping them into ranges. We
-                       // only include stack frames relevant to the events in
-                       // the range to reduce overhead.
-
-                       var (
-                               start = 0
-
-                               eventsSize = 0
-
-                               frames     = make(map[string]traceviewer.Frame)
-                               framesSize = 0
-                       )
-                       for i, ev := range sizes {
-                               eventsSize += ev.Sz
-
-                               // Add required stack frames. Note that they
-                               // may already be in the map.
-                               for _, id := range ev.Frames {
-                                       s := strconv.Itoa(id)
-                                       _, ok := frames[s]
-                                       if ok {
-                                               continue
-                                       }
-                                       f := allFrames[s]
-                                       frames[s] = f
-                                       framesSize += stackFrameEncodedSize(uint(id), f)
-                               }
-
-                               total := requiredSize + framesSize + eventsSize
-                               if total < max {
-                                       continue
-                               }
-
-                               // Reached max size, commit this range and
-                               // start a new range.
-                               startTime := time.Duration(sizes[start].Time * 1000)
-                               endTime := time.Duration(ev.Time * 1000)
-                               ranges = append(ranges, Range{
-                                       Name:      fmt.Sprintf("%v-%v", startTime, endTime),
-                                       Start:     start,
-                                       End:       i + 1,
-                                       StartTime: int64(startTime),
-                                       EndTime:   int64(endTime),
-                               })
-                               start = i + 1
-                               frames = make(map[string]traceviewer.Frame)
-                               framesSize = 0
-                               eventsSize = 0
-                       }
-                       if len(ranges) <= 1 {
-                               s.Ranges = nil
-                               return
-                       }
-
-                       if end := len(sizes) - 1; start < end {
-                               ranges = append(ranges, Range{
-                                       Name:      fmt.Sprintf("%v-%v", time.Duration(sizes[start].Time*1000), time.Duration(sizes[end].Time*1000)),
-                                       Start:     start,
-                                       End:       end,
-                                       StartTime: int64(sizes[start].Time * 1000),
-                                       EndTime:   int64(sizes[end].Time * 1000),
-                               })
-                       }
-                       s.Ranges = ranges
-               },
-       }
-}
-
-type countingWriter struct {
-       size int
-}
-
-func (cw *countingWriter) Write(data []byte) (int, error) {
-       cw.size += len(data)
-       return len(data), nil
-}
-
 type traceParams struct {
        parsed    trace.ParseResult
-       mode      traceviewMode
+       mode      traceviewer.Mode
        startTime int64
        endTime   int64
        maing     uint64          // for goroutine-oriented view, place this goroutine on the top row
@@ -520,59 +165,18 @@ type traceParams struct {
        tasks     []*taskDesc     // Tasks to be displayed. tasks[0] is the top-most task
 }
 
-type traceviewMode uint
-
-const (
-       modeGoroutineOriented traceviewMode = 1 << iota
-       modeTaskOriented
-)
-
 type traceContext struct {
        *traceParams
-       consumer  traceConsumer
-       frameTree frameNode
-       frameSeq  int
-       arrowSeq  uint64
-       gcount    uint64
-
-       heapStats, prevHeapStats     heapStats
-       threadStats, prevThreadStats threadStats
-       gstates, prevGstates         [gStateCount]int64
-
+       consumer traceviewer.TraceConsumer
+       emitter  *traceviewer.Emitter
+       arrowSeq uint64
+       gcount   uint64
        regionID int // last emitted region id. incremented in each emitRegion call.
 }
 
-type heapStats struct {
-       heapAlloc uint64
-       nextGC    uint64
-}
-
-type threadStats struct {
-       insyscallRuntime int64 // system goroutine in syscall
-       insyscall        int64 // user goroutine in syscall
-       prunning         int64 // thread running P
-}
-
-type frameNode struct {
-       id       int
-       children map[uint64]frameNode
-}
-
-type gState int
-
-const (
-       gDead gState = iota
-       gRunnable
-       gRunning
-       gWaiting
-       gWaitingGC
-
-       gStateCount
-)
-
 type gInfo struct {
-       state      gState // current state
-       name       string // name chosen for this goroutine at first EvGoStart
+       state      traceviewer.GState // current state
+       name       string             // name chosen for this goroutine at first EvGoStart
        isSystemG  bool
        start      *trace.Event // most recent EvGoStart
        markAssist *trace.Event // if non-nil, the mark assist currently running.
@@ -596,19 +200,6 @@ type SortIndexArg struct {
        Index int `json:"sort_index"`
 }
 
-type traceConsumer struct {
-       consumeTimeUnit    func(unit string)
-       consumeViewerEvent func(v *traceviewer.Event, required bool)
-       consumeViewerFrame func(key string, f traceviewer.Frame)
-       flush              func()
-}
-
-const (
-       procsSection = 0 // where Goroutines or per-P timelines are presented.
-       statsSection = 1 // where counters are presented.
-       tasksSection = 2 // where Task hierarchy & timeline is presented.
-)
-
 // generateTrace generates json trace for trace-viewer:
 // https://github.com/google/trace-viewer
 // Trace format is described at:
@@ -616,14 +207,23 @@ const (
 // If mode==goroutineMode, generate trace for goroutine goid, otherwise whole trace.
 // startTime, endTime determine part of the trace that we are interested in.
 // gset restricts goroutines that are included in the resulting trace.
-func generateTrace(params *traceParams, consumer traceConsumer) error {
-       defer consumer.flush()
+func generateTrace(params *traceParams, consumer traceviewer.TraceConsumer) error {
+       emitter := traceviewer.NewEmitter(
+               consumer,
+               params.mode,
+               time.Duration(params.startTime),
+               time.Duration(params.endTime),
+       )
+       if params.mode&traceviewer.ModeGoroutineOriented != 0 {
+               emitter.SetResourceType("G")
+       } else {
+               emitter.SetResourceType("PROCS")
+       }
+       defer emitter.Flush()
 
-       ctx := &traceContext{traceParams: params}
-       ctx.frameTree.children = make(map[uint64]frameNode)
+       ctx := &traceContext{traceParams: params, emitter: emitter}
        ctx.consumer = consumer
 
-       ctx.consumer.consumeTimeUnit("ns")
        maxProc := 0
        ginfos := make(map[uint64]*gInfo)
        stacks := params.parsed.Stacks
@@ -640,17 +240,17 @@ func generateTrace(params *traceParams, consumer traceConsumer) error {
        // Since we make many calls to setGState, we record a sticky
        // error in setGStateErr and check it after every event.
        var setGStateErr error
-       setGState := func(ev *trace.Event, g uint64, oldState, newState gState) {
+       setGState := func(ev *trace.Event, g uint64, oldState, newState traceviewer.GState) {
                info := getGInfo(g)
-               if oldState == gWaiting && info.state == gWaitingGC {
-                       // For checking, gWaiting counts as any gWaiting*.
+               if oldState == traceviewer.GWaiting && info.state == traceviewer.GWaitingGC {
+                       // For checking, traceviewer.GWaiting counts as any traceviewer.GWaiting*.
                        oldState = info.state
                }
                if info.state != oldState && setGStateErr == nil {
                        setGStateErr = fmt.Errorf("expected G %d to be in state %d, but got state %d", g, oldState, info.state)
                }
-               ctx.gstates[info.state]--
-               ctx.gstates[newState]++
+
+               emitter.GoroutineTransition(time.Duration(ev.Ts), info.state, newState)
                info.state = newState
        }
 
@@ -658,13 +258,13 @@ func generateTrace(params *traceParams, consumer traceConsumer) error {
                // Handle state transitions before we filter out events.
                switch ev.Type {
                case trace.EvGoStart, trace.EvGoStartLabel:
-                       setGState(ev, ev.G, gRunnable, gRunning)
+                       setGState(ev, ev.G, traceviewer.GRunnable, traceviewer.GRunning)
                        info := getGInfo(ev.G)
                        info.start = ev
                case trace.EvProcStart:
-                       ctx.threadStats.prunning++
+                       emitter.IncThreadStateCount(time.Duration(ev.Ts), traceviewer.ThreadStateRunning, 1)
                case trace.EvProcStop:
-                       ctx.threadStats.prunning--
+                       emitter.IncThreadStateCount(time.Duration(ev.Ts), traceviewer.ThreadStateRunning, -1)
                case trace.EvGoCreate:
                        newG := ev.Args[0]
                        info := getGInfo(newG)
@@ -682,58 +282,59 @@ func generateTrace(params *traceParams, consumer traceConsumer) error {
                        info.isSystemG = trace.IsSystemGoroutine(fname)
 
                        ctx.gcount++
-                       setGState(ev, newG, gDead, gRunnable)
+                       setGState(ev, newG, traceviewer.GDead, traceviewer.GRunnable)
                case trace.EvGoEnd:
                        ctx.gcount--
-                       setGState(ev, ev.G, gRunning, gDead)
+                       setGState(ev, ev.G, traceviewer.GRunning, traceviewer.GDead)
                case trace.EvGoUnblock:
-                       setGState(ev, ev.Args[0], gWaiting, gRunnable)
+                       setGState(ev, ev.Args[0], traceviewer.GWaiting, traceviewer.GRunnable)
                case trace.EvGoSysExit:
-                       setGState(ev, ev.G, gWaiting, gRunnable)
+                       setGState(ev, ev.G, traceviewer.GWaiting, traceviewer.GRunnable)
                        if getGInfo(ev.G).isSystemG {
-                               ctx.threadStats.insyscallRuntime--
+                               emitter.IncThreadStateCount(time.Duration(ev.Ts), traceviewer.ThreadStateInSyscallRuntime, -1)
                        } else {
-                               ctx.threadStats.insyscall--
+                               emitter.IncThreadStateCount(time.Duration(ev.Ts), traceviewer.ThreadStateInSyscall, -1)
                        }
                case trace.EvGoSysBlock:
-                       setGState(ev, ev.G, gRunning, gWaiting)
+                       setGState(ev, ev.G, traceviewer.GRunning, traceviewer.GWaiting)
                        if getGInfo(ev.G).isSystemG {
-                               ctx.threadStats.insyscallRuntime++
+                               emitter.IncThreadStateCount(time.Duration(ev.Ts), traceviewer.ThreadStateInSyscallRuntime, 1)
                        } else {
-                               ctx.threadStats.insyscall++
+                               emitter.IncThreadStateCount(time.Duration(ev.Ts), traceviewer.ThreadStateInSyscall, 1)
                        }
                case trace.EvGoSched, trace.EvGoPreempt:
-                       setGState(ev, ev.G, gRunning, gRunnable)
+                       setGState(ev, ev.G, traceviewer.GRunning, traceviewer.GRunnable)
                case trace.EvGoStop,
                        trace.EvGoSleep, trace.EvGoBlock, trace.EvGoBlockSend, trace.EvGoBlockRecv,
                        trace.EvGoBlockSelect, trace.EvGoBlockSync, trace.EvGoBlockCond, trace.EvGoBlockNet:
-                       setGState(ev, ev.G, gRunning, gWaiting)
+                       setGState(ev, ev.G, traceviewer.GRunning, traceviewer.GWaiting)
                case trace.EvGoBlockGC:
-                       setGState(ev, ev.G, gRunning, gWaitingGC)
+                       setGState(ev, ev.G, traceviewer.GRunning, traceviewer.GWaitingGC)
                case trace.EvGCMarkAssistStart:
                        getGInfo(ev.G).markAssist = ev
                case trace.EvGCMarkAssistDone:
                        getGInfo(ev.G).markAssist = nil
                case trace.EvGoWaiting:
-                       setGState(ev, ev.G, gRunnable, gWaiting)
+                       setGState(ev, ev.G, traceviewer.GRunnable, traceviewer.GWaiting)
                case trace.EvGoInSyscall:
                        // Cancel out the effect of EvGoCreate at the beginning.
-                       setGState(ev, ev.G, gRunnable, gWaiting)
+                       setGState(ev, ev.G, traceviewer.GRunnable, traceviewer.GWaiting)
                        if getGInfo(ev.G).isSystemG {
-                               ctx.threadStats.insyscallRuntime++
+                               emitter.IncThreadStateCount(time.Duration(ev.Ts), traceviewer.ThreadStateInSyscallRuntime, 1)
                        } else {
-                               ctx.threadStats.insyscall++
+                               emitter.IncThreadStateCount(time.Duration(ev.Ts), traceviewer.ThreadStateInSyscall, 1)
                        }
                case trace.EvHeapAlloc:
-                       ctx.heapStats.heapAlloc = ev.Args[0]
+                       emitter.HeapAlloc(time.Duration(ev.Ts), ev.Args[0])
                case trace.EvHeapGoal:
-                       ctx.heapStats.nextGC = ev.Args[0]
+                       emitter.HeapGoal(time.Duration(ev.Ts), ev.Args[0])
                }
                if setGStateErr != nil {
                        return setGStateErr
                }
-               if ctx.gstates[gRunnable] < 0 || ctx.gstates[gRunning] < 0 || ctx.threadStats.insyscall < 0 || ctx.threadStats.insyscallRuntime < 0 {
-                       return fmt.Errorf("invalid state after processing %v: runnable=%d running=%d insyscall=%d insyscallRuntime=%d", ev, ctx.gstates[gRunnable], ctx.gstates[gRunning], ctx.threadStats.insyscall, ctx.threadStats.insyscallRuntime)
+
+               if err := emitter.Err(); err != nil {
+                       return fmt.Errorf("invalid state after processing %v: %s", ev, err)
                }
 
                // Ignore events that are from uninteresting goroutines
@@ -752,12 +353,12 @@ func generateTrace(params *traceParams, consumer traceConsumer) error {
                // Emit trace objects.
                switch ev.Type {
                case trace.EvProcStart:
-                       if ctx.mode&modeGoroutineOriented != 0 {
+                       if ctx.mode&traceviewer.ModeGoroutineOriented != 0 {
                                continue
                        }
                        ctx.emitInstant(ev, "proc start", "")
                case trace.EvProcStop:
-                       if ctx.mode&modeGoroutineOriented != 0 {
+                       if ctx.mode&traceviewer.ModeGoroutineOriented != 0 {
                                continue
                        }
                        ctx.emitInstant(ev, "proc stop", "")
@@ -765,7 +366,7 @@ func generateTrace(params *traceParams, consumer traceConsumer) error {
                        ctx.emitSlice(ev, "GC")
                case trace.EvGCDone:
                case trace.EvSTWStart:
-                       if ctx.mode&modeGoroutineOriented != 0 {
+                       if ctx.mode&traceviewer.ModeGoroutineOriented != 0 {
                                continue
                        }
                        ctx.emitSlice(ev, fmt.Sprintf("STW (%s)", ev.SArgs[0]))
@@ -832,46 +433,10 @@ func generateTrace(params *traceParams, consumer traceConsumer) error {
                                ctx.emitInstant(ev, "CPU profile sample", "")
                        }
                }
-               // Emit any counter updates.
-               ctx.emitThreadCounters(ev)
-               ctx.emitHeapCounters(ev)
-               ctx.emitGoroutineCounters(ev)
-       }
-
-       ctx.emitSectionFooter(statsSection, "STATS", 0)
-
-       if ctx.mode&modeTaskOriented != 0 {
-               ctx.emitSectionFooter(tasksSection, "TASKS", 1)
-       }
-
-       if ctx.mode&modeGoroutineOriented != 0 {
-               ctx.emitSectionFooter(procsSection, "G", 2)
-       } else {
-               ctx.emitSectionFooter(procsSection, "PROCS", 2)
-       }
-
-       ctx.emitFooter(&traceviewer.Event{Name: "thread_name", Phase: "M", PID: procsSection, TID: trace.GCP, Arg: &NameArg{"GC"}})
-       ctx.emitFooter(&traceviewer.Event{Name: "thread_sort_index", Phase: "M", PID: procsSection, TID: trace.GCP, Arg: &SortIndexArg{-6}})
-
-       ctx.emitFooter(&traceviewer.Event{Name: "thread_name", Phase: "M", PID: procsSection, TID: trace.NetpollP, Arg: &NameArg{"Network"}})
-       ctx.emitFooter(&traceviewer.Event{Name: "thread_sort_index", Phase: "M", PID: procsSection, TID: trace.NetpollP, Arg: &SortIndexArg{-5}})
-
-       ctx.emitFooter(&traceviewer.Event{Name: "thread_name", Phase: "M", PID: procsSection, TID: trace.TimerP, Arg: &NameArg{"Timers"}})
-       ctx.emitFooter(&traceviewer.Event{Name: "thread_sort_index", Phase: "M", PID: procsSection, TID: trace.TimerP, Arg: &SortIndexArg{-4}})
-
-       ctx.emitFooter(&traceviewer.Event{Name: "thread_name", Phase: "M", PID: procsSection, TID: trace.SyscallP, Arg: &NameArg{"Syscalls"}})
-       ctx.emitFooter(&traceviewer.Event{Name: "thread_sort_index", Phase: "M", PID: procsSection, TID: trace.SyscallP, Arg: &SortIndexArg{-3}})
-
-       // Display rows for Ps if we are in the default trace view mode (not goroutine-oriented presentation)
-       if ctx.mode&modeGoroutineOriented == 0 {
-               for i := 0; i <= maxProc; i++ {
-                       ctx.emitFooter(&traceviewer.Event{Name: "thread_name", Phase: "M", PID: procsSection, TID: uint64(i), Arg: &NameArg{fmt.Sprintf("Proc %v", i)}})
-                       ctx.emitFooter(&traceviewer.Event{Name: "thread_sort_index", Phase: "M", PID: procsSection, TID: uint64(i), Arg: &SortIndexArg{i}})
-               }
        }
 
        // Display task and its regions if we are in task-oriented presentation mode.
-       if ctx.mode&modeTaskOriented != 0 {
+       if ctx.mode&traceviewer.ModeTaskOriented != 0 {
                // sort tasks based on the task start time.
                sortedTask := make([]*taskDesc, len(ctx.tasks))
                copy(sortedTask, ctx.tasks)
@@ -888,7 +453,7 @@ func generateTrace(params *traceParams, consumer traceConsumer) error {
 
                        // If we are in goroutine-oriented mode, we draw regions.
                        // TODO(hyangah): add this for task/P-oriented mode (i.e., focustask view) too.
-                       if ctx.mode&modeGoroutineOriented != 0 {
+                       if ctx.mode&traceviewer.ModeGoroutineOriented != 0 {
                                for _, s := range task.regions {
                                        ctx.emitRegion(s)
                                }
@@ -897,34 +462,34 @@ func generateTrace(params *traceParams, consumer traceConsumer) error {
        }
 
        // Display goroutine rows if we are either in goroutine-oriented mode.
-       if ctx.mode&modeGoroutineOriented != 0 {
+       if ctx.mode&traceviewer.ModeGoroutineOriented != 0 {
                for k, v := range ginfos {
                        if !ctx.gs[k] {
                                continue
                        }
-                       ctx.emitFooter(&traceviewer.Event{Name: "thread_name", Phase: "M", PID: procsSection, TID: k, Arg: &NameArg{v.name}})
+                       emitter.Resource(k, v.name)
                }
-               // Row for the main goroutine (maing)
-               ctx.emitFooter(&traceviewer.Event{Name: "thread_sort_index", Phase: "M", PID: procsSection, TID: ctx.maing, Arg: &SortIndexArg{-2}})
+               emitter.Focus(ctx.maing)
+
                // Row for GC or global state (specified with G=0)
-               ctx.emitFooter(&traceviewer.Event{Name: "thread_sort_index", Phase: "M", PID: procsSection, TID: 0, Arg: &SortIndexArg{-1}})
+               ctx.emitFooter(&format.Event{Name: "thread_sort_index", Phase: "M", PID: format.ProcsSection, TID: 0, Arg: &SortIndexArg{-1}})
+       } else {
+               // Display rows for Ps if we are in the default trace view mode.
+               for i := 0; i <= maxProc; i++ {
+                       emitter.Resource(uint64(i), fmt.Sprintf("Proc %v", i))
+               }
        }
 
        return nil
 }
 
-func (ctx *traceContext) emit(e *traceviewer.Event) {
-       ctx.consumer.consumeViewerEvent(e, false)
+func (ctx *traceContext) emit(e *format.Event) {
+       ctx.consumer.ConsumeViewerEvent(e, false)
 }
 
-func (ctx *traceContext) emitFooter(e *traceviewer.Event) {
-       ctx.consumer.consumeViewerEvent(e, true)
-}
-func (ctx *traceContext) emitSectionFooter(sectionID uint64, name string, priority int) {
-       ctx.emitFooter(&traceviewer.Event{Name: "process_name", Phase: "M", PID: sectionID, Arg: &NameArg{name}})
-       ctx.emitFooter(&traceviewer.Event{Name: "process_sort_index", Phase: "M", PID: sectionID, Arg: &SortIndexArg{priority}})
+func (ctx *traceContext) emitFooter(e *format.Event) {
+       ctx.consumer.ConsumeViewerEvent(e, true)
 }
-
 func (ctx *traceContext) time(ev *trace.Event) float64 {
        // Trace viewer wants timestamps in microseconds.
        return float64(ev.Ts) / 1000
@@ -942,7 +507,7 @@ func tsWithinRange(ts, s, e int64) bool {
 }
 
 func (ctx *traceContext) proc(ev *trace.Event) uint64 {
-       if ctx.mode&modeGoroutineOriented != 0 && ev.P < trace.FakeP {
+       if ctx.mode&traceviewer.ModeGoroutineOriented != 0 && ev.P < trace.FakeP {
                return ev.G
        } else {
                return uint64(ev.P)
@@ -953,7 +518,7 @@ func (ctx *traceContext) emitSlice(ev *trace.Event, name string) {
        ctx.emit(ctx.makeSlice(ev, name))
 }
 
-func (ctx *traceContext) makeSlice(ev *trace.Event, name string) *traceviewer.Event {
+func (ctx *traceContext) makeSlice(ev *trace.Event, name string) *format.Event {
        // If ViewerEvent.Dur is not a positive value,
        // trace viewer handles it as a non-terminating time interval.
        // Avoid it by setting the field with a small value.
@@ -961,18 +526,18 @@ func (ctx *traceContext) makeSlice(ev *trace.Event, name string) *traceviewer.Ev
        if ev.Link.Ts-ev.Ts <= 0 {
                durationUsec = 0.0001 // 0.1 nanoseconds
        }
-       sl := &traceviewer.Event{
+       sl := &format.Event{
                Name:     name,
                Phase:    "X",
                Time:     ctx.time(ev),
                Dur:      durationUsec,
                TID:      ctx.proc(ev),
-               Stack:    ctx.stack(ev.Stk),
-               EndStack: ctx.stack(ev.Link.Stk),
+               Stack:    ctx.emitter.Stack(ev.Stk),
+               EndStack: ctx.emitter.Stack(ev.Link.Stk),
        }
 
        // grey out non-overlapping events if the event is not a global event (ev.G == 0)
-       if ctx.mode&modeTaskOriented != 0 && ev.G != 0 {
+       if ctx.mode&traceviewer.ModeTaskOriented != 0 && ev.G != 0 {
                // include P information.
                if t := ev.Type; t == trace.EvGoStart || t == trace.EvGoStartLabel {
                        type Arg struct {
@@ -1000,25 +565,25 @@ func (ctx *traceContext) emitTask(task *taskDesc, sortIndex int) {
        taskName := task.name
        durationUsec := float64(task.lastTimestamp()-task.firstTimestamp()) / 1e3
 
-       ctx.emitFooter(&traceviewer.Event{Name: "thread_name", Phase: "M", PID: tasksSection, TID: taskRow, Arg: &NameArg{fmt.Sprintf("T%d %s", task.id, taskName)}})
-       ctx.emit(&traceviewer.Event{Name: "thread_sort_index", Phase: "M", PID: tasksSection, TID: taskRow, Arg: &SortIndexArg{sortIndex}})
+       ctx.emitFooter(&format.Event{Name: "thread_name", Phase: "M", PID: format.TasksSection, TID: taskRow, Arg: &NameArg{fmt.Sprintf("T%d %s", task.id, taskName)}})
+       ctx.emit(&format.Event{Name: "thread_sort_index", Phase: "M", PID: format.TasksSection, TID: taskRow, Arg: &SortIndexArg{sortIndex}})
        ts := float64(task.firstTimestamp()) / 1e3
-       sl := &traceviewer.Event{
+       sl := &format.Event{
                Name:  taskName,
                Phase: "X",
                Time:  ts,
                Dur:   durationUsec,
-               PID:   tasksSection,
+               PID:   format.TasksSection,
                TID:   taskRow,
                Cname: pickTaskColor(task.id),
        }
        targ := TaskArg{ID: task.id}
        if task.create != nil {
-               sl.Stack = ctx.stack(task.create.Stk)
+               sl.Stack = ctx.emitter.Stack(task.create.Stk)
                targ.StartG = task.create.G
        }
        if task.end != nil {
-               sl.EndStack = ctx.stack(task.end.Stk)
+               sl.EndStack = ctx.emitter.Stack(task.end.Stk)
                targ.EndG = task.end.G
        }
        sl.Arg = targ
@@ -1026,8 +591,8 @@ func (ctx *traceContext) emitTask(task *taskDesc, sortIndex int) {
 
        if task.create != nil && task.create.Type == trace.EvUserTaskCreate && task.create.Args[1] != 0 {
                ctx.arrowSeq++
-               ctx.emit(&traceviewer.Event{Name: "newTask", Phase: "s", TID: task.create.Args[1], ID: ctx.arrowSeq, Time: ts, PID: tasksSection})
-               ctx.emit(&traceviewer.Event{Name: "newTask", Phase: "t", TID: taskRow, ID: ctx.arrowSeq, Time: ts, PID: tasksSection})
+               ctx.emit(&format.Event{Name: "newTask", Phase: "s", TID: task.create.Args[1], ID: ctx.arrowSeq, Time: ts, PID: format.TasksSection})
+               ctx.emit(&format.Event{Name: "newTask", Phase: "t", TID: taskRow, ID: ctx.arrowSeq, Time: ts, PID: format.TasksSection})
        }
 }
 
@@ -1048,7 +613,7 @@ func (ctx *traceContext) emitRegion(s regionDesc) {
        scopeID := fmt.Sprintf("%x", id)
        name := s.Name
 
-       sl0 := &traceviewer.Event{
+       sl0 := &format.Event{
                Category: "Region",
                Name:     name,
                Phase:    "b",
@@ -1059,11 +624,11 @@ func (ctx *traceContext) emitRegion(s regionDesc) {
                Cname:    pickTaskColor(s.TaskID),
        }
        if s.Start != nil {
-               sl0.Stack = ctx.stack(s.Start.Stk)
+               sl0.Stack = ctx.emitter.Stack(s.Start.Stk)
        }
        ctx.emit(sl0)
 
-       sl1 := &traceviewer.Event{
+       sl1 := &format.Event{
                Category: "Region",
                Name:     name,
                Phase:    "e",
@@ -1075,70 +640,18 @@ func (ctx *traceContext) emitRegion(s regionDesc) {
                Arg:      RegionArg{TaskID: s.TaskID},
        }
        if s.End != nil {
-               sl1.Stack = ctx.stack(s.End.Stk)
+               sl1.Stack = ctx.emitter.Stack(s.End.Stk)
        }
        ctx.emit(sl1)
 }
 
-type heapCountersArg struct {
-       Allocated uint64
-       NextGC    uint64
-}
-
-func (ctx *traceContext) emitHeapCounters(ev *trace.Event) {
-       if ctx.prevHeapStats == ctx.heapStats {
-               return
-       }
-       diff := uint64(0)
-       if ctx.heapStats.nextGC > ctx.heapStats.heapAlloc {
-               diff = ctx.heapStats.nextGC - ctx.heapStats.heapAlloc
-       }
-       if tsWithinRange(ev.Ts, ctx.startTime, ctx.endTime) {
-               ctx.emit(&traceviewer.Event{Name: "Heap", Phase: "C", Time: ctx.time(ev), PID: 1, Arg: &heapCountersArg{ctx.heapStats.heapAlloc, diff}})
-       }
-       ctx.prevHeapStats = ctx.heapStats
-}
-
-type goroutineCountersArg struct {
-       Running   uint64
-       Runnable  uint64
-       GCWaiting uint64
-}
-
-func (ctx *traceContext) emitGoroutineCounters(ev *trace.Event) {
-       if ctx.prevGstates == ctx.gstates {
-               return
-       }
-       if tsWithinRange(ev.Ts, ctx.startTime, ctx.endTime) {
-               ctx.emit(&traceviewer.Event{Name: "Goroutines", Phase: "C", Time: ctx.time(ev), PID: 1, Arg: &goroutineCountersArg{uint64(ctx.gstates[gRunning]), uint64(ctx.gstates[gRunnable]), uint64(ctx.gstates[gWaitingGC])}})
-       }
-       ctx.prevGstates = ctx.gstates
-}
-
-type threadCountersArg struct {
-       Running   int64
-       InSyscall int64
-}
-
-func (ctx *traceContext) emitThreadCounters(ev *trace.Event) {
-       if ctx.prevThreadStats == ctx.threadStats {
-               return
-       }
-       if tsWithinRange(ev.Ts, ctx.startTime, ctx.endTime) {
-               ctx.emit(&traceviewer.Event{Name: "Threads", Phase: "C", Time: ctx.time(ev), PID: 1, Arg: &threadCountersArg{
-                       Running:   ctx.threadStats.prunning,
-                       InSyscall: ctx.threadStats.insyscall}})
-       }
-       ctx.prevThreadStats = ctx.threadStats
-}
-
 func (ctx *traceContext) emitInstant(ev *trace.Event, name, category string) {
        if !tsWithinRange(ev.Ts, ctx.startTime, ctx.endTime) {
                return
        }
 
        cname := ""
-       if ctx.mode&modeTaskOriented != 0 {
+       if ctx.mode&traceviewer.ModeTaskOriented != 0 {
                taskID, isUserAnnotation := isUserAnnotationEvent(ev)
 
                show := false
@@ -1163,14 +676,14 @@ func (ctx *traceContext) emitInstant(ev *trace.Event, name, category string) {
                }
                arg = &Arg{ev.Args[0]}
        }
-       ctx.emit(&traceviewer.Event{
+       ctx.emit(&format.Event{
                Name:     name,
                Category: category,
                Phase:    "I",
                Scope:    "t",
                Time:     ctx.time(ev),
                TID:      ctx.proc(ev),
-               Stack:    ctx.stack(ev.Stk),
+               Stack:    ctx.emitter.Stack(ev.Stk),
                Cname:    cname,
                Arg:      arg})
 }
@@ -1181,7 +694,7 @@ func (ctx *traceContext) emitArrow(ev *trace.Event, name string) {
                // For example, a goroutine was unblocked but was not scheduled before trace stop.
                return
        }
-       if ctx.mode&modeGoroutineOriented != 0 && (!ctx.gs[ev.Link.G] || ev.Link.Ts < ctx.startTime || ev.Link.Ts > ctx.endTime) {
+       if ctx.mode&traceviewer.ModeGoroutineOriented != 0 && (!ctx.gs[ev.Link.G] || ev.Link.Ts < ctx.startTime || ev.Link.Ts > ctx.endTime) {
                return
        }
 
@@ -1192,7 +705,7 @@ func (ctx *traceContext) emitArrow(ev *trace.Event, name string) {
        }
 
        color := ""
-       if ctx.mode&modeTaskOriented != 0 {
+       if ctx.mode&traceviewer.ModeTaskOriented != 0 {
                overlapping := false
                // skip non-overlapping arrows.
                for _, task := range ctx.tasks {
@@ -1207,32 +720,8 @@ func (ctx *traceContext) emitArrow(ev *trace.Event, name string) {
        }
 
        ctx.arrowSeq++
-       ctx.emit(&traceviewer.Event{Name: name, Phase: "s", TID: ctx.proc(ev), ID: ctx.arrowSeq, Time: ctx.time(ev), Stack: ctx.stack(ev.Stk), Cname: color})
-       ctx.emit(&traceviewer.Event{Name: name, Phase: "t", TID: ctx.proc(ev.Link), ID: ctx.arrowSeq, Time: ctx.time(ev.Link), Cname: color})
-}
-
-func (ctx *traceContext) stack(stk []*trace.Frame) int {
-       return ctx.buildBranch(ctx.frameTree, stk)
-}
-
-// buildBranch builds one branch in the prefix tree rooted at ctx.frameTree.
-func (ctx *traceContext) buildBranch(parent frameNode, stk []*trace.Frame) int {
-       if len(stk) == 0 {
-               return parent.id
-       }
-       last := len(stk) - 1
-       frame := stk[last]
-       stk = stk[:last]
-
-       node, ok := parent.children[frame.PC]
-       if !ok {
-               ctx.frameSeq++
-               node.id = ctx.frameSeq
-               node.children = make(map[uint64]frameNode)
-               parent.children[frame.PC] = node
-               ctx.consumer.consumeViewerFrame(strconv.Itoa(node.id), traceviewer.Frame{Name: fmt.Sprintf("%v:%v", frame.Fn, frame.Line), Parent: parent.id})
-       }
-       return ctx.buildBranch(node, stk)
+       ctx.emit(&format.Event{Name: name, Phase: "s", TID: ctx.proc(ev), ID: ctx.arrowSeq, Time: ctx.time(ev), Stack: ctx.emitter.Stack(ev.Stk), Cname: color})
+       ctx.emit(&format.Event{Name: name, Phase: "t", TID: ctx.proc(ev.Link), ID: ctx.arrowSeq, Time: ctx.time(ev.Link), Cname: color})
 }
 
 // firstTimestamp returns the timestamp of the first event record.
@@ -1253,61 +742,6 @@ func lastTimestamp() int64 {
        return 0
 }
 
-type jsonWriter struct {
-       w   io.Writer
-       enc *json.Encoder
-}
-
-func viewerDataTraceConsumer(w io.Writer, start, end int64) traceConsumer {
-       allFrames := make(map[string]traceviewer.Frame)
-       requiredFrames := make(map[string]traceviewer.Frame)
-       enc := json.NewEncoder(w)
-       written := 0
-       index := int64(-1)
-
-       io.WriteString(w, "{")
-       return traceConsumer{
-               consumeTimeUnit: func(unit string) {
-                       io.WriteString(w, `"displayTimeUnit":`)
-                       enc.Encode(unit)
-                       io.WriteString(w, ",")
-               },
-               consumeViewerEvent: func(v *traceviewer.Event, required bool) {
-                       index++
-                       if !required && (index < start || index > end) {
-                               // not in the range. Skip!
-                               return
-                       }
-                       walkStackFrames(allFrames, v.Stack, func(id int) {
-                               s := strconv.Itoa(id)
-                               requiredFrames[s] = allFrames[s]
-                       })
-                       walkStackFrames(allFrames, v.EndStack, func(id int) {
-                               s := strconv.Itoa(id)
-                               requiredFrames[s] = allFrames[s]
-                       })
-                       if written == 0 {
-                               io.WriteString(w, `"traceEvents": [`)
-                       }
-                       if written > 0 {
-                               io.WriteString(w, ",")
-                       }
-                       enc.Encode(v)
-                       // TODO: get rid of the extra \n inserted by enc.Encode.
-                       // Same should be applied to splittingTraceConsumer.
-                       written++
-               },
-               consumeViewerFrame: func(k string, v traceviewer.Frame) {
-                       allFrames[k] = v
-               },
-               flush: func() {
-                       io.WriteString(w, `], "stackFrames":`)
-                       enc.Encode(requiredFrames)
-                       io.WriteString(w, `}`)
-               },
-       }
-}
-
 // Mapping from more reasonable color names to the reserved color names in
 // https://github.com/catapult-project/catapult/blob/master/tracing/tracing/base/color_scheme.html#L50
 // The chrome trace viewer allows only those as cname values.
index 87fd3a3515c8f018906959644daf2dd9ef5c8054..d315fad47179f56771961e95ea2a635470a03655 100644 (file)
@@ -7,9 +7,10 @@
 package main
 
 import (
-       "cmd/internal/traceviewer"
        "context"
        "internal/trace"
+       "internal/trace/traceviewer"
+       "internal/trace/traceviewer/format"
        "io"
        rtrace "runtime/trace"
        "strings"
@@ -78,10 +79,10 @@ func TestGoroutineCount(t *testing.T) {
 
        // Use the default viewerDataTraceConsumer but replace
        // consumeViewerEvent to intercept the ViewerEvents for testing.
-       c := viewerDataTraceConsumer(io.Discard, 0, 1<<63-1)
-       c.consumeViewerEvent = func(ev *traceviewer.Event, _ bool) {
+       c := traceviewer.ViewerDataTraceConsumer(io.Discard, 0, 1<<63-1)
+       c.ConsumeViewerEvent = func(ev *format.Event, _ bool) {
                if ev.Name == "Goroutines" {
-                       cnt := ev.Arg.(*goroutineCountersArg)
+                       cnt := ev.Arg.(*format.GoroutineCountersArg)
                        if cnt.Runnable+cnt.Running > 2 {
                                t.Errorf("goroutine count=%+v; want no more than 2 goroutines in runnable/running state", cnt)
                        }
@@ -131,7 +132,7 @@ func TestGoroutineFilter(t *testing.T) {
                gs:      map[uint64]bool{10: true},
        }
 
-       c := viewerDataTraceConsumer(io.Discard, 0, 1<<63-1)
+       c := traceviewer.ViewerDataTraceConsumer(io.Discard, 0, 1<<63-1)
        if err := generateTrace(params, c); err != nil {
                t.Fatalf("generateTrace failed: %v", err)
        }
@@ -163,10 +164,10 @@ func TestPreemptedMarkAssist(t *testing.T) {
                endTime: int64(1<<63 - 1),
        }
 
-       c := viewerDataTraceConsumer(io.Discard, 0, 1<<63-1)
+       c := traceviewer.ViewerDataTraceConsumer(io.Discard, 0, 1<<63-1)
 
        marks := 0
-       c.consumeViewerEvent = func(ev *traceviewer.Event, _ bool) {
+       c.ConsumeViewerEvent = func(ev *format.Event, _ bool) {
                if strings.Contains(ev.Name, "MARK ASSIST") {
                        marks++
                }
@@ -208,16 +209,16 @@ func TestFoo(t *testing.T) {
 
        params := &traceParams{
                parsed:    res,
-               mode:      modeTaskOriented,
+               mode:      traceviewer.ModeTaskOriented,
                startTime: task.firstTimestamp() - 1,
                endTime:   task.lastTimestamp() + 1,
                tasks:     []*taskDesc{task},
        }
 
-       c := viewerDataTraceConsumer(io.Discard, 0, 1<<63-1)
+       c := traceviewer.ViewerDataTraceConsumer(io.Discard, 0, 1<<63-1)
 
        var logBeforeTaskEnd, logAfterTaskEnd bool
-       c.consumeViewerEvent = func(ev *traceviewer.Event, _ bool) {
+       c.ConsumeViewerEvent = func(ev *format.Event, _ bool) {
                if ev.Name == "log before task ends" {
                        logBeforeTaskEnd = true
                }
index 87ad86fce8b0de824f1cf297048e3c2adc3a97e4..e6346354276184d7ee2999972c018cfc4d80db0c 100644 (file)
@@ -8,9 +8,10 @@ package main
 
 import (
        "bytes"
-       "cmd/internal/traceviewer"
        "internal/goexperiment"
        traceparser "internal/trace"
+       "internal/trace/traceviewer"
+       "internal/trace/traceviewer/format"
        "io"
        "runtime"
        "runtime/trace"
@@ -87,10 +88,10 @@ func TestGoroutineInSyscall(t *testing.T) {
 
        // Check only one thread for the pipe read goroutine is
        // considered in-syscall.
-       c := viewerDataTraceConsumer(io.Discard, 0, 1<<63-1)
-       c.consumeViewerEvent = func(ev *traceviewer.Event, _ bool) {
+       c := traceviewer.ViewerDataTraceConsumer(io.Discard, 0, 1<<63-1)
+       c.ConsumeViewerEvent = func(ev *format.Event, _ bool) {
                if ev.Name == "Threads" {
-                       arg := ev.Arg.(*threadCountersArg)
+                       arg := ev.Arg.(*format.ThreadCountersArg)
                        if arg.InSyscall > 1 {
                                t.Errorf("%d threads in syscall at time %v; want less than 1 thread in syscall", arg.InSyscall, ev.Time)
                        }
diff --git a/src/cmd/trace/v2/gen.go b/src/cmd/trace/v2/gen.go
new file mode 100644 (file)
index 0000000..cf89603
--- /dev/null
@@ -0,0 +1,249 @@
+// 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.
+
+package trace
+
+import (
+       "internal/trace"
+       "internal/trace/traceviewer"
+       tracev2 "internal/trace/v2"
+       "strings"
+)
+
+// generator is an interface for generating a JSON trace for the trace viewer
+// from a trace. Each method in this interface is a handler for a kind of event
+// that is interesting to render in the UI via the JSON trace.
+type generator interface {
+       // Global parts.
+       Sync() // Notifies the generator of an EventSync event.
+       StackSample(ctx *traceContext, ev *tracev2.Event)
+       GlobalRange(ctx *traceContext, ev *tracev2.Event)
+       GlobalMetric(ctx *traceContext, ev *tracev2.Event)
+
+       // Goroutine parts.
+       GoroutineLabel(ctx *traceContext, ev *tracev2.Event)
+       GoroutineRange(ctx *traceContext, ev *tracev2.Event)
+       GoroutineTransition(ctx *traceContext, ev *tracev2.Event)
+
+       // Proc parts.
+       ProcRange(ctx *traceContext, ev *tracev2.Event)
+       ProcTransition(ctx *traceContext, ev *tracev2.Event)
+
+       // Finish indicates the end of the trace and finalizes generation.
+       Finish(ctx *traceContext, endTime tracev2.Time)
+}
+
+// runGenerator produces a trace into ctx by running the generator over the parsed trace.
+func runGenerator(ctx *traceContext, g generator, parsed *parsedTrace) {
+       for i := range parsed.events {
+               ev := &parsed.events[i]
+
+               switch ev.Kind() {
+               case tracev2.EventSync:
+                       g.Sync()
+               case tracev2.EventStackSample:
+                       g.StackSample(ctx, ev)
+               case tracev2.EventRangeBegin, tracev2.EventRangeActive, tracev2.EventRangeEnd:
+                       r := ev.Range()
+                       switch r.Scope.Kind {
+                       case tracev2.ResourceGoroutine:
+                               g.GoroutineRange(ctx, ev)
+                       case tracev2.ResourceProc:
+                               g.ProcRange(ctx, ev)
+                       case tracev2.ResourceNone:
+                               g.GlobalRange(ctx, ev)
+                       }
+               case tracev2.EventMetric:
+                       g.GlobalMetric(ctx, ev)
+               case tracev2.EventLabel:
+                       l := ev.Label()
+                       if l.Resource.Kind == tracev2.ResourceGoroutine {
+                               g.GoroutineLabel(ctx, ev)
+                       }
+               case tracev2.EventStateTransition:
+                       switch ev.StateTransition().Resource.Kind {
+                       case tracev2.ResourceProc:
+                               g.ProcTransition(ctx, ev)
+                       case tracev2.ResourceGoroutine:
+                               g.GoroutineTransition(ctx, ev)
+                       }
+               }
+       }
+       g.Finish(ctx, parsed.events[len(parsed.events)-1].Time())
+}
+
+// Building blocks for generators.
+
+// stackSampleGenerator implements a generic handler for stack sample events.
+// The provided resource is the resource the stack sample should count against.
+type stackSampleGenerator[R resource] struct {
+       // getResource is a function to extract a resource ID from a stack sample event.
+       getResource func(*tracev2.Event) R
+}
+
+// StackSample implements a stack sample event handler. It expects ev to be one such event.
+func (g *stackSampleGenerator[R]) StackSample(ctx *traceContext, ev *tracev2.Event) {
+       id := g.getResource(ev)
+       if id == R(noResource) {
+               // We have nowhere to put this in the UI.
+               return
+       }
+       ctx.Instant(traceviewer.InstantEvent{
+               Name:     "CPU profile sample",
+               Ts:       ctx.elapsed(ev.Time()),
+               Resource: uint64(id),
+               Stack:    ctx.Stack(viewerFrames(ev.Stack())),
+       })
+}
+
+// globalRangeGenerator implements a generic handler for EventRange* events that pertain
+// to tracev2.ResourceNone (the global scope).
+type globalRangeGenerator struct {
+       ranges   map[string]activeRange
+       seenSync bool
+}
+
+// Sync notifies the generator of an EventSync event.
+func (g *globalRangeGenerator) Sync() {
+       g.seenSync = true
+}
+
+// GlobalRange implements a handler for EventRange* events whose Scope.Kind is ResourceNone.
+// It expects ev to be one such event.
+func (g *globalRangeGenerator) GlobalRange(ctx *traceContext, ev *tracev2.Event) {
+       if g.ranges == nil {
+               g.ranges = make(map[string]activeRange)
+       }
+       r := ev.Range()
+       switch ev.Kind() {
+       case tracev2.EventRangeBegin:
+               g.ranges[r.Name] = activeRange{ev.Time(), ev.Stack()}
+       case tracev2.EventRangeActive:
+               // If we've seen a Sync event, then Active events are always redundant.
+               if !g.seenSync {
+                       // Otherwise, they extend back to the start of the trace.
+                       g.ranges[r.Name] = activeRange{ctx.startTime, ev.Stack()}
+               }
+       case tracev2.EventRangeEnd:
+               // Only emit GC events, because we have nowhere to
+               // put other events.
+               ar := g.ranges[r.Name]
+               if strings.Contains(r.Name, "GC") {
+                       ctx.Slice(traceviewer.SliceEvent{
+                               Name:     r.Name,
+                               Ts:       ctx.elapsed(ar.time),
+                               Dur:      ev.Time().Sub(ar.time),
+                               Resource: trace.GCP,
+                               Stack:    ctx.Stack(viewerFrames(ar.stack)),
+                               EndStack: ctx.Stack(viewerFrames(ev.Stack())),
+                       })
+               }
+               delete(g.ranges, r.Name)
+       }
+}
+
+// Finish flushes any outstanding ranges at the end of the trace.
+func (g *globalRangeGenerator) Finish(ctx *traceContext, endTime tracev2.Time) {
+       for name, ar := range g.ranges {
+               if !strings.Contains(name, "GC") {
+                       continue
+               }
+               ctx.Slice(traceviewer.SliceEvent{
+                       Name:     name,
+                       Ts:       ctx.elapsed(ar.time),
+                       Dur:      endTime.Sub(ar.time),
+                       Resource: trace.GCP,
+                       Stack:    ctx.Stack(viewerFrames(ar.stack)),
+               })
+       }
+}
+
+// globalMetricGenerator implements a generic handler for Metric events.
+type globalMetricGenerator struct {
+}
+
+// GlobalMetric implements an event handler for EventMetric events. ev must be one such event.
+func (g *globalMetricGenerator) GlobalMetric(ctx *traceContext, ev *tracev2.Event) {
+       m := ev.Metric()
+       switch m.Name {
+       case "/memory/classes/heap/objects:bytes":
+               ctx.HeapAlloc(ctx.elapsed(ev.Time()), m.Value.Uint64())
+       case "/gc/heap/goal:bytes":
+               ctx.HeapGoal(ctx.elapsed(ev.Time()), m.Value.Uint64())
+       case "/sched/gomaxprocs:threads":
+               ctx.Gomaxprocs(m.Value.Uint64())
+       }
+}
+
+// procRangeGenerator implements a generic handler for EventRange* events whose Scope.Kind is
+// ResourceProc.
+type procRangeGenerator struct {
+       ranges   map[tracev2.Range]activeRange
+       seenSync bool
+}
+
+// Sync notifies the generator of an EventSync event.
+func (g *procRangeGenerator) Sync() {
+       g.seenSync = true
+}
+
+// ProcRange implements a handler for EventRange* events whose Scope.Kind is ResourceProc.
+// It expects ev to be one such event.
+func (g *procRangeGenerator) ProcRange(ctx *traceContext, ev *tracev2.Event) {
+       if g.ranges == nil {
+               g.ranges = make(map[tracev2.Range]activeRange)
+       }
+       r := ev.Range()
+       switch ev.Kind() {
+       case tracev2.EventRangeBegin:
+               g.ranges[r] = activeRange{ev.Time(), ev.Stack()}
+       case tracev2.EventRangeActive:
+               // If we've seen a Sync event, then Active events are always redundant.
+               if !g.seenSync {
+                       // Otherwise, they extend back to the start of the trace.
+                       g.ranges[r] = activeRange{ctx.startTime, ev.Stack()}
+               }
+       case tracev2.EventRangeEnd:
+               // Emit proc-based ranges.
+               ar := g.ranges[r]
+               ctx.Slice(traceviewer.SliceEvent{
+                       Name:     r.Name,
+                       Ts:       ctx.elapsed(ar.time),
+                       Dur:      ev.Time().Sub(ar.time),
+                       Resource: uint64(r.Scope.Proc()),
+                       Stack:    ctx.Stack(viewerFrames(ar.stack)),
+                       EndStack: ctx.Stack(viewerFrames(ev.Stack())),
+               })
+               delete(g.ranges, r)
+       }
+}
+
+// Finish flushes any outstanding ranges at the end of the trace.
+func (g *procRangeGenerator) Finish(ctx *traceContext, endTime tracev2.Time) {
+       for r, ar := range g.ranges {
+               ctx.Slice(traceviewer.SliceEvent{
+                       Name:     r.Name,
+                       Ts:       ctx.elapsed(ar.time),
+                       Dur:      endTime.Sub(ar.time),
+                       Resource: uint64(r.Scope.Proc()),
+                       Stack:    ctx.Stack(viewerFrames(ar.stack)),
+               })
+       }
+}
+
+// activeRange represents an active EventRange* range.
+type activeRange struct {
+       time  tracev2.Time
+       stack tracev2.Stack
+}
+
+// completedRange represents a completed EventRange* range.
+type completedRange struct {
+       name       string
+       startTime  tracev2.Time
+       endTime    tracev2.Time
+       startStack tracev2.Stack
+       endStack   tracev2.Stack
+       arg        any
+}
diff --git a/src/cmd/trace/v2/gstate.go b/src/cmd/trace/v2/gstate.go
new file mode 100644 (file)
index 0000000..c0c100c
--- /dev/null
@@ -0,0 +1,362 @@
+// 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.
+
+package trace
+
+import (
+       "fmt"
+       "internal/trace"
+       "internal/trace/traceviewer"
+       "internal/trace/traceviewer/format"
+       tracev2 "internal/trace/v2"
+       "strings"
+)
+
+// resource is a generic constraint interface for resource IDs.
+type resource interface{ tracev2.GoID | tracev2.ProcID }
+
+// noResource indicates the lack of a resource.
+const noResource = -1
+
+// gState represents the trace viewer state of a goroutine in a trace.
+//
+// The type parameter on this type is the resource which is used to construct
+// a timeline of events. e.g. R=ProcID for a proc-oriented view, R=GoID for
+// a goroutine-oriented view, etc.
+type gState[R resource] struct {
+       baseName  string
+       named     bool   // Whether baseName has been set.
+       label     string // EventLabel extension.
+       isSystemG bool
+
+       executing R // The resource this goroutine is executing on. (Could be itself.)
+
+       // lastStopStack is the stack trace at the point of the last
+       // call to the stop method. This tends to be a more reliable way
+       // of picking up stack traces, since the parser doesn't provide
+       // a stack for every state transition event.
+       lastStopStack tracev2.Stack
+
+       // activeRanges is the set of all active ranges on the goroutine.
+       activeRanges map[string]activeRange
+
+       // completedRanges is a list of ranges that completed since before the
+       // goroutine stopped executing. These are flushed on every stop or block.
+       completedRanges []completedRange
+
+       // startRunning is the most recent event that caused a goroutine to
+       // transition to GoRunning.
+       startRunningTime tracev2.Time
+
+       // startSyscall is the most recent event that caused a goroutine to
+       // transition to GoSyscall.
+       syscall struct {
+               time   tracev2.Time
+               stack  tracev2.Stack
+               active bool
+       }
+
+       // startBlockReason is the StateTransition.Reason of the most recent
+       // event that caused a gorotuine to transition to GoWaiting.
+       startBlockReason string
+
+       // startCause is the event that allowed this goroutine to start running.
+       // It's used to generate flow events. This is typically something like
+       // an unblock event or a goroutine creation event.
+       //
+       // startCause.resource is the resource on which startCause happened, but is
+       // listed separately because the cause may have happened on a resource that
+       // isn't R (or perhaps on some abstract nebulous resource, like trace.NetpollP).
+       startCause struct {
+               time     tracev2.Time
+               name     string
+               resource uint64
+               stack    tracev2.Stack
+       }
+}
+
+// newGState constructs a new goroutine state for the goroutine
+// identified by the provided ID.
+func newGState[R resource](goID tracev2.GoID) *gState[R] {
+       return &gState[R]{
+               baseName:     fmt.Sprintf("G%d", goID),
+               executing:    R(noResource),
+               activeRanges: make(map[string]activeRange),
+       }
+}
+
+// augmentName attempts to use stk to augment the name of the goroutine
+// with stack information. This stack must be related to the goroutine
+// in some way, but it doesn't really matter which stack.
+func (gs *gState[R]) augmentName(stk tracev2.Stack) {
+       if gs.named {
+               return
+       }
+       if stk == tracev2.NoStack {
+               return
+       }
+       name := lastFunc(stk)
+       gs.baseName += fmt.Sprintf(" %s", name)
+       gs.named = true
+       gs.isSystemG = trace.IsSystemGoroutine(name)
+}
+
+// setLabel adds an additional label to the goroutine's name.
+func (gs *gState[R]) setLabel(label string) {
+       gs.label = label
+}
+
+// name returns a name for the goroutine.
+func (gs *gState[R]) name() string {
+       name := gs.baseName
+       if gs.label != "" {
+               name += " (" + gs.label + ")"
+       }
+       return name
+}
+
+// setStartCause sets the reason a goroutine will be allowed to start soon.
+// For example, via unblocking or exiting a blocked syscall.
+func (gs *gState[R]) setStartCause(ts tracev2.Time, name string, resource uint64, stack tracev2.Stack) {
+       gs.startCause.time = ts
+       gs.startCause.name = name
+       gs.startCause.resource = resource
+       gs.startCause.stack = stack
+}
+
+// created indicates that this goroutine was just created by the provided creator.
+func (gs *gState[R]) created(ts tracev2.Time, creator R, stack tracev2.Stack) {
+       if creator == R(noResource) {
+               return
+       }
+       gs.setStartCause(ts, "go", uint64(creator), stack)
+}
+
+// start indicates that a goroutine has started running on a proc.
+func (gs *gState[R]) start(ts tracev2.Time, resource R, ctx *traceContext) {
+       // Set the time for all the active ranges.
+       for name := range gs.activeRanges {
+               gs.activeRanges[name] = activeRange{ts, tracev2.NoStack}
+       }
+
+       if gs.startCause.name != "" {
+               // It has a start cause. Emit a flow event.
+               ctx.Arrow(traceviewer.ArrowEvent{
+                       Name:         gs.startCause.name,
+                       Start:        ctx.elapsed(gs.startCause.time),
+                       End:          ctx.elapsed(ts),
+                       FromResource: uint64(gs.startCause.resource),
+                       ToResource:   uint64(resource),
+                       FromStack:    ctx.Stack(viewerFrames(gs.startCause.stack)),
+               })
+               gs.startCause.time = 0
+               gs.startCause.name = ""
+               gs.startCause.resource = 0
+               gs.startCause.stack = tracev2.NoStack
+       }
+       gs.executing = resource
+       gs.startRunningTime = ts
+}
+
+// syscallBegin indicates that the goroutine entered a syscall on a proc.
+func (gs *gState[R]) syscallBegin(ts tracev2.Time, resource R, stack tracev2.Stack) {
+       gs.syscall.time = ts
+       gs.syscall.stack = stack
+       gs.syscall.active = true
+       if gs.executing == R(noResource) {
+               gs.executing = resource
+               gs.startRunningTime = ts
+       }
+}
+
+// syscallEnd ends the syscall slice, wherever the syscall is at. This is orthogonal
+// to blockedSyscallEnd -- both must be called when a syscall ends and that syscall
+// blocked. They're kept separate because syscallEnd indicates the point at which the
+// goroutine is no longer executing on the resource (e.g. a proc) whereas blockedSyscallEnd
+// is the point at which the goroutine actually exited the syscall regardless of which
+// resource that happened on.
+func (gs *gState[R]) syscallEnd(ts tracev2.Time, blocked bool, ctx *traceContext) {
+       if !gs.syscall.active {
+               return
+       }
+       blockString := "no"
+       if blocked {
+               blockString = "yes"
+       }
+       gs.completedRanges = append(gs.completedRanges, completedRange{
+               name:       "syscall",
+               startTime:  gs.syscall.time,
+               endTime:    ts,
+               startStack: gs.syscall.stack,
+               arg:        format.BlockedArg{Blocked: blockString},
+       })
+       gs.syscall.active = false
+       gs.syscall.time = 0
+       gs.syscall.stack = tracev2.NoStack
+}
+
+// blockedSyscallEnd indicates the point at which the blocked syscall ended. This is distinct
+// and orthogonal to syscallEnd; both must be called if the syscall blocked. This sets up an instant
+// to emit a flow event from, indicating explicitly that this goroutine was unblocked by the system.
+func (gs *gState[R]) blockedSyscallEnd(ts tracev2.Time, stack tracev2.Stack, ctx *traceContext) {
+       name := "exit blocked syscall"
+       gs.setStartCause(ts, name, trace.SyscallP, stack)
+
+       // Emit an syscall exit instant event for the "Syscall" lane.
+       ctx.Instant(traceviewer.InstantEvent{
+               Name:     name,
+               Ts:       ctx.elapsed(ts),
+               Resource: trace.SyscallP,
+               Stack:    ctx.Stack(viewerFrames(stack)),
+       })
+}
+
+// unblock indicates that the goroutine gs represents has been unblocked.
+func (gs *gState[R]) unblock(ts tracev2.Time, stack tracev2.Stack, resource R, ctx *traceContext) {
+       // Unblocking goroutine.
+       name := "unblock"
+       viewerResource := uint64(resource)
+       if strings.Contains(gs.startBlockReason, "network") {
+               // Emit an unblock instant event for the "Network" lane.
+               ctx.Instant(traceviewer.InstantEvent{
+                       Name:     name,
+                       Ts:       ctx.elapsed(ts),
+                       Resource: trace.NetpollP,
+                       Stack:    ctx.Stack(viewerFrames(stack)),
+               })
+               gs.startBlockReason = ""
+               viewerResource = trace.NetpollP
+       }
+       if viewerResource != 0 {
+               gs.setStartCause(ts, name, viewerResource, stack)
+       }
+}
+
+// block indicates that the goroutine has stopped executing on a proc -- specifically,
+// it blocked for some reason.
+func (gs *gState[R]) block(ts tracev2.Time, stack tracev2.Stack, reason string, ctx *traceContext) {
+       gs.startBlockReason = reason
+       gs.stop(ts, stack, ctx)
+}
+
+// stop indicates that the goroutine has stopped executing on a proc.
+func (gs *gState[R]) stop(ts tracev2.Time, stack tracev2.Stack, ctx *traceContext) {
+       // Emit the execution time slice.
+       var stk int
+       if gs.lastStopStack != tracev2.NoStack {
+               stk = ctx.Stack(viewerFrames(gs.lastStopStack))
+       }
+       // Check invariants.
+       if gs.startRunningTime == 0 {
+               panic("silently broken trace or generator invariant (startRunningTime != 0) not held")
+       }
+       if gs.executing == R(noResource) {
+               panic("non-executing goroutine stopped")
+       }
+       ctx.Slice(traceviewer.SliceEvent{
+               Name:     gs.name(),
+               Ts:       ctx.elapsed(gs.startRunningTime),
+               Dur:      ts.Sub(gs.startRunningTime),
+               Resource: uint64(gs.executing),
+               Stack:    stk,
+       })
+
+       // Flush completed ranges.
+       for _, cr := range gs.completedRanges {
+               ctx.Slice(traceviewer.SliceEvent{
+                       Name:     cr.name,
+                       Ts:       ctx.elapsed(cr.startTime),
+                       Dur:      cr.endTime.Sub(cr.startTime),
+                       Resource: uint64(gs.executing),
+                       Stack:    ctx.Stack(viewerFrames(cr.startStack)),
+                       EndStack: ctx.Stack(viewerFrames(cr.endStack)),
+                       Arg:      cr.arg,
+               })
+       }
+       gs.completedRanges = gs.completedRanges[:0]
+
+       // Continue in-progress ranges.
+       for name, r := range gs.activeRanges {
+               // Check invariant.
+               if r.time == 0 {
+                       panic("silently broken trace or generator invariant (activeRanges time != 0) not held")
+               }
+               ctx.Slice(traceviewer.SliceEvent{
+                       Name:     name,
+                       Ts:       ctx.elapsed(r.time),
+                       Dur:      ts.Sub(r.time),
+                       Resource: uint64(gs.executing),
+                       Stack:    ctx.Stack(viewerFrames(r.stack)),
+               })
+       }
+
+       // Clear the range info.
+       for name := range gs.activeRanges {
+               gs.activeRanges[name] = activeRange{0, tracev2.NoStack}
+       }
+
+       gs.startRunningTime = 0
+       gs.lastStopStack = stack
+       gs.executing = R(noResource)
+}
+
+// finalize writes out any in-progress slices as if the goroutine stopped.
+// This must only be used once the trace has been fully processed and no
+// further events will be processed. This method may leave the gState in
+// an inconsistent state.
+func (gs *gState[R]) finish(ts tracev2.Time, ctx *traceContext) {
+       if gs.executing != R(noResource) {
+               gs.syscallEnd(ts, false, ctx)
+               gs.stop(ts, tracev2.NoStack, ctx)
+       }
+}
+
+// rangeBegin indicates the start of a special range of time.
+func (gs *gState[R]) rangeBegin(ts tracev2.Time, name string, stack tracev2.Stack) {
+       if gs.executing != R(noResource) {
+               // If we're executing, start the slice from here.
+               gs.activeRanges[name] = activeRange{ts, stack}
+       } else {
+               // If the goroutine isn't executing, there's no place for
+               // us to create a slice from. Wait until it starts executing.
+               gs.activeRanges[name] = activeRange{0, stack}
+       }
+}
+
+// rangeActive indicates that a special range of time has been in progress.
+func (gs *gState[R]) rangeActive(name string) {
+       if gs.executing != R(noResource) {
+               // If we're executing, and the range is active, then start
+               // from wherever the goroutine started running from.
+               gs.activeRanges[name] = activeRange{gs.startRunningTime, tracev2.NoStack}
+       } else {
+               // If the goroutine isn't executing, there's no place for
+               // us to create a slice from. Wait until it starts executing.
+               gs.activeRanges[name] = activeRange{0, tracev2.NoStack}
+       }
+}
+
+// rangeEnd indicates the end of a special range of time.
+func (gs *gState[R]) rangeEnd(ts tracev2.Time, name string, stack tracev2.Stack, ctx *traceContext) {
+       if gs.executing != R(noResource) {
+               r := gs.activeRanges[name]
+               gs.completedRanges = append(gs.completedRanges, completedRange{
+                       name:       name,
+                       startTime:  r.time,
+                       endTime:    ts,
+                       startStack: r.stack,
+                       endStack:   stack,
+               })
+       }
+       delete(gs.activeRanges, name)
+}
+
+func lastFunc(s tracev2.Stack) string {
+       var last tracev2.StackFrame
+       s.Frames(func(f tracev2.StackFrame) bool {
+               last = f
+               return true
+       })
+       return last.Func
+}
diff --git a/src/cmd/trace/v2/jsontrace.go b/src/cmd/trace/v2/jsontrace.go
new file mode 100644 (file)
index 0000000..5b98850
--- /dev/null
@@ -0,0 +1,67 @@
+// 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.
+
+package trace
+
+import (
+       "log"
+       "math"
+       "net/http"
+       "strconv"
+       "time"
+
+       "internal/trace/traceviewer"
+       tracev2 "internal/trace/v2"
+)
+
+func JSONTraceHandler(parsed *parsedTrace) http.Handler {
+       return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+               // Parse start and end options. Both or none must be present.
+               start := int64(0)
+               end := int64(math.MaxInt64)
+               if startStr, endStr := r.FormValue("start"), r.FormValue("end"); startStr != "" && endStr != "" {
+                       var err error
+                       start, err = strconv.ParseInt(startStr, 10, 64)
+                       if err != nil {
+                               log.Printf("failed to parse start parameter %q: %v", startStr, err)
+                               return
+                       }
+
+                       end, err = strconv.ParseInt(endStr, 10, 64)
+                       if err != nil {
+                               log.Printf("failed to parse end parameter %q: %v", endStr, err)
+                               return
+                       }
+               }
+
+               c := traceviewer.ViewerDataTraceConsumer(w, start, end)
+               if err := generateTrace(parsed, c); err != nil {
+                       log.Printf("failed to generate trace: %v", err)
+               }
+       })
+}
+
+// traceContext is a wrapper around a traceviewer.Emitter with some additional
+// information that's useful to most parts of trace viewer JSON emission.
+type traceContext struct {
+       *traceviewer.Emitter
+       startTime tracev2.Time
+}
+
+// elapsed returns the elapsed time between the trace time and the start time
+// of the trace.
+func (ctx *traceContext) elapsed(now tracev2.Time) time.Duration {
+       return now.Sub(ctx.startTime)
+}
+
+func generateTrace(parsed *parsedTrace, c traceviewer.TraceConsumer) error {
+       ctx := &traceContext{
+               Emitter:   traceviewer.NewEmitter(c, 0, time.Duration(0), time.Duration(math.MaxInt64)),
+               startTime: parsed.events[0].Time(),
+       }
+       defer ctx.Flush()
+
+       runGenerator(ctx, newProcGenerator(), parsed)
+       return nil
+}
diff --git a/src/cmd/trace/v2/jsontrace_test.go b/src/cmd/trace/v2/jsontrace_test.go
new file mode 100644 (file)
index 0000000..7e0b794
--- /dev/null
@@ -0,0 +1,291 @@
+// 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.
+
+package trace
+
+import (
+       "bytes"
+       "encoding/json"
+       tracev1 "internal/trace"
+       "io"
+       "net/http/httptest"
+       "os"
+       "path/filepath"
+       "slices"
+       "strconv"
+       "strings"
+       "testing"
+       "time"
+
+       "internal/trace/traceviewer/format"
+       "internal/trace/v2/raw"
+)
+
+func TestJSONTraceHandler(t *testing.T) {
+       testPaths, err := filepath.Glob("./testdata/*.test")
+       if err != nil {
+               t.Fatalf("discovering tests: %v", err)
+       }
+       for _, testPath := range testPaths {
+               t.Run(filepath.Base(testPath), func(t *testing.T) {
+                       parsed := getTestTrace(t, testPath)
+                       data := recordJSONTraceHandlerResponse(t, parsed)
+                       // TODO(mknyszek): Check that there's one at most goroutine per proc at any given time.
+                       checkExecutionTimes(t, data)
+                       checkPlausibleHeapMetrics(t, data)
+                       // TODO(mknyszek): Check for plausible thread and goroutine metrics.
+                       checkMetaNamesEmitted(t, data, "process_name", []string{"STATS", "PROCS"})
+                       checkMetaNamesEmitted(t, data, "thread_name", []string{"GC", "Network", "Timers", "Syscalls", "Proc 0"})
+                       checkProcStartStop(t, data)
+                       checkSyscalls(t, data)
+                       checkNetworkUnblock(t, data)
+                       // TODO(mknyszek): Check for flow events.
+               })
+       }
+}
+
+func checkSyscalls(t *testing.T, data format.Data) {
+       data = filterViewerTrace(data,
+               filterEventName("syscall"),
+               filterStackRootFunc("main.blockingSyscall"))
+       if len(data.Events) <= 1 {
+               t.Errorf("got %d events, want > 1", len(data.Events))
+       }
+       data = filterViewerTrace(data, filterBlocked("yes"))
+       if len(data.Events) != 1 {
+               t.Errorf("got %d events, want 1", len(data.Events))
+       }
+}
+
+type eventFilterFn func(*format.Event, *format.Data) bool
+
+func filterEventName(name string) eventFilterFn {
+       return func(e *format.Event, _ *format.Data) bool {
+               return e.Name == name
+       }
+}
+
+// filterGoRoutineName returns an event filter that returns true if the event's
+// goroutine name is equal to name.
+func filterGoRoutineName(name string) eventFilterFn {
+       return func(e *format.Event, _ *format.Data) bool {
+               return parseGoroutineName(e) == name
+       }
+}
+
+// parseGoroutineName returns the goroutine name from the event's name field.
+// E.g. if e.Name is "G42 main.cpu10", this returns "main.cpu10".
+func parseGoroutineName(e *format.Event) string {
+       parts := strings.SplitN(e.Name, " ", 2)
+       if len(parts) != 2 || !strings.HasPrefix(parts[0], "G") {
+               return ""
+       }
+       return parts[1]
+}
+
+// filterBlocked returns an event filter that returns true if the event's
+// "blocked" argument is equal to blocked.
+func filterBlocked(blocked string) eventFilterFn {
+       return func(e *format.Event, _ *format.Data) bool {
+               m, ok := e.Arg.(map[string]any)
+               if !ok {
+                       return false
+               }
+               return m["blocked"] == blocked
+       }
+}
+
+// filterStackRootFunc returns an event filter that returns true if the function
+// at the root of the stack trace is named name.
+func filterStackRootFunc(name string) eventFilterFn {
+       return func(e *format.Event, data *format.Data) bool {
+               frames := stackFrames(data, e.Stack)
+               rootFrame := frames[len(frames)-1]
+               return strings.HasPrefix(rootFrame, name+":")
+       }
+}
+
+// filterViewerTrace returns a copy of data with only the events that pass all
+// of the given filters.
+func filterViewerTrace(data format.Data, fns ...eventFilterFn) (filtered format.Data) {
+       filtered = data
+       filtered.Events = nil
+       for _, e := range data.Events {
+               keep := true
+               for _, fn := range fns {
+                       keep = keep && fn(e, &filtered)
+               }
+               if keep {
+                       filtered.Events = append(filtered.Events, e)
+               }
+       }
+       return
+}
+
+func stackFrames(data *format.Data, stackID int) (frames []string) {
+       for {
+               frame, ok := data.Frames[strconv.Itoa(stackID)]
+               if !ok {
+                       return
+               }
+               frames = append(frames, frame.Name)
+               stackID = frame.Parent
+       }
+}
+
+func checkProcStartStop(t *testing.T, data format.Data) {
+       procStarted := map[uint64]bool{}
+       for _, e := range data.Events {
+               if e.Name == "proc start" {
+                       if procStarted[e.TID] == true {
+                               t.Errorf("proc started twice: %d", e.TID)
+                       }
+                       procStarted[e.TID] = true
+               }
+               if e.Name == "proc stop" {
+                       if procStarted[e.TID] == false {
+                               t.Errorf("proc stopped twice: %d", e.TID)
+                       }
+                       procStarted[e.TID] = false
+               }
+       }
+       if got, want := len(procStarted), 8; got != want {
+               t.Errorf("wrong number of procs started/stopped got=%d want=%d", got, want)
+       }
+}
+
+func checkNetworkUnblock(t *testing.T, data format.Data) {
+       count := 0
+       var netBlockEv *format.Event
+       for _, e := range data.Events {
+               if e.TID == tracev1.NetpollP && e.Name == "unblock" && e.Phase == "I" && e.Scope == "t" {
+                       count++
+                       netBlockEv = e
+               }
+       }
+       if netBlockEv == nil {
+               t.Error("failed to find a network unblock")
+       }
+       if count == 0 || count > 2 {
+               t.Errorf("found too many network block events: want 1 or 2, found %d", count)
+       }
+       // TODO(mknyszek): Check for the flow of this event to some slice event of a goroutine running.
+}
+
+func checkExecutionTimes(t *testing.T, data format.Data) {
+       cpu10 := sumExecutionTime(filterViewerTrace(data, filterGoRoutineName("main.cpu10")))
+       cpu20 := sumExecutionTime(filterViewerTrace(data, filterGoRoutineName("main.cpu20")))
+       if cpu10 <= 0 || cpu20 <= 0 || cpu10 >= cpu20 {
+               t.Errorf("bad execution times: cpu10=%v, cpu20=%v", cpu10, cpu20)
+       }
+}
+
+func checkMetaNamesEmitted(t *testing.T, data format.Data, category string, want []string) {
+       t.Helper()
+       names := metaEventNameArgs(category, data)
+       for _, wantName := range want {
+               if !slices.Contains(names, wantName) {
+                       t.Errorf("%s: names=%v, want %q", category, names, wantName)
+               }
+       }
+}
+
+func metaEventNameArgs(category string, data format.Data) (names []string) {
+       for _, e := range data.Events {
+               if e.Name == category && e.Phase == "M" {
+                       names = append(names, e.Arg.(map[string]any)["name"].(string))
+               }
+       }
+       return
+}
+
+func checkPlausibleHeapMetrics(t *testing.T, data format.Data) {
+       hms := heapMetrics(data)
+       var nonZeroAllocated, nonZeroNextGC bool
+       for _, hm := range hms {
+               if hm.Allocated > 0 {
+                       nonZeroAllocated = true
+               }
+               if hm.NextGC > 0 {
+                       nonZeroNextGC = true
+               }
+       }
+
+       if !nonZeroAllocated {
+               t.Errorf("nonZeroAllocated=%v, want true", nonZeroAllocated)
+       }
+       if !nonZeroNextGC {
+               t.Errorf("nonZeroNextGC=%v, want true", nonZeroNextGC)
+       }
+}
+
+func heapMetrics(data format.Data) (metrics []format.HeapCountersArg) {
+       for _, e := range data.Events {
+               if e.Phase == "C" && e.Name == "Heap" {
+                       j, _ := json.Marshal(e.Arg)
+                       var metric format.HeapCountersArg
+                       json.Unmarshal(j, &metric)
+                       metrics = append(metrics, metric)
+               }
+       }
+       return
+}
+
+func recordJSONTraceHandlerResponse(t *testing.T, parsed *parsedTrace) format.Data {
+       h := JSONTraceHandler(parsed)
+       recorder := httptest.NewRecorder()
+       r := httptest.NewRequest("GET", "/jsontrace", nil)
+       h.ServeHTTP(recorder, r)
+
+       var data format.Data
+       if err := json.Unmarshal(recorder.Body.Bytes(), &data); err != nil {
+               t.Fatal(err)
+       }
+       return data
+}
+
+func sumExecutionTime(data format.Data) (sum time.Duration) {
+       for _, e := range data.Events {
+               sum += time.Duration(e.Dur) * time.Microsecond
+       }
+       return
+}
+
+func getTestTrace(t *testing.T, testPath string) *parsedTrace {
+       t.Helper()
+
+       // First read in the text trace and write it out as bytes.
+       f, err := os.Open(testPath)
+       if err != nil {
+               t.Fatalf("failed to open test %s: %v", testPath, err)
+       }
+       r, err := raw.NewTextReader(f)
+       if err != nil {
+               t.Fatalf("failed to read test %s: %v", testPath, err)
+       }
+       var trace bytes.Buffer
+       w, err := raw.NewWriter(&trace, r.Version())
+       if err != nil {
+               t.Fatalf("failed to write out test %s: %v", testPath, err)
+       }
+       for {
+               ev, err := r.ReadEvent()
+               if err == io.EOF {
+                       break
+               }
+               if err != nil {
+                       t.Fatalf("failed to read test %s: %v", testPath, err)
+               }
+               if err := w.WriteEvent(ev); err != nil {
+                       t.Fatalf("failed to write out test %s: %v", testPath, err)
+               }
+       }
+
+       // Parse the test trace.
+       parsed, err := parseTrace(&trace)
+       if err != nil {
+               t.Fatalf("failed to parse trace: %v", err)
+       }
+       return parsed
+}
diff --git a/src/cmd/trace/v2/main.go b/src/cmd/trace/v2/main.go
new file mode 100644 (file)
index 0000000..93c9d89
--- /dev/null
@@ -0,0 +1,136 @@
+// 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.
+
+package trace
+
+import (
+       "fmt"
+       "internal/trace/traceviewer"
+       tracev2 "internal/trace/v2"
+       "io"
+       "log"
+       "net"
+       "net/http"
+       "os"
+
+       "internal/trace/v2/raw"
+
+       "cmd/internal/browser"
+)
+
+// Main is the main function for cmd/trace v2.
+func Main(traceFile, httpAddr, pprof string, debug int) error {
+       tracef, err := os.Open(traceFile)
+       if err != nil {
+               return fmt.Errorf("failed to read trace file: %w", err)
+       }
+       defer tracef.Close()
+
+       // Debug flags.
+       switch debug {
+       case 1:
+               return debugProcessedEvents(tracef)
+       case 2:
+               return debugRawEvents(tracef)
+       }
+
+       ln, err := net.Listen("tcp", httpAddr)
+       if err != nil {
+               return fmt.Errorf("failed to create server socket: %w", err)
+       }
+
+       addr := "http://" + ln.Addr().String()
+       log.Print("Parsing trace...")
+       parsed, err := parseTrace(tracef)
+       if err != nil {
+               return err
+       }
+       // N.B. tracef not needed after this point.
+       // We might double-close, but that's fine; we ignore the error.
+       tracef.Close()
+
+       log.Print("Splitting trace...")
+       ranges, err := splitTrace(parsed)
+       if err != nil {
+               return err
+       }
+
+       log.Printf("Opening browser. Trace viewer is listening on %s", addr)
+       browser.Open(addr)
+
+       mux := http.NewServeMux()
+       mux.Handle("/", traceviewer.MainHandler(ranges))
+       mux.Handle("/trace", traceviewer.TraceHandler())
+       mux.Handle("/jsontrace", JSONTraceHandler(parsed))
+       mux.Handle("/static/", traceviewer.StaticHandler())
+
+       err = http.Serve(ln, mux)
+       return fmt.Errorf("failed to start http server: %w", err)
+}
+
+type parsedTrace struct {
+       events []tracev2.Event
+}
+
+func parseTrace(trace io.Reader) (*parsedTrace, error) {
+       r, err := tracev2.NewReader(trace)
+       if err != nil {
+               return nil, fmt.Errorf("failed to create trace reader: %w", err)
+       }
+       var t parsedTrace
+       for {
+               ev, err := r.ReadEvent()
+               if err == io.EOF {
+                       break
+               } else if err != nil {
+                       return nil, fmt.Errorf("failed to read event: %w", err)
+               }
+               t.events = append(t.events, ev)
+       }
+       return &t, nil
+}
+
+// splitTrace splits the trace into a number of ranges, each resulting in approx 100 MiB of
+// json output (the trace viewer can hardly handle more).
+func splitTrace(parsed *parsedTrace) ([]traceviewer.Range, error) {
+       // TODO(mknyszek): Split traces by generation by doing a quick first pass over the
+       // trace to identify all the generation boundaries.
+       s, c := traceviewer.SplittingTraceConsumer(100 << 20) // 100 MiB
+       if err := generateTrace(parsed, c); err != nil {
+               return nil, err
+       }
+       return s.Ranges, nil
+}
+
+func debugProcessedEvents(trace io.Reader) error {
+       tr, err := tracev2.NewReader(trace)
+       if err != nil {
+               return err
+       }
+       for {
+               ev, err := tr.ReadEvent()
+               if err == io.EOF {
+                       return nil
+               } else if err != nil {
+                       return err
+               }
+               fmt.Println(ev.String())
+       }
+}
+
+func debugRawEvents(trace io.Reader) error {
+       rr, err := raw.NewReader(trace)
+       if err != nil {
+               return err
+       }
+       for {
+               ev, err := rr.ReadEvent()
+               if err == io.EOF {
+                       return nil
+               } else if err != nil {
+                       return err
+               }
+               fmt.Println(ev.String())
+       }
+}
diff --git a/src/cmd/trace/v2/procgen.go b/src/cmd/trace/v2/procgen.go
new file mode 100644 (file)
index 0000000..a49f9ec
--- /dev/null
@@ -0,0 +1,209 @@
+// 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.
+
+package trace
+
+import (
+       "fmt"
+       "internal/trace/traceviewer"
+       "internal/trace/traceviewer/format"
+       tracev2 "internal/trace/v2"
+)
+
+var _ generator = &procGenerator{}
+
+type procGenerator struct {
+       globalRangeGenerator
+       globalMetricGenerator
+       procRangeGenerator
+       stackSampleGenerator[tracev2.ProcID]
+
+       gStates   map[tracev2.GoID]*gState[tracev2.ProcID]
+       inSyscall map[tracev2.ProcID]*gState[tracev2.ProcID]
+       maxProc   tracev2.ProcID
+}
+
+func newProcGenerator() *procGenerator {
+       pg := new(procGenerator)
+       pg.stackSampleGenerator.getResource = func(ev *tracev2.Event) tracev2.ProcID {
+               return ev.Proc()
+       }
+       pg.gStates = make(map[tracev2.GoID]*gState[tracev2.ProcID])
+       pg.inSyscall = make(map[tracev2.ProcID]*gState[tracev2.ProcID])
+       return pg
+}
+
+func (g *procGenerator) Sync() {
+       g.globalRangeGenerator.Sync()
+       g.procRangeGenerator.Sync()
+}
+
+func (g *procGenerator) GoroutineLabel(ctx *traceContext, ev *tracev2.Event) {
+       l := ev.Label()
+       g.gStates[l.Resource.Goroutine()].setLabel(l.Label)
+}
+
+func (g *procGenerator) GoroutineRange(ctx *traceContext, ev *tracev2.Event) {
+       r := ev.Range()
+       switch ev.Kind() {
+       case tracev2.EventRangeBegin:
+               g.gStates[r.Scope.Goroutine()].rangeBegin(ev.Time(), r.Name, ev.Stack())
+       case tracev2.EventRangeActive:
+               g.gStates[r.Scope.Goroutine()].rangeActive(r.Name)
+       case tracev2.EventRangeEnd:
+               gs := g.gStates[r.Scope.Goroutine()]
+               gs.rangeEnd(ev.Time(), r.Name, ev.Stack(), ctx)
+       }
+}
+
+func (g *procGenerator) GoroutineTransition(ctx *traceContext, ev *tracev2.Event) {
+       st := ev.StateTransition()
+       goID := st.Resource.Goroutine()
+
+       // If we haven't seen this goroutine before, create a new
+       // gState for it.
+       gs, ok := g.gStates[goID]
+       if !ok {
+               gs = newGState[tracev2.ProcID](goID)
+               g.gStates[goID] = gs
+       }
+       // If we haven't already named this goroutine, try to name it.
+       gs.augmentName(st.Stack)
+
+       // Handle the goroutine state transition.
+       from, to := st.Goroutine()
+       if from == to {
+               // Filter out no-op events.
+               return
+       }
+       if from == tracev2.GoRunning && !to.Executing() {
+               if to == tracev2.GoWaiting {
+                       // Goroutine started blocking.
+                       gs.block(ev.Time(), ev.Stack(), st.Reason, ctx)
+               } else {
+                       gs.stop(ev.Time(), ev.Stack(), ctx)
+               }
+       }
+       if !from.Executing() && to == tracev2.GoRunning {
+               start := ev.Time()
+               if from == tracev2.GoUndetermined {
+                       // Back-date the event to the start of the trace.
+                       start = ctx.startTime
+               }
+               gs.start(start, ev.Proc(), ctx)
+       }
+
+       if from == tracev2.GoWaiting {
+               // Goroutine was unblocked.
+               gs.unblock(ev.Time(), ev.Stack(), ev.Proc(), ctx)
+       }
+       if from == tracev2.GoNotExist && to == tracev2.GoRunnable {
+               // Goroutine was created.
+               gs.created(ev.Time(), ev.Proc(), ev.Stack())
+       }
+       if from == tracev2.GoSyscall && to != tracev2.GoRunning {
+               // Goroutine exited a blocked syscall.
+               gs.blockedSyscallEnd(ev.Time(), ev.Stack(), ctx)
+       }
+
+       // Handle syscalls.
+       if to == tracev2.GoSyscall && ev.Proc() != tracev2.NoProc {
+               start := ev.Time()
+               if from == tracev2.GoUndetermined {
+                       // Back-date the event to the start of the trace.
+                       start = ctx.startTime
+               }
+               // Write down that we've entered a syscall. Note: we might have no P here
+               // if we're in a cgo callback or this is a transition from GoUndetermined
+               // (i.e. the G has been blocked in a syscall).
+               gs.syscallBegin(start, ev.Proc(), ev.Stack())
+               g.inSyscall[ev.Proc()] = gs
+       }
+       // Check if we're exiting a non-blocking syscall.
+       _, didNotBlock := g.inSyscall[ev.Proc()]
+       if from == tracev2.GoSyscall && didNotBlock {
+               gs.syscallEnd(ev.Time(), false, ctx)
+               delete(g.inSyscall, ev.Proc())
+       }
+
+       // Note down the goroutine transition.
+       _, inMarkAssist := gs.activeRanges["GC mark assist"]
+       ctx.GoroutineTransition(ctx.elapsed(ev.Time()), viewerGState(from, inMarkAssist), viewerGState(to, inMarkAssist))
+}
+
+func (g *procGenerator) ProcTransition(ctx *traceContext, ev *tracev2.Event) {
+       st := ev.StateTransition()
+       proc := st.Resource.Proc()
+
+       g.maxProc = max(g.maxProc, proc)
+       viewerEv := traceviewer.InstantEvent{
+               Resource: uint64(proc),
+               Stack:    ctx.Stack(viewerFrames(ev.Stack())),
+       }
+
+       from, to := st.Proc()
+       if from == to {
+               // Filter out no-op events.
+               return
+       }
+       if to.Executing() {
+               start := ev.Time()
+               if from == tracev2.ProcUndetermined {
+                       start = ctx.startTime
+               }
+               viewerEv.Name = "proc start"
+               viewerEv.Arg = format.ThreadIDArg{ThreadID: uint64(ev.Thread())}
+               viewerEv.Ts = ctx.elapsed(start)
+               ctx.IncThreadStateCount(ctx.elapsed(start), traceviewer.ThreadStateRunning, 1)
+       }
+       if from.Executing() {
+               start := ev.Time()
+               viewerEv.Name = "proc stop"
+               viewerEv.Ts = ctx.elapsed(start)
+               ctx.IncThreadStateCount(ctx.elapsed(start), traceviewer.ThreadStateRunning, -1)
+
+               // Check if this proc was in a syscall before it stopped.
+               // This means the syscall blocked. We need to emit it to the
+               // viewer at this point because we only display the time the
+               // syscall occupied a P when the viewer is in per-P mode.
+               //
+               // TODO(mknyszek): We could do better in a per-M mode because
+               // all events have to happen on *some* thread, and in v2 traces
+               // we know what that thread is.
+               gs, ok := g.inSyscall[proc]
+               if ok {
+                       // Emit syscall slice for blocked syscall.
+                       gs.syscallEnd(start, true, ctx)
+                       gs.stop(start, ev.Stack(), ctx)
+                       delete(g.inSyscall, proc)
+               }
+       }
+       // TODO(mknyszek): Consider modeling procs differently and have them be
+       // transition to and from NotExist when GOMAXPROCS changes. We can emit
+       // events for this to clearly delineate GOMAXPROCS changes.
+
+       if viewerEv.Name != "" {
+               ctx.Instant(viewerEv)
+       }
+}
+
+func (g *procGenerator) Finish(ctx *traceContext, endTime tracev2.Time) {
+       ctx.SetResourceType("PROCS")
+
+       // Finish off ranges first. It doesn't really matter for the global ranges,
+       // but the proc ranges need to either be a subset of a goroutine slice or
+       // their own slice entirely. If the former, it needs to end first.
+       g.procRangeGenerator.Finish(ctx, endTime)
+       g.globalRangeGenerator.Finish(ctx, endTime)
+
+       // Finish off all the goroutine slices.
+       for _, gs := range g.gStates {
+               gs.finish(endTime, ctx)
+       }
+
+       // Name all the procs to the emitter.
+       for i := uint64(0); i <= uint64(g.maxProc); i++ {
+               ctx.Resource(i, fmt.Sprintf("Proc %v", i))
+       }
+}
diff --git a/src/cmd/trace/v2/testdata/generate.go b/src/cmd/trace/v2/testdata/generate.go
new file mode 100644 (file)
index 0000000..c0658b2
--- /dev/null
@@ -0,0 +1,6 @@
+// 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.
+
+//go:generate go run mktests.go
+package testdata
diff --git a/src/cmd/trace/v2/testdata/go122.test b/src/cmd/trace/v2/testdata/go122.test
new file mode 100644 (file)
index 0000000..36a035d
--- /dev/null
@@ -0,0 +1,4366 @@
+Trace Go1.22
+EventBatch gen=1 m=18446744073709551615 time=420903766321 size=5
+Frequency freq=15625000
+EventBatch gen=1 m=2852347 time=420902165664 size=321
+ProcStart dt=1006 p=6 p_seq=1
+GoStart dt=38 g=14 g_seq=1
+GoStop dt=299059 reason_string=16 stack=52
+GoStart dt=17 g=14 g_seq=2
+GoStop dt=316380 reason_string=16 stack=52
+GoStart dt=10 g=14 g_seq=3
+GoUnblock dt=165829 g=1 g_seq=59 stack=53
+GoDestroy dt=195
+GoStart dt=19 g=1 g_seq=60
+HeapAlloc dt=44 heapalloc_value=23256928
+HeapAlloc dt=19 heapalloc_value=23265088
+GoCreate dt=32 new_g=66 new_stack=54 stack=55
+GoBlock dt=12 reason_string=12 stack=56
+GoStart dt=5 g=66 g_seq=1
+HeapAlloc dt=199 heapalloc_value=23273224
+HeapAlloc dt=13 heapalloc_value=23281032
+GoSyscallBegin dt=19 p_seq=2 stack=57
+GoSyscallEnd dt=30
+GoSyscallBegin dt=10 p_seq=3 stack=58
+GoSyscallEnd dt=17
+GoSyscallBegin dt=295 p_seq=4 stack=59
+GoSyscallEnd dt=16
+GoSyscallBegin dt=6 p_seq=5 stack=60
+GoSyscallEnd dt=14
+HeapAlloc dt=216 heapalloc_value=23289000
+HeapAlloc dt=15 heapalloc_value=23296376
+HeapAlloc dt=19 heapalloc_value=23304328
+GoSyscallBegin dt=16 p_seq=6 stack=61
+GoSyscallEnd dt=15
+GoSyscallBegin dt=7 p_seq=7 stack=62
+GoSyscallEnd dt=14
+GoSyscallBegin dt=12 p_seq=8 stack=63
+ProcStart dt=787812 p=7 p_seq=8
+GoSyscallEndBlocked dt=6
+GoStart dt=1 g=66 g_seq=2
+GoUnblock dt=40 g=1 g_seq=61 stack=66
+GoDestroy dt=191
+GoStart dt=23 g=1 g_seq=62
+GoStop dt=27 reason_string=16 stack=67
+GoStart dt=12 g=1 g_seq=63
+HeapAlloc dt=433 heapalloc_value=23321416
+HeapAlloc dt=23 heapalloc_value=23329608
+HeapAlloc dt=27 heapalloc_value=23337800
+HeapAlloc dt=113 heapalloc_value=23344536
+HeapAlloc dt=447 heapalloc_value=23352728
+HeapAlloc dt=38 heapalloc_value=23360856
+GoSyscallBegin dt=19 p_seq=9 stack=68
+GoSyscallEnd dt=927
+HeapAlloc dt=22 heapalloc_value=23368952
+GoSyscallBegin dt=16 p_seq=10 stack=69
+GoSyscallEnd dt=30
+GoSyscallBegin dt=10 p_seq=11 stack=70
+GoSyscallEnd dt=20
+HeapAlloc dt=287 heapalloc_value=23434488
+GoSyscallBegin dt=45 p_seq=12 stack=71
+GoSyscallEnd dt=234
+GoSyscallBegin dt=11 p_seq=13 stack=71
+GoSyscallEnd dt=109
+GoSyscallBegin dt=77 p_seq=14 stack=72
+GoSyscallEnd dt=54
+GoSyscallBegin dt=22 p_seq=15 stack=73
+GoSyscallEnd dt=41
+GoSyscallBegin dt=24 p_seq=16 stack=74
+GoSyscallEnd dt=173
+GoSyscallBegin dt=11 p_seq=17 stack=75
+GoSyscallEnd dt=68
+HeapAlloc dt=134 heapalloc_value=23442648
+HeapAlloc dt=18 heapalloc_value=23450744
+GoCreate dt=23 new_g=82 new_stack=76 stack=77
+HeapAlloc dt=256 heapalloc_value=23458456
+GoSyscallBegin dt=293 p_seq=18 stack=78
+GoSyscallEnd dt=1156
+GoBlock dt=522 reason_string=7 stack=80
+ProcStop dt=25
+EventBatch gen=1 m=2852346 time=420902051246 size=68
+ProcStart dt=304 p=5 p_seq=1
+ProcStop dt=237
+ProcStart dt=1645 p=5 p_seq=2
+ProcStop dt=30
+ProcStart dt=2505 p=1 p_seq=31
+GoStart dt=199 g=34 g_seq=5
+GoBlock dt=29 reason_string=15 stack=26
+ProcStop dt=25
+ProcStart dt=103771 p=1 p_seq=32
+GoStart dt=185 g=10 g_seq=1
+GoStop dt=304886 reason_string=16 stack=52
+GoStart dt=20 g=10 g_seq=2
+GoStop dt=316414 reason_string=16 stack=52
+GoStart dt=20 g=10 g_seq=3
+GoDestroy dt=159939
+ProcStop dt=47
+EventBatch gen=1 m=2852345 time=420901844115 size=3554
+ProcStart dt=108 p=4 p_seq=1
+ProcStop dt=283
+ProcStart dt=3670 p=0 p_seq=27
+GoStart dt=473 g=1 g_seq=19
+GCMarkAssistEnd dt=34
+HeapAlloc dt=33 heapalloc_value=4117744
+HeapAlloc dt=544 heapalloc_value=4124912
+GCSweepBegin dt=49 stack=38
+GCSweepEnd dt=1131 swept_value=827392 reclaimed_value=0
+HeapAlloc dt=64 heapalloc_value=4133104
+GCSweepBegin dt=44 stack=38
+GCSweepEnd dt=192 swept_value=139264 reclaimed_value=0
+HeapAlloc dt=12 heapalloc_value=4141296
+HeapAlloc dt=29 heapalloc_value=4149488
+HeapAlloc dt=19 heapalloc_value=4157680
+HeapAlloc dt=24 heapalloc_value=4165872
+HeapAlloc dt=23 heapalloc_value=4174064
+GCSweepBegin dt=34 stack=39
+GCSweepEnd dt=33 swept_value=67108864 reclaimed_value=0
+HeapAlloc dt=8 heapalloc_value=4182256
+HeapAlloc dt=117 heapalloc_value=4190448
+HeapAlloc dt=27 heapalloc_value=4198640
+HeapAlloc dt=19 heapalloc_value=4206832
+HeapAlloc dt=23 heapalloc_value=4215024
+HeapAlloc dt=20 heapalloc_value=4223216
+HeapAlloc dt=18 heapalloc_value=4231408
+HeapAlloc dt=70 heapalloc_value=4239600
+HeapAlloc dt=19 heapalloc_value=4247792
+HeapAlloc dt=16 heapalloc_value=4255984
+HeapAlloc dt=16 heapalloc_value=4264176
+HeapAlloc dt=15 heapalloc_value=4272368
+HeapAlloc dt=18 heapalloc_value=4280560
+HeapAlloc dt=15 heapalloc_value=4288752
+HeapAlloc dt=15 heapalloc_value=4296944
+HeapAlloc dt=17 heapalloc_value=4305136
+HeapAlloc dt=18 heapalloc_value=4313328
+HeapAlloc dt=17 heapalloc_value=4321520
+HeapAlloc dt=14 heapalloc_value=4329712
+HeapAlloc dt=15 heapalloc_value=4337904
+HeapAlloc dt=16 heapalloc_value=4346096
+HeapAlloc dt=15 heapalloc_value=4354288
+HeapAlloc dt=17 heapalloc_value=4362480
+HeapAlloc dt=38 heapalloc_value=4370672
+HeapAlloc dt=22 heapalloc_value=4378864
+HeapAlloc dt=23 heapalloc_value=4387056
+HeapAlloc dt=22 heapalloc_value=4395248
+HeapAlloc dt=27 heapalloc_value=4403440
+HeapAlloc dt=27 heapalloc_value=4411632
+HeapAlloc dt=29 heapalloc_value=4419824
+HeapAlloc dt=25 heapalloc_value=4428016
+HeapAlloc dt=25 heapalloc_value=4436208
+HeapAlloc dt=21 heapalloc_value=4444400
+GoBlock dt=45 reason_string=19 stack=21
+ProcStop dt=283
+ProcStart dt=17671 p=1 p_seq=16
+ProcStop dt=21
+ProcStart dt=2566 p=0 p_seq=30
+ProcStop dt=12
+ProcStart dt=16741 p=0 p_seq=31
+GoUnblock dt=27 g=1 g_seq=22 stack=0
+GoStart dt=174 g=1 g_seq=23
+HeapAlloc dt=39 heapalloc_value=5574896
+HeapAlloc dt=20 heapalloc_value=5583088
+HeapAlloc dt=13 heapalloc_value=5591280
+HeapAlloc dt=12 heapalloc_value=5599472
+HeapAlloc dt=12 heapalloc_value=5607664
+HeapAlloc dt=12 heapalloc_value=5615856
+HeapAlloc dt=13 heapalloc_value=5624048
+HeapAlloc dt=41 heapalloc_value=5632240
+HeapAlloc dt=12 heapalloc_value=5640432
+HeapAlloc dt=13 heapalloc_value=5648624
+HeapAlloc dt=11 heapalloc_value=5656816
+HeapAlloc dt=12 heapalloc_value=5665008
+HeapAlloc dt=8 heapalloc_value=5673200
+HeapAlloc dt=39 heapalloc_value=5804272
+HeapAlloc dt=2903 heapalloc_value=5812464
+HeapAlloc dt=14 heapalloc_value=5820656
+HeapAlloc dt=77 heapalloc_value=5828848
+HeapAlloc dt=10 heapalloc_value=5837040
+HeapAlloc dt=8 heapalloc_value=5845232
+HeapAlloc dt=48 heapalloc_value=5853424
+HeapAlloc dt=9 heapalloc_value=5861616
+HeapAlloc dt=8 heapalloc_value=5869808
+HeapAlloc dt=8 heapalloc_value=5878000
+HeapAlloc dt=9 heapalloc_value=5886192
+HeapAlloc dt=8 heapalloc_value=5894384
+HeapAlloc dt=8 heapalloc_value=5902576
+HeapAlloc dt=8 heapalloc_value=5910768
+HeapAlloc dt=8 heapalloc_value=5918960
+HeapAlloc dt=8 heapalloc_value=5927152
+HeapAlloc dt=8 heapalloc_value=5935344
+HeapAlloc dt=8 heapalloc_value=5943536
+HeapAlloc dt=17 heapalloc_value=5951728
+HeapAlloc dt=8 heapalloc_value=5959920
+HeapAlloc dt=6 heapalloc_value=5968112
+HeapAlloc dt=6 heapalloc_value=5976304
+HeapAlloc dt=6 heapalloc_value=5984496
+HeapAlloc dt=7 heapalloc_value=5992688
+HeapAlloc dt=6 heapalloc_value=6000880
+HeapAlloc dt=6 heapalloc_value=6009072
+HeapAlloc dt=7 heapalloc_value=6017264
+HeapAlloc dt=6 heapalloc_value=6025456
+HeapAlloc dt=6 heapalloc_value=6033648
+HeapAlloc dt=6 heapalloc_value=6041840
+HeapAlloc dt=6 heapalloc_value=6050032
+HeapAlloc dt=7 heapalloc_value=6058224
+HeapAlloc dt=44 heapalloc_value=6066416
+HeapAlloc dt=8 heapalloc_value=6074608
+HeapAlloc dt=71 heapalloc_value=6082800
+HeapAlloc dt=8 heapalloc_value=6090992
+HeapAlloc dt=6 heapalloc_value=6099184
+HeapAlloc dt=7 heapalloc_value=6107376
+HeapAlloc dt=6 heapalloc_value=6115568
+HeapAlloc dt=6 heapalloc_value=6123760
+HeapAlloc dt=7 heapalloc_value=6131952
+HeapAlloc dt=6 heapalloc_value=6140144
+HeapAlloc dt=6 heapalloc_value=6148336
+HeapAlloc dt=6 heapalloc_value=6156528
+HeapAlloc dt=7 heapalloc_value=6164720
+HeapAlloc dt=6 heapalloc_value=6172912
+HeapAlloc dt=6 heapalloc_value=6181104
+HeapAlloc dt=6 heapalloc_value=6189296
+HeapAlloc dt=6 heapalloc_value=6197488
+HeapAlloc dt=7 heapalloc_value=6205680
+HeapAlloc dt=6 heapalloc_value=6213872
+HeapAlloc dt=6 heapalloc_value=6222064
+HeapAlloc dt=6 heapalloc_value=6230256
+HeapAlloc dt=6 heapalloc_value=6238448
+HeapAlloc dt=7 heapalloc_value=6246640
+HeapAlloc dt=6 heapalloc_value=6254832
+HeapAlloc dt=6 heapalloc_value=6263024
+HeapAlloc dt=6 heapalloc_value=6271216
+HeapAlloc dt=6 heapalloc_value=6279408
+HeapAlloc dt=6 heapalloc_value=6287600
+HeapAlloc dt=7 heapalloc_value=6295792
+HeapAlloc dt=6 heapalloc_value=6303984
+HeapAlloc dt=7 heapalloc_value=6312176
+HeapAlloc dt=6 heapalloc_value=6320368
+HeapAlloc dt=6 heapalloc_value=6328560
+HeapAlloc dt=6 heapalloc_value=6336752
+HeapAlloc dt=70 heapalloc_value=6344944
+HeapAlloc dt=139 heapalloc_value=6353136
+HeapAlloc dt=8 heapalloc_value=6361328
+HeapAlloc dt=7 heapalloc_value=6369520
+HeapAlloc dt=6 heapalloc_value=6377712
+HeapAlloc dt=6 heapalloc_value=6385904
+HeapAlloc dt=6 heapalloc_value=6394096
+HeapAlloc dt=6 heapalloc_value=6402288
+HeapAlloc dt=7 heapalloc_value=6410480
+HeapAlloc dt=6 heapalloc_value=6418672
+HeapAlloc dt=6 heapalloc_value=6426864
+HeapAlloc dt=6 heapalloc_value=6435056
+HeapAlloc dt=6 heapalloc_value=6443248
+HeapAlloc dt=6 heapalloc_value=6451440
+HeapAlloc dt=7 heapalloc_value=6459632
+HeapAlloc dt=6 heapalloc_value=6467824
+HeapAlloc dt=6 heapalloc_value=6476016
+HeapAlloc dt=6 heapalloc_value=6484208
+HeapAlloc dt=42 heapalloc_value=6492400
+HeapAlloc dt=8 heapalloc_value=6500592
+HeapAlloc dt=6 heapalloc_value=6508784
+HeapAlloc dt=6 heapalloc_value=6516976
+HeapAlloc dt=7 heapalloc_value=6525168
+HeapAlloc dt=6 heapalloc_value=6533360
+HeapAlloc dt=6 heapalloc_value=6541552
+HeapAlloc dt=6 heapalloc_value=6549744
+HeapAlloc dt=6 heapalloc_value=6557936
+HeapAlloc dt=7 heapalloc_value=6566128
+HeapAlloc dt=6 heapalloc_value=6574320
+HeapAlloc dt=6 heapalloc_value=6582512
+HeapAlloc dt=7 heapalloc_value=6590704
+HeapAlloc dt=6 heapalloc_value=6598896
+HeapAlloc dt=66 heapalloc_value=6607088
+HeapAlloc dt=8 heapalloc_value=6615280
+HeapAlloc dt=6 heapalloc_value=6623472
+HeapAlloc dt=6 heapalloc_value=6631664
+HeapAlloc dt=7 heapalloc_value=6639856
+HeapAlloc dt=6 heapalloc_value=6648048
+HeapAlloc dt=6 heapalloc_value=6656240
+HeapAlloc dt=7 heapalloc_value=6664432
+HeapAlloc dt=6 heapalloc_value=6672624
+HeapAlloc dt=6 heapalloc_value=6680816
+HeapAlloc dt=6 heapalloc_value=6689008
+HeapAlloc dt=6 heapalloc_value=6697200
+HeapAlloc dt=7 heapalloc_value=6705392
+HeapAlloc dt=6 heapalloc_value=6713584
+HeapAlloc dt=6 heapalloc_value=6721776
+GoBlock dt=13 reason_string=19 stack=21
+ProcStop dt=220
+ProcStart dt=17605 p=1 p_seq=18
+ProcStop dt=18
+ProcStart dt=8830 p=4 p_seq=2
+ProcStop dt=26
+ProcStart dt=16773 p=0 p_seq=36
+ProcStop dt=12
+ProcStart dt=1445 p=1 p_seq=20
+ProcStop dt=12
+ProcStart dt=16751 p=1 p_seq=21
+GoUnblock dt=16 g=1 g_seq=33 stack=0
+GoStart dt=189 g=1 g_seq=34
+HeapAlloc dt=54 heapalloc_value=9892080
+HeapAlloc dt=21 heapalloc_value=9900272
+HeapAlloc dt=64 heapalloc_value=9908464
+HeapAlloc dt=13 heapalloc_value=9916656
+HeapAlloc dt=13 heapalloc_value=9924848
+HeapAlloc dt=12 heapalloc_value=9933040
+HeapAlloc dt=11 heapalloc_value=9941232
+HeapAlloc dt=13 heapalloc_value=9949424
+HeapAlloc dt=12 heapalloc_value=9957616
+HeapAlloc dt=48 heapalloc_value=9965808
+HeapAlloc dt=338 heapalloc_value=9974000
+HeapAlloc dt=16 heapalloc_value=9982192
+HeapAlloc dt=10 heapalloc_value=9990384
+HeapAlloc dt=8 heapalloc_value=9998576
+HeapAlloc dt=8 heapalloc_value=10006768
+HeapAlloc dt=10 heapalloc_value=10014960
+HeapAlloc dt=8 heapalloc_value=10023152
+HeapAlloc dt=7 heapalloc_value=10031344
+HeapAlloc dt=9 heapalloc_value=10039536
+HeapAlloc dt=6 heapalloc_value=10047728
+HeapAlloc dt=52 heapalloc_value=10055920
+HeapAlloc dt=8 heapalloc_value=10064112
+HeapAlloc dt=7 heapalloc_value=10072304
+HeapAlloc dt=7 heapalloc_value=10080496
+HeapAlloc dt=7 heapalloc_value=10088688
+HeapAlloc dt=7 heapalloc_value=10096880
+HeapAlloc dt=90 heapalloc_value=10105072
+HeapAlloc dt=8 heapalloc_value=10113264
+HeapAlloc dt=8 heapalloc_value=10121456
+HeapAlloc dt=7 heapalloc_value=10129648
+HeapAlloc dt=7 heapalloc_value=10137840
+HeapAlloc dt=7 heapalloc_value=10146032
+HeapAlloc dt=6 heapalloc_value=10154224
+HeapAlloc dt=7 heapalloc_value=10162416
+HeapAlloc dt=7 heapalloc_value=10170608
+HeapAlloc dt=7 heapalloc_value=10178800
+HeapAlloc dt=6 heapalloc_value=10186992
+HeapAlloc dt=7 heapalloc_value=10195184
+HeapAlloc dt=7 heapalloc_value=10203376
+HeapAlloc dt=7 heapalloc_value=10211568
+HeapAlloc dt=6 heapalloc_value=10219760
+HeapAlloc dt=8 heapalloc_value=10227952
+HeapAlloc dt=97 heapalloc_value=10236144
+HeapAlloc dt=9 heapalloc_value=10244336
+HeapAlloc dt=6 heapalloc_value=10252528
+HeapAlloc dt=7 heapalloc_value=10260720
+HeapAlloc dt=7 heapalloc_value=10268912
+HeapAlloc dt=6 heapalloc_value=10277104
+HeapAlloc dt=7 heapalloc_value=10285296
+HeapAlloc dt=7 heapalloc_value=10293488
+HeapAlloc dt=73 heapalloc_value=10301680
+HeapAlloc dt=8 heapalloc_value=10309872
+HeapAlloc dt=6 heapalloc_value=10318064
+HeapAlloc dt=7 heapalloc_value=10326256
+HeapAlloc dt=7 heapalloc_value=10334448
+HeapAlloc dt=6 heapalloc_value=10342640
+HeapAlloc dt=7 heapalloc_value=10350832
+HeapAlloc dt=7 heapalloc_value=10359024
+HeapAlloc dt=7 heapalloc_value=10367216
+HeapAlloc dt=6 heapalloc_value=10375408
+HeapAlloc dt=7 heapalloc_value=10383600
+HeapAlloc dt=7 heapalloc_value=10391792
+HeapAlloc dt=7 heapalloc_value=10399984
+HeapAlloc dt=6 heapalloc_value=10408176
+HeapAlloc dt=7 heapalloc_value=10416368
+HeapAlloc dt=7 heapalloc_value=10424560
+HeapAlloc dt=6 heapalloc_value=10432752
+HeapAlloc dt=7 heapalloc_value=10440944
+HeapAlloc dt=7 heapalloc_value=10449136
+HeapAlloc dt=6 heapalloc_value=10457328
+HeapAlloc dt=7 heapalloc_value=10465520
+HeapAlloc dt=96 heapalloc_value=10473712
+HeapAlloc dt=8 heapalloc_value=10481904
+HeapAlloc dt=6 heapalloc_value=10490096
+HeapAlloc dt=68 heapalloc_value=10498288
+HeapAlloc dt=8 heapalloc_value=10506480
+HeapAlloc dt=7 heapalloc_value=10514672
+HeapAlloc dt=7 heapalloc_value=10522864
+HeapAlloc dt=6 heapalloc_value=10531056
+HeapAlloc dt=7 heapalloc_value=10539248
+HeapAlloc dt=7 heapalloc_value=10547440
+HeapAlloc dt=7 heapalloc_value=10555632
+HeapAlloc dt=6 heapalloc_value=10563824
+HeapAlloc dt=7 heapalloc_value=10572016
+HeapAlloc dt=7 heapalloc_value=10580208
+HeapAlloc dt=6 heapalloc_value=10588400
+HeapAlloc dt=7 heapalloc_value=10596592
+HeapAlloc dt=7 heapalloc_value=10604784
+HeapAlloc dt=7 heapalloc_value=10612976
+HeapAlloc dt=7 heapalloc_value=10621168
+HeapAlloc dt=6 heapalloc_value=10629360
+HeapAlloc dt=7 heapalloc_value=10637552
+HeapAlloc dt=7 heapalloc_value=10645744
+HeapAlloc dt=6 heapalloc_value=10653936
+HeapAlloc dt=7 heapalloc_value=10662128
+HeapAlloc dt=7 heapalloc_value=10670320
+HeapAlloc dt=6 heapalloc_value=10678512
+HeapAlloc dt=7 heapalloc_value=10686704
+HeapAlloc dt=7 heapalloc_value=10694896
+HeapAlloc dt=7 heapalloc_value=10703088
+HeapAlloc dt=7 heapalloc_value=10711280
+HeapAlloc dt=6 heapalloc_value=10719472
+HeapAlloc dt=7 heapalloc_value=10727664
+HeapAlloc dt=7 heapalloc_value=10735856
+HeapAlloc dt=7 heapalloc_value=10744048
+HeapAlloc dt=6 heapalloc_value=10752240
+HeapAlloc dt=78 heapalloc_value=10760432
+HeapAlloc dt=8 heapalloc_value=10768624
+HeapAlloc dt=6 heapalloc_value=10776816
+HeapAlloc dt=7 heapalloc_value=10785008
+HeapAlloc dt=7 heapalloc_value=10793200
+HeapAlloc dt=7 heapalloc_value=10801392
+HeapAlloc dt=6 heapalloc_value=10809584
+HeapAlloc dt=7 heapalloc_value=10817776
+HeapAlloc dt=65 heapalloc_value=10825968
+HeapAlloc dt=9 heapalloc_value=10834160
+HeapAlloc dt=6 heapalloc_value=10842352
+HeapAlloc dt=7 heapalloc_value=10850544
+HeapAlloc dt=6 heapalloc_value=10858736
+HeapAlloc dt=7 heapalloc_value=10866928
+HeapAlloc dt=7 heapalloc_value=10875120
+HeapAlloc dt=7 heapalloc_value=10883312
+HeapAlloc dt=6 heapalloc_value=10891504
+HeapAlloc dt=44 heapalloc_value=10899696
+HeapAlloc dt=7 heapalloc_value=10907888
+GoBlock dt=13 reason_string=19 stack=21
+ProcStop dt=198
+ProcStart dt=17586 p=0 p_seq=38
+ProcStop dt=21
+ProcStart dt=5052 p=1 p_seq=24
+ProcStop dt=13
+ProcStart dt=16760 p=1 p_seq=26
+GoUnblock dt=19 g=1 g_seq=39 stack=0
+GoStart dt=169 g=1 g_seq=40
+HeapAlloc dt=52 heapalloc_value=13250800
+HeapAlloc dt=19 heapalloc_value=13258992
+HeapAlloc dt=9 heapalloc_value=13267184
+HeapAlloc dt=82 heapalloc_value=13275376
+HeapAlloc dt=12 heapalloc_value=13283568
+HeapAlloc dt=9 heapalloc_value=13291760
+HeapAlloc dt=9 heapalloc_value=13299952
+HeapAlloc dt=10 heapalloc_value=13308144
+HeapAlloc dt=10 heapalloc_value=13316336
+HeapAlloc dt=7 heapalloc_value=13324528
+HeapAlloc dt=6 heapalloc_value=13332720
+HeapAlloc dt=6 heapalloc_value=13340912
+HeapAlloc dt=6 heapalloc_value=13349104
+HeapAlloc dt=7 heapalloc_value=13357296
+HeapAlloc dt=6 heapalloc_value=13365488
+HeapAlloc dt=6 heapalloc_value=13373680
+HeapAlloc dt=520 heapalloc_value=13381872
+HeapAlloc dt=15 heapalloc_value=13390064
+HeapAlloc dt=7 heapalloc_value=13398256
+HeapAlloc dt=6 heapalloc_value=13406448
+HeapAlloc dt=8 heapalloc_value=13414640
+HeapAlloc dt=6 heapalloc_value=13422832
+HeapAlloc dt=6 heapalloc_value=13431024
+HeapAlloc dt=7 heapalloc_value=13439216
+HeapAlloc dt=8 heapalloc_value=13447408
+HeapAlloc dt=7 heapalloc_value=13455600
+HeapAlloc dt=6 heapalloc_value=13463792
+HeapAlloc dt=6 heapalloc_value=13471984
+HeapAlloc dt=48 heapalloc_value=13480176
+HeapAlloc dt=7 heapalloc_value=13488368
+HeapAlloc dt=6 heapalloc_value=13496560
+HeapAlloc dt=7 heapalloc_value=13504752
+HeapAlloc dt=9 heapalloc_value=13512944
+HeapAlloc dt=6 heapalloc_value=13521136
+HeapAlloc dt=7 heapalloc_value=13529328
+HeapAlloc dt=6 heapalloc_value=13537520
+HeapAlloc dt=7 heapalloc_value=13545712
+HeapAlloc dt=6 heapalloc_value=13553904
+HeapAlloc dt=7 heapalloc_value=13562096
+HeapAlloc dt=6 heapalloc_value=13570288
+HeapAlloc dt=8 heapalloc_value=13578480
+HeapAlloc dt=6 heapalloc_value=13586672
+HeapAlloc dt=6 heapalloc_value=13594864
+HeapAlloc dt=6 heapalloc_value=13603056
+HeapAlloc dt=6 heapalloc_value=13611248
+HeapAlloc dt=7 heapalloc_value=13619440
+HeapAlloc dt=6 heapalloc_value=13627632
+HeapAlloc dt=6 heapalloc_value=13635824
+HeapAlloc dt=76 heapalloc_value=13644016
+HeapAlloc dt=8 heapalloc_value=13652208
+HeapAlloc dt=6 heapalloc_value=13660400
+HeapAlloc dt=6 heapalloc_value=13668592
+HeapAlloc dt=6 heapalloc_value=13676784
+HeapAlloc dt=7 heapalloc_value=13684976
+HeapAlloc dt=6 heapalloc_value=13693168
+HeapAlloc dt=6 heapalloc_value=13701360
+HeapAlloc dt=8 heapalloc_value=13709552
+HeapAlloc dt=6 heapalloc_value=13717744
+HeapAlloc dt=64 heapalloc_value=13725936
+HeapAlloc dt=7 heapalloc_value=13734128
+HeapAlloc dt=7 heapalloc_value=13742320
+HeapAlloc dt=6 heapalloc_value=13750512
+HeapAlloc dt=6 heapalloc_value=13758704
+HeapAlloc dt=6 heapalloc_value=13766896
+HeapAlloc dt=8 heapalloc_value=13775088
+HeapAlloc dt=7 heapalloc_value=13783280
+HeapAlloc dt=6 heapalloc_value=13791472
+HeapAlloc dt=7 heapalloc_value=13799664
+HeapAlloc dt=6 heapalloc_value=13807856
+HeapAlloc dt=6 heapalloc_value=13816048
+HeapAlloc dt=6 heapalloc_value=13824240
+HeapAlloc dt=6 heapalloc_value=13832432
+HeapAlloc dt=9 heapalloc_value=13840624
+HeapAlloc dt=6 heapalloc_value=13848816
+HeapAlloc dt=6 heapalloc_value=13857008
+HeapAlloc dt=6 heapalloc_value=13865200
+HeapAlloc dt=7 heapalloc_value=13873392
+HeapAlloc dt=7 heapalloc_value=13881584
+HeapAlloc dt=6 heapalloc_value=13889776
+HeapAlloc dt=45 heapalloc_value=13897968
+HeapAlloc dt=75 heapalloc_value=13906160
+HeapAlloc dt=8 heapalloc_value=13914352
+HeapAlloc dt=6 heapalloc_value=13922544
+HeapAlloc dt=6 heapalloc_value=13930736
+HeapAlloc dt=7 heapalloc_value=13938928
+HeapAlloc dt=6 heapalloc_value=13947120
+HeapAlloc dt=6 heapalloc_value=13955312
+HeapAlloc dt=6 heapalloc_value=13963504
+HeapAlloc dt=6 heapalloc_value=13971696
+HeapAlloc dt=7 heapalloc_value=13979888
+HeapAlloc dt=6 heapalloc_value=13988080
+HeapAlloc dt=6 heapalloc_value=13996272
+HeapAlloc dt=6 heapalloc_value=14004464
+HeapAlloc dt=6 heapalloc_value=14012656
+HeapAlloc dt=6 heapalloc_value=14020848
+HeapAlloc dt=7 heapalloc_value=14029040
+HeapAlloc dt=6 heapalloc_value=14037232
+HeapAlloc dt=6 heapalloc_value=14045424
+HeapAlloc dt=7 heapalloc_value=14053616
+HeapAlloc dt=6 heapalloc_value=14061808
+HeapAlloc dt=6 heapalloc_value=14070000
+HeapAlloc dt=6 heapalloc_value=14078192
+HeapAlloc dt=6 heapalloc_value=14086384
+HeapAlloc dt=6 heapalloc_value=14094576
+HeapAlloc dt=9 heapalloc_value=14102768
+HeapAlloc dt=6 heapalloc_value=14110960
+HeapAlloc dt=7 heapalloc_value=14119152
+HeapAlloc dt=6 heapalloc_value=14127344
+HeapAlloc dt=7 heapalloc_value=14135536
+HeapAlloc dt=6 heapalloc_value=14143728
+HeapAlloc dt=6 heapalloc_value=14151920
+HeapAlloc dt=6 heapalloc_value=14160112
+HeapAlloc dt=69 heapalloc_value=14168304
+HeapAlloc dt=8 heapalloc_value=14176496
+HeapAlloc dt=6 heapalloc_value=14184688
+HeapAlloc dt=6 heapalloc_value=14192880
+HeapAlloc dt=7 heapalloc_value=14201072
+HeapAlloc dt=6 heapalloc_value=14209264
+HeapAlloc dt=6 heapalloc_value=14217456
+HeapAlloc dt=16 heapalloc_value=14586096
+HeapAlloc dt=3676 heapalloc_value=14594288
+HeapAlloc dt=11 heapalloc_value=14602480
+HeapAlloc dt=72 heapalloc_value=14610672
+HeapAlloc dt=10 heapalloc_value=14618864
+HeapAlloc dt=7 heapalloc_value=14627056
+HeapAlloc dt=9 heapalloc_value=14635248
+GoBlock dt=13 reason_string=19 stack=21
+ProcStop dt=219
+ProcStart dt=17778 p=2 p_seq=19
+ProcStop dt=25
+ProcStart dt=2221 p=1 p_seq=29
+ProcStop dt=18
+ProcStart dt=16821 p=1 p_seq=30
+GoUnblock dt=23 g=1 g_seq=43 stack=0
+GoStart dt=193 g=1 g_seq=44
+HeapAlloc dt=59 heapalloc_value=15667440
+HeapAlloc dt=26 heapalloc_value=15675632
+HeapAlloc dt=15 heapalloc_value=15683824
+HeapAlloc dt=10 heapalloc_value=15692016
+HeapAlloc dt=9 heapalloc_value=15700208
+HeapAlloc dt=10 heapalloc_value=15708400
+HeapAlloc dt=11 heapalloc_value=15716592
+HeapAlloc dt=9 heapalloc_value=15724784
+HeapAlloc dt=96 heapalloc_value=15732976
+HeapAlloc dt=324 heapalloc_value=15741168
+HeapAlloc dt=17 heapalloc_value=15749360
+HeapAlloc dt=9 heapalloc_value=15757552
+HeapAlloc dt=9 heapalloc_value=15765744
+HeapAlloc dt=7 heapalloc_value=15773936
+HeapAlloc dt=8 heapalloc_value=15782128
+HeapAlloc dt=6 heapalloc_value=15790320
+HeapAlloc dt=6 heapalloc_value=15798512
+HeapAlloc dt=8 heapalloc_value=15806704
+HeapAlloc dt=5 heapalloc_value=15814896
+HeapAlloc dt=7 heapalloc_value=15823088
+HeapAlloc dt=6 heapalloc_value=15831280
+HeapAlloc dt=6 heapalloc_value=15839472
+HeapAlloc dt=6 heapalloc_value=15847664
+HeapAlloc dt=6 heapalloc_value=15855856
+HeapAlloc dt=7 heapalloc_value=15864048
+HeapAlloc dt=10 heapalloc_value=15872240
+HeapAlloc dt=6 heapalloc_value=15880432
+HeapAlloc dt=6 heapalloc_value=15888624
+HeapAlloc dt=6 heapalloc_value=15896816
+HeapAlloc dt=7 heapalloc_value=15905008
+HeapAlloc dt=6 heapalloc_value=15913200
+HeapAlloc dt=6 heapalloc_value=15921392
+HeapAlloc dt=7 heapalloc_value=15929584
+HeapAlloc dt=8 heapalloc_value=15937776
+HeapAlloc dt=48 heapalloc_value=15945968
+HeapAlloc dt=7 heapalloc_value=15954160
+HeapAlloc dt=7 heapalloc_value=15962352
+HeapAlloc dt=6 heapalloc_value=15970544
+HeapAlloc dt=8 heapalloc_value=15978736
+HeapAlloc dt=6 heapalloc_value=15986928
+HeapAlloc dt=7 heapalloc_value=15995120
+HeapAlloc dt=104 heapalloc_value=16003312
+HeapAlloc dt=9 heapalloc_value=16011504
+HeapAlloc dt=8 heapalloc_value=16019696
+HeapAlloc dt=9 heapalloc_value=16027888
+HeapAlloc dt=8 heapalloc_value=16036080
+HeapAlloc dt=7 heapalloc_value=16044272
+HeapAlloc dt=6 heapalloc_value=16052464
+HeapAlloc dt=7 heapalloc_value=16060656
+HeapAlloc dt=6 heapalloc_value=16068848
+HeapAlloc dt=6 heapalloc_value=16077040
+HeapAlloc dt=6 heapalloc_value=16085232
+HeapAlloc dt=7 heapalloc_value=16093424
+HeapAlloc dt=6 heapalloc_value=16101616
+HeapAlloc dt=6 heapalloc_value=16109808
+HeapAlloc dt=6 heapalloc_value=16118000
+HeapAlloc dt=7 heapalloc_value=16126192
+HeapAlloc dt=6 heapalloc_value=16134384
+HeapAlloc dt=6 heapalloc_value=16142576
+HeapAlloc dt=6 heapalloc_value=16150768
+HeapAlloc dt=7 heapalloc_value=16158960
+HeapAlloc dt=6 heapalloc_value=16167152
+HeapAlloc dt=6 heapalloc_value=16175344
+HeapAlloc dt=78 heapalloc_value=16183536
+HeapAlloc dt=7 heapalloc_value=16191728
+HeapAlloc dt=6 heapalloc_value=16199920
+HeapAlloc dt=6 heapalloc_value=16208112
+HeapAlloc dt=7 heapalloc_value=16216304
+HeapAlloc dt=6 heapalloc_value=16224496
+HeapAlloc dt=6 heapalloc_value=16232688
+HeapAlloc dt=6 heapalloc_value=16240880
+HeapAlloc dt=6 heapalloc_value=16249072
+HeapAlloc dt=7 heapalloc_value=16257264
+HeapAlloc dt=73 heapalloc_value=16265456
+HeapAlloc dt=8 heapalloc_value=16273648
+HeapAlloc dt=6 heapalloc_value=16281840
+HeapAlloc dt=6 heapalloc_value=16290032
+HeapAlloc dt=6 heapalloc_value=16298224
+HeapAlloc dt=7 heapalloc_value=16306416
+HeapAlloc dt=6 heapalloc_value=16314608
+HeapAlloc dt=6 heapalloc_value=16322800
+HeapAlloc dt=6 heapalloc_value=16330992
+HeapAlloc dt=7 heapalloc_value=16339184
+HeapAlloc dt=6 heapalloc_value=16347376
+HeapAlloc dt=8 heapalloc_value=16355568
+HeapAlloc dt=44 heapalloc_value=16363760
+HeapAlloc dt=7 heapalloc_value=16371952
+HeapAlloc dt=6 heapalloc_value=16380144
+HeapAlloc dt=6 heapalloc_value=16388336
+HeapAlloc dt=6 heapalloc_value=16396528
+HeapAlloc dt=7 heapalloc_value=16404720
+HeapAlloc dt=6 heapalloc_value=16412912
+HeapAlloc dt=6 heapalloc_value=16421104
+HeapAlloc dt=6 heapalloc_value=16429296
+HeapAlloc dt=7 heapalloc_value=16437488
+HeapAlloc dt=6 heapalloc_value=16445680
+HeapAlloc dt=6 heapalloc_value=16453872
+HeapAlloc dt=6 heapalloc_value=16462064
+HeapAlloc dt=6 heapalloc_value=16470256
+HeapAlloc dt=6 heapalloc_value=16478448
+HeapAlloc dt=7 heapalloc_value=16486640
+HeapAlloc dt=6 heapalloc_value=16494832
+GCBegin dt=18 gc_seq=5 stack=41
+STWBegin dt=46 kind_string=22 stack=42
+GoUnblock dt=209 g=4 g_seq=7 stack=43
+ProcsChange dt=70 procs_value=8 stack=44
+STWEnd dt=24
+GCMarkAssistBegin dt=182 stack=30
+GCMarkAssistEnd dt=3877
+HeapAlloc dt=628 heapalloc_value=16509392
+HeapAlloc dt=22 heapalloc_value=16517584
+HeapAlloc dt=18 heapalloc_value=16525776
+HeapAlloc dt=371 heapalloc_value=16533968
+HeapAlloc dt=14 heapalloc_value=16542160
+HeapAlloc dt=11 heapalloc_value=16550352
+HeapAlloc dt=13 heapalloc_value=16558544
+HeapAlloc dt=13 heapalloc_value=16566736
+HeapAlloc dt=10 heapalloc_value=16574928
+HeapAlloc dt=10 heapalloc_value=16583120
+HeapAlloc dt=8 heapalloc_value=16591312
+HeapAlloc dt=8 heapalloc_value=16599504
+HeapAlloc dt=8 heapalloc_value=16607696
+HeapAlloc dt=7 heapalloc_value=16615888
+HeapAlloc dt=8 heapalloc_value=16624080
+HeapAlloc dt=8 heapalloc_value=16632272
+HeapAlloc dt=9 heapalloc_value=16640464
+HeapAlloc dt=7 heapalloc_value=16648656
+HeapAlloc dt=8 heapalloc_value=16656848
+HeapAlloc dt=9 heapalloc_value=16665040
+HeapAlloc dt=8 heapalloc_value=16673232
+HeapAlloc dt=9 heapalloc_value=16681424
+HeapAlloc dt=8 heapalloc_value=16689616
+GoBlock dt=17 reason_string=19 stack=21
+ProcStop dt=2869
+ProcStart dt=110180 p=4 p_seq=5
+GoStart dt=268 g=15 g_seq=1
+GoStop dt=304685 reason_string=16 stack=52
+GoStart dt=20 g=15 g_seq=2
+GoStop dt=316415 reason_string=16 stack=52
+GoStart dt=23 g=15 g_seq=3
+GoDestroy dt=160136
+ProcStop dt=32
+EventBatch gen=1 m=2852344 time=420901833895 size=3430
+ProcStart dt=383 p=2 p_seq=3
+GoStart dt=284 g=7 g_seq=1
+HeapAlloc dt=35 heapalloc_value=4055040
+GoBlock dt=148 reason_string=15 stack=26
+ProcStop dt=12
+ProcStart dt=791 p=1 p_seq=8
+ProcStop dt=4
+ProcStart dt=817 p=1 p_seq=9
+ProcStop dt=14
+ProcStart dt=796 p=0 p_seq=21
+ProcStop dt=9
+ProcStart dt=393 p=1 p_seq=11
+ProcStop dt=19
+ProcStart dt=324 p=2 p_seq=9
+GoStart dt=339 g=25 g_seq=1
+GoBlock dt=112 reason_string=15 stack=26
+ProcStop dt=4
+ProcStart dt=1331 p=1 p_seq=15
+GoUnblock dt=13 g=9 g_seq=2 stack=0
+GoStart dt=145 g=9 g_seq=3
+GoLabel dt=1 label_string=2
+STWBegin dt=4838 kind_string=23 stack=34
+GoUnblock dt=44 g=1 g_seq=18 stack=35
+HeapAlloc dt=17 heapalloc_value=4112624
+GoStatus dt=15 g=3 m=18446744073709551615 gstatus=4
+GoUnblock dt=5 g=3 g_seq=1 stack=36
+GCEnd dt=4 gc_seq=2
+HeapGoal dt=5 heapgoal_value=8644048
+ProcsChange dt=37 procs_value=8 stack=37
+STWEnd dt=1475
+GoBlock dt=2304 reason_string=15 stack=26
+GoStart dt=12 g=3 g_seq=2
+GoBlock dt=2449 reason_string=14 stack=40
+ProcStop dt=16
+ProcStart dt=67967 p=1 p_seq=19
+GoUnblock dt=21 g=9 g_seq=4 stack=0
+GoStart dt=191 g=9 g_seq=5
+GoLabel dt=1 label_string=2
+GoStop dt=4205 reason_string=16 stack=45
+GoStart dt=189 g=9 g_seq=6
+STWBegin dt=1152 kind_string=23 stack=34
+GoUnblock dt=46 g=1 g_seq=29 stack=35
+HeapAlloc dt=17 heapalloc_value=8626416
+GoUnblock dt=11 g=3 g_seq=3 stack=36
+GCEnd dt=5 gc_seq=4
+HeapGoal dt=5 heapgoal_value=17671632
+ProcsChange dt=43 procs_value=8 stack=37
+STWEnd dt=28
+GoBlock dt=1941 reason_string=15 stack=26
+GoStart dt=12 g=3 g_seq=4
+GoBlock dt=4694 reason_string=14 stack=40
+GoUnblock dt=33 g=1 g_seq=31 stack=0
+GoStart dt=214 g=1 g_seq=32
+HeapAlloc dt=62 heapalloc_value=8646896
+HeapAlloc dt=32 heapalloc_value=8655088
+HeapAlloc dt=18 heapalloc_value=8663280
+HeapAlloc dt=18 heapalloc_value=8671472
+HeapAlloc dt=15 heapalloc_value=8679664
+HeapAlloc dt=18 heapalloc_value=8687856
+HeapAlloc dt=17 heapalloc_value=8696048
+HeapAlloc dt=17 heapalloc_value=8704240
+HeapAlloc dt=19 heapalloc_value=8712432
+HeapAlloc dt=24 heapalloc_value=8720624
+HeapAlloc dt=20 heapalloc_value=8728816
+HeapAlloc dt=31 heapalloc_value=8737008
+HeapAlloc dt=19 heapalloc_value=8745200
+HeapAlloc dt=14 heapalloc_value=8753392
+HeapAlloc dt=14 heapalloc_value=8761584
+HeapAlloc dt=15 heapalloc_value=8769776
+HeapAlloc dt=17 heapalloc_value=8777968
+HeapAlloc dt=16 heapalloc_value=8786160
+HeapAlloc dt=16 heapalloc_value=8794352
+HeapAlloc dt=13 heapalloc_value=8802544
+HeapAlloc dt=14 heapalloc_value=8810736
+HeapAlloc dt=12 heapalloc_value=8818928
+HeapAlloc dt=38 heapalloc_value=9040112
+HeapAlloc dt=3065 heapalloc_value=9048304
+HeapAlloc dt=21 heapalloc_value=9056496
+HeapAlloc dt=16 heapalloc_value=9064688
+HeapAlloc dt=22 heapalloc_value=9072880
+HeapAlloc dt=37 heapalloc_value=9081072
+HeapAlloc dt=28 heapalloc_value=9089264
+HeapAlloc dt=30 heapalloc_value=9097456
+HeapAlloc dt=22 heapalloc_value=9105648
+HeapAlloc dt=36 heapalloc_value=9113840
+HeapAlloc dt=30 heapalloc_value=9122032
+HeapAlloc dt=28 heapalloc_value=9130224
+HeapAlloc dt=26 heapalloc_value=9138416
+HeapAlloc dt=27 heapalloc_value=9146608
+HeapAlloc dt=31 heapalloc_value=9154800
+HeapAlloc dt=37 heapalloc_value=9162992
+HeapAlloc dt=24 heapalloc_value=9171184
+HeapAlloc dt=27 heapalloc_value=9179376
+HeapAlloc dt=26 heapalloc_value=9187568
+HeapAlloc dt=34 heapalloc_value=9195760
+HeapAlloc dt=30 heapalloc_value=9203952
+HeapAlloc dt=30 heapalloc_value=9212144
+HeapAlloc dt=30 heapalloc_value=9220336
+HeapAlloc dt=29 heapalloc_value=9228528
+HeapAlloc dt=28 heapalloc_value=9236720
+HeapAlloc dt=46 heapalloc_value=9244912
+HeapAlloc dt=118 heapalloc_value=9253104
+HeapAlloc dt=31 heapalloc_value=9261296
+HeapAlloc dt=39 heapalloc_value=9269488
+HeapAlloc dt=27 heapalloc_value=9277680
+HeapAlloc dt=32 heapalloc_value=9285872
+HeapAlloc dt=27 heapalloc_value=9294064
+HeapAlloc dt=32 heapalloc_value=9302256
+HeapAlloc dt=33 heapalloc_value=9310448
+HeapAlloc dt=39 heapalloc_value=9318640
+HeapAlloc dt=30 heapalloc_value=9326832
+HeapAlloc dt=33 heapalloc_value=9335024
+HeapAlloc dt=28 heapalloc_value=9343216
+HeapAlloc dt=27 heapalloc_value=9351408
+HeapAlloc dt=27 heapalloc_value=9359600
+HeapAlloc dt=26 heapalloc_value=9367792
+HeapAlloc dt=36 heapalloc_value=9375984
+HeapAlloc dt=20 heapalloc_value=9384176
+HeapAlloc dt=16 heapalloc_value=9392368
+HeapAlloc dt=17 heapalloc_value=9400560
+HeapAlloc dt=22 heapalloc_value=9408752
+HeapAlloc dt=7 heapalloc_value=9416944
+HeapAlloc dt=49 heapalloc_value=9425136
+HeapAlloc dt=7 heapalloc_value=9433328
+HeapAlloc dt=7 heapalloc_value=9441520
+HeapAlloc dt=74 heapalloc_value=9449712
+HeapAlloc dt=8 heapalloc_value=9457904
+HeapAlloc dt=6 heapalloc_value=9466096
+HeapAlloc dt=7 heapalloc_value=9474288
+HeapAlloc dt=6 heapalloc_value=9482480
+HeapAlloc dt=6 heapalloc_value=9490672
+HeapAlloc dt=7 heapalloc_value=9498864
+HeapAlloc dt=6 heapalloc_value=9507056
+HeapAlloc dt=6 heapalloc_value=9515248
+HeapAlloc dt=6 heapalloc_value=9523440
+HeapAlloc dt=6 heapalloc_value=9531632
+HeapAlloc dt=6 heapalloc_value=9539824
+HeapAlloc dt=7 heapalloc_value=9548016
+HeapAlloc dt=7 heapalloc_value=9556208
+HeapAlloc dt=5 heapalloc_value=9564400
+HeapAlloc dt=7 heapalloc_value=9572592
+HeapAlloc dt=6 heapalloc_value=9580784
+HeapAlloc dt=6 heapalloc_value=9588976
+HeapAlloc dt=6 heapalloc_value=9597168
+HeapAlloc dt=6 heapalloc_value=9605360
+HeapAlloc dt=6 heapalloc_value=9613552
+HeapAlloc dt=7 heapalloc_value=9621744
+HeapAlloc dt=6 heapalloc_value=9629936
+HeapAlloc dt=43 heapalloc_value=9638128
+HeapAlloc dt=7 heapalloc_value=9646320
+HeapAlloc dt=7 heapalloc_value=9654512
+HeapAlloc dt=6 heapalloc_value=9662704
+HeapAlloc dt=6 heapalloc_value=9670896
+HeapAlloc dt=6 heapalloc_value=9679088
+HeapAlloc dt=10 heapalloc_value=9687280
+HeapAlloc dt=7 heapalloc_value=9695472
+HeapAlloc dt=8 heapalloc_value=9703664
+HeapAlloc dt=726 heapalloc_value=9711856
+HeapAlloc dt=16 heapalloc_value=9720048
+HeapAlloc dt=7 heapalloc_value=9728240
+HeapAlloc dt=6 heapalloc_value=9736432
+HeapAlloc dt=6 heapalloc_value=9744624
+HeapAlloc dt=6 heapalloc_value=9752816
+HeapAlloc dt=7 heapalloc_value=9761008
+HeapAlloc dt=6 heapalloc_value=9769200
+HeapAlloc dt=63 heapalloc_value=9777392
+HeapAlloc dt=8 heapalloc_value=9785584
+HeapAlloc dt=6 heapalloc_value=9793776
+HeapAlloc dt=7 heapalloc_value=9801968
+HeapAlloc dt=7 heapalloc_value=9810160
+HeapAlloc dt=6 heapalloc_value=9818352
+HeapAlloc dt=6 heapalloc_value=9826544
+HeapAlloc dt=7 heapalloc_value=9834736
+HeapAlloc dt=43 heapalloc_value=9842928
+HeapAlloc dt=7 heapalloc_value=9851120
+HeapAlloc dt=7 heapalloc_value=9859312
+HeapAlloc dt=6 heapalloc_value=9867504
+HeapAlloc dt=6 heapalloc_value=9875696
+HeapAlloc dt=6 heapalloc_value=9883888
+GoBlock dt=13 reason_string=19 stack=21
+ProcStop dt=225
+ProcStart dt=17576 p=0 p_seq=37
+ProcStop dt=18
+ProcStart dt=2169 p=1 p_seq=22
+ProcStop dt=14
+ProcStart dt=16799 p=1 p_seq=23
+GoUnblock dt=15 g=1 g_seq=35 stack=0
+GoStart dt=168 g=1 g_seq=36
+HeapAlloc dt=44 heapalloc_value=10916080
+HeapAlloc dt=18 heapalloc_value=10924272
+HeapAlloc dt=13 heapalloc_value=10932464
+HeapAlloc dt=12 heapalloc_value=10940656
+HeapAlloc dt=11 heapalloc_value=10948848
+HeapAlloc dt=12 heapalloc_value=10957040
+HeapAlloc dt=9 heapalloc_value=10965232
+HeapAlloc dt=11 heapalloc_value=10973424
+HeapAlloc dt=9 heapalloc_value=10981616
+HeapAlloc dt=9 heapalloc_value=10989808
+HeapAlloc dt=6 heapalloc_value=10998000
+HeapAlloc dt=6 heapalloc_value=11006192
+HeapAlloc dt=7 heapalloc_value=11014384
+HeapAlloc dt=303 heapalloc_value=11022576
+HeapAlloc dt=15 heapalloc_value=11030768
+HeapAlloc dt=8 heapalloc_value=11038960
+HeapAlloc dt=6 heapalloc_value=11047152
+HeapAlloc dt=7 heapalloc_value=11055344
+HeapAlloc dt=6 heapalloc_value=11063536
+HeapAlloc dt=6 heapalloc_value=11071728
+HeapAlloc dt=6 heapalloc_value=11079920
+HeapAlloc dt=9 heapalloc_value=11088112
+HeapAlloc dt=6 heapalloc_value=11096304
+HeapAlloc dt=52 heapalloc_value=11104496
+HeapAlloc dt=8 heapalloc_value=11112688
+HeapAlloc dt=7 heapalloc_value=11120880
+HeapAlloc dt=6 heapalloc_value=11129072
+HeapAlloc dt=7 heapalloc_value=11137264
+HeapAlloc dt=396 heapalloc_value=11423984
+HeapAlloc dt=2772 heapalloc_value=11432176
+HeapAlloc dt=23 heapalloc_value=11440368
+HeapAlloc dt=13 heapalloc_value=11448560
+HeapAlloc dt=10 heapalloc_value=11456752
+HeapAlloc dt=9 heapalloc_value=11464944
+HeapAlloc dt=9 heapalloc_value=11473136
+HeapAlloc dt=9 heapalloc_value=11481328
+HeapAlloc dt=9 heapalloc_value=11489520
+HeapAlloc dt=9 heapalloc_value=11497712
+HeapAlloc dt=12 heapalloc_value=11505904
+HeapAlloc dt=9 heapalloc_value=11514096
+HeapAlloc dt=10 heapalloc_value=11522288
+HeapAlloc dt=9 heapalloc_value=11530480
+HeapAlloc dt=10 heapalloc_value=11538672
+HeapAlloc dt=10 heapalloc_value=11546864
+HeapAlloc dt=10 heapalloc_value=11555056
+HeapAlloc dt=9 heapalloc_value=11563248
+HeapAlloc dt=21 heapalloc_value=11571440
+HeapAlloc dt=9 heapalloc_value=11579632
+HeapAlloc dt=6 heapalloc_value=11587824
+HeapAlloc dt=7 heapalloc_value=11596016
+HeapAlloc dt=6 heapalloc_value=11604208
+HeapAlloc dt=6 heapalloc_value=11612400
+HeapAlloc dt=6 heapalloc_value=11620592
+HeapAlloc dt=103 heapalloc_value=11628784
+HeapAlloc dt=9 heapalloc_value=11636976
+HeapAlloc dt=7 heapalloc_value=11645168
+HeapAlloc dt=6 heapalloc_value=11653360
+HeapAlloc dt=7 heapalloc_value=11661552
+HeapAlloc dt=6 heapalloc_value=11669744
+HeapAlloc dt=6 heapalloc_value=11677936
+HeapAlloc dt=6 heapalloc_value=11686128
+HeapAlloc dt=6 heapalloc_value=11694320
+HeapAlloc dt=7 heapalloc_value=11702512
+HeapAlloc dt=6 heapalloc_value=11710704
+HeapAlloc dt=6 heapalloc_value=11718896
+HeapAlloc dt=6 heapalloc_value=11727088
+HeapAlloc dt=6 heapalloc_value=11735280
+HeapAlloc dt=6 heapalloc_value=11743472
+HeapAlloc dt=6 heapalloc_value=11751664
+HeapAlloc dt=6 heapalloc_value=11759856
+HeapAlloc dt=7 heapalloc_value=11768048
+HeapAlloc dt=5 heapalloc_value=11776240
+HeapAlloc dt=7 heapalloc_value=11784432
+HeapAlloc dt=6 heapalloc_value=11792624
+HeapAlloc dt=44 heapalloc_value=11800816
+HeapAlloc dt=82 heapalloc_value=11809008
+HeapAlloc dt=9 heapalloc_value=11817200
+HeapAlloc dt=6 heapalloc_value=11825392
+HeapAlloc dt=6 heapalloc_value=11833584
+HeapAlloc dt=7 heapalloc_value=11841776
+HeapAlloc dt=6 heapalloc_value=11849968
+HeapAlloc dt=6 heapalloc_value=11858160
+HeapAlloc dt=6 heapalloc_value=11866352
+HeapAlloc dt=7 heapalloc_value=11874544
+HeapAlloc dt=6 heapalloc_value=11882736
+HeapAlloc dt=6 heapalloc_value=11890928
+HeapAlloc dt=6 heapalloc_value=11899120
+HeapAlloc dt=6 heapalloc_value=11907312
+HeapAlloc dt=7 heapalloc_value=11915504
+HeapAlloc dt=6 heapalloc_value=11923696
+HeapAlloc dt=6 heapalloc_value=11931888
+HeapAlloc dt=6 heapalloc_value=11940080
+HeapAlloc dt=6 heapalloc_value=11948272
+HeapAlloc dt=6 heapalloc_value=11956464
+HeapAlloc dt=6 heapalloc_value=11964656
+HeapAlloc dt=6 heapalloc_value=11972848
+HeapAlloc dt=7 heapalloc_value=11981040
+HeapAlloc dt=6 heapalloc_value=11989232
+HeapAlloc dt=6 heapalloc_value=11997424
+HeapAlloc dt=6 heapalloc_value=12005616
+HeapAlloc dt=7 heapalloc_value=12013808
+HeapAlloc dt=6 heapalloc_value=12022000
+HeapAlloc dt=6 heapalloc_value=12030192
+HeapAlloc dt=6 heapalloc_value=12038384
+HeapAlloc dt=6 heapalloc_value=12046576
+HeapAlloc dt=6 heapalloc_value=12054768
+HeapAlloc dt=6 heapalloc_value=12062960
+HeapAlloc dt=67 heapalloc_value=12071152
+HeapAlloc dt=8 heapalloc_value=12079344
+HeapAlloc dt=7 heapalloc_value=12087536
+HeapAlloc dt=6 heapalloc_value=12095728
+HeapAlloc dt=6 heapalloc_value=12103920
+HeapAlloc dt=6 heapalloc_value=12112112
+HeapAlloc dt=6 heapalloc_value=12120304
+HeapAlloc dt=6 heapalloc_value=12128496
+HeapAlloc dt=6 heapalloc_value=12136688
+HeapAlloc dt=6 heapalloc_value=12144880
+HeapAlloc dt=59 heapalloc_value=12153072
+HeapAlloc dt=8 heapalloc_value=12161264
+HeapAlloc dt=6 heapalloc_value=12169456
+HeapAlloc dt=6 heapalloc_value=12177648
+HeapAlloc dt=6 heapalloc_value=12185840
+HeapAlloc dt=6 heapalloc_value=12194032
+HeapAlloc dt=7 heapalloc_value=12202224
+HeapAlloc dt=6 heapalloc_value=12210416
+HeapAlloc dt=6 heapalloc_value=12218608
+GoBlock dt=12 reason_string=19 stack=21
+ProcStop dt=223
+ProcStart dt=12071 p=1 p_seq=25
+GoUnblock dt=11 g=1 g_seq=37 stack=0
+GoStart dt=161 g=1 g_seq=38
+HeapAlloc dt=75 heapalloc_value=12226800
+HeapAlloc dt=11 heapalloc_value=12234992
+HeapAlloc dt=6 heapalloc_value=12243184
+HeapAlloc dt=6 heapalloc_value=12251376
+HeapAlloc dt=7 heapalloc_value=12259568
+HeapAlloc dt=6 heapalloc_value=12267760
+HeapAlloc dt=6 heapalloc_value=12275952
+HeapAlloc dt=6 heapalloc_value=12284144
+HeapAlloc dt=6 heapalloc_value=12292336
+HeapAlloc dt=7 heapalloc_value=12300528
+HeapAlloc dt=6 heapalloc_value=12308720
+HeapAlloc dt=6 heapalloc_value=12316912
+HeapAlloc dt=7 heapalloc_value=12325104
+HeapAlloc dt=87 heapalloc_value=12333296
+HeapAlloc dt=25 heapalloc_value=12341488
+HeapAlloc dt=7 heapalloc_value=12349680
+HeapAlloc dt=6 heapalloc_value=12357872
+HeapAlloc dt=7 heapalloc_value=12366064
+HeapAlloc dt=10 heapalloc_value=12374256
+HeapAlloc dt=7 heapalloc_value=12382448
+HeapAlloc dt=9 heapalloc_value=12390640
+HeapAlloc dt=6 heapalloc_value=12398832
+HeapAlloc dt=6 heapalloc_value=12407024
+HeapAlloc dt=7 heapalloc_value=12415216
+HeapAlloc dt=6 heapalloc_value=12423408
+HeapAlloc dt=44 heapalloc_value=12431600
+HeapAlloc dt=7 heapalloc_value=12439792
+HeapAlloc dt=7 heapalloc_value=12447984
+HeapAlloc dt=6 heapalloc_value=12456176
+HeapAlloc dt=6 heapalloc_value=12464368
+HeapAlloc dt=6 heapalloc_value=12472560
+HeapAlloc dt=6 heapalloc_value=12480752
+HeapAlloc dt=7 heapalloc_value=12488944
+HeapAlloc dt=6 heapalloc_value=12497136
+HeapAlloc dt=6 heapalloc_value=12505328
+HeapAlloc dt=6 heapalloc_value=12513520
+HeapAlloc dt=6 heapalloc_value=12521712
+HeapAlloc dt=7 heapalloc_value=12529904
+HeapAlloc dt=6 heapalloc_value=12538096
+HeapAlloc dt=6 heapalloc_value=12546288
+HeapAlloc dt=6 heapalloc_value=12554480
+HeapAlloc dt=6 heapalloc_value=12562672
+HeapAlloc dt=6 heapalloc_value=12570864
+HeapAlloc dt=11 heapalloc_value=12579056
+HeapAlloc dt=6 heapalloc_value=12587248
+HeapAlloc dt=455 heapalloc_value=12595440
+HeapAlloc dt=12 heapalloc_value=12603632
+HeapAlloc dt=7 heapalloc_value=12611824
+HeapAlloc dt=6 heapalloc_value=12620016
+HeapAlloc dt=7 heapalloc_value=12628208
+HeapAlloc dt=6 heapalloc_value=12636400
+HeapAlloc dt=6 heapalloc_value=12644592
+HeapAlloc dt=6 heapalloc_value=12652784
+HeapAlloc dt=7 heapalloc_value=12660976
+HeapAlloc dt=6 heapalloc_value=12669168
+HeapAlloc dt=97 heapalloc_value=12677360
+HeapAlloc dt=8 heapalloc_value=12685552
+HeapAlloc dt=6 heapalloc_value=12693744
+HeapAlloc dt=6 heapalloc_value=12701936
+HeapAlloc dt=6 heapalloc_value=12710128
+HeapAlloc dt=6 heapalloc_value=12718320
+HeapAlloc dt=6 heapalloc_value=12726512
+HeapAlloc dt=7 heapalloc_value=12734704
+HeapAlloc dt=6 heapalloc_value=12742896
+HeapAlloc dt=6 heapalloc_value=12751088
+HeapAlloc dt=6 heapalloc_value=12759280
+HeapAlloc dt=7 heapalloc_value=12767472
+HeapAlloc dt=7 heapalloc_value=12775664
+HeapAlloc dt=6 heapalloc_value=12783856
+HeapAlloc dt=6 heapalloc_value=12792048
+HeapAlloc dt=6 heapalloc_value=12800240
+HeapAlloc dt=7 heapalloc_value=12808432
+HeapAlloc dt=6 heapalloc_value=12816624
+HeapAlloc dt=6 heapalloc_value=12824816
+HeapAlloc dt=6 heapalloc_value=12833008
+HeapAlloc dt=6 heapalloc_value=12841200
+HeapAlloc dt=42 heapalloc_value=12849392
+HeapAlloc dt=79 heapalloc_value=12857584
+HeapAlloc dt=8 heapalloc_value=12865776
+HeapAlloc dt=6 heapalloc_value=12873968
+HeapAlloc dt=6 heapalloc_value=12882160
+HeapAlloc dt=7 heapalloc_value=12890352
+HeapAlloc dt=6 heapalloc_value=12898544
+HeapAlloc dt=6 heapalloc_value=12906736
+HeapAlloc dt=6 heapalloc_value=12914928
+HeapAlloc dt=7 heapalloc_value=12923120
+HeapAlloc dt=6 heapalloc_value=12931312
+HeapAlloc dt=6 heapalloc_value=12939504
+HeapAlloc dt=6 heapalloc_value=12947696
+HeapAlloc dt=6 heapalloc_value=12955888
+HeapAlloc dt=6 heapalloc_value=12964080
+HeapAlloc dt=6 heapalloc_value=12972272
+HeapAlloc dt=6 heapalloc_value=12980464
+HeapAlloc dt=7 heapalloc_value=12988656
+HeapAlloc dt=6 heapalloc_value=12996848
+HeapAlloc dt=6 heapalloc_value=13005040
+HeapAlloc dt=6 heapalloc_value=13013232
+HeapAlloc dt=7 heapalloc_value=13021424
+HeapAlloc dt=6 heapalloc_value=13029616
+HeapAlloc dt=6 heapalloc_value=13037808
+HeapAlloc dt=6 heapalloc_value=13046000
+HeapAlloc dt=6 heapalloc_value=13054192
+HeapAlloc dt=7 heapalloc_value=13062384
+HeapAlloc dt=6 heapalloc_value=13070576
+HeapAlloc dt=6 heapalloc_value=13078768
+HeapAlloc dt=6 heapalloc_value=13086960
+HeapAlloc dt=6 heapalloc_value=13095152
+HeapAlloc dt=7 heapalloc_value=13103344
+HeapAlloc dt=6 heapalloc_value=13111536
+HeapAlloc dt=67 heapalloc_value=13119728
+HeapAlloc dt=8 heapalloc_value=13127920
+HeapAlloc dt=6 heapalloc_value=13136112
+HeapAlloc dt=6 heapalloc_value=13144304
+HeapAlloc dt=7 heapalloc_value=13152496
+HeapAlloc dt=6 heapalloc_value=13160688
+HeapAlloc dt=6 heapalloc_value=13168880
+HeapAlloc dt=6 heapalloc_value=13177072
+HeapAlloc dt=6 heapalloc_value=13185264
+HeapAlloc dt=6 heapalloc_value=13193456
+HeapAlloc dt=105 heapalloc_value=13201648
+HeapAlloc dt=8 heapalloc_value=13209840
+HeapAlloc dt=6 heapalloc_value=13218032
+HeapAlloc dt=6 heapalloc_value=13226224
+HeapAlloc dt=6 heapalloc_value=13234416
+HeapAlloc dt=6 heapalloc_value=13242608
+GoBlock dt=10 reason_string=19 stack=21
+ProcStop dt=13
+ProcStart dt=3484 p=2 p_seq=18
+ProcStop dt=18
+ProcStart dt=5821 p=1 p_seq=27
+ProcStop dt=12
+ProcStart dt=16793 p=1 p_seq=28
+GoUnblock dt=16 g=1 g_seq=41 stack=0
+GoStart dt=193 g=1 g_seq=42
+HeapAlloc dt=36 heapalloc_value=14643440
+HeapAlloc dt=29 heapalloc_value=14651632
+HeapAlloc dt=16 heapalloc_value=14659824
+HeapAlloc dt=20 heapalloc_value=14668016
+HeapAlloc dt=13 heapalloc_value=14676208
+HeapAlloc dt=84 heapalloc_value=14684400
+HeapAlloc dt=17 heapalloc_value=14692592
+HeapAlloc dt=12 heapalloc_value=14700784
+HeapAlloc dt=12 heapalloc_value=14708976
+HeapAlloc dt=12 heapalloc_value=14717168
+HeapAlloc dt=12 heapalloc_value=14725360
+HeapAlloc dt=22 heapalloc_value=14733552
+HeapAlloc dt=12 heapalloc_value=14741744
+HeapAlloc dt=13 heapalloc_value=14749936
+HeapAlloc dt=12 heapalloc_value=14758128
+HeapAlloc dt=11 heapalloc_value=14766320
+HeapAlloc dt=13 heapalloc_value=14774512
+HeapAlloc dt=12 heapalloc_value=14782704
+HeapAlloc dt=12 heapalloc_value=14790896
+HeapAlloc dt=61 heapalloc_value=14799088
+HeapAlloc dt=13 heapalloc_value=14807280
+HeapAlloc dt=7 heapalloc_value=14815472
+HeapAlloc dt=11 heapalloc_value=14823664
+HeapAlloc dt=9 heapalloc_value=14831856
+HeapAlloc dt=11 heapalloc_value=14840048
+HeapAlloc dt=6 heapalloc_value=14848240
+HeapAlloc dt=7 heapalloc_value=14856432
+HeapAlloc dt=9 heapalloc_value=14864624
+HeapAlloc dt=6 heapalloc_value=14872816
+HeapAlloc dt=6 heapalloc_value=14881008
+HeapAlloc dt=46 heapalloc_value=14889200
+HeapAlloc dt=8 heapalloc_value=14897392
+HeapAlloc dt=6 heapalloc_value=14905584
+HeapAlloc dt=7 heapalloc_value=14913776
+HeapAlloc dt=6 heapalloc_value=14921968
+HeapAlloc dt=7 heapalloc_value=14930160
+HeapAlloc dt=7 heapalloc_value=14938352
+HeapAlloc dt=6 heapalloc_value=14946544
+HeapAlloc dt=155 heapalloc_value=14954736
+HeapAlloc dt=9 heapalloc_value=14962928
+HeapAlloc dt=6 heapalloc_value=14971120
+HeapAlloc dt=7 heapalloc_value=14979312
+HeapAlloc dt=6 heapalloc_value=14987504
+HeapAlloc dt=6 heapalloc_value=14995696
+HeapAlloc dt=6 heapalloc_value=15003888
+HeapAlloc dt=6 heapalloc_value=15012080
+HeapAlloc dt=8 heapalloc_value=15020272
+HeapAlloc dt=6 heapalloc_value=15028464
+HeapAlloc dt=7 heapalloc_value=15036656
+HeapAlloc dt=6 heapalloc_value=15044848
+HeapAlloc dt=6 heapalloc_value=15053040
+HeapAlloc dt=6 heapalloc_value=15061232
+HeapAlloc dt=6 heapalloc_value=15069424
+HeapAlloc dt=6 heapalloc_value=15077616
+HeapAlloc dt=8 heapalloc_value=15085808
+HeapAlloc dt=6 heapalloc_value=15094000
+HeapAlloc dt=7 heapalloc_value=15102192
+HeapAlloc dt=6 heapalloc_value=15110384
+HeapAlloc dt=6 heapalloc_value=15118576
+HeapAlloc dt=6 heapalloc_value=15126768
+HeapAlloc dt=68 heapalloc_value=15134960
+HeapAlloc dt=8 heapalloc_value=15143152
+HeapAlloc dt=6 heapalloc_value=15151344
+HeapAlloc dt=6 heapalloc_value=15159536
+HeapAlloc dt=6 heapalloc_value=15167728
+HeapAlloc dt=6 heapalloc_value=15175920
+HeapAlloc dt=6 heapalloc_value=15184112
+HeapAlloc dt=6 heapalloc_value=15192304
+HeapAlloc dt=6 heapalloc_value=15200496
+HeapAlloc dt=6 heapalloc_value=15208688
+HeapAlloc dt=68 heapalloc_value=15216880
+HeapAlloc dt=8 heapalloc_value=15225072
+HeapAlloc dt=7 heapalloc_value=15233264
+HeapAlloc dt=6 heapalloc_value=15241456
+HeapAlloc dt=6 heapalloc_value=15249648
+HeapAlloc dt=7 heapalloc_value=15257840
+HeapAlloc dt=6 heapalloc_value=15266032
+HeapAlloc dt=6 heapalloc_value=15274224
+HeapAlloc dt=8 heapalloc_value=15282416
+HeapAlloc dt=6 heapalloc_value=15290608
+HeapAlloc dt=7 heapalloc_value=15298800
+HeapAlloc dt=43 heapalloc_value=15306992
+HeapAlloc dt=7 heapalloc_value=15315184
+HeapAlloc dt=6 heapalloc_value=15323376
+HeapAlloc dt=7 heapalloc_value=15331568
+HeapAlloc dt=6 heapalloc_value=15339760
+HeapAlloc dt=8 heapalloc_value=15347952
+HeapAlloc dt=6 heapalloc_value=15356144
+HeapAlloc dt=6 heapalloc_value=15364336
+HeapAlloc dt=7 heapalloc_value=15372528
+HeapAlloc dt=6 heapalloc_value=15380720
+HeapAlloc dt=6 heapalloc_value=15388912
+HeapAlloc dt=6 heapalloc_value=15397104
+HeapAlloc dt=7 heapalloc_value=15405296
+HeapAlloc dt=8 heapalloc_value=15413488
+HeapAlloc dt=6 heapalloc_value=15421680
+HeapAlloc dt=6 heapalloc_value=15429872
+HeapAlloc dt=6 heapalloc_value=15438064
+HeapAlloc dt=7 heapalloc_value=15446256
+HeapAlloc dt=7 heapalloc_value=15454448
+HeapAlloc dt=6 heapalloc_value=15462640
+HeapAlloc dt=6 heapalloc_value=15470832
+HeapAlloc dt=470 heapalloc_value=15479024
+HeapAlloc dt=14 heapalloc_value=15487216
+HeapAlloc dt=6 heapalloc_value=15495408
+HeapAlloc dt=7 heapalloc_value=15503600
+HeapAlloc dt=6 heapalloc_value=15511792
+HeapAlloc dt=7 heapalloc_value=15519984
+HeapAlloc dt=6 heapalloc_value=15528176
+HeapAlloc dt=6 heapalloc_value=15536368
+HeapAlloc dt=6 heapalloc_value=15544560
+HeapAlloc dt=5 heapalloc_value=15552752
+HeapAlloc dt=6 heapalloc_value=15560944
+HeapAlloc dt=6 heapalloc_value=15569136
+HeapAlloc dt=6 heapalloc_value=15577328
+HeapAlloc dt=6 heapalloc_value=15585520
+HeapAlloc dt=6 heapalloc_value=15593712
+HeapAlloc dt=6 heapalloc_value=15601904
+HeapAlloc dt=6 heapalloc_value=15610096
+HeapAlloc dt=6 heapalloc_value=15618288
+HeapAlloc dt=6 heapalloc_value=15626480
+HeapAlloc dt=6 heapalloc_value=15634672
+HeapAlloc dt=6 heapalloc_value=15642864
+HeapAlloc dt=6 heapalloc_value=15651056
+HeapAlloc dt=77 heapalloc_value=15659248
+GoBlock dt=13 reason_string=19 stack=21
+ProcStop dt=214
+ProcStart dt=17833 p=2 p_seq=20
+ProcStop dt=18
+ProcStart dt=9948 p=4 p_seq=4
+ProcStop dt=23
+ProcStart dt=5868 p=3 p_seq=6
+ProcStop dt=25
+ProcStart dt=94440 p=3 p_seq=7
+ProcStop dt=17
+ProcStart dt=7801 p=3 p_seq=8
+GoStart dt=172 g=13 g_seq=1
+GoStop dt=306385 reason_string=16 stack=52
+GoStart dt=19 g=13 g_seq=2
+GoStop dt=316412 reason_string=16 stack=52
+GoStart dt=14 g=13 g_seq=3
+GoDestroy dt=158437
+ProcStop dt=31
+EventBatch gen=1 m=2852342 time=420901452973 size=3683
+ProcStart dt=335 p=2 p_seq=1
+GoStart dt=164 g=21 g_seq=1
+HeapAlloc dt=242 heapalloc_value=1654784
+GoSyscallBegin dt=3053 p_seq=2 stack=17
+GoSyscallEnd dt=264
+GoBlock dt=22 reason_string=15 stack=18
+ProcStop dt=21
+ProcStart dt=370120 p=0 p_seq=11
+ProcStop dt=21
+ProcStart dt=7624 p=1 p_seq=5
+ProcStop dt=18
+ProcStart dt=386 p=2 p_seq=4
+GoStart dt=180 g=24 g_seq=1
+GoBlock dt=122 reason_string=15 stack=26
+ProcStop dt=14
+ProcStart dt=378 p=2 p_seq=7
+ProcStop dt=16
+ProcStart dt=1400 p=2 p_seq=8
+GoStart dt=127 g=9 g_seq=1
+GoBlock dt=106 reason_string=15 stack=26
+ProcStop dt=5
+ProcStart dt=482 p=1 p_seq=14
+ProcStop dt=11
+ProcStart dt=2026 p=3 p_seq=2
+HeapAlloc dt=470 heapalloc_value=4079616
+HeapAlloc dt=451 heapalloc_value=4128768
+HeapAlloc dt=21 heapalloc_value=4136960
+GoStart dt=1190 g=4 g_seq=2
+GoBlock dt=29 reason_string=15 stack=32
+ProcStop dt=34
+ProcStart dt=77810 p=3 p_seq=3
+ProcStop dt=32
+ProcStart dt=600 p=3 p_seq=4
+GoUnblock dt=14 g=25 g_seq=6 stack=0
+GoStart dt=184 g=25 g_seq=7
+GoLabel dt=3 label_string=2
+GoBlock dt=145 reason_string=15 stack=26
+ProcStop dt=27
+ProcStart dt=122643 p=3 p_seq=5
+GoStart dt=236 g=4 g_seq=8
+GoBlock dt=24 reason_string=15 stack=32
+GoUnblock dt=25 g=8 g_seq=4 stack=0
+GoStart dt=9 g=8 g_seq=5
+GoLabel dt=1 label_string=4
+GoBlock dt=1341 reason_string=15 stack=26
+GoUnblock dt=4399 g=1 g_seq=45 stack=0
+GoStart dt=12 g=1 g_seq=46
+HeapAlloc dt=416 heapalloc_value=16705232
+HeapAlloc dt=47 heapalloc_value=16721328
+HeapAlloc dt=35 heapalloc_value=16729520
+HeapAlloc dt=24 heapalloc_value=16737712
+HeapAlloc dt=26 heapalloc_value=16745904
+HeapAlloc dt=24 heapalloc_value=16754096
+HeapAlloc dt=13 heapalloc_value=16762288
+HeapAlloc dt=15 heapalloc_value=16770480
+HeapAlloc dt=14 heapalloc_value=16778672
+HeapAlloc dt=14 heapalloc_value=16786864
+HeapAlloc dt=14 heapalloc_value=16795056
+HeapAlloc dt=13 heapalloc_value=16803248
+HeapAlloc dt=12 heapalloc_value=16811440
+HeapAlloc dt=14 heapalloc_value=16819632
+HeapAlloc dt=13 heapalloc_value=16827824
+HeapAlloc dt=13 heapalloc_value=16836016
+HeapAlloc dt=14 heapalloc_value=16844208
+HeapAlloc dt=14 heapalloc_value=16852400
+HeapAlloc dt=13 heapalloc_value=16860592
+HeapAlloc dt=13 heapalloc_value=16868784
+HeapAlloc dt=12 heapalloc_value=16876976
+HeapAlloc dt=19 heapalloc_value=16885168
+HeapAlloc dt=15 heapalloc_value=16893360
+HeapAlloc dt=14 heapalloc_value=16901552
+HeapAlloc dt=14 heapalloc_value=16909744
+HeapAlloc dt=13 heapalloc_value=16917936
+HeapAlloc dt=13 heapalloc_value=16926128
+HeapAlloc dt=12 heapalloc_value=16934320
+HeapAlloc dt=14 heapalloc_value=16942512
+HeapAlloc dt=14 heapalloc_value=16950704
+HeapAlloc dt=12 heapalloc_value=16958896
+HeapAlloc dt=13 heapalloc_value=16967088
+HeapAlloc dt=479 heapalloc_value=16975280
+HeapAlloc dt=207 heapalloc_value=16983472
+HeapAlloc dt=15 heapalloc_value=16991664
+HeapAlloc dt=111 heapalloc_value=16999856
+HeapAlloc dt=14 heapalloc_value=17008048
+HeapAlloc dt=13 heapalloc_value=17016240
+HeapAlloc dt=13 heapalloc_value=17024432
+HeapAlloc dt=13 heapalloc_value=17032624
+HeapAlloc dt=12 heapalloc_value=17040816
+HeapAlloc dt=14 heapalloc_value=17049008
+HeapAlloc dt=13 heapalloc_value=17057200
+HeapAlloc dt=15 heapalloc_value=17065392
+HeapAlloc dt=14 heapalloc_value=17073584
+HeapAlloc dt=15 heapalloc_value=17081776
+HeapAlloc dt=14 heapalloc_value=17089968
+HeapAlloc dt=14 heapalloc_value=17098160
+HeapAlloc dt=14 heapalloc_value=17106352
+HeapAlloc dt=15 heapalloc_value=17114544
+HeapAlloc dt=14 heapalloc_value=17122736
+HeapAlloc dt=19 heapalloc_value=17130928
+HeapAlloc dt=20 heapalloc_value=17139120
+HeapAlloc dt=19 heapalloc_value=17147312
+HeapAlloc dt=14 heapalloc_value=17155504
+HeapAlloc dt=14 heapalloc_value=17163696
+HeapAlloc dt=15 heapalloc_value=17171888
+HeapAlloc dt=14 heapalloc_value=17180080
+HeapAlloc dt=14 heapalloc_value=17188272
+HeapAlloc dt=16 heapalloc_value=17196464
+HeapAlloc dt=147 heapalloc_value=17204656
+HeapAlloc dt=17 heapalloc_value=17212848
+HeapAlloc dt=14 heapalloc_value=17221040
+HeapAlloc dt=15 heapalloc_value=17229232
+HeapAlloc dt=133 heapalloc_value=17237424
+HeapAlloc dt=66 heapalloc_value=17245616
+HeapAlloc dt=17 heapalloc_value=17253808
+HeapAlloc dt=14 heapalloc_value=17262000
+HeapAlloc dt=14 heapalloc_value=17270192
+HeapAlloc dt=15 heapalloc_value=17278384
+HeapAlloc dt=14 heapalloc_value=17286576
+HeapAlloc dt=14 heapalloc_value=17294768
+HeapAlloc dt=17 heapalloc_value=17302960
+HeapAlloc dt=14 heapalloc_value=17311152
+GoStop dt=24 reason_string=16 stack=46
+GoStart dt=859 g=1 g_seq=47
+HeapAlloc dt=19 heapalloc_value=17319344
+HeapAlloc dt=16 heapalloc_value=17327536
+HeapAlloc dt=14 heapalloc_value=17335728
+HeapAlloc dt=14 heapalloc_value=17343920
+HeapAlloc dt=15 heapalloc_value=17352112
+HeapAlloc dt=14 heapalloc_value=17360304
+HeapAlloc dt=14 heapalloc_value=17368496
+HeapAlloc dt=14 heapalloc_value=17376688
+HeapAlloc dt=18 heapalloc_value=17384880
+HeapAlloc dt=17 heapalloc_value=17393072
+HeapAlloc dt=14 heapalloc_value=17401264
+HeapAlloc dt=18 heapalloc_value=17409456
+HeapAlloc dt=14 heapalloc_value=17417648
+HeapAlloc dt=14 heapalloc_value=17425840
+HeapAlloc dt=15 heapalloc_value=17434032
+HeapAlloc dt=12 heapalloc_value=17442224
+HeapAlloc dt=18 heapalloc_value=17450416
+HeapAlloc dt=69 heapalloc_value=17458608
+HeapAlloc dt=15 heapalloc_value=17466800
+HeapAlloc dt=14 heapalloc_value=17474992
+HeapAlloc dt=12 heapalloc_value=17483184
+HeapAlloc dt=14 heapalloc_value=17491376
+HeapAlloc dt=405 heapalloc_value=17499568
+GoStop dt=11 reason_string=16 stack=31
+ProcStop dt=10
+ProcStart dt=1071 p=0 p_seq=41
+GoStart dt=509 g=1 g_seq=48
+HeapAlloc dt=31 heapalloc_value=16800656
+GCSweepBegin dt=40 stack=38
+GCSweepEnd dt=407 swept_value=827392 reclaimed_value=0
+HeapAlloc dt=25 heapalloc_value=16808848
+GCSweepBegin dt=25 stack=38
+GCSweepEnd dt=1029 swept_value=827392 reclaimed_value=0
+HeapAlloc dt=20 heapalloc_value=16817040
+GCSweepBegin dt=33 stack=38
+GCSweepEnd dt=1076 swept_value=827392 reclaimed_value=0
+HeapAlloc dt=13 heapalloc_value=16825232
+GCSweepBegin dt=30 stack=38
+GCSweepEnd dt=1298 swept_value=827392 reclaimed_value=0
+HeapAlloc dt=17 heapalloc_value=16833424
+GCSweepBegin dt=29 stack=38
+GCSweepEnd dt=1140 swept_value=827392 reclaimed_value=0
+HeapAlloc dt=11 heapalloc_value=16841616
+GCSweepBegin dt=32 stack=38
+GCSweepEnd dt=1161 swept_value=827392 reclaimed_value=0
+HeapAlloc dt=14 heapalloc_value=16849808
+GCSweepBegin dt=31 stack=38
+GCSweepEnd dt=763 swept_value=827392 reclaimed_value=0
+HeapAlloc dt=12 heapalloc_value=16858000
+GCSweepBegin dt=29 stack=38
+GCSweepEnd dt=1113 swept_value=827392 reclaimed_value=0
+HeapAlloc dt=9 heapalloc_value=16866192
+GCSweepBegin dt=25 stack=38
+GCSweepEnd dt=1068 swept_value=827392 reclaimed_value=0
+HeapAlloc dt=21 heapalloc_value=16874384
+GCSweepBegin dt=36 stack=38
+GCSweepEnd dt=478 swept_value=827392 reclaimed_value=0
+HeapAlloc dt=7 heapalloc_value=16882576
+GCSweepBegin dt=16 stack=38
+GCSweepEnd dt=32 swept_value=90112 reclaimed_value=0
+HeapAlloc dt=11 heapalloc_value=16890768
+HeapAlloc dt=31 heapalloc_value=16898960
+HeapAlloc dt=24 heapalloc_value=16907152
+HeapAlloc dt=17 heapalloc_value=16915344
+HeapAlloc dt=17 heapalloc_value=16923536
+HeapAlloc dt=23 heapalloc_value=16931728
+HeapAlloc dt=18 heapalloc_value=16939920
+HeapAlloc dt=22 heapalloc_value=16948112
+HeapAlloc dt=17 heapalloc_value=16956304
+HeapAlloc dt=16 heapalloc_value=16964496
+HeapAlloc dt=16 heapalloc_value=16972688
+HeapAlloc dt=106 heapalloc_value=16980880
+HeapAlloc dt=19 heapalloc_value=16989072
+HeapAlloc dt=16 heapalloc_value=16997264
+HeapAlloc dt=13 heapalloc_value=17005456
+HeapAlloc dt=13 heapalloc_value=17013648
+HeapAlloc dt=96 heapalloc_value=17021840
+HeapAlloc dt=16 heapalloc_value=17030032
+GoBlock dt=18 reason_string=19 stack=21
+ProcStop dt=315
+ProcStart dt=17450 p=2 p_seq=23
+ProcStop dt=14
+ProcStart dt=6669 p=0 p_seq=44
+ProcStop dt=11
+ProcStart dt=16752 p=0 p_seq=45
+GoUnblock dt=14 g=1 g_seq=51 stack=0
+GoStart dt=146 g=1 g_seq=52
+HeapAlloc dt=31 heapalloc_value=18529168
+HeapAlloc dt=21 heapalloc_value=18537360
+HeapAlloc dt=13 heapalloc_value=18545552
+HeapAlloc dt=77 heapalloc_value=18553744
+HeapAlloc dt=21 heapalloc_value=18561936
+HeapAlloc dt=15 heapalloc_value=18570128
+HeapAlloc dt=12 heapalloc_value=18578320
+HeapAlloc dt=12 heapalloc_value=18586512
+HeapAlloc dt=12 heapalloc_value=18594704
+HeapAlloc dt=16 heapalloc_value=18602896
+HeapAlloc dt=14 heapalloc_value=18611088
+HeapAlloc dt=13 heapalloc_value=18619280
+HeapAlloc dt=17 heapalloc_value=18627472
+HeapAlloc dt=13 heapalloc_value=18635664
+HeapAlloc dt=14 heapalloc_value=18643856
+HeapAlloc dt=12 heapalloc_value=18652048
+HeapAlloc dt=12 heapalloc_value=18660240
+HeapAlloc dt=12 heapalloc_value=18668432
+HeapAlloc dt=12 heapalloc_value=18676624
+HeapAlloc dt=12 heapalloc_value=18684816
+HeapAlloc dt=93 heapalloc_value=18693008
+HeapAlloc dt=17 heapalloc_value=18701200
+HeapAlloc dt=12 heapalloc_value=18709392
+HeapAlloc dt=13 heapalloc_value=18717584
+HeapAlloc dt=15 heapalloc_value=18725776
+HeapAlloc dt=12 heapalloc_value=18733968
+HeapAlloc dt=13 heapalloc_value=18742160
+HeapAlloc dt=14 heapalloc_value=18750352
+HeapAlloc dt=12 heapalloc_value=18758544
+HeapAlloc dt=54 heapalloc_value=18766736
+HeapAlloc dt=13 heapalloc_value=18774928
+HeapAlloc dt=13 heapalloc_value=18783120
+HeapAlloc dt=12 heapalloc_value=18791312
+HeapAlloc dt=13 heapalloc_value=18799504
+HeapAlloc dt=12 heapalloc_value=18807696
+HeapAlloc dt=13 heapalloc_value=18815888
+HeapAlloc dt=12 heapalloc_value=18824080
+HeapAlloc dt=13 heapalloc_value=18832272
+HeapAlloc dt=12 heapalloc_value=18840464
+HeapAlloc dt=13 heapalloc_value=18848656
+HeapAlloc dt=12 heapalloc_value=18856848
+HeapAlloc dt=13 heapalloc_value=18865040
+HeapAlloc dt=13 heapalloc_value=18873232
+HeapAlloc dt=12 heapalloc_value=18881424
+HeapAlloc dt=14 heapalloc_value=18889616
+HeapAlloc dt=13 heapalloc_value=18897808
+HeapAlloc dt=12 heapalloc_value=18906000
+HeapAlloc dt=13 heapalloc_value=18914192
+HeapAlloc dt=13 heapalloc_value=18922384
+HeapAlloc dt=86 heapalloc_value=18930576
+HeapAlloc dt=15 heapalloc_value=18938768
+HeapAlloc dt=13 heapalloc_value=18946960
+HeapAlloc dt=26 heapalloc_value=18955152
+HeapAlloc dt=19 heapalloc_value=18963344
+HeapAlloc dt=12 heapalloc_value=18971536
+HeapAlloc dt=14 heapalloc_value=18979728
+HeapAlloc dt=14 heapalloc_value=18987920
+HeapAlloc dt=13 heapalloc_value=18996112
+HeapAlloc dt=12 heapalloc_value=19004304
+HeapAlloc dt=64 heapalloc_value=19012496
+HeapAlloc dt=15 heapalloc_value=19020688
+HeapAlloc dt=14 heapalloc_value=19028880
+HeapAlloc dt=14 heapalloc_value=19037072
+HeapAlloc dt=16 heapalloc_value=19045264
+HeapAlloc dt=77 heapalloc_value=19053456
+HeapAlloc dt=16 heapalloc_value=19061648
+HeapAlloc dt=13 heapalloc_value=19069840
+HeapAlloc dt=16 heapalloc_value=19078032
+HeapAlloc dt=12 heapalloc_value=19086224
+HeapAlloc dt=12 heapalloc_value=19094416
+HeapAlloc dt=13 heapalloc_value=19102608
+HeapAlloc dt=14 heapalloc_value=19110800
+HeapAlloc dt=15 heapalloc_value=19118992
+HeapAlloc dt=14 heapalloc_value=19127184
+HeapAlloc dt=13 heapalloc_value=19135376
+HeapAlloc dt=13 heapalloc_value=19143568
+HeapAlloc dt=15 heapalloc_value=19151760
+HeapAlloc dt=18 heapalloc_value=19159952
+HeapAlloc dt=16 heapalloc_value=19168144
+HeapAlloc dt=15 heapalloc_value=19176336
+HeapAlloc dt=113 heapalloc_value=19184528
+HeapAlloc dt=17 heapalloc_value=19192720
+HeapAlloc dt=13 heapalloc_value=19200912
+HeapAlloc dt=18 heapalloc_value=19209104
+HeapAlloc dt=15 heapalloc_value=19217296
+HeapAlloc dt=18 heapalloc_value=19225488
+HeapAlloc dt=15 heapalloc_value=19233680
+HeapAlloc dt=16 heapalloc_value=19241872
+HeapAlloc dt=16 heapalloc_value=19250064
+HeapAlloc dt=15 heapalloc_value=19258256
+HeapAlloc dt=14 heapalloc_value=19266448
+HeapAlloc dt=15 heapalloc_value=19274640
+HeapAlloc dt=13 heapalloc_value=19282832
+HeapAlloc dt=20 heapalloc_value=19291024
+HeapAlloc dt=15 heapalloc_value=19299216
+HeapAlloc dt=16 heapalloc_value=19307408
+HeapAlloc dt=26 heapalloc_value=19315600
+HeapAlloc dt=9 heapalloc_value=19323792
+HeapAlloc dt=6 heapalloc_value=19331984
+HeapAlloc dt=7 heapalloc_value=19340176
+HeapAlloc dt=7 heapalloc_value=19348368
+HeapAlloc dt=8 heapalloc_value=19356560
+HeapAlloc dt=70 heapalloc_value=19364752
+HeapAlloc dt=8 heapalloc_value=19372944
+HeapAlloc dt=7 heapalloc_value=19381136
+HeapAlloc dt=6 heapalloc_value=19389328
+HeapAlloc dt=7 heapalloc_value=19397520
+HeapAlloc dt=8 heapalloc_value=19405712
+HeapAlloc dt=7 heapalloc_value=19413904
+HeapAlloc dt=7 heapalloc_value=19422096
+HeapAlloc dt=8 heapalloc_value=19430288
+HeapAlloc dt=7 heapalloc_value=19438480
+HeapAlloc dt=6 heapalloc_value=19446672
+HeapAlloc dt=7 heapalloc_value=19454864
+HeapAlloc dt=7 heapalloc_value=19463056
+HeapAlloc dt=7 heapalloc_value=19471248
+HeapAlloc dt=6 heapalloc_value=19479440
+HeapAlloc dt=7 heapalloc_value=19487632
+HeapAlloc dt=6 heapalloc_value=19495824
+HeapAlloc dt=7 heapalloc_value=19504016
+HeapAlloc dt=7 heapalloc_value=19512208
+HeapAlloc dt=6 heapalloc_value=19520400
+HeapAlloc dt=8 heapalloc_value=19528592
+HeapAlloc dt=53 heapalloc_value=19536784
+HeapAlloc dt=8 heapalloc_value=19544976
+GoBlock dt=12 reason_string=19 stack=21
+ProcStop dt=196
+ProcStart dt=17347 p=2 p_seq=25
+ProcStop dt=14
+ProcStart dt=2376 p=0 p_seq=48
+ProcStop dt=11
+ProcStart dt=16736 p=0 p_seq=49
+GoUnblock dt=12 g=1 g_seq=55 stack=0
+GoStart dt=137 g=1 g_seq=56
+HeapAlloc dt=24 heapalloc_value=20577168
+HeapAlloc dt=87 heapalloc_value=20585360
+HeapAlloc dt=9 heapalloc_value=20593552
+HeapAlloc dt=6 heapalloc_value=20601744
+HeapAlloc dt=7 heapalloc_value=20609936
+HeapAlloc dt=7 heapalloc_value=20618128
+HeapAlloc dt=6 heapalloc_value=20626320
+HeapAlloc dt=7 heapalloc_value=20634512
+HeapAlloc dt=7 heapalloc_value=20642704
+HeapAlloc dt=6 heapalloc_value=20650896
+HeapAlloc dt=7 heapalloc_value=20659088
+HeapAlloc dt=7 heapalloc_value=20667280
+HeapAlloc dt=238 heapalloc_value=20675472
+HeapAlloc dt=10 heapalloc_value=20683664
+HeapAlloc dt=6 heapalloc_value=20691856
+HeapAlloc dt=7 heapalloc_value=20700048
+HeapAlloc dt=7 heapalloc_value=20708240
+HeapAlloc dt=6 heapalloc_value=20716432
+HeapAlloc dt=7 heapalloc_value=20724624
+HeapAlloc dt=6 heapalloc_value=20732816
+HeapAlloc dt=46 heapalloc_value=20741008
+HeapAlloc dt=8 heapalloc_value=20749200
+HeapAlloc dt=7 heapalloc_value=20757392
+HeapAlloc dt=7 heapalloc_value=20765584
+HeapAlloc dt=7 heapalloc_value=20773776
+HeapAlloc dt=7 heapalloc_value=20781968
+HeapAlloc dt=6 heapalloc_value=20790160
+HeapAlloc dt=7 heapalloc_value=20798352
+HeapAlloc dt=7 heapalloc_value=20806544
+HeapAlloc dt=6 heapalloc_value=20814736
+HeapAlloc dt=7 heapalloc_value=20822928
+HeapAlloc dt=7 heapalloc_value=20831120
+HeapAlloc dt=7 heapalloc_value=20839312
+HeapAlloc dt=7 heapalloc_value=20847504
+HeapAlloc dt=6 heapalloc_value=20855696
+HeapAlloc dt=7 heapalloc_value=20863888
+HeapAlloc dt=6 heapalloc_value=20872080
+HeapAlloc dt=7 heapalloc_value=20880272
+HeapAlloc dt=7 heapalloc_value=20888464
+HeapAlloc dt=6 heapalloc_value=20896656
+HeapAlloc dt=7 heapalloc_value=20904848
+HeapAlloc dt=7 heapalloc_value=20913040
+HeapAlloc dt=6 heapalloc_value=20921232
+HeapAlloc dt=7 heapalloc_value=20929424
+HeapAlloc dt=74 heapalloc_value=20937616
+HeapAlloc dt=8 heapalloc_value=20945808
+HeapAlloc dt=7 heapalloc_value=20954000
+HeapAlloc dt=6 heapalloc_value=20962192
+HeapAlloc dt=7 heapalloc_value=20970384
+HeapAlloc dt=7 heapalloc_value=20978576
+HeapAlloc dt=7 heapalloc_value=20986768
+HeapAlloc dt=6 heapalloc_value=20994960
+HeapAlloc dt=7 heapalloc_value=21003152
+HeapAlloc dt=7 heapalloc_value=21011344
+HeapAlloc dt=7 heapalloc_value=21019536
+HeapAlloc dt=6 heapalloc_value=21027728
+HeapAlloc dt=7 heapalloc_value=21035920
+HeapAlloc dt=6 heapalloc_value=21044112
+HeapAlloc dt=7 heapalloc_value=21052304
+HeapAlloc dt=7 heapalloc_value=21060496
+HeapAlloc dt=6 heapalloc_value=21068688
+HeapAlloc dt=7 heapalloc_value=21076880
+HeapAlloc dt=6 heapalloc_value=21085072
+HeapAlloc dt=7 heapalloc_value=21093264
+HeapAlloc dt=7 heapalloc_value=21101456
+HeapAlloc dt=90 heapalloc_value=21109648
+HeapAlloc dt=8 heapalloc_value=21117840
+HeapAlloc dt=6 heapalloc_value=21126032
+HeapAlloc dt=7 heapalloc_value=21134224
+HeapAlloc dt=7 heapalloc_value=21142416
+HeapAlloc dt=7 heapalloc_value=21150608
+HeapAlloc dt=6 heapalloc_value=21158800
+HeapAlloc dt=44 heapalloc_value=21166992
+HeapAlloc dt=7 heapalloc_value=21175184
+HeapAlloc dt=7 heapalloc_value=21183376
+HeapAlloc dt=7 heapalloc_value=21191568
+HeapAlloc dt=71 heapalloc_value=21199760
+HeapAlloc dt=8 heapalloc_value=21207952
+HeapAlloc dt=7 heapalloc_value=21216144
+HeapAlloc dt=7 heapalloc_value=21224336
+HeapAlloc dt=7 heapalloc_value=21232528
+HeapAlloc dt=6 heapalloc_value=21240720
+HeapAlloc dt=7 heapalloc_value=21248912
+HeapAlloc dt=7 heapalloc_value=21257104
+HeapAlloc dt=6 heapalloc_value=21265296
+HeapAlloc dt=7 heapalloc_value=21273488
+HeapAlloc dt=6 heapalloc_value=21281680
+HeapAlloc dt=7 heapalloc_value=21289872
+HeapAlloc dt=7 heapalloc_value=21298064
+HeapAlloc dt=6 heapalloc_value=21306256
+HeapAlloc dt=7 heapalloc_value=21314448
+HeapAlloc dt=6 heapalloc_value=21322640
+HeapAlloc dt=7 heapalloc_value=21330832
+HeapAlloc dt=7 heapalloc_value=21339024
+HeapAlloc dt=6 heapalloc_value=21347216
+HeapAlloc dt=7 heapalloc_value=21355408
+HeapAlloc dt=6 heapalloc_value=21363600
+HeapAlloc dt=43 heapalloc_value=21371792
+HeapAlloc dt=8 heapalloc_value=21379984
+HeapAlloc dt=7 heapalloc_value=21388176
+HeapAlloc dt=7 heapalloc_value=21396368
+HeapAlloc dt=6 heapalloc_value=21404560
+HeapAlloc dt=7 heapalloc_value=21412752
+HeapAlloc dt=7 heapalloc_value=21420944
+HeapAlloc dt=6 heapalloc_value=21429136
+HeapAlloc dt=7 heapalloc_value=21437328
+HeapAlloc dt=6 heapalloc_value=21445520
+HeapAlloc dt=7 heapalloc_value=21453712
+HeapAlloc dt=68 heapalloc_value=21461904
+HeapAlloc dt=8 heapalloc_value=21470096
+HeapAlloc dt=6 heapalloc_value=21478288
+HeapAlloc dt=7 heapalloc_value=21486480
+HeapAlloc dt=6 heapalloc_value=21494672
+HeapAlloc dt=7 heapalloc_value=21502864
+HeapAlloc dt=7 heapalloc_value=21511056
+HeapAlloc dt=6 heapalloc_value=21519248
+HeapAlloc dt=7 heapalloc_value=21527440
+HeapAlloc dt=6 heapalloc_value=21535632
+HeapAlloc dt=7 heapalloc_value=21543824
+HeapAlloc dt=7 heapalloc_value=21552016
+HeapAlloc dt=6 heapalloc_value=21560208
+HeapAlloc dt=7 heapalloc_value=21568400
+HeapAlloc dt=7 heapalloc_value=21576592
+HeapAlloc dt=7 heapalloc_value=21584784
+HeapAlloc dt=6 heapalloc_value=21592976
+GoBlock dt=11 reason_string=19 stack=21
+ProcStop dt=159
+ProcStart dt=1372 p=0 p_seq=51
+GoUnblock dt=19 g=1 g_seq=57 stack=0
+GoStart dt=211 g=1 g_seq=58
+HeapAlloc dt=39 heapalloc_value=21601168
+HeapAlloc dt=16 heapalloc_value=21609360
+HeapAlloc dt=8 heapalloc_value=21617552
+HeapAlloc dt=6 heapalloc_value=21625744
+HeapAlloc dt=101 heapalloc_value=21633936
+HeapAlloc dt=8 heapalloc_value=21642128
+HeapAlloc dt=7 heapalloc_value=21650320
+HeapAlloc dt=6 heapalloc_value=21658512
+HeapAlloc dt=7 heapalloc_value=21666704
+HeapAlloc dt=6 heapalloc_value=21674896
+HeapAlloc dt=6 heapalloc_value=21683088
+HeapAlloc dt=7 heapalloc_value=21691280
+HeapAlloc dt=6 heapalloc_value=21699472
+HeapAlloc dt=7 heapalloc_value=21707664
+HeapAlloc dt=6 heapalloc_value=21715856
+HeapAlloc dt=102 heapalloc_value=21724048
+HeapAlloc dt=8 heapalloc_value=21732240
+HeapAlloc dt=6 heapalloc_value=21740432
+HeapAlloc dt=7 heapalloc_value=21748624
+HeapAlloc dt=6 heapalloc_value=21756816
+HeapAlloc dt=7 heapalloc_value=21765008
+HeapAlloc dt=6 heapalloc_value=21773200
+HeapAlloc dt=7 heapalloc_value=21781392
+HeapAlloc dt=44 heapalloc_value=21789584
+HeapAlloc dt=7 heapalloc_value=21797776
+HeapAlloc dt=8 heapalloc_value=21805968
+HeapAlloc dt=7 heapalloc_value=21814160
+HeapAlloc dt=6 heapalloc_value=21822352
+HeapAlloc dt=7 heapalloc_value=21830544
+HeapAlloc dt=6 heapalloc_value=21838736
+HeapAlloc dt=7 heapalloc_value=21846928
+HeapAlloc dt=6 heapalloc_value=21855120
+HeapAlloc dt=6 heapalloc_value=21863312
+HeapAlloc dt=7 heapalloc_value=21871504
+HeapAlloc dt=6 heapalloc_value=21879696
+HeapAlloc dt=7 heapalloc_value=21887888
+HeapAlloc dt=6 heapalloc_value=21896080
+HeapAlloc dt=7 heapalloc_value=21904272
+HeapAlloc dt=6 heapalloc_value=21912464
+HeapAlloc dt=7 heapalloc_value=21920656
+HeapAlloc dt=6 heapalloc_value=21928848
+HeapAlloc dt=6 heapalloc_value=21937040
+HeapAlloc dt=7 heapalloc_value=21945232
+HeapAlloc dt=6 heapalloc_value=21953424
+HeapAlloc dt=7 heapalloc_value=21961616
+HeapAlloc dt=6 heapalloc_value=21969808
+HeapAlloc dt=7 heapalloc_value=21978000
+HeapAlloc dt=248 heapalloc_value=21986192
+HeapAlloc dt=18 heapalloc_value=21994384
+HeapAlloc dt=7 heapalloc_value=22002576
+HeapAlloc dt=6 heapalloc_value=22010768
+HeapAlloc dt=7 heapalloc_value=22018960
+HeapAlloc dt=6 heapalloc_value=22027152
+HeapAlloc dt=7 heapalloc_value=22035344
+HeapAlloc dt=6 heapalloc_value=22043536
+HeapAlloc dt=7 heapalloc_value=22051728
+HeapAlloc dt=6 heapalloc_value=22059920
+HeapAlloc dt=7 heapalloc_value=22068112
+HeapAlloc dt=16 heapalloc_value=22657936
+HeapAlloc dt=3547 heapalloc_value=22666128
+HeapAlloc dt=3135 heapalloc_value=22674320
+HeapAlloc dt=11 heapalloc_value=22682512
+HeapAlloc dt=8 heapalloc_value=22690704
+HeapAlloc dt=8 heapalloc_value=22698896
+HeapAlloc dt=8 heapalloc_value=22707088
+HeapAlloc dt=10 heapalloc_value=22715280
+HeapAlloc dt=8 heapalloc_value=22723472
+HeapAlloc dt=8 heapalloc_value=22731664
+HeapAlloc dt=71 heapalloc_value=22739856
+HeapAlloc dt=10 heapalloc_value=22748048
+HeapAlloc dt=8 heapalloc_value=22756240
+HeapAlloc dt=9 heapalloc_value=22764432
+HeapAlloc dt=8 heapalloc_value=22772624
+HeapAlloc dt=8 heapalloc_value=22780816
+HeapAlloc dt=9 heapalloc_value=22789008
+HeapAlloc dt=47 heapalloc_value=22797200
+HeapAlloc dt=9 heapalloc_value=22805392
+HeapAlloc dt=9 heapalloc_value=22813584
+HeapAlloc dt=8 heapalloc_value=22821776
+HeapAlloc dt=9 heapalloc_value=22829968
+HeapAlloc dt=17 heapalloc_value=22838160
+HeapAlloc dt=8 heapalloc_value=22846352
+HeapAlloc dt=6 heapalloc_value=22854544
+HeapAlloc dt=7 heapalloc_value=22862736
+HeapAlloc dt=6 heapalloc_value=22870928
+HeapAlloc dt=6 heapalloc_value=22879120
+HeapAlloc dt=6 heapalloc_value=22887312
+HeapAlloc dt=6 heapalloc_value=22895504
+HeapAlloc dt=7 heapalloc_value=22903696
+HeapAlloc dt=6 heapalloc_value=22911888
+HeapAlloc dt=6 heapalloc_value=22920080
+HeapAlloc dt=6 heapalloc_value=22928272
+HeapAlloc dt=6 heapalloc_value=22936464
+HeapAlloc dt=6 heapalloc_value=22944656
+HeapAlloc dt=7 heapalloc_value=22952848
+HeapAlloc dt=6 heapalloc_value=22961040
+HeapAlloc dt=8 heapalloc_value=22969232
+HeapAlloc dt=6 heapalloc_value=22977424
+HeapAlloc dt=6 heapalloc_value=22985616
+HeapAlloc dt=6 heapalloc_value=22993808
+HeapAlloc dt=43 heapalloc_value=23002000
+HeapAlloc dt=8 heapalloc_value=23010192
+HeapAlloc dt=6 heapalloc_value=23018384
+HeapAlloc dt=7 heapalloc_value=23026576
+HeapAlloc dt=76 heapalloc_value=23034768
+HeapAlloc dt=9 heapalloc_value=23042960
+HeapAlloc dt=6 heapalloc_value=23051152
+HeapAlloc dt=7 heapalloc_value=23059344
+HeapAlloc dt=6 heapalloc_value=23067536
+HeapAlloc dt=6 heapalloc_value=23075728
+HeapAlloc dt=7 heapalloc_value=23083920
+HeapAlloc dt=6 heapalloc_value=23092112
+HeapAlloc dt=6 heapalloc_value=23100304
+HeapAlloc dt=6 heapalloc_value=23108496
+HeapAlloc dt=6 heapalloc_value=23116688
+HeapAlloc dt=6 heapalloc_value=23124880
+HeapAlloc dt=7 heapalloc_value=23133072
+HeapAlloc dt=6 heapalloc_value=23141264
+HeapAlloc dt=8 heapalloc_value=23149456
+HeapAlloc dt=6 heapalloc_value=23157648
+HeapAlloc dt=6 heapalloc_value=23165840
+HeapAlloc dt=7 heapalloc_value=23174032
+HeapAlloc dt=6 heapalloc_value=23182224
+HeapAlloc dt=7 heapalloc_value=23190416
+HeapAlloc dt=6 heapalloc_value=23198608
+HeapAlloc dt=6 heapalloc_value=23206800
+HeapAlloc dt=22 heapalloc_value=23214912
+HeapAlloc dt=22 heapalloc_value=23223008
+HeapAlloc dt=21 heapalloc_value=23224960
+GoCreate dt=50 new_g=10 new_stack=49 stack=50
+GoCreate dt=193 new_g=11 new_stack=49 stack=50
+GoCreate dt=10 new_g=12 new_stack=49 stack=50
+GoCreate dt=5 new_g=13 new_stack=49 stack=50
+HeapAlloc dt=120 heapalloc_value=23232736
+GoCreate dt=9 new_g=14 new_stack=49 stack=50
+GoCreate dt=8 new_g=15 new_stack=49 stack=50
+GoCreate dt=7 new_g=16 new_stack=49 stack=50
+GoCreate dt=8 new_g=50 new_stack=49 stack=50
+GoBlock dt=17 reason_string=10 stack=51
+GoStart dt=7 g=50 g_seq=1
+GoStop dt=306070 reason_string=16 stack=52
+GoStart dt=17 g=50 g_seq=2
+GoStop dt=316463 reason_string=16 stack=52
+GoStart dt=9 g=50 g_seq=3
+GoDestroy dt=158709
+ProcStop dt=33
+ProcStart dt=9387 p=7 p_seq=3
+ProcStop dt=14
+ProcStart dt=63662 p=7 p_seq=4
+ProcStop dt=14
+ProcStart dt=16745 p=7 p_seq=5
+GoUnblock dt=39 g=19 g_seq=2 stack=0
+GoStart dt=155 g=19 g_seq=3
+HeapAlloc dt=297 heapalloc_value=23312520
+GoBlock dt=30 reason_string=12 stack=11
+ProcStop dt=28
+ProcStart dt=706341 p=7 p_seq=6
+ProcStop dt=15
+ProcStart dt=50 p=7 p_seq=7
+ProcStop dt=8
+ProcStart dt=3274 p=6 p_seq=14
+ProcStop dt=13
+ProcStart dt=2696 p=4 p_seq=6
+ProcStop dt=17
+ProcStart dt=416 p=7 p_seq=19
+GoUnblock dt=7 g=1 g_seq=64 stack=0
+GoStart dt=7 g=1 g_seq=65
+GoSyscallBegin dt=33 p_seq=20 stack=81
+GoSyscallEnd dt=43
+GoSyscallBegin dt=134 p_seq=21 stack=82
+GoSyscallEnd dt=38
+GoSyscallBegin dt=10 p_seq=22 stack=83
+GoSyscallEnd dt=40
+GoSyscallBegin dt=7 p_seq=23 stack=84
+GoSyscallEnd dt=26
+GoSyscallBegin dt=10 p_seq=24 stack=85
+GoSyscallEnd dt=31
+GoSyscallBegin dt=39 p_seq=25 stack=86
+GoSyscallEnd dt=61
+GoBlock dt=13 reason_string=7 stack=87
+ProcStop dt=15
+EventBatch gen=1 m=2852341 time=420901453987 size=3492
+ProcStart dt=448 p=3 p_seq=1
+ProcStop dt=26
+ProcStart dt=312314 p=0 p_seq=4
+ProcStop dt=17
+ProcStart dt=16776 p=0 p_seq=5
+GoUnblock dt=31 g=1 g_seq=3 stack=0
+GoStart dt=182 g=1 g_seq=4
+HeapAlloc dt=181 heapalloc_value=1662976
+HeapAlloc dt=25 heapalloc_value=1671168
+HeapAlloc dt=210 heapalloc_value=1679360
+HeapAlloc dt=19 heapalloc_value=1687552
+HeapAlloc dt=15 heapalloc_value=1695744
+HeapAlloc dt=8 heapalloc_value=1703936
+HeapAlloc dt=15 heapalloc_value=1712128
+HeapAlloc dt=7 heapalloc_value=1720320
+HeapAlloc dt=9 heapalloc_value=1728512
+HeapAlloc dt=5 heapalloc_value=1736704
+HeapAlloc dt=8 heapalloc_value=1761280
+HeapAlloc dt=9 heapalloc_value=1769472
+HeapAlloc dt=8 heapalloc_value=1777664
+HeapAlloc dt=6 heapalloc_value=1785856
+HeapAlloc dt=8 heapalloc_value=1794048
+HeapAlloc dt=6 heapalloc_value=1802240
+HeapAlloc dt=6 heapalloc_value=1810432
+HeapAlloc dt=6 heapalloc_value=1818624
+HeapAlloc dt=6 heapalloc_value=1826816
+HeapAlloc dt=5 heapalloc_value=1851392
+HeapAlloc dt=62 heapalloc_value=1859584
+HeapAlloc dt=8 heapalloc_value=1867776
+HeapAlloc dt=6 heapalloc_value=1875968
+HeapAlloc dt=6 heapalloc_value=1884160
+HeapAlloc dt=6 heapalloc_value=1892352
+HeapAlloc dt=6 heapalloc_value=1900544
+HeapAlloc dt=6 heapalloc_value=1908736
+HeapAlloc dt=6 heapalloc_value=1916928
+HeapAlloc dt=75 heapalloc_value=1925120
+HeapAlloc dt=8 heapalloc_value=1933312
+HeapAlloc dt=6 heapalloc_value=1941504
+HeapAlloc dt=7 heapalloc_value=1949696
+HeapAlloc dt=5 heapalloc_value=1957888
+HeapAlloc dt=7 heapalloc_value=1966080
+HeapAlloc dt=7 heapalloc_value=1974272
+HeapAlloc dt=6 heapalloc_value=1982464
+HeapAlloc dt=13 heapalloc_value=2007040
+HeapAlloc dt=12 heapalloc_value=2015232
+HeapAlloc dt=7 heapalloc_value=2023424
+HeapAlloc dt=6 heapalloc_value=2031616
+HeapAlloc dt=6 heapalloc_value=2039808
+HeapAlloc dt=6 heapalloc_value=2048000
+HeapAlloc dt=8 heapalloc_value=2056192
+HeapAlloc dt=6 heapalloc_value=2064384
+HeapAlloc dt=6 heapalloc_value=2072576
+HeapAlloc dt=6 heapalloc_value=2080768
+HeapAlloc dt=6 heapalloc_value=2088960
+HeapAlloc dt=6 heapalloc_value=2097152
+HeapAlloc dt=6 heapalloc_value=2105344
+HeapAlloc dt=6 heapalloc_value=2113536
+HeapAlloc dt=9 heapalloc_value=2121728
+HeapAlloc dt=5 heapalloc_value=2129920
+HeapAlloc dt=67 heapalloc_value=2138112
+HeapAlloc dt=7 heapalloc_value=2146304
+HeapAlloc dt=7 heapalloc_value=2154496
+HeapAlloc dt=5 heapalloc_value=2162688
+HeapAlloc dt=6 heapalloc_value=2170880
+HeapAlloc dt=6 heapalloc_value=2179072
+HeapAlloc dt=79 heapalloc_value=2187264
+HeapAlloc dt=8 heapalloc_value=2195456
+HeapAlloc dt=6 heapalloc_value=2203648
+HeapAlloc dt=6 heapalloc_value=2211840
+HeapAlloc dt=6 heapalloc_value=2220032
+HeapAlloc dt=6 heapalloc_value=2228224
+HeapAlloc dt=6 heapalloc_value=2236416
+HeapAlloc dt=6 heapalloc_value=2244608
+HeapAlloc dt=8 heapalloc_value=2252800
+HeapAlloc dt=6 heapalloc_value=2260992
+HeapAlloc dt=6 heapalloc_value=2269184
+HeapAlloc dt=5 heapalloc_value=2310144
+HeapAlloc dt=19 heapalloc_value=2318336
+HeapAlloc dt=6 heapalloc_value=2326528
+HeapAlloc dt=7 heapalloc_value=2334720
+HeapAlloc dt=6 heapalloc_value=2342912
+HeapAlloc dt=6 heapalloc_value=2351104
+HeapAlloc dt=43 heapalloc_value=2359296
+HeapAlloc dt=8 heapalloc_value=2367488
+HeapAlloc dt=6 heapalloc_value=2375680
+HeapAlloc dt=8 heapalloc_value=2383872
+HeapAlloc dt=6 heapalloc_value=2392064
+HeapAlloc dt=6 heapalloc_value=2400256
+HeapAlloc dt=6 heapalloc_value=2408448
+HeapAlloc dt=6 heapalloc_value=2416640
+HeapAlloc dt=6 heapalloc_value=2424832
+HeapAlloc dt=6 heapalloc_value=2433024
+HeapAlloc dt=90 heapalloc_value=2441216
+HeapAlloc dt=74 heapalloc_value=2449408
+HeapAlloc dt=7 heapalloc_value=2457600
+HeapAlloc dt=7 heapalloc_value=2465792
+HeapAlloc dt=5 heapalloc_value=2473984
+HeapAlloc dt=6 heapalloc_value=2482176
+HeapAlloc dt=6 heapalloc_value=2490368
+HeapAlloc dt=6 heapalloc_value=2498560
+HeapAlloc dt=6 heapalloc_value=2506752
+HeapAlloc dt=8 heapalloc_value=2514944
+HeapAlloc dt=6 heapalloc_value=2523136
+HeapAlloc dt=7 heapalloc_value=2531328
+HeapAlloc dt=6 heapalloc_value=2539520
+HeapAlloc dt=6 heapalloc_value=2547712
+HeapAlloc dt=6 heapalloc_value=2555904
+HeapAlloc dt=6 heapalloc_value=2564096
+HeapAlloc dt=6 heapalloc_value=2572288
+HeapAlloc dt=8 heapalloc_value=2580480
+HeapAlloc dt=6 heapalloc_value=2588672
+HeapAlloc dt=28 heapalloc_value=2596864
+HeapAlloc dt=8 heapalloc_value=2605056
+HeapAlloc dt=5 heapalloc_value=2613248
+HeapAlloc dt=6 heapalloc_value=2621440
+HeapAlloc dt=6 heapalloc_value=2629632
+HeapAlloc dt=7 heapalloc_value=2637824
+HeapAlloc dt=8 heapalloc_value=2646016
+HeapAlloc dt=6 heapalloc_value=2654208
+HeapAlloc dt=13 heapalloc_value=2686976
+HeapAlloc dt=23 heapalloc_value=2695168
+HeapAlloc dt=6 heapalloc_value=2703360
+HeapAlloc dt=75 heapalloc_value=2711552
+HeapAlloc dt=55 heapalloc_value=2719744
+HeapAlloc dt=8 heapalloc_value=2727936
+HeapAlloc dt=6 heapalloc_value=2736128
+HeapAlloc dt=6 heapalloc_value=2744320
+HeapAlloc dt=6 heapalloc_value=2752512
+HeapAlloc dt=6 heapalloc_value=2760704
+HeapAlloc dt=6 heapalloc_value=2768896
+HeapAlloc dt=9 heapalloc_value=2777088
+HeapAlloc dt=5 heapalloc_value=2785280
+HeapAlloc dt=6 heapalloc_value=2793472
+HeapAlloc dt=6 heapalloc_value=2801664
+HeapAlloc dt=6 heapalloc_value=2809856
+HeapAlloc dt=6 heapalloc_value=2818048
+HeapAlloc dt=6 heapalloc_value=2826240
+HeapAlloc dt=6 heapalloc_value=2834432
+GoBlock dt=19 reason_string=19 stack=21
+ProcStop dt=236
+ProcStart dt=17547 p=1 p_seq=2
+ProcStop dt=18
+ProcStart dt=5588 p=0 p_seq=8
+ProcStop dt=13
+ProcStart dt=16789 p=0 p_seq=9
+GoUnblock dt=17 g=1 g_seq=7 stack=0
+GoStart dt=173 g=1 g_seq=8
+HeapAlloc dt=54 heapalloc_value=3915776
+HeapAlloc dt=17 heapalloc_value=3923968
+HeapAlloc dt=6 heapalloc_value=3932160
+HeapAlloc dt=6 heapalloc_value=3940352
+HeapAlloc dt=8 heapalloc_value=3948544
+HeapAlloc dt=10 heapalloc_value=3956736
+HeapAlloc dt=7 heapalloc_value=3964928
+HeapAlloc dt=10 heapalloc_value=4038656
+GCBegin dt=207 gc_seq=1 stack=22
+GoCreate dt=117 new_g=5 new_stack=23 stack=24
+GoSyscallBegin dt=172 p_seq=10 stack=25
+ProcStop dt=2
+ProcStart dt=6567 p=0 p_seq=12
+GoSyscallEndBlocked dt=4
+GoStart dt=1 g=1 g_seq=9
+GoCreate dt=36 new_g=6 new_stack=23 stack=24
+GoSyscallBegin dt=11 p_seq=13 stack=25
+ProcStop dt=1
+ProcStart dt=815 p=0 p_seq=15
+GoSyscallEndBlocked dt=2
+GoStart dt=1 g=1 g_seq=10
+GoCreate dt=23 new_g=7 new_stack=23 stack=24
+GoSyscallBegin dt=4 p_seq=16 stack=25
+ProcStop dt=1
+ProcStart dt=814 p=1 p_seq=6
+GoSyscallEndBlocked dt=2
+GoStart dt=1 g=1 g_seq=11
+GoCreate dt=14 new_g=24 new_stack=23 stack=24
+GoSyscallBegin dt=122 p_seq=7 stack=25
+ProcStop dt=1
+ProcStart dt=519 p=2 p_seq=5
+GoSyscallEndBlocked dt=1
+GoStart dt=1 g=1 g_seq=12
+HeapAlloc dt=19 heapalloc_value=4063232
+GoCreate dt=21 new_g=34 new_stack=23 stack=24
+GoSyscallBegin dt=5 p_seq=6 stack=25
+ProcStop dt=1
+ProcStart dt=924 p=0 p_seq=19
+GoSyscallEndBlocked dt=1
+GoStart dt=1 g=1 g_seq=13
+GoCreate dt=19 new_g=8 new_stack=23 stack=24
+GoSyscallBegin dt=140 p_seq=20 stack=25
+ProcStop dt=2
+ProcStart dt=512 p=0 p_seq=22
+GoSyscallEndBlocked dt=1
+GoStart dt=1 g=1 g_seq=14
+GoCreate dt=14 new_g=9 new_stack=23 stack=24
+GoSyscallBegin dt=3 p_seq=23 stack=25
+ProcStop dt=1
+ProcStart dt=375 p=1 p_seq=12
+GoSyscallEndBlocked dt=2
+GoStart dt=1 g=1 g_seq=15
+HeapAlloc dt=36 heapalloc_value=4071424
+GoCreate dt=13 new_g=25 new_stack=23 stack=24
+GoSyscallBegin dt=115 p_seq=13 stack=25
+ProcStop dt=1
+ProcStart dt=623 p=2 p_seq=10
+GoSyscallEndBlocked dt=1
+GoStart dt=1 g=1 g_seq=16
+STWBegin dt=37 kind_string=22 stack=27
+GoStatus dt=138 g=4 m=18446744073709551615 gstatus=4
+GoUnblock dt=7 g=4 g_seq=1 stack=28
+ProcsChange dt=158 procs_value=8 stack=29
+STWEnd dt=25
+GCMarkAssistBegin dt=1078 stack=30
+GCMarkAssistEnd dt=684
+HeapAlloc dt=15 heapalloc_value=4087808
+HeapAlloc dt=21 heapalloc_value=4096000
+HeapAlloc dt=11 heapalloc_value=4104192
+HeapAlloc dt=9 heapalloc_value=4112384
+HeapAlloc dt=9 heapalloc_value=4120576
+HeapAlloc dt=736 heapalloc_value=4145152
+HeapAlloc dt=27 heapalloc_value=4153344
+HeapAlloc dt=19 heapalloc_value=4161536
+HeapAlloc dt=15 heapalloc_value=4169728
+HeapAlloc dt=19 heapalloc_value=4177920
+HeapAlloc dt=15 heapalloc_value=4186112
+HeapAlloc dt=11 heapalloc_value=4194304
+HeapAlloc dt=16 heapalloc_value=4202496
+HeapAlloc dt=16 heapalloc_value=4210688
+HeapAlloc dt=9 heapalloc_value=4218880
+HeapAlloc dt=9 heapalloc_value=4227072
+HeapAlloc dt=9 heapalloc_value=4235264
+HeapAlloc dt=9 heapalloc_value=4243456
+HeapAlloc dt=10 heapalloc_value=4251648
+HeapAlloc dt=9 heapalloc_value=4259840
+HeapAlloc dt=20 heapalloc_value=4268032
+GoStop dt=11 reason_string=16 stack=31
+GoStart dt=361 g=1 g_seq=17
+HeapAlloc dt=16 heapalloc_value=4276224
+HeapAlloc dt=10 heapalloc_value=4284416
+HeapAlloc dt=9 heapalloc_value=4292608
+HeapAlloc dt=10 heapalloc_value=4300800
+HeapAlloc dt=9 heapalloc_value=4308992
+HeapAlloc dt=10 heapalloc_value=4317184
+HeapAlloc dt=9 heapalloc_value=4325376
+HeapAlloc dt=9 heapalloc_value=4333568
+HeapAlloc dt=11 heapalloc_value=4341760
+HeapAlloc dt=9 heapalloc_value=4349952
+HeapAlloc dt=67 heapalloc_value=4358144
+HeapAlloc dt=10 heapalloc_value=4366336
+HeapAlloc dt=10 heapalloc_value=4374528
+HeapAlloc dt=9 heapalloc_value=4382720
+HeapAlloc dt=9 heapalloc_value=4390912
+HeapAlloc dt=9 heapalloc_value=4399104
+HeapAlloc dt=283 heapalloc_value=4407296
+HeapAlloc dt=15 heapalloc_value=4415488
+HeapAlloc dt=7 heapalloc_value=4423680
+HeapAlloc dt=7 heapalloc_value=4431872
+HeapAlloc dt=7 heapalloc_value=4440064
+HeapAlloc dt=7 heapalloc_value=4448256
+HeapAlloc dt=7 heapalloc_value=4456448
+HeapAlloc dt=7 heapalloc_value=4464640
+HeapAlloc dt=7 heapalloc_value=4472832
+HeapAlloc dt=7 heapalloc_value=4481024
+HeapAlloc dt=7 heapalloc_value=4489216
+HeapAlloc dt=7 heapalloc_value=4497408
+HeapAlloc dt=7 heapalloc_value=4505600
+HeapAlloc dt=6 heapalloc_value=4513792
+HeapAlloc dt=7 heapalloc_value=4521984
+HeapAlloc dt=39 heapalloc_value=4530176
+HeapAlloc dt=8 heapalloc_value=4538368
+HeapAlloc dt=8 heapalloc_value=4546560
+HeapAlloc dt=7 heapalloc_value=4554752
+HeapAlloc dt=7 heapalloc_value=4562944
+HeapAlloc dt=10 heapalloc_value=4571136
+HeapAlloc dt=9 heapalloc_value=4579328
+HeapAlloc dt=72 heapalloc_value=4587520
+HeapAlloc dt=9 heapalloc_value=4595712
+HeapAlloc dt=7 heapalloc_value=4603904
+HeapAlloc dt=7 heapalloc_value=4612096
+HeapAlloc dt=7 heapalloc_value=4620288
+HeapAlloc dt=7 heapalloc_value=4628480
+HeapAlloc dt=7 heapalloc_value=4636672
+HeapAlloc dt=7 heapalloc_value=4644864
+HeapAlloc dt=8 heapalloc_value=4653056
+HeapAlloc dt=7 heapalloc_value=4661248
+HeapAlloc dt=266 heapalloc_value=4669440
+HeapAlloc dt=9 heapalloc_value=4677632
+HeapAlloc dt=50 heapalloc_value=4685824
+HeapAlloc dt=9 heapalloc_value=4694016
+HeapAlloc dt=7 heapalloc_value=4702208
+HeapAlloc dt=8 heapalloc_value=4710400
+HeapAlloc dt=7 heapalloc_value=4718592
+HeapAlloc dt=7 heapalloc_value=4726784
+HeapAlloc dt=7 heapalloc_value=4734976
+HeapAlloc dt=7 heapalloc_value=4743168
+GCMarkAssistBegin dt=9 stack=30
+HeapAlloc dt=40 heapalloc_value=4751360
+GoBlock dt=247 reason_string=10 stack=33
+ProcStop dt=18
+ProcStart dt=5438 p=2 p_seq=11
+ProcStop dt=22
+ProcStart dt=70608 p=2 p_seq=12
+GoUnblock dt=18 g=25 g_seq=4 stack=0
+GoStart dt=190 g=25 g_seq=5
+GoLabel dt=1 label_string=2
+GoBlock dt=594 reason_string=15 stack=26
+ProcStop dt=28
+ProcStart dt=802 p=2 p_seq=13
+ProcStop dt=17
+ProcStart dt=2684 p=2 p_seq=14
+ProcStop dt=29
+ProcStart dt=382 p=2 p_seq=15
+ProcStop dt=51
+ProcStart dt=2622 p=2 p_seq=16
+ProcStop dt=22
+ProcStart dt=66146 p=2 p_seq=17
+ProcStop dt=20
+ProcStart dt=49429 p=0 p_seq=40
+GoUnblock dt=13 g=9 g_seq=7 stack=0
+GoStart dt=174 g=9 g_seq=8
+GoLabel dt=1 label_string=2
+GoBlock dt=1963 reason_string=15 stack=26
+ProcStop dt=4345
+ProcStart dt=16958 p=2 p_seq=22
+ProcStop dt=18
+ProcStart dt=723 p=0 p_seq=42
+ProcStop dt=10
+ProcStart dt=16754 p=0 p_seq=43
+GoUnblock dt=14 g=1 g_seq=49 stack=0
+GoStart dt=152 g=1 g_seq=50
+HeapAlloc dt=32 heapalloc_value=17038224
+HeapAlloc dt=24 heapalloc_value=17046416
+HeapAlloc dt=15 heapalloc_value=17054608
+HeapAlloc dt=16 heapalloc_value=17062800
+HeapAlloc dt=13 heapalloc_value=17070992
+HeapAlloc dt=14 heapalloc_value=17079184
+HeapAlloc dt=17 heapalloc_value=17087376
+HeapAlloc dt=14 heapalloc_value=17095568
+HeapAlloc dt=14 heapalloc_value=17103760
+HeapAlloc dt=13 heapalloc_value=17111952
+HeapAlloc dt=81 heapalloc_value=17120144
+HeapAlloc dt=20 heapalloc_value=17128336
+HeapAlloc dt=14 heapalloc_value=17136528
+HeapAlloc dt=14 heapalloc_value=17144720
+HeapAlloc dt=16 heapalloc_value=17152912
+HeapAlloc dt=15 heapalloc_value=17161104
+HeapAlloc dt=13 heapalloc_value=17169296
+HeapAlloc dt=13 heapalloc_value=17177488
+HeapAlloc dt=16 heapalloc_value=17185680
+HeapAlloc dt=15 heapalloc_value=17193872
+HeapAlloc dt=14 heapalloc_value=17202064
+HeapAlloc dt=13 heapalloc_value=17210256
+HeapAlloc dt=16 heapalloc_value=17218448
+HeapAlloc dt=14 heapalloc_value=17226640
+HeapAlloc dt=14 heapalloc_value=17234832
+HeapAlloc dt=16 heapalloc_value=17243024
+HeapAlloc dt=16 heapalloc_value=17251216
+HeapAlloc dt=15 heapalloc_value=17259408
+HeapAlloc dt=14 heapalloc_value=17267600
+HeapAlloc dt=13 heapalloc_value=17275792
+HeapAlloc dt=45 heapalloc_value=17283984
+HeapAlloc dt=18 heapalloc_value=17292176
+HeapAlloc dt=16 heapalloc_value=17300368
+HeapAlloc dt=16 heapalloc_value=17308560
+HeapAlloc dt=15 heapalloc_value=17316752
+HeapAlloc dt=17 heapalloc_value=17324944
+HeapAlloc dt=15 heapalloc_value=17333136
+HeapAlloc dt=14 heapalloc_value=17341328
+HeapAlloc dt=16 heapalloc_value=17349520
+HeapAlloc dt=14 heapalloc_value=17357712
+HeapAlloc dt=14 heapalloc_value=17365904
+HeapAlloc dt=12 heapalloc_value=17374096
+HeapAlloc dt=14 heapalloc_value=17382288
+HeapAlloc dt=13 heapalloc_value=17390480
+HeapAlloc dt=13 heapalloc_value=17398672
+HeapAlloc dt=13 heapalloc_value=17406864
+HeapAlloc dt=36 heapalloc_value=17873808
+HeapAlloc dt=3813 heapalloc_value=17882000
+HeapAlloc dt=47 heapalloc_value=17890192
+HeapAlloc dt=10 heapalloc_value=17898384
+HeapAlloc dt=10 heapalloc_value=17906576
+HeapAlloc dt=12 heapalloc_value=17914768
+HeapAlloc dt=21 heapalloc_value=17922960
+HeapAlloc dt=17 heapalloc_value=17931152
+HeapAlloc dt=12 heapalloc_value=17939344
+HeapAlloc dt=13 heapalloc_value=17947536
+HeapAlloc dt=24 heapalloc_value=17955728
+HeapAlloc dt=91 heapalloc_value=17963920
+HeapAlloc dt=11 heapalloc_value=17972112
+HeapAlloc dt=9 heapalloc_value=17980304
+HeapAlloc dt=11 heapalloc_value=17988496
+HeapAlloc dt=8 heapalloc_value=17996688
+HeapAlloc dt=9 heapalloc_value=18004880
+HeapAlloc dt=9 heapalloc_value=18013072
+HeapAlloc dt=10 heapalloc_value=18021264
+HeapAlloc dt=9 heapalloc_value=18029456
+HeapAlloc dt=9 heapalloc_value=18037648
+HeapAlloc dt=8 heapalloc_value=18045840
+HeapAlloc dt=11 heapalloc_value=18054032
+HeapAlloc dt=8 heapalloc_value=18062224
+HeapAlloc dt=9 heapalloc_value=18070416
+HeapAlloc dt=9 heapalloc_value=18078608
+HeapAlloc dt=8 heapalloc_value=18086800
+HeapAlloc dt=9 heapalloc_value=18094992
+HeapAlloc dt=9 heapalloc_value=18103184
+HeapAlloc dt=8 heapalloc_value=18111376
+HeapAlloc dt=11 heapalloc_value=18119568
+HeapAlloc dt=9 heapalloc_value=18127760
+HeapAlloc dt=52 heapalloc_value=18135952
+HeapAlloc dt=10 heapalloc_value=18144144
+HeapAlloc dt=12 heapalloc_value=18152336
+HeapAlloc dt=10 heapalloc_value=18160528
+HeapAlloc dt=10 heapalloc_value=18168720
+HeapAlloc dt=25 heapalloc_value=18176912
+HeapAlloc dt=37 heapalloc_value=18185104
+HeapAlloc dt=32 heapalloc_value=18193296
+HeapAlloc dt=27 heapalloc_value=18201488
+HeapAlloc dt=27 heapalloc_value=18209680
+HeapAlloc dt=29 heapalloc_value=18217872
+HeapAlloc dt=28 heapalloc_value=18226064
+HeapAlloc dt=22 heapalloc_value=18234256
+HeapAlloc dt=32 heapalloc_value=18242448
+HeapAlloc dt=30 heapalloc_value=18250640
+HeapAlloc dt=26 heapalloc_value=18258832
+HeapAlloc dt=30 heapalloc_value=18267024
+HeapAlloc dt=33 heapalloc_value=18275216
+HeapAlloc dt=27 heapalloc_value=18283408
+HeapAlloc dt=33 heapalloc_value=18291600
+HeapAlloc dt=25 heapalloc_value=18299792
+HeapAlloc dt=40 heapalloc_value=18307984
+HeapAlloc dt=23 heapalloc_value=18316176
+HeapAlloc dt=32 heapalloc_value=18324368
+HeapAlloc dt=31 heapalloc_value=18332560
+HeapAlloc dt=30 heapalloc_value=18340752
+HeapAlloc dt=25 heapalloc_value=18348944
+HeapAlloc dt=32 heapalloc_value=18357136
+HeapAlloc dt=30 heapalloc_value=18365328
+HeapAlloc dt=32 heapalloc_value=18373520
+HeapAlloc dt=34 heapalloc_value=18381712
+HeapAlloc dt=30 heapalloc_value=18389904
+HeapAlloc dt=31 heapalloc_value=18398096
+HeapAlloc dt=29 heapalloc_value=18406288
+HeapAlloc dt=29 heapalloc_value=18414480
+HeapAlloc dt=29 heapalloc_value=18422672
+HeapAlloc dt=28 heapalloc_value=18430864
+HeapAlloc dt=35 heapalloc_value=18439056
+HeapAlloc dt=31 heapalloc_value=18447248
+HeapAlloc dt=30 heapalloc_value=18455440
+HeapAlloc dt=116 heapalloc_value=18463632
+HeapAlloc dt=21 heapalloc_value=18471824
+HeapAlloc dt=13 heapalloc_value=18480016
+HeapAlloc dt=65 heapalloc_value=18488208
+HeapAlloc dt=21 heapalloc_value=18496400
+HeapAlloc dt=16 heapalloc_value=18504592
+HeapAlloc dt=14 heapalloc_value=18512784
+HeapAlloc dt=13 heapalloc_value=18520976
+GoBlock dt=19 reason_string=19 stack=21
+ProcStop dt=197
+ProcStart dt=17439 p=2 p_seq=24
+ProcStop dt=12
+ProcStart dt=2355 p=0 p_seq=46
+ProcStop dt=8
+ProcStart dt=16730 p=0 p_seq=47
+GoUnblock dt=11 g=1 g_seq=53 stack=0
+GoStart dt=144 g=1 g_seq=54
+HeapAlloc dt=26 heapalloc_value=19553168
+HeapAlloc dt=13 heapalloc_value=19561360
+HeapAlloc dt=8 heapalloc_value=19569552
+HeapAlloc dt=6 heapalloc_value=19577744
+HeapAlloc dt=7 heapalloc_value=19585936
+HeapAlloc dt=7 heapalloc_value=19594128
+HeapAlloc dt=69 heapalloc_value=19602320
+HeapAlloc dt=7 heapalloc_value=19610512
+HeapAlloc dt=7 heapalloc_value=19618704
+HeapAlloc dt=250 heapalloc_value=19626896
+HeapAlloc dt=9 heapalloc_value=19635088
+HeapAlloc dt=7 heapalloc_value=19643280
+HeapAlloc dt=7 heapalloc_value=19651472
+HeapAlloc dt=7 heapalloc_value=19659664
+HeapAlloc dt=7 heapalloc_value=19667856
+HeapAlloc dt=7 heapalloc_value=19676048
+HeapAlloc dt=7 heapalloc_value=19684240
+HeapAlloc dt=6 heapalloc_value=19692432
+HeapAlloc dt=8 heapalloc_value=19700624
+HeapAlloc dt=6 heapalloc_value=19708816
+HeapAlloc dt=7 heapalloc_value=19717008
+HeapAlloc dt=7 heapalloc_value=19725200
+HeapAlloc dt=6 heapalloc_value=19733392
+HeapAlloc dt=7 heapalloc_value=19741584
+HeapAlloc dt=7 heapalloc_value=19749776
+HeapAlloc dt=6 heapalloc_value=19757968
+HeapAlloc dt=7 heapalloc_value=19766160
+HeapAlloc dt=7 heapalloc_value=19774352
+HeapAlloc dt=6 heapalloc_value=19782544
+HeapAlloc dt=7 heapalloc_value=19790736
+HeapAlloc dt=7 heapalloc_value=19798928
+HeapAlloc dt=6 heapalloc_value=19807120
+HeapAlloc dt=48 heapalloc_value=19815312
+HeapAlloc dt=8 heapalloc_value=19823504
+HeapAlloc dt=6 heapalloc_value=19831696
+HeapAlloc dt=7 heapalloc_value=19839888
+HeapAlloc dt=6 heapalloc_value=19848080
+HeapAlloc dt=7 heapalloc_value=19856272
+HeapAlloc dt=7 heapalloc_value=19864464
+HeapAlloc dt=7 heapalloc_value=19872656
+HeapAlloc dt=6 heapalloc_value=19880848
+HeapAlloc dt=70 heapalloc_value=19889040
+HeapAlloc dt=8 heapalloc_value=19897232
+HeapAlloc dt=7 heapalloc_value=19905424
+HeapAlloc dt=8 heapalloc_value=19913616
+HeapAlloc dt=9 heapalloc_value=19921808
+HeapAlloc dt=6 heapalloc_value=19930000
+HeapAlloc dt=7 heapalloc_value=19938192
+HeapAlloc dt=6 heapalloc_value=19946384
+HeapAlloc dt=7 heapalloc_value=19954576
+HeapAlloc dt=7 heapalloc_value=19962768
+HeapAlloc dt=6 heapalloc_value=19970960
+HeapAlloc dt=7 heapalloc_value=19979152
+HeapAlloc dt=7 heapalloc_value=19987344
+HeapAlloc dt=6 heapalloc_value=19995536
+HeapAlloc dt=7 heapalloc_value=20003728
+HeapAlloc dt=6 heapalloc_value=20011920
+HeapAlloc dt=7 heapalloc_value=20020112
+HeapAlloc dt=7 heapalloc_value=20028304
+HeapAlloc dt=7 heapalloc_value=20036496
+HeapAlloc dt=7 heapalloc_value=20044688
+HeapAlloc dt=6 heapalloc_value=20052880
+HeapAlloc dt=177 heapalloc_value=20061072
+HeapAlloc dt=8 heapalloc_value=20069264
+HeapAlloc dt=7 heapalloc_value=20077456
+HeapAlloc dt=7 heapalloc_value=20085648
+HeapAlloc dt=6 heapalloc_value=20093840
+HeapAlloc dt=7 heapalloc_value=20102032
+HeapAlloc dt=7 heapalloc_value=20110224
+HeapAlloc dt=46 heapalloc_value=20118416
+HeapAlloc dt=8 heapalloc_value=20126608
+HeapAlloc dt=6 heapalloc_value=20134800
+HeapAlloc dt=7 heapalloc_value=20142992
+HeapAlloc dt=494 heapalloc_value=20151184
+HeapAlloc dt=13 heapalloc_value=20159376
+HeapAlloc dt=8 heapalloc_value=20167568
+HeapAlloc dt=6 heapalloc_value=20175760
+HeapAlloc dt=93 heapalloc_value=20183952
+HeapAlloc dt=7 heapalloc_value=20192144
+HeapAlloc dt=6 heapalloc_value=20200336
+HeapAlloc dt=7 heapalloc_value=20208528
+HeapAlloc dt=7 heapalloc_value=20216720
+HeapAlloc dt=6 heapalloc_value=20224912
+HeapAlloc dt=46 heapalloc_value=20233104
+HeapAlloc dt=8 heapalloc_value=20241296
+HeapAlloc dt=6 heapalloc_value=20249488
+HeapAlloc dt=7 heapalloc_value=20257680
+HeapAlloc dt=7 heapalloc_value=20265872
+HeapAlloc dt=6 heapalloc_value=20274064
+HeapAlloc dt=7 heapalloc_value=20282256
+HeapAlloc dt=7 heapalloc_value=20290448
+HeapAlloc dt=7 heapalloc_value=20298640
+HeapAlloc dt=6 heapalloc_value=20306832
+HeapAlloc dt=7 heapalloc_value=20315024
+HeapAlloc dt=6 heapalloc_value=20323216
+HeapAlloc dt=7 heapalloc_value=20331408
+HeapAlloc dt=6 heapalloc_value=20339600
+HeapAlloc dt=7 heapalloc_value=20347792
+HeapAlloc dt=7 heapalloc_value=20355984
+HeapAlloc dt=6 heapalloc_value=20364176
+HeapAlloc dt=7 heapalloc_value=20372368
+HeapAlloc dt=7 heapalloc_value=20380560
+HeapAlloc dt=6 heapalloc_value=20388752
+HeapAlloc dt=7 heapalloc_value=20396944
+HeapAlloc dt=7 heapalloc_value=20405136
+HeapAlloc dt=68 heapalloc_value=20413328
+HeapAlloc dt=8 heapalloc_value=20421520
+HeapAlloc dt=6 heapalloc_value=20429712
+HeapAlloc dt=7 heapalloc_value=20437904
+HeapAlloc dt=7 heapalloc_value=20446096
+HeapAlloc dt=6 heapalloc_value=20454288
+HeapAlloc dt=7 heapalloc_value=20462480
+HeapAlloc dt=7 heapalloc_value=20470672
+HeapAlloc dt=7 heapalloc_value=20478864
+HeapAlloc dt=6 heapalloc_value=20487056
+HeapAlloc dt=7 heapalloc_value=20495248
+HeapAlloc dt=7 heapalloc_value=20503440
+HeapAlloc dt=6 heapalloc_value=20511632
+HeapAlloc dt=7 heapalloc_value=20519824
+HeapAlloc dt=7 heapalloc_value=20528016
+HeapAlloc dt=6 heapalloc_value=20536208
+HeapAlloc dt=7 heapalloc_value=20544400
+HeapAlloc dt=7 heapalloc_value=20552592
+HeapAlloc dt=6 heapalloc_value=20560784
+HeapAlloc dt=7 heapalloc_value=20568976
+GoBlock dt=13 reason_string=19 stack=21
+ProcStop dt=190
+ProcStart dt=17383 p=2 p_seq=26
+ProcStop dt=13
+ProcStart dt=1688 p=0 p_seq=50
+ProcStop dt=9
+ProcStart dt=16778 p=7 p_seq=1
+GoStart dt=16 g=12 g_seq=1
+GoStop dt=300490 reason_string=16 stack=52
+GoStart dt=19 g=12 g_seq=2
+GoStop dt=316380 reason_string=16 stack=52
+GoStart dt=17 g=12 g_seq=3
+GoDestroy dt=164357
+ProcStop dt=28
+ProcStart dt=1828 p=7 p_seq=2
+ProcStop dt=17
+ProcStart dt=81856 p=5 p_seq=4
+ProcStop dt=18
+ProcStart dt=688851 p=6 p_seq=10
+ProcStop dt=18
+ProcStart dt=16754 p=6 p_seq=11
+HeapAlloc dt=31 heapalloc_value=23313224
+GoCreate dt=50 new_g=67 new_stack=64 stack=0
+GoStart dt=169 g=67 g_seq=1
+GoSyscallBegin dt=30 p_seq=12 stack=65
+GoSyscallEnd dt=257
+GoDestroy dt=6
+ProcStop dt=8
+ProcStart dt=1281 p=6 p_seq=13
+ProcStop dt=20
+ProcStart dt=3460 p=6 p_seq=15
+GoStart dt=1376 g=82 g_seq=1
+GoSyscallBegin dt=34 p_seq=16 stack=79
+GoSyscallEnd dt=172
+HeapAlloc dt=3741 heapalloc_value=23466520
+HeapAlloc dt=37 heapalloc_value=23474712
+GoSyscallBegin dt=381 p_seq=17 stack=88
+GoSyscallEnd dt=29
+GoSyscallBegin dt=9 p_seq=18 stack=89
+GoSyscallEnd dt=33
+GoSyscallBegin dt=6 p_seq=19 stack=90
+GoSyscallEnd dt=20
+GoSyscallBegin dt=5 p_seq=20 stack=91
+GoSyscallEnd dt=25
+GoBlock dt=19 reason_string=19 stack=92
+ProcStop dt=69
+ProcStart dt=17618 p=7 p_seq=26
+ProcStop dt=33
+ProcStart dt=468 p=7 p_seq=27
+GoUnblock dt=5 g=1 g_seq=66 stack=0
+GoStart dt=5 g=1 g_seq=67
+GoSyscallBegin dt=14 p_seq=28 stack=86
+GoSyscallEnd dt=70
+GoSyscallBegin dt=82 p_seq=29 stack=95
+GoSyscallEnd dt=579
+HeapAlloc dt=276 heapalloc_value=23482840
+EventBatch gen=1 m=2852340 time=420901451500 size=3466
+ProcStart dt=290 p=0 p_seq=1
+GoStart dt=264 g=19 g_seq=1
+GoBlock dt=542 reason_string=12 stack=11
+GoStart dt=20 g=20 g_seq=1
+GoBlock dt=922 reason_string=12 stack=16
+GoStart dt=19 g=22 g_seq=1
+GoDestroy dt=156281
+ProcStop dt=46
+ProcStart dt=66693 p=0 p_seq=2
+ProcStop dt=20
+ProcStart dt=89853 p=0 p_seq=3
+ProcStop dt=20
+ProcStart dt=17575 p=1 p_seq=1
+ProcStop dt=20
+ProcStart dt=2159 p=0 p_seq=6
+ProcStop dt=13
+ProcStart dt=16751 p=0 p_seq=7
+GoUnblock dt=32 g=1 g_seq=5 stack=0
+GoStart dt=182 g=1 g_seq=6
+HeapAlloc dt=62 heapalloc_value=2842624
+HeapAlloc dt=25 heapalloc_value=2850816
+HeapAlloc dt=14 heapalloc_value=2859008
+HeapAlloc dt=11 heapalloc_value=2867200
+HeapAlloc dt=8 heapalloc_value=2875392
+HeapAlloc dt=9 heapalloc_value=2883584
+HeapAlloc dt=9 heapalloc_value=2891776
+HeapAlloc dt=8 heapalloc_value=2899968
+HeapAlloc dt=11 heapalloc_value=2908160
+HeapAlloc dt=102 heapalloc_value=2916352
+HeapAlloc dt=10 heapalloc_value=2924544
+HeapAlloc dt=13 heapalloc_value=2932736
+HeapAlloc dt=7 heapalloc_value=2940928
+HeapAlloc dt=8 heapalloc_value=2949120
+HeapAlloc dt=9 heapalloc_value=2957312
+HeapAlloc dt=8 heapalloc_value=2965504
+HeapAlloc dt=90 heapalloc_value=2973696
+HeapAlloc dt=9 heapalloc_value=2981888
+HeapAlloc dt=7 heapalloc_value=2990080
+HeapAlloc dt=8 heapalloc_value=2998272
+HeapAlloc dt=7 heapalloc_value=3006464
+HeapAlloc dt=6 heapalloc_value=3014656
+HeapAlloc dt=48 heapalloc_value=3022848
+HeapAlloc dt=7 heapalloc_value=3031040
+HeapAlloc dt=9 heapalloc_value=3039232
+HeapAlloc dt=6 heapalloc_value=3047424
+HeapAlloc dt=7 heapalloc_value=3055616
+HeapAlloc dt=8 heapalloc_value=3063808
+HeapAlloc dt=7 heapalloc_value=3072000
+HeapAlloc dt=7 heapalloc_value=3080192
+HeapAlloc dt=6 heapalloc_value=3088384
+HeapAlloc dt=7 heapalloc_value=3096576
+HeapAlloc dt=8 heapalloc_value=3104768
+HeapAlloc dt=8 heapalloc_value=3112960
+HeapAlloc dt=6 heapalloc_value=3121152
+HeapAlloc dt=7 heapalloc_value=3129344
+HeapAlloc dt=6 heapalloc_value=3137536
+HeapAlloc dt=6 heapalloc_value=3145728
+HeapAlloc dt=7 heapalloc_value=3153920
+HeapAlloc dt=6 heapalloc_value=3162112
+HeapAlloc dt=9 heapalloc_value=3170304
+HeapAlloc dt=6 heapalloc_value=3178496
+HeapAlloc dt=6 heapalloc_value=3186688
+HeapAlloc dt=7 heapalloc_value=3194880
+HeapAlloc dt=6 heapalloc_value=3203072
+HeapAlloc dt=7 heapalloc_value=3211264
+HeapAlloc dt=730 heapalloc_value=3260416
+HeapAlloc dt=3100 heapalloc_value=3268608
+HeapAlloc dt=18 heapalloc_value=3276800
+HeapAlloc dt=102 heapalloc_value=3284992
+HeapAlloc dt=9 heapalloc_value=3293184
+HeapAlloc dt=7 heapalloc_value=3301376
+HeapAlloc dt=6 heapalloc_value=3309568
+HeapAlloc dt=7 heapalloc_value=3317760
+HeapAlloc dt=6 heapalloc_value=3325952
+HeapAlloc dt=6 heapalloc_value=3334144
+HeapAlloc dt=7 heapalloc_value=3342336
+HeapAlloc dt=6 heapalloc_value=3350528
+HeapAlloc dt=7 heapalloc_value=3358720
+HeapAlloc dt=6 heapalloc_value=3366912
+HeapAlloc dt=44 heapalloc_value=3375104
+HeapAlloc dt=8 heapalloc_value=3383296
+HeapAlloc dt=6 heapalloc_value=3391488
+HeapAlloc dt=7 heapalloc_value=3399680
+HeapAlloc dt=6 heapalloc_value=3407872
+HeapAlloc dt=7 heapalloc_value=3416064
+HeapAlloc dt=7 heapalloc_value=3424256
+HeapAlloc dt=6 heapalloc_value=3432448
+HeapAlloc dt=6 heapalloc_value=3440640
+HeapAlloc dt=7 heapalloc_value=3448832
+HeapAlloc dt=6 heapalloc_value=3457024
+HeapAlloc dt=7 heapalloc_value=3465216
+HeapAlloc dt=6 heapalloc_value=3473408
+HeapAlloc dt=6 heapalloc_value=3481600
+HeapAlloc dt=7 heapalloc_value=3489792
+HeapAlloc dt=73 heapalloc_value=3497984
+HeapAlloc dt=8 heapalloc_value=3506176
+HeapAlloc dt=7 heapalloc_value=3514368
+HeapAlloc dt=6 heapalloc_value=3522560
+HeapAlloc dt=6 heapalloc_value=3530752
+HeapAlloc dt=7 heapalloc_value=3538944
+HeapAlloc dt=7 heapalloc_value=3547136
+HeapAlloc dt=6 heapalloc_value=3555328
+HeapAlloc dt=7 heapalloc_value=3563520
+HeapAlloc dt=6 heapalloc_value=3571712
+HeapAlloc dt=6 heapalloc_value=3579904
+HeapAlloc dt=47 heapalloc_value=3588096
+HeapAlloc dt=7 heapalloc_value=3596288
+HeapAlloc dt=6 heapalloc_value=3604480
+HeapAlloc dt=7 heapalloc_value=3612672
+HeapAlloc dt=6 heapalloc_value=3620864
+HeapAlloc dt=7 heapalloc_value=3629056
+HeapAlloc dt=6 heapalloc_value=3637248
+HeapAlloc dt=7 heapalloc_value=3645440
+HeapAlloc dt=6 heapalloc_value=3653632
+HeapAlloc dt=6 heapalloc_value=3661824
+HeapAlloc dt=7 heapalloc_value=3670016
+HeapAlloc dt=6 heapalloc_value=3678208
+HeapAlloc dt=6 heapalloc_value=3686400
+HeapAlloc dt=7 heapalloc_value=3694592
+HeapAlloc dt=6 heapalloc_value=3702784
+HeapAlloc dt=7 heapalloc_value=3710976
+HeapAlloc dt=6 heapalloc_value=3719168
+HeapAlloc dt=6 heapalloc_value=3727360
+HeapAlloc dt=7 heapalloc_value=3735552
+HeapAlloc dt=6 heapalloc_value=3743744
+HeapAlloc dt=9 heapalloc_value=3751936
+HeapAlloc dt=72 heapalloc_value=3760128
+HeapAlloc dt=8 heapalloc_value=3768320
+HeapAlloc dt=7 heapalloc_value=3776512
+HeapAlloc dt=6 heapalloc_value=3784704
+HeapAlloc dt=7 heapalloc_value=3792896
+HeapAlloc dt=8 heapalloc_value=3801088
+HeapAlloc dt=64 heapalloc_value=3809280
+HeapAlloc dt=8 heapalloc_value=3817472
+HeapAlloc dt=6 heapalloc_value=3825664
+HeapAlloc dt=7 heapalloc_value=3833856
+HeapAlloc dt=6 heapalloc_value=3842048
+HeapAlloc dt=7 heapalloc_value=3850240
+HeapAlloc dt=6 heapalloc_value=3858432
+HeapAlloc dt=6 heapalloc_value=3866624
+HeapAlloc dt=7 heapalloc_value=3874816
+HeapAlloc dt=7 heapalloc_value=3883008
+HeapAlloc dt=6 heapalloc_value=3891200
+HeapAlloc dt=7 heapalloc_value=3899392
+HeapAlloc dt=6 heapalloc_value=3907584
+GoBlock dt=19 reason_string=19 stack=21
+ProcStop dt=232
+ProcStart dt=17560 p=1 p_seq=3
+ProcStop dt=23
+ProcStart dt=25946 p=0 p_seq=28
+ProcStop dt=14
+ProcStart dt=16839 p=0 p_seq=29
+GoUnblock dt=21 g=1 g_seq=20 stack=0
+GoStart dt=209 g=1 g_seq=21
+HeapAlloc dt=60 heapalloc_value=4452592
+HeapAlloc dt=28 heapalloc_value=4460784
+HeapAlloc dt=29 heapalloc_value=4468976
+HeapAlloc dt=17 heapalloc_value=4477168
+HeapAlloc dt=19 heapalloc_value=4485360
+HeapAlloc dt=26 heapalloc_value=4493552
+HeapAlloc dt=17 heapalloc_value=4501744
+HeapAlloc dt=21 heapalloc_value=4509936
+HeapAlloc dt=22 heapalloc_value=4518128
+HeapAlloc dt=22 heapalloc_value=4526320
+HeapAlloc dt=36 heapalloc_value=4624624
+HeapAlloc dt=174 heapalloc_value=4632816
+HeapAlloc dt=22 heapalloc_value=4641008
+HeapAlloc dt=23 heapalloc_value=4649200
+HeapAlloc dt=144 heapalloc_value=4657392
+HeapAlloc dt=18 heapalloc_value=4665584
+HeapAlloc dt=19 heapalloc_value=4673776
+HeapAlloc dt=59 heapalloc_value=4681968
+HeapAlloc dt=15 heapalloc_value=4690160
+HeapAlloc dt=10 heapalloc_value=4698352
+HeapAlloc dt=20 heapalloc_value=4706544
+HeapAlloc dt=37 heapalloc_value=4714736
+HeapAlloc dt=33 heapalloc_value=4722928
+HeapAlloc dt=32 heapalloc_value=4731120
+HeapAlloc dt=30 heapalloc_value=4739312
+HeapAlloc dt=33 heapalloc_value=4747504
+HeapAlloc dt=28 heapalloc_value=4755696
+HeapAlloc dt=10 heapalloc_value=4763888
+HeapAlloc dt=9 heapalloc_value=4772080
+HeapAlloc dt=10 heapalloc_value=4780272
+HeapAlloc dt=10 heapalloc_value=4788464
+HeapAlloc dt=12 heapalloc_value=4796656
+HeapAlloc dt=11 heapalloc_value=4804848
+HeapAlloc dt=9 heapalloc_value=4813040
+HeapAlloc dt=9 heapalloc_value=4821232
+HeapAlloc dt=9 heapalloc_value=4829424
+HeapAlloc dt=9 heapalloc_value=4837616
+HeapAlloc dt=10 heapalloc_value=4845808
+HeapAlloc dt=10 heapalloc_value=4854000
+HeapAlloc dt=105 heapalloc_value=4862192
+HeapAlloc dt=13 heapalloc_value=4870384
+HeapAlloc dt=10 heapalloc_value=4878576
+HeapAlloc dt=9 heapalloc_value=4886768
+HeapAlloc dt=59 heapalloc_value=4894960
+HeapAlloc dt=11 heapalloc_value=4903152
+HeapAlloc dt=10 heapalloc_value=4911344
+HeapAlloc dt=9 heapalloc_value=4919536
+HeapAlloc dt=11 heapalloc_value=4927728
+HeapAlloc dt=12 heapalloc_value=4935920
+HeapAlloc dt=10 heapalloc_value=4944112
+HeapAlloc dt=9 heapalloc_value=4952304
+HeapAlloc dt=10 heapalloc_value=4960496
+HeapAlloc dt=9 heapalloc_value=4968688
+HeapAlloc dt=10 heapalloc_value=4976880
+HeapAlloc dt=9 heapalloc_value=4985072
+HeapAlloc dt=12 heapalloc_value=4993264
+HeapAlloc dt=9 heapalloc_value=5001456
+HeapAlloc dt=9 heapalloc_value=5009648
+HeapAlloc dt=10 heapalloc_value=5017840
+HeapAlloc dt=9 heapalloc_value=5026032
+HeapAlloc dt=10 heapalloc_value=5034224
+HeapAlloc dt=9 heapalloc_value=5042416
+HeapAlloc dt=10 heapalloc_value=5050608
+HeapAlloc dt=11 heapalloc_value=5058800
+HeapAlloc dt=10 heapalloc_value=5066992
+HeapAlloc dt=14 heapalloc_value=5075184
+HeapAlloc dt=9 heapalloc_value=5083376
+HeapAlloc dt=10 heapalloc_value=5091568
+HeapAlloc dt=9 heapalloc_value=5099760
+HeapAlloc dt=10 heapalloc_value=5107952
+HeapAlloc dt=10 heapalloc_value=5116144
+HeapAlloc dt=21 heapalloc_value=5124336
+HeapAlloc dt=11 heapalloc_value=5132528
+HeapAlloc dt=8 heapalloc_value=5140720
+HeapAlloc dt=7 heapalloc_value=5148912
+HeapAlloc dt=8 heapalloc_value=5157104
+HeapAlloc dt=9 heapalloc_value=5165296
+HeapAlloc dt=10 heapalloc_value=5173488
+HeapAlloc dt=78 heapalloc_value=5181680
+HeapAlloc dt=11 heapalloc_value=5189872
+HeapAlloc dt=7 heapalloc_value=5198064
+HeapAlloc dt=8 heapalloc_value=5206256
+HeapAlloc dt=8 heapalloc_value=5214448
+HeapAlloc dt=7 heapalloc_value=5222640
+HeapAlloc dt=10 heapalloc_value=5230832
+HeapAlloc dt=7 heapalloc_value=5239024
+HeapAlloc dt=8 heapalloc_value=5247216
+HeapAlloc dt=7 heapalloc_value=5255408
+HeapAlloc dt=8 heapalloc_value=5263600
+HeapAlloc dt=7 heapalloc_value=5271792
+HeapAlloc dt=8 heapalloc_value=5279984
+HeapAlloc dt=8 heapalloc_value=5288176
+HeapAlloc dt=96 heapalloc_value=5296368
+HeapAlloc dt=11 heapalloc_value=5304560
+HeapAlloc dt=53 heapalloc_value=5312752
+HeapAlloc dt=9 heapalloc_value=5320944
+HeapAlloc dt=8 heapalloc_value=5329136
+HeapAlloc dt=8 heapalloc_value=5337328
+HeapAlloc dt=7 heapalloc_value=5345520
+HeapAlloc dt=8 heapalloc_value=5353712
+HeapAlloc dt=9 heapalloc_value=5361904
+HeapAlloc dt=8 heapalloc_value=5370096
+HeapAlloc dt=7 heapalloc_value=5378288
+HeapAlloc dt=8 heapalloc_value=5386480
+HeapAlloc dt=7 heapalloc_value=5394672
+HeapAlloc dt=7 heapalloc_value=5402864
+HeapAlloc dt=8 heapalloc_value=5411056
+HeapAlloc dt=8 heapalloc_value=5419248
+HeapAlloc dt=9 heapalloc_value=5427440
+HeapAlloc dt=7 heapalloc_value=5435632
+HeapAlloc dt=8 heapalloc_value=5443824
+HeapAlloc dt=7 heapalloc_value=5452016
+HeapAlloc dt=8 heapalloc_value=5460208
+HeapAlloc dt=7 heapalloc_value=5468400
+HeapAlloc dt=8 heapalloc_value=5476592
+HeapAlloc dt=7 heapalloc_value=5484784
+HeapAlloc dt=10 heapalloc_value=5492976
+HeapAlloc dt=8 heapalloc_value=5501168
+HeapAlloc dt=7 heapalloc_value=5509360
+HeapAlloc dt=8 heapalloc_value=5517552
+HeapAlloc dt=7 heapalloc_value=5525744
+HeapAlloc dt=8 heapalloc_value=5533936
+HeapAlloc dt=8 heapalloc_value=5542128
+HeapAlloc dt=8 heapalloc_value=5550320
+HeapAlloc dt=84 heapalloc_value=5558512
+HeapAlloc dt=10 heapalloc_value=5566704
+GoBlock dt=17 reason_string=19 stack=21
+ProcStop dt=237
+ProcStart dt=17614 p=1 p_seq=17
+ProcStop dt=23
+ProcStart dt=4599 p=0 p_seq=32
+ProcStop dt=14
+ProcStart dt=16769 p=0 p_seq=33
+GoUnblock dt=22 g=1 g_seq=24 stack=0
+GoStart dt=189 g=1 g_seq=25
+HeapAlloc dt=55 heapalloc_value=6729968
+HeapAlloc dt=24 heapalloc_value=6738160
+HeapAlloc dt=12 heapalloc_value=6746352
+HeapAlloc dt=9 heapalloc_value=6754544
+HeapAlloc dt=10 heapalloc_value=6762736
+HeapAlloc dt=11 heapalloc_value=6770928
+HeapAlloc dt=8 heapalloc_value=6779120
+HeapAlloc dt=12 heapalloc_value=6787312
+HeapAlloc dt=8 heapalloc_value=6795504
+HeapAlloc dt=7 heapalloc_value=6803696
+HeapAlloc dt=9 heapalloc_value=6811888
+HeapAlloc dt=6 heapalloc_value=6820080
+HeapAlloc dt=6 heapalloc_value=6828272
+HeapAlloc dt=6 heapalloc_value=6836464
+HeapAlloc dt=6 heapalloc_value=6844656
+HeapAlloc dt=6 heapalloc_value=6852848
+HeapAlloc dt=6 heapalloc_value=6861040
+HeapAlloc dt=595 heapalloc_value=6869232
+HeapAlloc dt=89 heapalloc_value=6877424
+HeapAlloc dt=8 heapalloc_value=6885616
+HeapAlloc dt=7 heapalloc_value=6893808
+HeapAlloc dt=8 heapalloc_value=6902000
+HeapAlloc dt=43 heapalloc_value=6910192
+HeapAlloc dt=7 heapalloc_value=6918384
+HeapAlloc dt=6 heapalloc_value=6926576
+HeapAlloc dt=7 heapalloc_value=6934768
+HeapAlloc dt=6 heapalloc_value=6942960
+HeapAlloc dt=6 heapalloc_value=6951152
+HeapAlloc dt=6 heapalloc_value=6959344
+HeapAlloc dt=6 heapalloc_value=6967536
+HeapAlloc dt=6 heapalloc_value=6975728
+HeapAlloc dt=5 heapalloc_value=6983920
+HeapAlloc dt=6 heapalloc_value=6992112
+HeapAlloc dt=6 heapalloc_value=7000304
+HeapAlloc dt=6 heapalloc_value=7008496
+HeapAlloc dt=6 heapalloc_value=7016688
+HeapAlloc dt=6 heapalloc_value=7024880
+HeapAlloc dt=8 heapalloc_value=7033072
+HeapAlloc dt=5 heapalloc_value=7041264
+HeapAlloc dt=6 heapalloc_value=7049456
+HeapAlloc dt=6 heapalloc_value=7057648
+HeapAlloc dt=6 heapalloc_value=7065840
+HeapAlloc dt=5 heapalloc_value=7074032
+HeapAlloc dt=6 heapalloc_value=7082224
+HeapAlloc dt=6 heapalloc_value=7090416
+HeapAlloc dt=6 heapalloc_value=7098608
+HeapAlloc dt=5 heapalloc_value=7106800
+HeapAlloc dt=43 heapalloc_value=7114992
+HeapAlloc dt=7 heapalloc_value=7123184
+HeapAlloc dt=74 heapalloc_value=7131376
+HeapAlloc dt=8 heapalloc_value=7139568
+HeapAlloc dt=6 heapalloc_value=7147760
+HeapAlloc dt=6 heapalloc_value=7155952
+HeapAlloc dt=5 heapalloc_value=7164144
+HeapAlloc dt=6 heapalloc_value=7172336
+HeapAlloc dt=6 heapalloc_value=7180528
+HeapAlloc dt=6 heapalloc_value=7188720
+HeapAlloc dt=6 heapalloc_value=7196912
+HeapAlloc dt=379 heapalloc_value=7368944
+HeapAlloc dt=4398 heapalloc_value=7377136
+HeapAlloc dt=19 heapalloc_value=7385328
+HeapAlloc dt=14 heapalloc_value=7393520
+HeapAlloc dt=16 heapalloc_value=7401712
+HeapAlloc dt=12 heapalloc_value=7409904
+HeapAlloc dt=11 heapalloc_value=7418096
+HeapAlloc dt=13 heapalloc_value=7426288
+HeapAlloc dt=12 heapalloc_value=7434480
+HeapAlloc dt=12 heapalloc_value=7442672
+HeapAlloc dt=11 heapalloc_value=7450864
+HeapAlloc dt=12 heapalloc_value=7459056
+HeapAlloc dt=13 heapalloc_value=7467248
+HeapAlloc dt=13 heapalloc_value=7475440
+HeapAlloc dt=12 heapalloc_value=7483632
+HeapAlloc dt=13 heapalloc_value=7491824
+HeapAlloc dt=12 heapalloc_value=7500016
+HeapAlloc dt=12 heapalloc_value=7508208
+HeapAlloc dt=11 heapalloc_value=7516400
+HeapAlloc dt=12 heapalloc_value=7524592
+HeapAlloc dt=14 heapalloc_value=7532784
+HeapAlloc dt=12 heapalloc_value=7540976
+HeapAlloc dt=12 heapalloc_value=7549168
+HeapAlloc dt=13 heapalloc_value=7557360
+HeapAlloc dt=96 heapalloc_value=7565552
+HeapAlloc dt=9 heapalloc_value=7573744
+HeapAlloc dt=7 heapalloc_value=7581936
+HeapAlloc dt=6 heapalloc_value=7590128
+HeapAlloc dt=6 heapalloc_value=7598320
+HeapAlloc dt=6 heapalloc_value=7606512
+HeapAlloc dt=6 heapalloc_value=7614704
+HeapAlloc dt=6 heapalloc_value=7622896
+HeapAlloc dt=7 heapalloc_value=7631088
+HeapAlloc dt=6 heapalloc_value=7639280
+HeapAlloc dt=6 heapalloc_value=7647472
+HeapAlloc dt=81 heapalloc_value=7655664
+HeapAlloc dt=8 heapalloc_value=7663856
+HeapAlloc dt=6 heapalloc_value=7672048
+HeapAlloc dt=6 heapalloc_value=7680240
+HeapAlloc dt=6 heapalloc_value=7688432
+HeapAlloc dt=6 heapalloc_value=7696624
+HeapAlloc dt=45 heapalloc_value=7704816
+HeapAlloc dt=8 heapalloc_value=7713008
+HeapAlloc dt=6 heapalloc_value=7721200
+HeapAlloc dt=6 heapalloc_value=7729392
+HeapAlloc dt=6 heapalloc_value=7737584
+HeapAlloc dt=6 heapalloc_value=7745776
+HeapAlloc dt=6 heapalloc_value=7753968
+HeapAlloc dt=6 heapalloc_value=7762160
+HeapAlloc dt=6 heapalloc_value=7770352
+HeapAlloc dt=6 heapalloc_value=7778544
+HeapAlloc dt=6 heapalloc_value=7786736
+HeapAlloc dt=6 heapalloc_value=7794928
+HeapAlloc dt=6 heapalloc_value=7803120
+HeapAlloc dt=6 heapalloc_value=7811312
+HeapAlloc dt=6 heapalloc_value=7819504
+HeapAlloc dt=6 heapalloc_value=7827696
+HeapAlloc dt=6 heapalloc_value=7835888
+HeapAlloc dt=6 heapalloc_value=7844080
+HeapAlloc dt=6 heapalloc_value=7852272
+HeapAlloc dt=6 heapalloc_value=7860464
+HeapAlloc dt=6 heapalloc_value=7868656
+HeapAlloc dt=6 heapalloc_value=7876848
+HeapAlloc dt=6 heapalloc_value=7885040
+HeapAlloc dt=7 heapalloc_value=7893232
+HeapAlloc dt=5 heapalloc_value=7901424
+HeapAlloc dt=7 heapalloc_value=7909616
+HeapAlloc dt=72 heapalloc_value=7917808
+GCBegin dt=27 gc_seq=3 stack=41
+STWBegin dt=46 kind_string=22 stack=42
+GoUnblock dt=163 g=4 g_seq=3 stack=43
+ProcsChange dt=106 procs_value=8 stack=44
+STWEnd dt=26
+GCMarkAssistBegin dt=206 stack=30
+GCMarkAssistEnd dt=1163
+GoBlock dt=20 reason_string=19 stack=21
+GoStart dt=199 g=4 g_seq=4
+GoBlock dt=21 reason_string=15 stack=32
+GoUnblock dt=111 g=8 g_seq=2 stack=0
+GoStart dt=272 g=8 g_seq=3
+GoLabel dt=3 label_string=4
+GoBlock dt=553 reason_string=15 stack=26
+GoUnblock dt=12 g=1 g_seq=26 stack=0
+GoStart dt=9 g=1 g_seq=27
+HeapAlloc dt=172 heapalloc_value=7926000
+HeapAlloc dt=24 heapalloc_value=7934192
+HeapAlloc dt=9 heapalloc_value=7942384
+HeapAlloc dt=9 heapalloc_value=7950576
+HeapAlloc dt=15 heapalloc_value=7958768
+HeapAlloc dt=11 heapalloc_value=7966960
+HeapAlloc dt=12 heapalloc_value=7975152
+HeapAlloc dt=10 heapalloc_value=7983344
+HeapAlloc dt=11 heapalloc_value=7991536
+HeapAlloc dt=8 heapalloc_value=7999728
+HeapAlloc dt=7 heapalloc_value=8007920
+HeapAlloc dt=7 heapalloc_value=8016112
+HeapAlloc dt=9 heapalloc_value=8024304
+HeapAlloc dt=8 heapalloc_value=8032496
+HeapAlloc dt=9 heapalloc_value=8040688
+HeapAlloc dt=8 heapalloc_value=8048880
+HeapAlloc dt=7 heapalloc_value=8057072
+HeapAlloc dt=7 heapalloc_value=8065264
+HeapAlloc dt=8 heapalloc_value=8073456
+HeapAlloc dt=229 heapalloc_value=8081648
+HeapAlloc dt=13 heapalloc_value=8089840
+HeapAlloc dt=7 heapalloc_value=8098032
+HeapAlloc dt=7 heapalloc_value=8106224
+HeapAlloc dt=44 heapalloc_value=8114416
+HeapAlloc dt=9 heapalloc_value=8122608
+HeapAlloc dt=7 heapalloc_value=8130800
+HeapAlloc dt=7 heapalloc_value=8138992
+HeapAlloc dt=263 heapalloc_value=8147184
+HeapAlloc dt=9 heapalloc_value=8155376
+HeapAlloc dt=8 heapalloc_value=8163568
+HeapAlloc dt=7 heapalloc_value=8171760
+HeapAlloc dt=6 heapalloc_value=8179952
+HeapAlloc dt=42 heapalloc_value=8188144
+HeapAlloc dt=7 heapalloc_value=8196336
+HeapAlloc dt=7 heapalloc_value=8204528
+HeapAlloc dt=7 heapalloc_value=8212720
+HeapAlloc dt=8 heapalloc_value=8220912
+HeapAlloc dt=7 heapalloc_value=8229104
+HeapAlloc dt=7 heapalloc_value=8237296
+HeapAlloc dt=7 heapalloc_value=8245488
+HeapAlloc dt=7 heapalloc_value=8253680
+HeapAlloc dt=7 heapalloc_value=8261872
+HeapAlloc dt=6 heapalloc_value=8270064
+HeapAlloc dt=7 heapalloc_value=8278256
+HeapAlloc dt=7 heapalloc_value=8286448
+HeapAlloc dt=7 heapalloc_value=8294640
+HeapAlloc dt=7 heapalloc_value=8302832
+HeapAlloc dt=7 heapalloc_value=8311024
+HeapAlloc dt=50 heapalloc_value=8319216
+HeapAlloc dt=11 heapalloc_value=8327408
+HeapAlloc dt=14 heapalloc_value=8335600
+HeapAlloc dt=14 heapalloc_value=8343792
+HeapAlloc dt=11 heapalloc_value=8351984
+HeapAlloc dt=11 heapalloc_value=8360176
+HeapAlloc dt=13 heapalloc_value=8368368
+HeapAlloc dt=11 heapalloc_value=8376560
+HeapAlloc dt=11 heapalloc_value=8384752
+HeapAlloc dt=12 heapalloc_value=8392944
+HeapAlloc dt=11 heapalloc_value=8401136
+HeapAlloc dt=257 heapalloc_value=8409328
+HeapAlloc dt=19 heapalloc_value=8417520
+HeapAlloc dt=17 heapalloc_value=8425712
+HeapAlloc dt=15 heapalloc_value=8433904
+HeapAlloc dt=14 heapalloc_value=8442096
+HeapAlloc dt=50 heapalloc_value=8450288
+HeapAlloc dt=14 heapalloc_value=8458480
+HeapAlloc dt=14 heapalloc_value=8466672
+HeapAlloc dt=15 heapalloc_value=8474864
+HeapAlloc dt=14 heapalloc_value=8483056
+HeapAlloc dt=12 heapalloc_value=8491248
+HeapAlloc dt=12 heapalloc_value=8499440
+HeapAlloc dt=13 heapalloc_value=8507632
+HeapAlloc dt=14 heapalloc_value=8515824
+HeapAlloc dt=12 heapalloc_value=8524016
+HeapAlloc dt=13 heapalloc_value=8532208
+HeapAlloc dt=13 heapalloc_value=8540400
+HeapAlloc dt=13 heapalloc_value=8548592
+HeapAlloc dt=16 heapalloc_value=8556784
+HeapAlloc dt=14 heapalloc_value=8564976
+HeapAlloc dt=14 heapalloc_value=8573168
+HeapAlloc dt=16 heapalloc_value=8581360
+HeapAlloc dt=14 heapalloc_value=8589552
+HeapAlloc dt=14 heapalloc_value=8597744
+HeapAlloc dt=59 heapalloc_value=8605936
+HeapAlloc dt=15 heapalloc_value=8614128
+HeapAlloc dt=12 heapalloc_value=8622320
+HeapAlloc dt=12 heapalloc_value=8630512
+HeapAlloc dt=11 heapalloc_value=8638704
+HeapAlloc dt=15 heapalloc_value=8646896
+HeapAlloc dt=12 heapalloc_value=8655088
+HeapAlloc dt=11 heapalloc_value=8663280
+HeapAlloc dt=292 heapalloc_value=8671472
+HeapAlloc dt=14 heapalloc_value=8679664
+HeapAlloc dt=12 heapalloc_value=8687856
+HeapAlloc dt=11 heapalloc_value=8696048
+HeapAlloc dt=12 heapalloc_value=8704240
+HeapAlloc dt=44 heapalloc_value=8712432
+HeapAlloc dt=14 heapalloc_value=8720624
+HeapAlloc dt=11 heapalloc_value=8728816
+HeapAlloc dt=14 heapalloc_value=8737008
+HeapAlloc dt=52 heapalloc_value=8745200
+HeapAlloc dt=13 heapalloc_value=8753392
+HeapAlloc dt=13 heapalloc_value=8761584
+HeapAlloc dt=12 heapalloc_value=8769776
+HeapAlloc dt=15 heapalloc_value=8777968
+HeapAlloc dt=12 heapalloc_value=8786160
+HeapAlloc dt=14 heapalloc_value=8794352
+HeapAlloc dt=18 heapalloc_value=8802544
+GoStop dt=25 reason_string=16 stack=46
+GoStart dt=658 g=1 g_seq=28
+HeapAlloc dt=14 heapalloc_value=8810736
+HeapAlloc dt=24 heapalloc_value=8818928
+HeapAlloc dt=12 heapalloc_value=8827120
+HeapAlloc dt=13 heapalloc_value=8835312
+HeapAlloc dt=15 heapalloc_value=8843504
+HeapAlloc dt=12 heapalloc_value=8851696
+HeapAlloc dt=16 heapalloc_value=8859888
+HeapAlloc dt=14 heapalloc_value=8868080
+HeapAlloc dt=14 heapalloc_value=8876272
+HeapAlloc dt=13 heapalloc_value=8884464
+HeapAlloc dt=12 heapalloc_value=8892656
+HeapAlloc dt=13 heapalloc_value=8900848
+HeapAlloc dt=15 heapalloc_value=8909040
+HeapAlloc dt=13 heapalloc_value=8917232
+HeapAlloc dt=15 heapalloc_value=8925424
+HeapAlloc dt=101 heapalloc_value=8933616
+GCMarkAssistBegin dt=13 stack=30
+GoBlock dt=37 reason_string=10 stack=33
+ProcStop dt=16
+ProcStart dt=1559 p=0 p_seq=34
+GoStart dt=433 g=1 g_seq=30
+GCMarkAssistEnd dt=16
+HeapAlloc dt=13 heapalloc_value=8630512
+GCSweepBegin dt=342 stack=47
+GCSweepEnd dt=22 swept_value=131072 reclaimed_value=0
+GCSweepBegin dt=19 stack=38
+GCSweepEnd dt=412 swept_value=827392 reclaimed_value=0
+HeapAlloc dt=32 heapalloc_value=8638704
+GoBlock dt=26 reason_string=19 stack=21
+ProcStop dt=31
+ProcStart dt=4598 p=0 p_seq=35
+ProcStop dt=23
+ProcStart dt=60434 p=0 p_seq=39
+GoStart dt=172 g=4 g_seq=6
+GoBlock dt=37 reason_string=15 stack=32
+ProcStop dt=17
+ProcStart dt=50232 p=2 p_seq=21
+GoUnblock dt=21 g=25 g_seq=8 stack=0
+GoStart dt=277 g=25 g_seq=9
+GoLabel dt=1 label_string=2
+STWBegin dt=10275 kind_string=23 stack=34
+GoUnblock dt=637 g=34 g_seq=4 stack=35
+HeapAlloc dt=30 heapalloc_value=16793488
+GoUnblock dt=20 g=3 g_seq=5 stack=36
+GCEnd dt=7 gc_seq=6
+HeapGoal dt=5 heapgoal_value=34005760
+ProcsChange dt=48 procs_value=8 stack=37
+STWEnd dt=40
+GoBlock dt=1283 reason_string=15 stack=26
+GoStart dt=14 g=3 g_seq=6
+GoBlock dt=10077 reason_string=14 stack=40
+ProcStop dt=21
+ProcStart dt=84537 p=2 p_seq=27
+GoStart dt=249 g=4 g_seq=10
+GoBlock dt=20 reason_string=15 stack=32
+ProcStop dt=102
+ProcStart dt=8641 p=2 p_seq=28
+GoStart dt=201 g=11 g_seq=1
+GoStop dt=305542 reason_string=16 stack=52
+GoStart dt=20 g=11 g_seq=2
+GoStop dt=316424 reason_string=16 stack=52
+GoStart dt=16 g=11 g_seq=3
+GoDestroy dt=159274
+ProcStop dt=45
+EventBatch gen=1 m=2852339 time=420901991582 size=23
+GoUnblock dt=137 g=4 g_seq=5 stack=0
+GoUnblock dt=157581 g=4 g_seq=9 stack=0
+ProcSteal dt=948232 p=6 p_seq=9 m=2852347
+EventBatch gen=1 m=2852338 time=420901450373 size=416
+ProcStatus dt=115 p=1 pstatus=1
+GoStatus dt=4 g=1 m=2852338 gstatus=2
+ProcsChange dt=217 procs_value=8 stack=1
+STWBegin dt=68 kind_string=21 stack=2
+HeapGoal dt=2 heapgoal_value=4194304
+ProcStatus dt=1 p=0 pstatus=2
+ProcStatus dt=4 p=2 pstatus=2
+ProcStatus dt=3 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=2 p=7 pstatus=2
+ProcsChange dt=65 procs_value=8 stack=3
+STWEnd dt=23
+HeapAlloc dt=190 heapalloc_value=1638400
+GoCreate dt=157 new_g=19 new_stack=4 stack=5
+GoCreate dt=565 new_g=20 new_stack=6 stack=7
+HeapAlloc dt=31 heapalloc_value=1646592
+GoCreate dt=523 new_g=21 new_stack=8 stack=9
+GoCreate dt=702 new_g=22 new_stack=10 stack=12
+GoCreate dt=377 new_g=23 new_stack=13 stack=14
+GoBlock dt=18 reason_string=10 stack=15
+GoStart dt=12 g=23 g_seq=1
+GoStop dt=222604 reason_string=16 stack=19
+GoStart dt=399 g=23 g_seq=2
+GoUnblock dt=89532 g=1 g_seq=1 stack=20
+GoDestroy dt=165
+GoStart dt=14 g=1 g_seq=2
+GoBlock dt=21 reason_string=19 stack=21
+ProcStop dt=257
+ProcStart dt=60623 p=1 p_seq=4
+GoStart dt=5704 g=5 g_seq=1
+HeapAlloc dt=34 heapalloc_value=4046848
+GoBlock dt=461 reason_string=15 stack=26
+ProcStop dt=25
+ProcStart dt=294 p=0 p_seq=14
+GoStart dt=9 g=6 g_seq=1
+GoBlock dt=506 reason_string=15 stack=26
+ProcStop dt=8
+ProcStart dt=230 p=0 p_seq=17
+ProcStop dt=23
+ProcStart dt=1406 p=0 p_seq=18
+GoStart dt=339 g=34 g_seq=1
+GoBlock dt=291 reason_string=15 stack=26
+ProcStop dt=13
+ProcStart dt=465 p=1 p_seq=10
+GoStart dt=173 g=8 g_seq=1
+GoBlock dt=120 reason_string=15 stack=26
+ProcStop dt=12
+ProcStart dt=353 p=0 p_seq=24
+ProcStop dt=17
+ProcStart dt=968 p=0 p_seq=25
+ProcStop dt=6
+ProcStart dt=554 p=0 p_seq=26
+GoUnblock dt=16 g=25 g_seq=2 stack=0
+GoStart dt=334 g=25 g_seq=3
+GoLabel dt=1 label_string=2
+GoBlock dt=2066 reason_string=15 stack=26
+ProcStop dt=24
+ProcStart dt=202889 p=4 p_seq=3
+GoUnblock dt=53 g=34 g_seq=2 stack=0
+HeapAlloc dt=50 heapalloc_value=16498416
+HeapAlloc dt=32 heapalloc_value=16501200
+HeapAlloc dt=4276 heapalloc_value=16697040
+GoStart dt=1376 g=34 g_seq=3
+GoLabel dt=2 label_string=4
+HeapAlloc dt=69 heapalloc_value=16713136
+GoBlock dt=35 reason_string=10 stack=48
+ProcStop dt=50
+ProcStart dt=111183 p=5 p_seq=3
+HeapAlloc dt=56 heapalloc_value=23234784
+HeapAlloc dt=25 heapalloc_value=23242144
+HeapAlloc dt=343 heapalloc_value=23249312
+GoStart dt=1532 g=16 g_seq=1
+GoStop dt=302128 reason_string=16 stack=52
+GoStart dt=13 g=16 g_seq=2
+GoStop dt=316412 reason_string=16 stack=52
+GoStart dt=10 g=16 g_seq=3
+GoDestroy dt=162712
+ProcStop dt=30
+ProcStart dt=798510 p=5 p_seq=5
+ProcStop dt=29
+ProcStart dt=4349 p=6 p_seq=21
+ProcStop dt=41
+ProcStart dt=16784 p=6 p_seq=22
+GoUnblock dt=14 g=82 g_seq=2 stack=0
+GoStart dt=161 g=82 g_seq=3
+GoSyscallBegin dt=27 p_seq=23 stack=93
+GoSyscallEnd dt=663
+GoSyscallBegin dt=102 p_seq=24 stack=94
+GoSyscallEnd dt=258
+GoDestroy dt=9
+ProcStop dt=24
+EventBatch gen=1 m=18446744073709551615 time=420903766597 size=28
+GoStatus dt=69 g=2 m=18446744073709551615 gstatus=4
+GoStatus dt=2 g=18 m=18446744073709551615 gstatus=4
+EventBatch gen=1 m=18446744073709551615 time=420903767161 size=4524
+Stacks
+Stack id=20 nframes=3
+       pc=4700772 func=24 file=25 line=81
+       pc=5073062 func=26 file=25 line=87
+       pc=5072984 func=27 file=28 line=105
+Stack id=71 nframes=21
+       pc=4746903 func=29 file=30 line=736
+       pc=4807597 func=31 file=32 line=181
+       pc=4807573 func=33 file=34 line=736
+       pc=4807216 func=35 file=34 line=160
+       pc=4813553 func=36 file=37 line=29
+       pc=4813545 func=38 file=39 line=118
+       pc=4735439 func=40 file=41 line=335
+       pc=5034447 func=42 file=41 line=354
+       pc=5034407 func=43 file=44 line=55
+       pc=5039623 func=45 file=46 line=40
+       pc=5060942 func=47 file=48 line=373
+       pc=4696033 func=49 file=50 line=74
+       pc=5026795 func=51 file=50 line=65
+       pc=5026766 func=52 file=48 line=373
+       pc=5040478 func=53 file=54 line=57
+       pc=5014167 func=55 file=56 line=154
+       pc=5051652 func=57 file=58 line=182
+       pc=4960356 func=59 file=58 line=172
+       pc=4960318 func=60 file=61 line=734
+       pc=4961094 func=62 file=61 line=808
+       pc=5070695 func=63 file=28 line=53
+Stack id=21 nframes=3
+       pc=4633684 func=64 file=65 line=195
+       pc=5073512 func=66 file=28 line=125
+       pc=5070323 func=63 file=28 line=32
+Stack id=38 nframes=9
+       pc=4578453 func=67 file=68 line=352
+       pc=4353540 func=69 file=70 line=521
+       pc=4290908 func=71 file=72 line=147
+       pc=4288626 func=73 file=74 line=182
+       pc=4252996 func=75 file=76 line=948
+       pc=4254486 func=77 file=76 line=1149
+       pc=4522824 func=78 file=79 line=103
+       pc=5073532 func=66 file=28 line=127
+       pc=5070323 func=63 file=28 line=32
+Stack id=34 nframes=1
+       pc=4314212 func=80 file=81 line=1446
+Stack id=13 nframes=1
+       pc=5072896 func=27 file=28 line=102
+Stack id=48 nframes=2
+       pc=4307927 func=82 file=81 line=807
+       pc=4314212 func=80 file=81 line=1446
+Stack id=65 nframes=7
+       pc=4747354 func=83 file=30 line=964
+       pc=4808839 func=84 file=32 line=209
+       pc=4808831 func=33 file=34 line=736
+       pc=4808384 func=85 file=34 line=380
+       pc=4813744 func=86 file=37 line=46
+       pc=4813736 func=87 file=39 line=183
+       pc=5072644 func=88 file=28 line=89
+Stack id=63 nframes=3
+       pc=4746903 func=29 file=30 line=736
+       pc=5072295 func=31 file=32 line=181
+       pc=5072241 func=89 file=28 line=90
+Stack id=85 nframes=15
+       pc=4750130 func=90 file=30 line=1488
+       pc=4811799 func=91 file=32 line=462
+       pc=4811777 func=92 file=93 line=17
+       pc=5052502 func=94 file=95 line=21
+       pc=5048264 func=96 file=97 line=245
+       pc=5050832 func=98 file=58 line=114
+       pc=5049860 func=99 file=58 line=68
+       pc=5049861 func=100 file=58 line=64
+       pc=4958364 func=101 file=61 line=651
+       pc=4956653 func=102 file=61 line=616
+       pc=4954291 func=103 file=61 line=517
+       pc=4952889 func=104 file=61 line=508
+       pc=4951126 func=105 file=61 line=434
+       pc=4951127 func=106 file=61 line=401
+       pc=5070980 func=63 file=28 line=68
+Stack id=1 nframes=4
+       pc=4576875 func=107 file=68 line=255
+       pc=4561423 func=108 file=109 line=237
+       pc=5069285 func=110 file=111 line=125
+       pc=5070075 func=63 file=28 line=20
+Stack id=7 nframes=4
+       pc=4567652 func=112 file=109 line=868
+       pc=4561732 func=108 file=109 line=258
+       pc=5069285 func=110 file=111 line=125
+       pc=5070075 func=63 file=28 line=20
+Stack id=88 nframes=8
+       pc=4750130 func=90 file=30 line=1488
+       pc=4811799 func=91 file=32 line=462
+       pc=4811777 func=92 file=93 line=17
+       pc=5052074 func=113 file=114 line=15
+       pc=5048202 func=96 file=97 line=239
+       pc=5051452 func=115 file=58 line=156
+       pc=5048431 func=116 file=97 line=315
+       pc=5071227 func=117 file=28 line=59
+Stack id=16 nframes=3
+       pc=4225233 func=118 file=119 line=442
+       pc=4568106 func=120 file=109 line=928
+       pc=4567719 func=121 file=109 line=871
+Stack id=95 nframes=8
+       pc=4746468 func=122 file=30 line=335
+       pc=4806160 func=123 file=124 line=24
+       pc=4806130 func=125 file=34 line=81
+       pc=4803890 func=126 file=127 line=213
+       pc=4806308 func=128 file=34 line=104
+       pc=4988529 func=129 file=130 line=37
+       pc=5026133 func=131 file=48 line=203
+       pc=5071131 func=63 file=28 line=74
+Stack id=94 nframes=8
+       pc=4746468 func=122 file=30 line=335
+       pc=4806160 func=123 file=124 line=24
+       pc=4806130 func=125 file=34 line=81
+       pc=4803890 func=126 file=127 line=213
+       pc=4806308 func=128 file=34 line=104
+       pc=4988529 func=129 file=130 line=37
+       pc=5026133 func=131 file=48 line=203
+       pc=5071317 func=117 file=28 line=66
+Stack id=43 nframes=6
+       pc=4637735 func=132 file=133 line=474
+       pc=4307012 func=134 file=81 line=684
+       pc=4255286 func=77 file=76 line=1292
+       pc=4522824 func=78 file=79 line=103
+       pc=5073532 func=66 file=28 line=127
+       pc=5070323 func=63 file=28 line=32
+Stack id=26 nframes=2
+       pc=4433005 func=135 file=136 line=402
+       pc=4313604 func=80 file=81 line=1310
+Stack id=66 nframes=2
+       pc=4221878 func=137 file=119 line=145
+       pc=5072533 func=89 file=28 line=94
+Stack id=55 nframes=1
+       pc=5070565 func=63 file=28 line=47
+Stack id=42 nframes=4
+       pc=4255286 func=77 file=76 line=1292
+       pc=4522824 func=78 file=79 line=103
+       pc=5073532 func=66 file=28 line=127
+       pc=5070323 func=63 file=28 line=32
+Stack id=14 nframes=1
+       pc=5070300 func=63 file=28 line=28
+Stack id=56 nframes=2
+       pc=4225233 func=118 file=119 line=442
+       pc=5070586 func=63 file=28 line=48
+Stack id=24 nframes=6
+       pc=4313307 func=138 file=81 line=1234
+       pc=4306780 func=134 file=81 line=663
+       pc=4255286 func=77 file=76 line=1292
+       pc=4524282 func=139 file=79 line=246
+       pc=5073584 func=66 file=28 line=127
+       pc=5070323 func=63 file=28 line=32
+Stack id=45 nframes=1
+       pc=0 func=0 file=0 line=0
+Stack id=44 nframes=5
+       pc=4307322 func=134 file=81 line=746
+       pc=4255286 func=77 file=76 line=1292
+       pc=4522824 func=78 file=79 line=103
+       pc=5073532 func=66 file=28 line=127
+       pc=5070323 func=63 file=28 line=32
+Stack id=6 nframes=1
+       pc=4567680 func=121 file=109 line=868
+Stack id=11 nframes=3
+       pc=4225233 func=118 file=119 line=442
+       pc=4568106 func=120 file=109 line=928
+       pc=4570874 func=140 file=141 line=54
+Stack id=4 nframes=1
+       pc=4570816 func=140 file=141 line=42
+Stack id=22 nframes=4
+       pc=4255286 func=77 file=76 line=1292
+       pc=4524282 func=139 file=79 line=246
+       pc=5073584 func=66 file=28 line=127
+       pc=5070323 func=63 file=28 line=32
+Stack id=83 nframes=15
+       pc=4750130 func=90 file=30 line=1488
+       pc=4811799 func=91 file=32 line=462
+       pc=4811777 func=92 file=93 line=17
+       pc=5047242 func=142 file=143 line=88
+       pc=5048249 func=96 file=97 line=244
+       pc=5050832 func=98 file=58 line=114
+       pc=5049860 func=99 file=58 line=68
+       pc=5049861 func=100 file=58 line=64
+       pc=4958364 func=101 file=61 line=651
+       pc=4956653 func=102 file=61 line=616
+       pc=4954291 func=103 file=61 line=517
+       pc=4952889 func=104 file=61 line=508
+       pc=4951126 func=105 file=61 line=434
+       pc=4951127 func=106 file=61 line=401
+       pc=5070980 func=63 file=28 line=68
+Stack id=37 nframes=3
+       pc=4310566 func=144 file=81 line=1087
+       pc=4308676 func=82 file=81 line=927
+       pc=4314212 func=80 file=81 line=1446
+Stack id=9 nframes=2
+       pc=5069359 func=110 file=111 line=128
+       pc=5070075 func=63 file=28 line=20
+Stack id=35 nframes=2
+       pc=4308599 func=82 file=81 line=915
+       pc=4314212 func=80 file=81 line=1446
+Stack id=72 nframes=20
+       pc=4746468 func=122 file=30 line=335
+       pc=4806160 func=123 file=124 line=24
+       pc=4806130 func=125 file=34 line=81
+       pc=4803890 func=126 file=127 line=213
+       pc=4806308 func=128 file=34 line=104
+       pc=4816631 func=145 file=146 line=315
+       pc=5040044 func=147 file=37 line=23
+       pc=5040027 func=148 file=44 line=23
+       pc=5039886 func=45 file=46 line=53
+       pc=5060942 func=47 file=48 line=373
+       pc=4696033 func=49 file=50 line=74
+       pc=5026795 func=51 file=50 line=65
+       pc=5026766 func=52 file=48 line=373
+       pc=5040478 func=53 file=54 line=57
+       pc=5014167 func=55 file=56 line=154
+       pc=5051652 func=57 file=58 line=182
+       pc=4960356 func=59 file=58 line=172
+       pc=4960318 func=60 file=61 line=734
+       pc=4961094 func=62 file=61 line=808
+       pc=5070695 func=63 file=28 line=53
+Stack id=3 nframes=4
+       pc=4442379 func=149 file=136 line=1382
+       pc=4561715 func=108 file=109 line=255
+       pc=5069285 func=110 file=111 line=125
+       pc=5070075 func=63 file=28 line=20
+Stack id=19 nframes=1
+       pc=5072969 func=27 file=28 line=104
+Stack id=61 nframes=5
+       pc=4746660 func=150 file=30 line=432
+       pc=4737158 func=151 file=152 line=106
+       pc=4806697 func=153 file=34 line=129
+       pc=5072228 func=154 file=146 line=90
+       pc=5072241 func=89 file=28 line=90
+Stack id=79 nframes=8
+       pc=4748798 func=155 file=30 line=1421
+       pc=4743029 func=156 file=157 line=684
+       pc=4810951 func=158 file=159 line=17
+       pc=4809725 func=160 file=34 line=602
+       pc=4992776 func=161 file=162 line=172
+       pc=5051421 func=115 file=58 line=152
+       pc=5048431 func=116 file=97 line=315
+       pc=5071227 func=117 file=28 line=59
+Stack id=91 nframes=8
+       pc=4750130 func=90 file=30 line=1488
+       pc=4811799 func=91 file=32 line=462
+       pc=4811777 func=92 file=93 line=17
+       pc=5052502 func=94 file=95 line=21
+       pc=5048264 func=96 file=97 line=245
+       pc=5051452 func=115 file=58 line=156
+       pc=5048431 func=116 file=97 line=315
+       pc=5071227 func=117 file=28 line=59
+Stack id=62 nframes=5
+       pc=4746660 func=150 file=30 line=432
+       pc=4737232 func=151 file=152 line=118
+       pc=4806697 func=153 file=34 line=129
+       pc=5072228 func=154 file=146 line=90
+       pc=5072241 func=89 file=28 line=90
+Stack id=75 nframes=9
+       pc=4748164 func=163 file=30 line=1213
+       pc=5044432 func=164 file=54 line=170
+       pc=5040531 func=53 file=54 line=57
+       pc=5014167 func=55 file=56 line=154
+       pc=5051652 func=57 file=58 line=182
+       pc=4960356 func=59 file=58 line=172
+       pc=4960318 func=60 file=61 line=734
+       pc=4961094 func=62 file=61 line=808
+       pc=5070695 func=63 file=28 line=53
+Stack id=73 nframes=11
+       pc=4750130 func=90 file=30 line=1488
+       pc=5046866 func=91 file=32 line=462
+       pc=5046876 func=165 file=166 line=28
+       pc=5043829 func=164 file=54 line=152
+       pc=5040531 func=53 file=54 line=57
+       pc=5014167 func=55 file=56 line=154
+       pc=5051652 func=57 file=58 line=182
+       pc=4960356 func=59 file=58 line=172
+       pc=4960318 func=60 file=61 line=734
+       pc=4961094 func=62 file=61 line=808
+       pc=5070695 func=63 file=28 line=53
+Stack id=87 nframes=4
+       pc=4807527 func=35 file=34 line=164
+       pc=4988612 func=167 file=130 line=55
+       pc=5025316 func=168 file=48 line=179
+       pc=5071115 func=63 file=28 line=73
+Stack id=84 nframes=15
+       pc=4750130 func=90 file=30 line=1488
+       pc=4811799 func=91 file=32 line=462
+       pc=4811777 func=92 file=93 line=17
+       pc=5052347 func=94 file=95 line=18
+       pc=5048264 func=96 file=97 line=245
+       pc=5050832 func=98 file=58 line=114
+       pc=5049860 func=99 file=58 line=68
+       pc=5049861 func=100 file=58 line=64
+       pc=4958364 func=101 file=61 line=651
+       pc=4956653 func=102 file=61 line=616
+       pc=4954291 func=103 file=61 line=517
+       pc=4952889 func=104 file=61 line=508
+       pc=4951126 func=105 file=61 line=434
+       pc=4951127 func=106 file=61 line=401
+       pc=5070980 func=63 file=28 line=68
+Stack id=92 nframes=2
+       pc=4633684 func=64 file=65 line=195
+       pc=5071262 func=117 file=28 line=63
+Stack id=40 nframes=2
+       pc=4352030 func=169 file=136 line=408
+       pc=4351996 func=170 file=70 line=317
+Stack id=89 nframes=8
+       pc=4750130 func=90 file=30 line=1488
+       pc=4811799 func=91 file=32 line=462
+       pc=4811777 func=92 file=93 line=17
+       pc=5047242 func=142 file=143 line=88
+       pc=5048249 func=96 file=97 line=244
+       pc=5051452 func=115 file=58 line=156
+       pc=5048431 func=116 file=97 line=315
+       pc=5071227 func=117 file=28 line=59
+Stack id=53 nframes=3
+       pc=4700772 func=24 file=25 line=81
+       pc=5071718 func=26 file=25 line=87
+       pc=5071644 func=171 file=28 line=41
+Stack id=81 nframes=16
+       pc=4749883 func=172 file=30 line=1478
+       pc=4744812 func=173 file=32 line=313
+       pc=4991029 func=174 file=162 line=149
+       pc=5041979 func=175 file=54 line=124
+       pc=5040762 func=53 file=54 line=70
+       pc=5014167 func=55 file=56 line=154
+       pc=5050219 func=98 file=58 line=78
+       pc=5049860 func=99 file=58 line=68
+       pc=5049861 func=100 file=58 line=64
+       pc=4958364 func=101 file=61 line=651
+       pc=4956653 func=102 file=61 line=616
+       pc=4954291 func=103 file=61 line=517
+       pc=4952889 func=104 file=61 line=508
+       pc=4951126 func=105 file=61 line=434
+       pc=4951127 func=106 file=61 line=401
+       pc=5070980 func=63 file=28 line=68
+Stack id=23 nframes=1
+       pc=4313376 func=80 file=81 line=1276
+Stack id=52 nframes=1
+       pc=5071629 func=171 file=28 line=40
+Stack id=28 nframes=6
+       pc=4637735 func=132 file=133 line=474
+       pc=4307012 func=134 file=81 line=684
+       pc=4255286 func=77 file=76 line=1292
+       pc=4524282 func=139 file=79 line=246
+       pc=5073584 func=66 file=28 line=127
+       pc=5070323 func=63 file=28 line=32
+Stack id=12 nframes=1
+       pc=5070234 func=63 file=28 line=27
+Stack id=76 nframes=1
+       pc=5071200 func=117 file=28 line=58
+Stack id=60 nframes=5
+       pc=4746660 func=150 file=30 line=432
+       pc=4737232 func=151 file=152 line=118
+       pc=4815748 func=176 file=146 line=218
+       pc=4817144 func=177 file=178 line=21
+       pc=5072014 func=89 file=28 line=82
+Stack id=64 nframes=1
+       pc=5072608 func=88 file=28 line=89
+Stack id=47 nframes=11
+       pc=4578453 func=67 file=68 line=352
+       pc=4353540 func=69 file=70 line=521
+       pc=4352604 func=179 file=70 line=389
+       pc=4358543 func=180 file=70 line=926
+       pc=4290148 func=71 file=72 line=84
+       pc=4288626 func=73 file=74 line=182
+       pc=4252996 func=75 file=76 line=948
+       pc=4254486 func=77 file=76 line=1149
+       pc=4522824 func=78 file=79 line=103
+       pc=5073532 func=66 file=28 line=127
+       pc=5070323 func=63 file=28 line=32
+Stack id=68 nframes=19
+       pc=4745679 func=181 file=30 line=98
+       pc=4814954 func=182 file=157 line=280
+       pc=4814931 func=183 file=184 line=15
+       pc=4816145 func=185 file=146 line=272
+       pc=4814141 func=186 file=39 line=334
+       pc=5034884 func=187 file=39 line=314
+       pc=5034871 func=188 file=44 line=76
+       pc=5039575 func=45 file=46 line=35
+       pc=5060942 func=47 file=48 line=373
+       pc=4696033 func=49 file=50 line=74
+       pc=5026795 func=51 file=50 line=65
+       pc=5026766 func=52 file=48 line=373
+       pc=5040478 func=53 file=54 line=57
+       pc=5014167 func=55 file=56 line=154
+       pc=5051652 func=57 file=58 line=182
+       pc=4960356 func=59 file=58 line=172
+       pc=4960318 func=60 file=61 line=734
+       pc=4961094 func=62 file=61 line=808
+       pc=5070695 func=63 file=28 line=53
+Stack id=77 nframes=1
+       pc=5070924 func=63 file=28 line=58
+Stack id=78 nframes=16
+       pc=4749256 func=189 file=30 line=1442
+       pc=4744549 func=190 file=32 line=298
+       pc=4989295 func=174 file=162 line=59
+       pc=5041979 func=175 file=54 line=124
+       pc=5040762 func=53 file=54 line=70
+       pc=5014167 func=55 file=56 line=154
+       pc=5050219 func=98 file=58 line=78
+       pc=5049860 func=99 file=58 line=68
+       pc=5049861 func=100 file=58 line=64
+       pc=4958364 func=101 file=61 line=651
+       pc=4956653 func=102 file=61 line=616
+       pc=4954291 func=103 file=61 line=517
+       pc=4952889 func=104 file=61 line=508
+       pc=4951126 func=105 file=61 line=434
+       pc=4951127 func=106 file=61 line=401
+       pc=5070980 func=63 file=28 line=68
+Stack id=54 nframes=1
+       pc=5071968 func=89 file=28 line=81
+Stack id=32 nframes=2
+       pc=4342189 func=191 file=192 line=425
+       pc=4343672 func=193 file=192 line=658
+Stack id=57 nframes=5
+       pc=4746660 func=150 file=30 line=432
+       pc=4737158 func=151 file=152 line=106
+       pc=4815748 func=176 file=146 line=218
+       pc=4817109 func=177 file=178 line=21
+       pc=5072014 func=89 file=28 line=82
+Stack id=74 nframes=10
+       pc=4749032 func=194 file=30 line=1432
+       pc=4744421 func=195 file=32 line=290
+       pc=5044292 func=164 file=54 line=167
+       pc=5040531 func=53 file=54 line=57
+       pc=5014167 func=55 file=56 line=154
+       pc=5051652 func=57 file=58 line=182
+       pc=4960356 func=59 file=58 line=172
+       pc=4960318 func=60 file=61 line=734
+       pc=4961094 func=62 file=61 line=808
+       pc=5070695 func=63 file=28 line=53
+Stack id=18 nframes=1
+       pc=5069604 func=196 file=111 line=130
+Stack id=5 nframes=4
+       pc=4570709 func=197 file=141 line=42
+       pc=4561720 func=108 file=109 line=257
+       pc=5069285 func=110 file=111 line=125
+       pc=5070075 func=63 file=28 line=20
+Stack id=90 nframes=8
+       pc=4750130 func=90 file=30 line=1488
+       pc=4811799 func=91 file=32 line=462
+       pc=4811777 func=92 file=93 line=17
+       pc=5052347 func=94 file=95 line=18
+       pc=5048264 func=96 file=97 line=245
+       pc=5051452 func=115 file=58 line=156
+       pc=5048431 func=116 file=97 line=315
+       pc=5071227 func=117 file=28 line=59
+Stack id=33 nframes=7
+       pc=4307927 func=82 file=81 line=807
+       pc=4324210 func=198 file=199 line=564
+       pc=4255603 func=200 file=76 line=1337
+       pc=4253576 func=77 file=76 line=1025
+       pc=4522824 func=78 file=79 line=103
+       pc=5073532 func=66 file=28 line=127
+       pc=5070323 func=63 file=28 line=32
+Stack id=70 nframes=19
+       pc=4746660 func=150 file=30 line=432
+       pc=4737232 func=151 file=152 line=118
+       pc=4815748 func=176 file=146 line=218
+       pc=4816367 func=185 file=146 line=301
+       pc=4814141 func=186 file=39 line=334
+       pc=5034884 func=187 file=39 line=314
+       pc=5034871 func=188 file=44 line=76
+       pc=5039575 func=45 file=46 line=35
+       pc=5060942 func=47 file=48 line=373
+       pc=4696033 func=49 file=50 line=74
+       pc=5026795 func=51 file=50 line=65
+       pc=5026766 func=52 file=48 line=373
+       pc=5040478 func=53 file=54 line=57
+       pc=5014167 func=55 file=56 line=154
+       pc=5051652 func=57 file=58 line=182
+       pc=4960356 func=59 file=58 line=172
+       pc=4960318 func=60 file=61 line=734
+       pc=4961094 func=62 file=61 line=808
+       pc=5070695 func=63 file=28 line=53
+Stack id=8 nframes=1
+       pc=5069536 func=196 file=111 line=128
+Stack id=15 nframes=2
+       pc=4701031 func=201 file=25 line=116
+       pc=5070313 func=63 file=28 line=29
+Stack id=86 nframes=7
+       pc=4746903 func=29 file=30 line=736
+       pc=4807597 func=31 file=32 line=181
+       pc=4807573 func=33 file=34 line=736
+       pc=4807216 func=35 file=34 line=160
+       pc=4988612 func=167 file=130 line=55
+       pc=5025316 func=168 file=48 line=179
+       pc=5071115 func=63 file=28 line=73
+Stack id=67 nframes=1
+       pc=0 func=0 file=0 line=0
+Stack id=80 nframes=15
+       pc=4990958 func=202 file=34 line=683
+       pc=4990987 func=174 file=162 line=141
+       pc=5041979 func=175 file=54 line=124
+       pc=5040762 func=53 file=54 line=70
+       pc=5014167 func=55 file=56 line=154
+       pc=5050219 func=98 file=58 line=78
+       pc=5049860 func=99 file=58 line=68
+       pc=5049861 func=100 file=58 line=64
+       pc=4958364 func=101 file=61 line=651
+       pc=4956653 func=102 file=61 line=616
+       pc=4954291 func=103 file=61 line=517
+       pc=4952889 func=104 file=61 line=508
+       pc=4951126 func=105 file=61 line=434
+       pc=4951127 func=106 file=61 line=401
+       pc=5070980 func=63 file=28 line=68
+Stack id=93 nframes=7
+       pc=4747354 func=83 file=30 line=964
+       pc=4808839 func=84 file=32 line=209
+       pc=4808831 func=33 file=34 line=736
+       pc=4808384 func=85 file=34 line=380
+       pc=4988868 func=203 file=130 line=96
+       pc=5025764 func=204 file=48 line=191
+       pc=5071301 func=117 file=28 line=65
+Stack id=46 nframes=1
+       pc=5070323 func=63 file=28 line=32
+Stack id=25 nframes=5
+       pc=4306780 func=134 file=81 line=663
+       pc=4255286 func=77 file=76 line=1292
+       pc=4524282 func=139 file=79 line=246
+       pc=5073584 func=66 file=28 line=127
+       pc=5070323 func=63 file=28 line=32
+Stack id=58 nframes=5
+       pc=4746660 func=150 file=30 line=432
+       pc=4737232 func=151 file=152 line=118
+       pc=4815748 func=176 file=146 line=218
+       pc=4817109 func=177 file=178 line=21
+       pc=5072014 func=89 file=28 line=82
+Stack id=39 nframes=9
+       pc=4365530 func=205 file=206 line=958
+       pc=4291537 func=207 file=72 line=254
+       pc=4291127 func=71 file=72 line=170
+       pc=4288626 func=73 file=74 line=182
+       pc=4252996 func=75 file=76 line=948
+       pc=4254486 func=77 file=76 line=1149
+       pc=4522824 func=78 file=79 line=103
+       pc=5073532 func=66 file=28 line=127
+       pc=5070323 func=63 file=28 line=32
+Stack id=2 nframes=3
+       pc=4561444 func=108 file=109 line=238
+       pc=5069285 func=110 file=111 line=125
+       pc=5070075 func=63 file=28 line=20
+Stack id=50 nframes=1
+       pc=5070361 func=63 file=28 line=38
+Stack id=10 nframes=1
+       pc=5072672 func=208 file=28 line=97
+Stack id=41 nframes=4
+       pc=4255286 func=77 file=76 line=1292
+       pc=4522824 func=78 file=79 line=103
+       pc=5073532 func=66 file=28 line=127
+       pc=5070323 func=63 file=28 line=32
+Stack id=31 nframes=3
+       pc=4522824 func=78 file=79 line=103
+       pc=5073532 func=66 file=28 line=127
+       pc=5070323 func=63 file=28 line=32
+Stack id=36 nframes=4
+       pc=4637735 func=132 file=133 line=474
+       pc=4309597 func=144 file=81 line=965
+       pc=4308676 func=82 file=81 line=927
+       pc=4314212 func=80 file=81 line=1446
+Stack id=69 nframes=19
+       pc=4746660 func=150 file=30 line=432
+       pc=4737158 func=151 file=152 line=106
+       pc=4815748 func=176 file=146 line=218
+       pc=4816367 func=185 file=146 line=301
+       pc=4814141 func=186 file=39 line=334
+       pc=5034884 func=187 file=39 line=314
+       pc=5034871 func=188 file=44 line=76
+       pc=5039575 func=45 file=46 line=35
+       pc=5060942 func=47 file=48 line=373
+       pc=4696033 func=49 file=50 line=74
+       pc=5026795 func=51 file=50 line=65
+       pc=5026766 func=52 file=48 line=373
+       pc=5040478 func=53 file=54 line=57
+       pc=5014167 func=55 file=56 line=154
+       pc=5051652 func=57 file=58 line=182
+       pc=4960356 func=59 file=58 line=172
+       pc=4960318 func=60 file=61 line=734
+       pc=4961094 func=62 file=61 line=808
+       pc=5070695 func=63 file=28 line=53
+Stack id=59 nframes=5
+       pc=4746660 func=150 file=30 line=432
+       pc=4737158 func=151 file=152 line=106
+       pc=4815748 func=176 file=146 line=218
+       pc=4817144 func=177 file=178 line=21
+       pc=5072014 func=89 file=28 line=82
+Stack id=30 nframes=7
+       pc=4578913 func=209 file=68 line=378
+       pc=4323996 func=198 file=199 line=536
+       pc=4255603 func=200 file=76 line=1337
+       pc=4253576 func=77 file=76 line=1025
+       pc=4522824 func=78 file=79 line=103
+       pc=5073532 func=66 file=28 line=127
+       pc=5070323 func=63 file=28 line=32
+Stack id=51 nframes=2
+       pc=4701031 func=201 file=25 line=116
+       pc=5070481 func=63 file=28 line=43
+Stack id=49 nframes=1
+       pc=5071552 func=171 file=28 line=38
+Stack id=29 nframes=5
+       pc=4307322 func=134 file=81 line=746
+       pc=4255286 func=77 file=76 line=1292
+       pc=4524282 func=139 file=79 line=246
+       pc=5073584 func=66 file=28 line=127
+       pc=5070323 func=63 file=28 line=32
+Stack id=82 nframes=15
+       pc=4750130 func=90 file=30 line=1488
+       pc=4811799 func=91 file=32 line=462
+       pc=4811777 func=92 file=93 line=17
+       pc=5052074 func=113 file=114 line=15
+       pc=5048202 func=96 file=97 line=239
+       pc=5050832 func=98 file=58 line=114
+       pc=5049860 func=99 file=58 line=68
+       pc=5049861 func=100 file=58 line=64
+       pc=4958364 func=101 file=61 line=651
+       pc=4956653 func=102 file=61 line=616
+       pc=4954291 func=103 file=61 line=517
+       pc=4952889 func=104 file=61 line=508
+       pc=4951126 func=105 file=61 line=434
+       pc=4951127 func=106 file=61 line=401
+       pc=5070980 func=63 file=28 line=68
+Stack id=27 nframes=4
+       pc=4255286 func=77 file=76 line=1292
+       pc=4524282 func=139 file=79 line=246
+       pc=5073584 func=66 file=28 line=127
+       pc=5070323 func=63 file=28 line=32
+Stack id=17 nframes=7
+       pc=4747354 func=83 file=30 line=964
+       pc=4808839 func=84 file=32 line=209
+       pc=4808831 func=33 file=34 line=736
+       pc=4808384 func=85 file=34 line=380
+       pc=4813744 func=86 file=37 line=46
+       pc=4813736 func=87 file=39 line=183
+       pc=5069594 func=196 file=111 line=134
+EventBatch gen=1 m=18446744073709551615 time=420901448919 size=6914
+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="GC sweep termination"
+String id=23
+       data="GC mark termination"
+String id=24
+       data="sync.(*WaitGroup).Add"
+String id=25
+       data="/usr/local/google/home/mknyszek/work/go-1/src/sync/waitgroup.go"
+String id=26
+       data="sync.(*WaitGroup).Done"
+String id=27
+       data="main.cpu20"
+String id=28
+       data="/usr/local/google/home/mknyszek/work/go-1/src/cmd/trace/v2/testdata/testprog/main.go"
+String id=29
+       data="syscall.read"
+String id=30
+       data="/usr/local/google/home/mknyszek/work/go-1/src/syscall/zsyscall_linux_amd64.go"
+String id=31
+       data="syscall.Read"
+String id=32
+       data="/usr/local/google/home/mknyszek/work/go-1/src/syscall/syscall_unix.go"
+String id=33
+       data="internal/poll.ignoringEINTRIO"
+String id=34
+       data="/usr/local/google/home/mknyszek/work/go-1/src/internal/poll/fd_unix.go"
+String id=35
+       data="internal/poll.(*FD).Read"
+String id=36
+       data="os.(*File).read"
+String id=37
+       data="/usr/local/google/home/mknyszek/work/go-1/src/os/file_posix.go"
+String id=38
+       data="os.(*File).Read"
+String id=39
+       data="/usr/local/google/home/mknyszek/work/go-1/src/os/file.go"
+String id=40
+       data="io.ReadAtLeast"
+String id=41
+       data="/usr/local/google/home/mknyszek/work/go-1/src/io/io.go"
+String id=42
+       data="io.ReadFull"
+String id=43
+       data="net.(*file).readLine"
+String id=44
+       data="/usr/local/google/home/mknyszek/work/go-1/src/net/parse.go"
+String id=45
+       data="net.maxListenerBacklog"
+String id=46
+       data="/usr/local/google/home/mknyszek/work/go-1/src/net/sock_linux.go"
+String id=47
+       data="net.listenerBacklog.func1"
+String id=48
+       data="/usr/local/google/home/mknyszek/work/go-1/src/net/net.go"
+String id=49
+       data="sync.(*Once).doSlow"
+String id=50
+       data="/usr/local/google/home/mknyszek/work/go-1/src/sync/once.go"
+String id=51
+       data="sync.(*Once).Do"
+String id=52
+       data="net.listenerBacklog"
+String id=53
+       data="net.socket"
+String id=54
+       data="/usr/local/google/home/mknyszek/work/go-1/src/net/sock_posix.go"
+String id=55
+       data="net.internetSocket"
+String id=56
+       data="/usr/local/google/home/mknyszek/work/go-1/src/net/ipsock_posix.go"
+String id=57
+       data="net.(*sysListener).listenTCPProto"
+String id=58
+       data="/usr/local/google/home/mknyszek/work/go-1/src/net/tcpsock_posix.go"
+String id=59
+       data="net.(*sysListener).listenTCP"
+String id=60
+       data="net.(*ListenConfig).Listen"
+String id=61
+       data="/usr/local/google/home/mknyszek/work/go-1/src/net/dial.go"
+String id=62
+       data="net.Listen"
+String id=63
+       data="main.main"
+String id=64
+       data="time.Sleep"
+String id=65
+       data="/usr/local/google/home/mknyszek/work/go-1/src/runtime/time.go"
+String id=66
+       data="main.allocHog"
+String id=67
+       data="runtime.traceLocker.GCSweepSpan"
+String id=68
+       data="/usr/local/google/home/mknyszek/work/go-1/src/runtime/trace2runtime.go"
+String id=69
+       data="runtime.(*sweepLocked).sweep"
+String id=70
+       data="/usr/local/google/home/mknyszek/work/go-1/src/runtime/mgcsweep.go"
+String id=71
+       data="runtime.(*mcentral).cacheSpan"
+String id=72
+       data="/usr/local/google/home/mknyszek/work/go-1/src/runtime/mcentral.go"
+String id=73
+       data="runtime.(*mcache).refill"
+String id=74
+       data="/usr/local/google/home/mknyszek/work/go-1/src/runtime/mcache.go"
+String id=75
+       data="runtime.(*mcache).nextFree"
+String id=76
+       data="/usr/local/google/home/mknyszek/work/go-1/src/runtime/malloc.go"
+String id=77
+       data="runtime.mallocgc"
+String id=78
+       data="runtime.makeslice"
+String id=79
+       data="/usr/local/google/home/mknyszek/work/go-1/src/runtime/slice.go"
+String id=80
+       data="runtime.gcBgMarkWorker"
+String id=81
+       data="/usr/local/google/home/mknyszek/work/go-1/src/runtime/mgc.go"
+String id=82
+       data="runtime.gcMarkDone"
+String id=83
+       data="syscall.write"
+String id=84
+       data="syscall.Write"
+String id=85
+       data="internal/poll.(*FD).Write"
+String id=86
+       data="os.(*File).write"
+String id=87
+       data="os.(*File).Write"
+String id=88
+       data="main.blockingSyscall.func1"
+String id=89
+       data="main.blockingSyscall"
+String id=90
+       data="syscall.setsockopt"
+String id=91
+       data="syscall.SetsockoptInt"
+String id=92
+       data="internal/poll.(*FD).SetsockoptInt"
+String id=93
+       data="/usr/local/google/home/mknyszek/work/go-1/src/internal/poll/sockopt.go"
+String id=94
+       data="net.setKeepAlivePeriod"
+String id=95
+       data="/usr/local/google/home/mknyszek/work/go-1/src/net/tcpsockopt_unix.go"
+String id=96
+       data="net.newTCPConn"
+String id=97
+       data="/usr/local/google/home/mknyszek/work/go-1/src/net/tcpsock.go"
+String id=98
+       data="net.(*sysDialer).doDialTCPProto"
+String id=99
+       data="net.(*sysDialer).doDialTCP"
+String id=100
+       data="net.(*sysDialer).dialTCP"
+String id=101
+       data="net.(*sysDialer).dialSingle"
+String id=102
+       data="net.(*sysDialer).dialSerial"
+String id=103
+       data="net.(*sysDialer).dialParallel"
+String id=104
+       data="net.(*Dialer).DialContext"
+String id=105
+       data="net.(*Dialer).Dial"
+String id=106
+       data="net.Dial"
+String id=107
+       data="runtime.traceLocker.Gomaxprocs"
+String id=108
+       data="runtime.StartTrace"
+String id=109
+       data="/usr/local/google/home/mknyszek/work/go-1/src/runtime/trace2.go"
+String id=110
+       data="runtime/trace.Start"
+String id=111
+       data="/usr/local/google/home/mknyszek/work/go-1/src/runtime/trace/trace.go"
+String id=112
+       data="runtime.(*traceAdvancerState).start"
+String id=113
+       data="net.setNoDelay"
+String id=114
+       data="/usr/local/google/home/mknyszek/work/go-1/src/net/tcpsockopt_posix.go"
+String id=115
+       data="net.(*TCPListener).accept"
+String id=116
+       data="net.(*TCPListener).Accept"
+String id=117
+       data="main.main.func2"
+String id=118
+       data="runtime.chanrecv1"
+String id=119
+       data="/usr/local/google/home/mknyszek/work/go-1/src/runtime/chan.go"
+String id=120
+       data="runtime.(*wakeableSleep).sleep"
+String id=121
+       data="runtime.(*traceAdvancerState).start.func1"
+String id=122
+       data="syscall.Close"
+String id=123
+       data="internal/poll.(*SysFile).destroy"
+String id=124
+       data="/usr/local/google/home/mknyszek/work/go-1/src/internal/poll/fd_unixjs.go"
+String id=125
+       data="internal/poll.(*FD).destroy"
+String id=126
+       data="internal/poll.(*FD).decref"
+String id=127
+       data="/usr/local/google/home/mknyszek/work/go-1/src/internal/poll/fd_mutex.go"
+String id=128
+       data="internal/poll.(*FD).Close"
+String id=129
+       data="net.(*netFD).Close"
+String id=130
+       data="/usr/local/google/home/mknyszek/work/go-1/src/net/fd_posix.go"
+String id=131
+       data="net.(*conn).Close"
+String id=132
+       data="runtime.systemstack_switch"
+String id=133
+       data="/usr/local/google/home/mknyszek/work/go-1/src/runtime/asm_amd64.s"
+String id=134
+       data="runtime.gcStart"
+String id=135
+       data="runtime.gopark"
+String id=136
+       data="/usr/local/google/home/mknyszek/work/go-1/src/runtime/proc.go"
+String id=137
+       data="runtime.chansend1"
+String id=138
+       data="runtime.gcBgMarkStartWorkers"
+String id=139
+       data="runtime.growslice"
+String id=140
+       data="runtime.traceStartReadCPU.func1"
+String id=141
+       data="/usr/local/google/home/mknyszek/work/go-1/src/runtime/trace2cpu.go"
+String id=142
+       data="net.setKeepAlive"
+String id=143
+       data="/usr/local/google/home/mknyszek/work/go-1/src/net/sockopt_posix.go"
+String id=144
+       data="runtime.gcMarkTermination"
+String id=145
+       data="os.(*file).close"
+String id=146
+       data="/usr/local/google/home/mknyszek/work/go-1/src/os/file_unix.go"
+String id=147
+       data="os.(*File).Close"
+String id=148
+       data="net.(*file).close"
+String id=149
+       data="runtime.startTheWorld"
+String id=150
+       data="syscall.fcntl"
+String id=151
+       data="syscall.SetNonblock"
+String id=152
+       data="/usr/local/google/home/mknyszek/work/go-1/src/syscall/exec_unix.go"
+String id=153
+       data="internal/poll.(*FD).SetBlocking"
+String id=154
+       data="os.(*File).Fd"
+String id=155
+       data="syscall.accept4"
+String id=156
+       data="syscall.Accept4"
+String id=157
+       data="/usr/local/google/home/mknyszek/work/go-1/src/syscall/syscall_linux.go"
+String id=158
+       data="internal/poll.accept"
+String id=159
+       data="/usr/local/google/home/mknyszek/work/go-1/src/internal/poll/sock_cloexec.go"
+String id=160
+       data="internal/poll.(*FD).Accept"
+String id=161
+       data="net.(*netFD).accept"
+String id=162
+       data="/usr/local/google/home/mknyszek/work/go-1/src/net/fd_unix.go"
+String id=163
+       data="syscall.Listen"
+String id=164
+       data="net.(*netFD).listenStream"
+String id=165
+       data="net.setDefaultListenerSockopts"
+String id=166
+       data="/usr/local/google/home/mknyszek/work/go-1/src/net/sockopt_linux.go"
+String id=167
+       data="net.(*netFD).Read"
+String id=168
+       data="net.(*conn).Read"
+String id=169
+       data="runtime.goparkunlock"
+String id=170
+       data="runtime.bgsweep"
+String id=171
+       data="main.main.func1"
+String id=172
+       data="syscall.getsockopt"
+String id=173
+       data="syscall.GetsockoptInt"
+String id=174
+       data="net.(*netFD).connect"
+String id=175
+       data="net.(*netFD).dial"
+String id=176
+       data="os.newFile"
+String id=177
+       data="os.Pipe"
+String id=178
+       data="/usr/local/google/home/mknyszek/work/go-1/src/os/pipe2_unix.go"
+String id=179
+       data="runtime.sweepone"
+String id=180
+       data="runtime.deductSweepCredit"
+String id=181
+       data="syscall.openat"
+String id=182
+       data="syscall.Open"
+String id=183
+       data="os.open"
+String id=184
+       data="/usr/local/google/home/mknyszek/work/go-1/src/os/file_open_unix.go"
+String id=185
+       data="os.openFileNolog"
+String id=186
+       data="os.OpenFile"
+String id=187
+       data="os.Open"
+String id=188
+       data="net.open"
+String id=189
+       data="syscall.connect"
+String id=190
+       data="syscall.Connect"
+String id=191
+       data="runtime.(*scavengerState).park"
+String id=192
+       data="/usr/local/google/home/mknyszek/work/go-1/src/runtime/mgcscavenge.go"
+String id=193
+       data="runtime.bgscavenge"
+String id=194
+       data="syscall.bind"
+String id=195
+       data="syscall.Bind"
+String id=196
+       data="runtime/trace.Start.func1"
+String id=197
+       data="runtime.traceStartReadCPU"
+String id=198
+       data="runtime.gcAssistAlloc"
+String id=199
+       data="/usr/local/google/home/mknyszek/work/go-1/src/runtime/mgcmark.go"
+String id=200
+       data="runtime.deductAssistCredit"
+String id=201
+       data="sync.(*WaitGroup).Wait"
+String id=202
+       data="internal/poll.(*FD).WaitWrite"
+String id=203
+       data="net.(*netFD).Write"
+String id=204
+       data="net.(*conn).Write"
+String id=205
+       data="runtime.(*mheap).alloc"
+String id=206
+       data="/usr/local/google/home/mknyszek/work/go-1/src/runtime/mheap.go"
+String id=207
+       data="runtime.(*mcentral).grow"
+String id=208
+       data="main.cpu10"
+String id=209
+       data="runtime.traceLocker.GCMarkAssistStart"
diff --git a/src/cmd/trace/v2/testdata/mktests.go b/src/cmd/trace/v2/testdata/mktests.go
new file mode 100644 (file)
index 0000000..143e8ec
--- /dev/null
@@ -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.
+
+//go:build ignore
+
+package main
+
+import (
+       "bytes"
+       "fmt"
+       "internal/trace/v2/raw"
+       "internal/trace/v2/version"
+       "io"
+       "log"
+       "os"
+       "os/exec"
+)
+
+func main() {
+       // Create command.
+       var trace, stderr bytes.Buffer
+       cmd := exec.Command("go", "run", "./testprog/main.go")
+       // TODO(mknyszek): Remove if goexperiment.Exectracer2 becomes the default.
+       cmd.Env = append(os.Environ(), "GOEXPERIMENT=exectracer2")
+       cmd.Stdout = &trace
+       cmd.Stderr = &stderr
+
+       // Run trace program; the trace will appear in stdout.
+       fmt.Fprintln(os.Stderr, "running trace program...")
+       if err := cmd.Run(); err != nil {
+               log.Fatalf("running trace program: %v:\n%s", err, stderr.String())
+       }
+
+       // Create file.
+       f, err := os.Create(fmt.Sprintf("./go1%d.test", version.Current))
+       if err != nil {
+               log.Fatalf("creating output file: %v", err)
+       }
+       defer f.Close()
+
+       // Write out the trace.
+       r, err := raw.NewReader(&trace)
+       if err != nil {
+               log.Fatalf("reading trace: %v", err)
+       }
+       w, err := raw.NewTextWriter(f, version.Current)
+       for {
+               ev, err := r.ReadEvent()
+               if err == io.EOF {
+                       break
+               }
+               if err != nil {
+                       log.Fatalf("reading trace: %v", err)
+               }
+               if err := w.WriteEvent(ev); err != nil {
+                       log.Fatalf("writing trace: %v", err)
+               }
+       }
+}
diff --git a/src/cmd/trace/v2/testdata/testprog/main.go b/src/cmd/trace/v2/testdata/testprog/main.go
new file mode 100644 (file)
index 0000000..fcf4dc1
--- /dev/null
@@ -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.
+
+package main
+
+import (
+       "fmt"
+       "log"
+       "net"
+       "os"
+       "runtime"
+       "runtime/trace"
+       "sync"
+       "syscall"
+       "time"
+)
+
+func main() {
+       if err := trace.Start(os.Stdout); err != nil {
+               log.Fatal(err)
+       }
+
+       // checkExecutionTimes relies on this.
+       var wg sync.WaitGroup
+       wg.Add(2)
+       go cpu10(&wg)
+       go cpu20(&wg)
+       wg.Wait()
+
+       // checkHeapMetrics relies on this.
+       allocHog(25 * time.Millisecond)
+
+       // checkProcStartStop relies on this.
+       var wg2 sync.WaitGroup
+       for i := 0; i < runtime.GOMAXPROCS(0); i++ {
+               wg2.Add(1)
+               go func() {
+                       defer wg2.Done()
+                       cpuHog(50 * time.Millisecond)
+               }()
+       }
+       wg2.Wait()
+
+       // checkSyscalls relies on this.
+       done := make(chan error)
+       go blockingSyscall(50*time.Millisecond, done)
+       if err := <-done; err != nil {
+               log.Fatal(err)
+       }
+
+       // checkNetworkUnblock relies on this.
+       ln, err := net.Listen("tcp", "127.0.0.1:0")
+       if err != nil {
+               log.Fatalf("listen failed: %v", err)
+       }
+       defer ln.Close()
+       go func() {
+               c, err := ln.Accept()
+               if err != nil {
+                       return
+               }
+               time.Sleep(time.Millisecond)
+               var buf [1]byte
+               c.Write(buf[:])
+               c.Close()
+       }()
+       c, err := net.Dial("tcp", ln.Addr().String())
+       if err != nil {
+               log.Fatalf("dial failed: %v", err)
+       }
+       var tmp [1]byte
+       c.Read(tmp[:])
+       c.Close()
+
+       trace.Stop()
+}
+
+// blockingSyscall blocks the current goroutine for duration d in a syscall and
+// sends a message to done when it is done or if the syscall failed.
+func blockingSyscall(d time.Duration, done chan<- error) {
+       r, w, err := os.Pipe()
+       if err != nil {
+               done <- err
+               return
+       }
+       start := time.Now()
+       msg := []byte("hello")
+       time.AfterFunc(d, func() { w.Write(msg) })
+       _, err = syscall.Read(int(r.Fd()), make([]byte, len(msg)))
+       if err == nil && time.Since(start) < d {
+               err = fmt.Errorf("syscall returned too early: want=%s got=%s", d, time.Since(start))
+       }
+       done <- err
+}
+
+func cpu10(wg *sync.WaitGroup) {
+       defer wg.Done()
+       cpuHog(10 * time.Millisecond)
+}
+
+func cpu20(wg *sync.WaitGroup) {
+       defer wg.Done()
+       cpuHog(20 * time.Millisecond)
+}
+
+func cpuHog(dt time.Duration) {
+       start := time.Now()
+       for i := 0; ; i++ {
+               if i%1000 == 0 && time.Since(start) > dt {
+                       return
+               }
+       }
+}
+
+func allocHog(dt time.Duration) {
+       start := time.Now()
+       var s [][]byte
+       for i := 0; ; i++ {
+               if i%1000 == 0 {
+                       if time.Since(start) > dt {
+                               return
+                       }
+                       // Take a break... this will generate a ton of events otherwise.
+                       time.Sleep(50 * time.Microsecond)
+               }
+               s = append(s, make([]byte, 1024))
+       }
+}
diff --git a/src/cmd/trace/v2/viewer.go b/src/cmd/trace/v2/viewer.go
new file mode 100644 (file)
index 0000000..de67fc4
--- /dev/null
@@ -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.
+
+package trace
+
+import (
+       "fmt"
+       "internal/trace"
+       "internal/trace/traceviewer"
+       tracev2 "internal/trace/v2"
+       "time"
+)
+
+// viewerFrames returns the frames of the stack of ev. The given frame slice is
+// used to store the frames to reduce allocations.
+func viewerFrames(stk tracev2.Stack) []*trace.Frame {
+       var frames []*trace.Frame
+       stk.Frames(func(f tracev2.StackFrame) bool {
+               frames = append(frames, &trace.Frame{
+                       PC:   f.PC,
+                       Fn:   f.Func,
+                       File: f.File,
+                       Line: int(f.Line),
+               })
+               return true
+       })
+       return frames
+}
+
+func viewerGState(state tracev2.GoState, inMarkAssist bool) traceviewer.GState {
+       switch state {
+       case tracev2.GoUndetermined:
+               return traceviewer.GDead
+       case tracev2.GoNotExist:
+               return traceviewer.GDead
+       case tracev2.GoRunnable:
+               return traceviewer.GRunnable
+       case tracev2.GoRunning:
+               return traceviewer.GRunning
+       case tracev2.GoWaiting:
+               if inMarkAssist {
+                       return traceviewer.GWaitingGC
+               }
+               return traceviewer.GWaiting
+       case tracev2.GoSyscall:
+               // N.B. A goroutine in a syscall is considered "executing" (state.Executing() == true).
+               return traceviewer.GRunning
+       default:
+               panic(fmt.Sprintf("unknown GoState: %s", state.String()))
+       }
+}
+
+func viewerTime(t time.Duration) float64 {
+       return float64(t) / float64(time.Microsecond)
+}
index 3d54fc7aac052ebd93e307fcf8286528863969b4..a6b1a613bb7ddbed1f43078212076531f096cbc0 100644 (file)
@@ -45,6 +45,7 @@ var depsRules = `
          internal/cpu, internal/goarch, internal/godebugs,
          internal/goexperiment, internal/goos,
          internal/goversion, internal/nettrace, internal/platform,
+         internal/trace/traceviewer/format,
          log/internal,
          unicode/utf8, unicode/utf16, unicode,
          unsafe;
@@ -633,6 +634,16 @@ var depsRules = `
        FMT, container/heap, math/rand, internal/trace/v2
        < internal/trace;
 
+       # cmd/trace dependencies.
+       FMT,
+       embed,
+       encoding/json,
+       html/template,
+       internal/trace,
+       internal/trace/traceviewer/format,
+       net/http
+       < internal/trace/traceviewer;
+
        # Coverage.
        FMT, crypto/md5, encoding/binary, regexp, sort, text/tabwriter, unsafe,
        internal/coverage, internal/coverage/uleb128
index 67fa60b8fb540a1969099a3bc3e728028b2f70be..3bbfbebab485a7daf6183697d361efaef25ed111 100644 (file)
@@ -136,17 +136,23 @@ type rawEvent struct {
        sargs []string
 }
 
-// readTrace does wire-format parsing and verification.
-// It does not care about specific event types and argument meaning.
-func readTrace(r io.Reader) (ver int, events []rawEvent, strings map[uint64]string, err error) {
+func ReadVersion(r io.Reader) (ver int, off int, err error) {
        // Read and validate trace header.
        var buf [16]byte
-       off, err := io.ReadFull(r, buf[:])
+       off, err = io.ReadFull(r, buf[:])
        if err != nil {
                err = fmt.Errorf("failed to read header: read %v, err %v", off, err)
                return
        }
        ver, err = parseHeader(buf[:])
+       return
+}
+
+// readTrace does wire-format parsing and verification.
+// It does not care about specific event types and argument meaning.
+func readTrace(r io.Reader) (ver int, events []rawEvent, strings map[uint64]string, err error) {
+       var off int
+       ver, off, err = ReadVersion(r)
        if err != nil {
                return
        }
@@ -161,6 +167,7 @@ func readTrace(r io.Reader) (ver int, events []rawEvent, strings map[uint64]stri
        }
 
        // Read events.
+       var buf [16]byte
        strings = make(map[uint64]string)
        for {
                // Read event type and number of arguments (1 byte).
diff --git a/src/internal/trace/traceviewer/emitter.go b/src/internal/trace/traceviewer/emitter.go
new file mode 100644 (file)
index 0000000..95cb1f3
--- /dev/null
@@ -0,0 +1,666 @@
+// 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.
+
+package traceviewer
+
+import (
+       "encoding/json"
+       "fmt"
+       "internal/trace"
+       "internal/trace/traceviewer/format"
+       "io"
+       "strconv"
+       "time"
+)
+
+type TraceConsumer struct {
+       ConsumeTimeUnit    func(unit string)
+       ConsumeViewerEvent func(v *format.Event, required bool)
+       ConsumeViewerFrame func(key string, f format.Frame)
+       Flush              func()
+}
+
+// ViewerDataTraceConsumer returns a TraceConsumer that writes to w. The
+// startIdx and endIdx are used for splitting large traces. They refer to
+// indexes in the traceEvents output array, not the events in the trace input.
+func ViewerDataTraceConsumer(w io.Writer, startIdx, endIdx int64) TraceConsumer {
+       allFrames := make(map[string]format.Frame)
+       requiredFrames := make(map[string]format.Frame)
+       enc := json.NewEncoder(w)
+       written := 0
+       index := int64(-1)
+
+       io.WriteString(w, "{")
+       return TraceConsumer{
+               ConsumeTimeUnit: func(unit string) {
+                       io.WriteString(w, `"displayTimeUnit":`)
+                       enc.Encode(unit)
+                       io.WriteString(w, ",")
+               },
+               ConsumeViewerEvent: func(v *format.Event, required bool) {
+                       index++
+                       if !required && (index < startIdx || index > endIdx) {
+                               // not in the range. Skip!
+                               return
+                       }
+                       WalkStackFrames(allFrames, v.Stack, func(id int) {
+                               s := strconv.Itoa(id)
+                               requiredFrames[s] = allFrames[s]
+                       })
+                       WalkStackFrames(allFrames, v.EndStack, func(id int) {
+                               s := strconv.Itoa(id)
+                               requiredFrames[s] = allFrames[s]
+                       })
+                       if written == 0 {
+                               io.WriteString(w, `"traceEvents": [`)
+                       }
+                       if written > 0 {
+                               io.WriteString(w, ",")
+                       }
+                       enc.Encode(v)
+                       // TODO(mknyszek): get rid of the extra \n inserted by enc.Encode.
+                       // Same should be applied to splittingTraceConsumer.
+                       written++
+               },
+               ConsumeViewerFrame: func(k string, v format.Frame) {
+                       allFrames[k] = v
+               },
+               Flush: func() {
+                       io.WriteString(w, `], "stackFrames":`)
+                       enc.Encode(requiredFrames)
+                       io.WriteString(w, `}`)
+               },
+       }
+}
+
+func SplittingTraceConsumer(max int) (*splitter, TraceConsumer) {
+       type eventSz struct {
+               Time   float64
+               Sz     int
+               Frames []int
+       }
+
+       var (
+               // data.Frames contains only the frames for required events.
+               data = format.Data{Frames: make(map[string]format.Frame)}
+
+               allFrames = make(map[string]format.Frame)
+
+               sizes []eventSz
+               cw    countingWriter
+       )
+
+       s := new(splitter)
+
+       return s, TraceConsumer{
+               ConsumeTimeUnit: func(unit string) {
+                       data.TimeUnit = unit
+               },
+               ConsumeViewerEvent: func(v *format.Event, required bool) {
+                       if required {
+                               // Store required events inside data so flush
+                               // can include them in the required part of the
+                               // trace.
+                               data.Events = append(data.Events, v)
+                               WalkStackFrames(allFrames, v.Stack, func(id int) {
+                                       s := strconv.Itoa(id)
+                                       data.Frames[s] = allFrames[s]
+                               })
+                               WalkStackFrames(allFrames, v.EndStack, func(id int) {
+                                       s := strconv.Itoa(id)
+                                       data.Frames[s] = allFrames[s]
+                               })
+                               return
+                       }
+                       enc := json.NewEncoder(&cw)
+                       enc.Encode(v)
+                       size := eventSz{Time: v.Time, Sz: cw.size + 1} // +1 for ",".
+                       // Add referenced stack frames. Their size is computed
+                       // in flush, where we can dedup across events.
+                       WalkStackFrames(allFrames, v.Stack, func(id int) {
+                               size.Frames = append(size.Frames, id)
+                       })
+                       WalkStackFrames(allFrames, v.EndStack, func(id int) {
+                               size.Frames = append(size.Frames, id) // This may add duplicates. We'll dedup later.
+                       })
+                       sizes = append(sizes, size)
+                       cw.size = 0
+               },
+               ConsumeViewerFrame: func(k string, v format.Frame) {
+                       allFrames[k] = v
+               },
+               Flush: func() {
+                       // Calculate size of the mandatory part of the trace.
+                       // This includes thread names and stack frames for
+                       // required events.
+                       cw.size = 0
+                       enc := json.NewEncoder(&cw)
+                       enc.Encode(data)
+                       requiredSize := cw.size
+
+                       // Then calculate size of each individual event and
+                       // their stack frames, grouping them into ranges. We
+                       // only include stack frames relevant to the events in
+                       // the range to reduce overhead.
+
+                       var (
+                               start = 0
+
+                               eventsSize = 0
+
+                               frames     = make(map[string]format.Frame)
+                               framesSize = 0
+                       )
+                       for i, ev := range sizes {
+                               eventsSize += ev.Sz
+
+                               // Add required stack frames. Note that they
+                               // may already be in the map.
+                               for _, id := range ev.Frames {
+                                       s := strconv.Itoa(id)
+                                       _, ok := frames[s]
+                                       if ok {
+                                               continue
+                                       }
+                                       f := allFrames[s]
+                                       frames[s] = f
+                                       framesSize += stackFrameEncodedSize(uint(id), f)
+                               }
+
+                               total := requiredSize + framesSize + eventsSize
+                               if total < max {
+                                       continue
+                               }
+
+                               // Reached max size, commit this range and
+                               // start a new range.
+                               startTime := time.Duration(sizes[start].Time * 1000)
+                               endTime := time.Duration(ev.Time * 1000)
+                               s.Ranges = append(s.Ranges, Range{
+                                       Name:      fmt.Sprintf("%v-%v", startTime, endTime),
+                                       Start:     start,
+                                       End:       i + 1,
+                                       StartTime: int64(startTime),
+                                       EndTime:   int64(endTime),
+                               })
+                               start = i + 1
+                               frames = make(map[string]format.Frame)
+                               framesSize = 0
+                               eventsSize = 0
+                       }
+                       if len(s.Ranges) <= 1 {
+                               s.Ranges = nil
+                               return
+                       }
+
+                       if end := len(sizes) - 1; start < end {
+                               s.Ranges = append(s.Ranges, Range{
+                                       Name:      fmt.Sprintf("%v-%v", time.Duration(sizes[start].Time*1000), time.Duration(sizes[end].Time*1000)),
+                                       Start:     start,
+                                       End:       end,
+                                       StartTime: int64(sizes[start].Time * 1000),
+                                       EndTime:   int64(sizes[end].Time * 1000),
+                               })
+                       }
+               },
+       }
+}
+
+type splitter struct {
+       Ranges []Range
+}
+
+type countingWriter struct {
+       size int
+}
+
+func (cw *countingWriter) Write(data []byte) (int, error) {
+       cw.size += len(data)
+       return len(data), nil
+}
+
+func stackFrameEncodedSize(id uint, f format.Frame) int {
+       // We want to know the marginal size of traceviewer.Data.Frames for
+       // each event. Running full JSON encoding of the map for each event is
+       // far too slow.
+       //
+       // Since the format is fixed, we can easily compute the size without
+       // encoding.
+       //
+       // A single entry looks like one of the following:
+       //
+       //   "1":{"name":"main.main:30"},
+       //   "10":{"name":"pkg.NewSession:173","parent":9},
+       //
+       // The parent is omitted if 0. The trailing comma is omitted from the
+       // last entry, but we don't need that much precision.
+       const (
+               baseSize = len(`"`) + len(`":{"name":"`) + len(`"},`)
+
+               // Don't count the trailing quote on the name, as that is
+               // counted in baseSize.
+               parentBaseSize = len(`,"parent":`)
+       )
+
+       size := baseSize
+
+       size += len(f.Name)
+
+       // Bytes for id (always positive).
+       for id > 0 {
+               size += 1
+               id /= 10
+       }
+
+       if f.Parent > 0 {
+               size += parentBaseSize
+               // Bytes for parent (always positive).
+               for f.Parent > 0 {
+                       size += 1
+                       f.Parent /= 10
+               }
+       }
+
+       return size
+}
+
+// WalkStackFrames calls fn for id and all of its parent frames from allFrames.
+func WalkStackFrames(allFrames map[string]format.Frame, id int, fn func(id int)) {
+       for id != 0 {
+               f, ok := allFrames[strconv.Itoa(id)]
+               if !ok {
+                       break
+               }
+               fn(id)
+               id = f.Parent
+       }
+}
+
+type Mode int
+
+const (
+       ModeGoroutineOriented Mode = 1 << iota
+       ModeTaskOriented
+)
+
+// NewEmitter returns a new Emitter that writes to c. The rangeStart and
+// rangeEnd args are used for splitting large traces.
+func NewEmitter(c TraceConsumer, mode Mode, rangeStart, rangeEnd time.Duration) *Emitter {
+       c.ConsumeTimeUnit("ns")
+
+       return &Emitter{
+               c:          c,
+               mode:       mode,
+               rangeStart: rangeStart,
+               rangeEnd:   rangeEnd,
+               frameTree:  frameNode{children: make(map[uint64]frameNode)},
+               resources:  make(map[uint64]string),
+       }
+}
+
+type Emitter struct {
+       c          TraceConsumer
+       mode       Mode
+       rangeStart time.Duration
+       rangeEnd   time.Duration
+
+       heapStats, prevHeapStats     heapStats
+       gstates, prevGstates         [gStateCount]int64
+       threadStats, prevThreadStats [threadStateCount]int64
+       gomaxprocs                   uint64
+       frameTree                    frameNode
+       frameSeq                     int
+       arrowSeq                     uint64
+       filter                       func(uint64) bool
+       resourceType                 string
+       resources                    map[uint64]string
+       focusResource                uint64
+}
+
+func (e *Emitter) Gomaxprocs(v uint64) {
+       if v > e.gomaxprocs {
+               e.gomaxprocs = v
+       }
+}
+
+func (e *Emitter) Resource(id uint64, name string) {
+       if e.filter != nil && !e.filter(id) {
+               return
+       }
+       e.resources[id] = name
+}
+
+func (e *Emitter) SetResourceType(name string) {
+       e.resourceType = name
+}
+
+func (e *Emitter) SetResourceFilter(filter func(uint64) bool) {
+       e.filter = filter
+}
+
+func (e *Emitter) Slice(s SliceEvent) {
+       if !e.tsWithinRange(s.Ts) && !e.tsWithinRange(s.Ts+s.Dur) {
+               return
+       }
+       if e.filter != nil && !e.filter(s.Resource) {
+               return
+       }
+       e.OptionalEvent(&format.Event{
+               Name:     s.Name,
+               Phase:    "X",
+               Time:     viewerTime(s.Ts),
+               Dur:      viewerTime(s.Dur),
+               TID:      s.Resource,
+               Stack:    s.Stack,
+               EndStack: s.EndStack,
+               Arg:      s.Arg,
+       })
+}
+
+type SliceEvent struct {
+       Name     string
+       Ts       time.Duration
+       Dur      time.Duration
+       Resource uint64
+       Stack    int
+       EndStack int
+       Arg      any
+}
+
+func (e *Emitter) Instant(i InstantEvent) {
+       if !e.tsWithinRange(i.Ts) {
+               return
+       }
+       if e.filter != nil && !e.filter(i.Resource) {
+               return
+       }
+       // TODO(mknyszek): Handle ModeTaskOriented here. See cmd/trace.(*traceContext).emitInstant.
+       cname := ""
+       e.OptionalEvent(&format.Event{
+               Name:     i.Name,
+               Category: i.Category,
+               Phase:    "I",
+               Scope:    "t",
+               Time:     viewerTime(i.Ts),
+               TID:      i.Resource,
+               Stack:    i.Stack,
+               Cname:    cname,
+               Arg:      i.Arg,
+       })
+}
+
+type InstantEvent struct {
+       Ts       time.Duration
+       Name     string
+       Category string
+       Resource uint64
+       Stack    int
+       Arg      any
+}
+
+func (e *Emitter) Arrow(a ArrowEvent) {
+       if !e.tsWithinRange(a.Start) || !e.tsWithinRange(a.End) {
+               return
+       }
+       if e.filter != nil && (!e.filter(a.FromResource) || !e.filter(a.ToResource)) {
+               return
+       }
+       // TODO(mknyszek): Handle ModeTaskOriented here. See cmd/trace.(*traceContext).emitArrow.
+       e.arrowSeq++
+       e.OptionalEvent(&format.Event{
+               Name:  a.Name,
+               Phase: "s",
+               TID:   a.FromResource,
+               ID:    e.arrowSeq,
+               Time:  viewerTime(a.Start),
+               Stack: a.FromStack,
+       })
+       e.OptionalEvent(&format.Event{
+               Name:  a.Name,
+               Phase: "t",
+               TID:   a.ToResource,
+               ID:    e.arrowSeq,
+               Time:  viewerTime(a.End),
+       })
+}
+
+type ArrowEvent struct {
+       Name         string
+       Start        time.Duration
+       End          time.Duration
+       FromResource uint64
+       FromStack    int
+       ToResource   uint64
+}
+
+func (e *Emitter) Event(ev *format.Event) {
+       e.c.ConsumeViewerEvent(ev, true)
+}
+
+func (e *Emitter) HeapAlloc(ts time.Duration, v uint64) {
+       e.heapStats.heapAlloc = v
+       e.emitHeapCounters(ts)
+}
+
+func (e *Emitter) Focus(id uint64) {
+       e.focusResource = id
+}
+
+func (e *Emitter) GoroutineTransition(ts time.Duration, from, to GState) {
+       e.gstates[from]--
+       e.gstates[to]++
+       if e.prevGstates == e.gstates {
+               return
+       }
+       if e.tsWithinRange(ts) {
+               e.OptionalEvent(&format.Event{
+                       Name:  "Goroutines",
+                       Phase: "C",
+                       Time:  viewerTime(ts),
+                       PID:   1,
+                       Arg: &format.GoroutineCountersArg{
+                               Running:   uint64(e.gstates[GRunning]),
+                               Runnable:  uint64(e.gstates[GRunnable]),
+                               GCWaiting: uint64(e.gstates[GWaitingGC]),
+                       },
+               })
+       }
+       e.prevGstates = e.gstates
+}
+
+func (e *Emitter) IncThreadStateCount(ts time.Duration, state ThreadState, delta int64) {
+       e.threadStats[state] += delta
+       if e.prevThreadStats == e.threadStats {
+               return
+       }
+       if e.tsWithinRange(ts) {
+               e.OptionalEvent(&format.Event{
+                       Name:  "Threads",
+                       Phase: "C",
+                       Time:  viewerTime(ts),
+                       PID:   1,
+                       Arg: &format.ThreadCountersArg{
+                               Running:   int64(e.threadStats[ThreadStateRunning]),
+                               InSyscall: int64(e.threadStats[ThreadStateInSyscall]),
+                               // TODO(mknyszek): Why is InSyscallRuntime not included here?
+                       },
+               })
+       }
+       e.prevThreadStats = e.threadStats
+}
+
+func (e *Emitter) HeapGoal(ts time.Duration, v uint64) {
+       // This cutoff at 1 PiB is a Workaround for https://github.com/golang/go/issues/63864.
+       //
+       // TODO(mknyszek): Remove this once the problem has been fixed.
+       const PB = 1 << 50
+       if v > PB {
+               v = 0
+       }
+       e.heapStats.nextGC = v
+       e.emitHeapCounters(ts)
+}
+
+func (e *Emitter) emitHeapCounters(ts time.Duration) {
+       if e.prevHeapStats == e.heapStats {
+               return
+       }
+       diff := uint64(0)
+       if e.heapStats.nextGC > e.heapStats.heapAlloc {
+               diff = e.heapStats.nextGC - e.heapStats.heapAlloc
+       }
+       if e.tsWithinRange(ts) {
+               e.OptionalEvent(&format.Event{
+                       Name:  "Heap",
+                       Phase: "C",
+                       Time:  viewerTime(ts),
+                       PID:   1,
+                       Arg:   &format.HeapCountersArg{Allocated: e.heapStats.heapAlloc, NextGC: diff},
+               })
+       }
+       e.prevHeapStats = e.heapStats
+}
+
+// Err returns an error if the emitter is in an invalid state.
+func (e *Emitter) Err() error {
+       if e.gstates[GRunnable] < 0 || e.gstates[GRunning] < 0 || e.threadStats[ThreadStateInSyscall] < 0 || e.threadStats[ThreadStateInSyscallRuntime] < 0 {
+               return fmt.Errorf(
+                       "runnable=%d running=%d insyscall=%d insyscallRuntime=%d",
+                       e.gstates[GRunnable],
+                       e.gstates[GRunning],
+                       e.threadStats[ThreadStateInSyscall],
+                       e.threadStats[ThreadStateInSyscallRuntime],
+               )
+       }
+       return nil
+}
+
+func (e *Emitter) tsWithinRange(ts time.Duration) bool {
+       return e.rangeStart <= ts && ts <= e.rangeEnd
+}
+
+// OptionalEvent emits ev if it's within the time range of of the consumer, i.e.
+// the selected trace split range.
+func (e *Emitter) OptionalEvent(ev *format.Event) {
+       e.c.ConsumeViewerEvent(ev, false)
+}
+
+func (e *Emitter) Flush() {
+       e.processMeta(format.StatsSection, "STATS", 0)
+       if e.mode&ModeTaskOriented != 0 {
+               e.processMeta(format.TasksSection, "TASKS", 1)
+       }
+
+       e.processMeta(format.ProcsSection, e.resourceType, 2)
+
+       e.threadMeta(format.ProcsSection, trace.GCP, "GC", -6)
+       e.threadMeta(format.ProcsSection, trace.NetpollP, "Network", -5)
+       e.threadMeta(format.ProcsSection, trace.TimerP, "Timers", -4)
+       e.threadMeta(format.ProcsSection, trace.SyscallP, "Syscalls", -3)
+
+       for id, name := range e.resources {
+               priority := int(id)
+               if e.focusResource != 0 && id == e.focusResource {
+                       // Put the focus goroutine on top.
+                       priority = -2
+               }
+               e.threadMeta(format.ProcsSection, id, name, priority)
+       }
+
+       e.c.Flush()
+}
+
+func (e *Emitter) threadMeta(sectionID, tid uint64, name string, priority int) {
+       e.Event(&format.Event{
+               Name:  "thread_name",
+               Phase: "M",
+               PID:   sectionID,
+               TID:   tid,
+               Arg:   &format.NameArg{Name: name},
+       })
+       e.Event(&format.Event{
+               Name:  "thread_sort_index",
+               Phase: "M",
+               PID:   sectionID,
+               TID:   tid,
+               Arg:   &format.SortIndexArg{Index: priority},
+       })
+}
+
+func (e *Emitter) processMeta(sectionID uint64, name string, priority int) {
+       e.Event(&format.Event{
+               Name:  "process_name",
+               Phase: "M",
+               PID:   sectionID,
+               Arg:   &format.NameArg{Name: name},
+       })
+       e.Event(&format.Event{
+               Name:  "process_sort_index",
+               Phase: "M",
+               PID:   sectionID,
+               Arg:   &format.SortIndexArg{Index: priority},
+       })
+}
+
+// Stack emits the given frames and returns a unique id for the stack. No
+// pointers to the given data are being retained beyond the call to Stack.
+func (e *Emitter) Stack(stk []*trace.Frame) int {
+       return e.buildBranch(e.frameTree, stk)
+}
+
+// buildBranch builds one branch in the prefix tree rooted at ctx.frameTree.
+func (e *Emitter) buildBranch(parent frameNode, stk []*trace.Frame) int {
+       if len(stk) == 0 {
+               return parent.id
+       }
+       last := len(stk) - 1
+       frame := stk[last]
+       stk = stk[:last]
+
+       node, ok := parent.children[frame.PC]
+       if !ok {
+               e.frameSeq++
+               node.id = e.frameSeq
+               node.children = make(map[uint64]frameNode)
+               parent.children[frame.PC] = node
+               e.c.ConsumeViewerFrame(strconv.Itoa(node.id), format.Frame{Name: fmt.Sprintf("%v:%v", frame.Fn, frame.Line), Parent: parent.id})
+       }
+       return e.buildBranch(node, stk)
+}
+
+type heapStats struct {
+       heapAlloc uint64
+       nextGC    uint64
+}
+
+func viewerTime(t time.Duration) float64 {
+       return float64(t) / float64(time.Microsecond)
+}
+
+type GState int
+
+const (
+       GDead GState = iota
+       GRunnable
+       GRunning
+       GWaiting
+       GWaitingGC
+
+       gStateCount
+)
+
+type ThreadState int
+
+const (
+       ThreadStateInSyscall ThreadState = iota
+       ThreadStateInSyscallRuntime
+       ThreadStateRunning
+
+       threadStateCount
+)
+
+type frameNode struct {
+       id       int
+       children map[uint64]frameNode
+}
similarity index 60%
rename from src/cmd/internal/traceviewer/format.go
rename to src/internal/trace/traceviewer/format/format.go
index 3636c1053de04708d0d85782ace7275d7a24d173..83f32767042d3a95814545d29d4a29de907a1200 100644 (file)
@@ -7,7 +7,10 @@
 //
 // The official description of the format is in this file:
 // https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/preview
-package traceviewer
+//
+// Note: This can't be part of the parent traceviewer package as that would
+// throw. go_bootstrap cannot depend on the cgo version of package net in ./make.bash.
+package format
 
 type Data struct {
        Events   []*Event         `json:"traceEvents"`
@@ -36,3 +39,41 @@ type Frame struct {
        Name   string `json:"name"`
        Parent int    `json:"parent,omitempty"`
 }
+
+type NameArg struct {
+       Name string `json:"name"`
+}
+
+type BlockedArg struct {
+       Blocked string `json:"blocked"`
+}
+
+type SortIndexArg struct {
+       Index int `json:"sort_index"`
+}
+
+type HeapCountersArg struct {
+       Allocated uint64
+       NextGC    uint64
+}
+
+const (
+       ProcsSection = 0 // where Goroutines or per-P timelines are presented.
+       StatsSection = 1 // where counters are presented.
+       TasksSection = 2 // where Task hierarchy & timeline is presented.
+)
+
+type GoroutineCountersArg struct {
+       Running   uint64
+       Runnable  uint64
+       GCWaiting uint64
+}
+
+type ThreadCountersArg struct {
+       Running   int64
+       InSyscall int64
+}
+
+type ThreadIDArg struct {
+       ThreadID uint64
+}
diff --git a/src/internal/trace/traceviewer/http.go b/src/internal/trace/traceviewer/http.go
new file mode 100644 (file)
index 0000000..0c58535
--- /dev/null
@@ -0,0 +1,375 @@
+// 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.
+
+package traceviewer
+
+import (
+       "embed"
+       "fmt"
+       "html/template"
+       "net/http"
+       "strings"
+)
+
+func MainHandler(ranges []Range) http.Handler {
+       return http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
+               if err := templMain.Execute(w, ranges); err != nil {
+                       http.Error(w, err.Error(), http.StatusInternalServerError)
+                       return
+               }
+       })
+}
+
+var templMain = template.Must(template.New("").Parse(`
+<html>
+<style>
+/* See https://github.com/golang/pkgsite/blob/master/static/shared/typography/typography.css */
+body {
+  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji';
+  font-size:   1rem;
+  line-height: normal;
+  max-width:   9in;
+  margin:      1em;
+}
+h1 { font-size: 1.5rem; }
+h2 { font-size: 1.375rem; }
+h1,h2 {
+  font-weight: 600;
+  line-height: 1.25em;
+  word-break: break-word;
+}
+p  { color: grey85; font-size:85%; }
+</style>
+<body>
+<h1>cmd/trace: the Go trace event viewer</h1>
+<p>
+  This web server provides various visualizations of an event log gathered during
+  the execution of a Go program that uses the <a href='https://pkg.go.dev/runtime/trace'>runtime/trace</a> package.
+</p>
+
+<h2>Event timelines for running goroutines</h2>
+{{if $}}
+<p>
+  Large traces are split into multiple sections of equal data size
+  (not duration) to avoid overwhelming the visualizer.
+</p>
+<ul>
+       {{range $e := $}}
+               <li><a href="{{$e.URL}}">View trace ({{$e.Name}})</a></li>
+       {{end}}
+</ul>
+{{else}}
+<ul>
+       <li><a href="/trace">View trace</a></li>
+</ul>
+{{end}}
+<p>
+  This view displays a timeline for each of the GOMAXPROCS logical
+  processors, showing which goroutine (if any) was running on that
+  logical processor at each moment.
+
+  Each goroutine has an identifying number (e.g. G123), main function,
+  and color.
+
+  A colored bar represents an uninterrupted span of execution.
+
+  Execution of a goroutine may migrate from one logical processor to another,
+  causing a single colored bar to be horizontally continuous but
+  vertically displaced.
+</p>
+<p>
+  Clicking on a span reveals information about it, such as its
+  duration, its causal predecessors and successors, and the stack trace
+  at the final moment when it yielded the logical processor, for example
+  because it made a system call or tried to acquire a mutex.
+
+  Directly underneath each bar, a smaller bar or more commonly a fine
+  vertical line indicates an event occurring during its execution.
+  Some of these are related to garbage collection; most indicate that
+  a goroutine yielded its logical processor but then immediately resumed execution
+  on the same logical processor. Clicking on the event displays the stack trace
+  at the moment it occurred.
+</p>
+<p>
+  The causal relationships between spans of goroutine execution
+  can be displayed by clicking the Flow Events button at the top.
+</p>
+<p>
+  At the top ("STATS"), there are three additional timelines that
+  display statistical information.
+
+  "Goroutines" is a time series of the count of existing goroutines;
+  clicking on it displays their breakdown by state at that moment:
+  running, runnable, or waiting.
+
+  "Heap" is a time series of the amount of heap memory allocated (in orange)
+  and (in green) the allocation limit at which the next GC cycle will begin.
+
+  "Threads" shows the number of kernel threads in existence: there is
+  always one kernel thread per logical processor, and additional threads
+  are created for calls to non-Go code such as a system call or a
+  function written in C.
+</p>
+<p>
+  Above the event trace for the first logical processor are
+  traces for various runtime-internal events.
+
+  The "GC" bar shows when the garbage collector is running, and in which stage.
+  Garbage collection may temporarily affect all the logical processors
+  and the other metrics.
+
+  The "Network", "Timers", and "Syscalls" traces indicate events in
+  the runtime that cause goroutines to wake up.
+</p>
+<p>
+  The visualization allows you to navigate events at scales ranging from several
+  seconds to a handful of nanoseconds.
+
+  Consult the documentation for the Chromium <a href='https://www.chromium.org/developers/how-tos/trace-event-profiling-tool/'>Trace Event Profiling Tool<a/>
+  for help navigating the view.
+</p>
+
+<ul>
+<li><a href="/goroutines">Goroutine analysis</a></li>
+</ul>
+<p>
+  This view displays information about each set of goroutines that
+  shares the same main function.
+
+  Clicking on a main function shows links to the four types of
+  blocking profile (see below) applied to that subset of goroutines.
+
+  It also shows a table of specific goroutine instances, with various
+  execution statistics and a link to the event timeline for each one.
+
+  The timeline displays only the selected goroutine and any others it
+  interacts with via block/unblock events. (The timeline is
+  goroutine-oriented rather than logical processor-oriented.)
+</p>
+
+<h2>Profiles</h2>
+<p>
+  Each link below displays a global profile in zoomable graph form as
+  produced by <a href='https://go.dev/blog/pprof'>pprof</a>'s "web" command.
+
+  In addition there is a link to download the profile for offline
+  analysis with pprof.
+
+  All four profiles represent causes of delay that prevent a goroutine
+  from running on a logical processor: because it was waiting for the network,
+  for a synchronization operation on a mutex or channel, for a system call,
+  or for a logical processor to become available.
+</p>
+<ul>
+<li><a href="/io">Network blocking profile</a> (<a href="/io?raw=1" download="io.profile">⬇</a>)</li>
+<li><a href="/block">Synchronization blocking profile</a> (<a href="/block?raw=1" download="block.profile">⬇</a>)</li>
+<li><a href="/syscall">Syscall blocking profile</a> (<a href="/syscall?raw=1" download="syscall.profile">⬇</a>)</li>
+<li><a href="/sched">Scheduler latency profile</a> (<a href="/sched?raw=1" download="sched.profile">⬇</a>)</li>
+</ul>
+
+<h2>User-defined tasks and regions</h2>
+<p>
+  The trace API allows a target program to annotate a <a
+  href='https://pkg.go.dev/runtime/trace#Region'>region</a> of code
+  within a goroutine, such as a key function, so that its performance
+  can be analyzed.
+
+  <a href='https://pkg.go.dev/runtime/trace#Log'>Log events</a> may be
+  associated with a region to record progress and relevant values.
+
+  The API also allows annotation of higher-level
+  <a href='https://pkg.go.dev/runtime/trace#Task'>tasks</a>,
+  which may involve work across many goroutines.
+</p>
+<p>
+  The links below display, for each region and task, a histogram of its execution times.
+
+  Each histogram bucket contains a sample trace that records the
+  sequence of events such as goroutine creations, log events, and
+  subregion start/end times.
+
+  For each task, you can click through to a logical-processor or
+  goroutine-oriented view showing the tasks and regions on the
+  timeline.
+
+  Such information may help uncover which steps in a region are
+  unexpectedly slow, or reveal relationships between the data values
+  logged in a request and its running time.
+</p>
+<ul>
+<li><a href="/usertasks">User-defined tasks</a></li>
+<li><a href="/userregions">User-defined regions</a></li>
+</ul>
+
+<h2>Garbage collection metrics</h2>
+<ul>
+<li><a href="/mmu">Minimum mutator utilization</a></li>
+</ul>
+<p>
+  This chart indicates the maximum GC pause time (the largest x value
+  for which y is zero), and more generally, the fraction of time that
+  the processors are available to application goroutines ("mutators"),
+  for any time window of a specified size, in the worst case.
+</p>
+</body>
+</html>
+`))
+
+type Range struct {
+       Name      string
+       Start     int
+       End       int
+       StartTime int64
+       EndTime   int64
+}
+
+func (r Range) URL() string {
+       return fmt.Sprintf("/trace?start=%d&end=%d", r.Start, r.End)
+}
+
+func TraceHandler() http.Handler {
+       return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+               if err := r.ParseForm(); err != nil {
+                       http.Error(w, err.Error(), http.StatusInternalServerError)
+                       return
+               }
+               html := strings.ReplaceAll(templTrace, "{{PARAMS}}", r.Form.Encode())
+               w.Write([]byte(html))
+       })
+}
+
+// https://chromium.googlesource.com/catapult/+/9508452e18f130c98499cb4c4f1e1efaedee8962/tracing/docs/embedding-trace-viewer.md
+// This is almost verbatim copy of https://chromium-review.googlesource.com/c/catapult/+/2062938/2/tracing/bin/index.html
+var templTrace = `
+<html>
+<head>
+<script src="/static/webcomponents.min.js"></script>
+<script>
+'use strict';
+
+function onTraceViewerImportFail() {
+  document.addEventListener('DOMContentLoaded', function() {
+    document.body.textContent =
+    '/static/trace_viewer_full.html is missing. File a bug in https://golang.org/issue';
+  });
+}
+</script>
+
+<link rel="import" href="/static/trace_viewer_full.html"
+      onerror="onTraceViewerImportFail(event)">
+
+<style type="text/css">
+  html, body {
+    box-sizing: border-box;
+    overflow: hidden;
+    margin: 0px;
+    padding: 0;
+    width: 100%;
+    height: 100%;
+  }
+  #trace-viewer {
+    width: 100%;
+    height: 100%;
+  }
+  #trace-viewer:focus {
+    outline: none;
+  }
+</style>
+<script>
+'use strict';
+(function() {
+  var viewer;
+  var url;
+  var model;
+
+  function load() {
+    var req = new XMLHttpRequest();
+    var isBinary = /[.]gz$/.test(url) || /[.]zip$/.test(url);
+    req.overrideMimeType('text/plain; charset=x-user-defined');
+    req.open('GET', url, true);
+    if (isBinary)
+      req.responseType = 'arraybuffer';
+
+    req.onreadystatechange = function(event) {
+      if (req.readyState !== 4)
+        return;
+
+      window.setTimeout(function() {
+        if (req.status === 200)
+          onResult(isBinary ? req.response : req.responseText);
+        else
+          onResultFail(req.status);
+      }, 0);
+    };
+    req.send(null);
+  }
+
+  function onResultFail(err) {
+    var overlay = new tr.ui.b.Overlay();
+    overlay.textContent = err + ': ' + url + ' could not be loaded';
+    overlay.title = 'Failed to fetch data';
+    overlay.visible = true;
+  }
+
+  function onResult(result) {
+    model = new tr.Model();
+    var opts = new tr.importer.ImportOptions();
+    opts.shiftWorldToZero = false;
+    var i = new tr.importer.Import(model, opts);
+    var p = i.importTracesWithProgressDialog([result]);
+    p.then(onModelLoaded, onImportFail);
+  }
+
+  function onModelLoaded() {
+    viewer.model = model;
+    viewer.viewTitle = "trace";
+
+    if (!model || model.bounds.isEmpty)
+      return;
+    var sel = window.location.hash.substr(1);
+    if (sel === '')
+      return;
+    var parts = sel.split(':');
+    var range = new (tr.b.Range || tr.b.math.Range)();
+    range.addValue(parseFloat(parts[0]));
+    range.addValue(parseFloat(parts[1]));
+    viewer.trackView.viewport.interestRange.set(range);
+  }
+
+  function onImportFail(err) {
+    var overlay = new tr.ui.b.Overlay();
+    overlay.textContent = tr.b.normalizeException(err).message;
+    overlay.title = 'Import error';
+    overlay.visible = true;
+  }
+
+  document.addEventListener('WebComponentsReady', function() {
+    var container = document.createElement('track-view-container');
+    container.id = 'track_view_container';
+
+    viewer = document.createElement('tr-ui-timeline-view');
+    viewer.track_view_container = container;
+    Polymer.dom(viewer).appendChild(container);
+
+    viewer.id = 'trace-viewer';
+    viewer.globalMode = true;
+    Polymer.dom(document.body).appendChild(viewer);
+
+    url = '/jsontrace?{{PARAMS}}';
+    load();
+  });
+}());
+</script>
+</head>
+<body>
+</body>
+</html>
+`
+
+//go:embed static/trace_viewer_full.html static/webcomponents.min.js
+var staticContent embed.FS
+
+func StaticHandler() http.Handler {
+       return http.FileServer(http.FS(staticContent))
+}
index bb4df8469e48103819bf2b95015d620285918d24..28189f80db85de5340a97e6083614a85300b872b 100644 (file)
@@ -16,7 +16,8 @@ import (
 type Version uint32
 
 const (
-       Go122 Version = 22
+       Go122   Version = 22
+       Current         = Go122
 )
 
 var versions = map[Version][]event.Spec{