blob: 223b06367663840bc4b65b96bfcd840c087e252b [file]
// Copyright 2026 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 (
"encoding/json"
"os"
"strings"
"time"
)
var (
debugTrace string
debugTraces []string
distEvents []*traceEvent
)
// This is a subset of the fields on internal/trace/traceviewer/format.go,
// which we can't use here because it's an internal package and cmd/dist
// needs to be buildable using another Go toolchain. That struct is in turn
// used to represent the Chrome Trace Viewer JSON format whose canonical
// documentation is this Google doc:
// https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/preview
type traceEvent struct {
Name string `json:"name,omitempty"`
Phase string `json:"ph"`
Time float64 `json:"ts"`
PID uint64 `json:"pid"`
TID uint64 `json:"tid"`
}
func maybeTraceFlag(name string) []string {
if debugTrace == "" {
return nil
}
f := pathf("%s/%s.trace", workdir, name)
debugTraces = append(debugTraces, f)
return []string{"-debug-trace=" + f}
}
func timeMicros(t time.Time) float64 {
return float64(t.UnixNano()) / float64(time.Microsecond)
}
type span string
func startSpan(name string) span {
if debugTrace == "" {
return ""
}
distEvents = append(distEvents, &traceEvent{Name: name, Phase: "B", Time: timeMicros(time.Now())})
return span(name)
}
func (s span) done() {
if s == "" {
return
}
distEvents = append(distEvents, &traceEvent{Name: string(s), Phase: "E", Time: timeMicros(time.Now())})
}
// writeTrace merges the -debug-trace outputs from the go command invocations and adds
// dist's own trace events in too. Because the traces have absolute timpstamps, we can
// essentially just concatenate them.
func writeTrace() {
f, err := os.Create(debugTrace)
if err != nil {
fatalf("opening trace file for write: %v", err)
}
f.WriteString("[\n")
enc := json.NewEncoder(f)
for _, ev := range distEvents {
if err := enc.Encode(ev); err != nil {
fatalf("marshaling trace event: %v", err)
}
f.WriteString(",")
}
for i, name := range debugTraces {
data, err := os.ReadFile(name)
if err != nil {
fatalf("reading trace file: %v", err)
}
// The trace is a json list: trim the start and end brackets.
events := strings.TrimSpace(string(data))
events = strings.TrimSuffix(strings.TrimPrefix(events, "["), "]")
f.WriteString(events)
if i != len(debugTraces)-1 {
f.WriteString(",")
}
}
f.WriteString("]\n")
if err := f.Close(); err != nil {
fatalf("closing trace file: %v", err)
}
}