Source file
src/cmd/dist/debugtrace.go
1
2
3
4
5 package main
6
7 import (
8 "encoding/json"
9 "io"
10 "os"
11 "strings"
12 "sync"
13 "time"
14 )
15
16 var (
17 debugTrace string
18 debugTraceAppend bool
19 traceMu sync.Mutex
20 debugTraces []string
21 distEvents []*traceEvent
22 )
23
24
25
26
27
28
29
30 type traceEvent struct {
31 Name string `json:"name,omitempty"`
32 Phase string `json:"ph"`
33 Time float64 `json:"ts"`
34 PID uint64 `json:"pid"`
35 TID uint64 `json:"tid"`
36 }
37
38 func maybeTraceFlag(name string) []string {
39 if debugTrace == "" {
40 return nil
41 }
42 f := pathf("%s/%s.trace", workdir, name)
43 debugTraces = append(debugTraces, f)
44 return []string{"-debug-trace=" + f}
45 }
46
47 func timeMicros(t time.Time) float64 {
48 return float64(t.UnixNano()) / float64(time.Microsecond)
49 }
50
51 type span struct {
52 name string
53 tid uint64
54 }
55
56 func startSpan(name string) span {
57 return startSpanTID(name, 0)
58 }
59
60 func startSpanTID(name string, tid uint64) span {
61 if debugTrace == "" {
62 return span{}
63 }
64 traceMu.Lock()
65 distEvents = append(distEvents, &traceEvent{Name: name, Phase: "B", Time: timeMicros(time.Now()), TID: tid})
66 traceMu.Unlock()
67 return span{name: name, tid: tid}
68 }
69
70 func (s span) done() {
71 if s.name == "" {
72 return
73 }
74 traceMu.Lock()
75 distEvents = append(distEvents, &traceEvent{Name: s.name, Phase: "E", Time: timeMicros(time.Now()), TID: s.tid})
76 traceMu.Unlock()
77 }
78
79
80
81
82 func writeTrace() {
83 var f *os.File
84 var err error
85 if debugTraceAppend {
86 f, err = os.OpenFile(debugTrace, os.O_RDWR|os.O_CREATE, 0o777)
87 if err != nil {
88 fatalf("open trace file for read/write: %v", err)
89 }
90 ok := func() bool {
91
92 fi, err := f.Stat()
93 if err != nil {
94 return false
95 }
96 size := fi.Size()
97 var lastTwo [2]byte
98 if size < 2 {
99 return false
100 }
101 if _, err := f.ReadAt(lastTwo[:], size-2); err != nil {
102 return false
103 }
104 if lastTwo != [2]byte{']', '\n'} {
105 return false
106 }
107 if _, err = f.Seek(-2, io.SeekEnd); err != nil {
108 return false
109 }
110 if _, err = f.WriteString(",\n"); err != nil {
111 return false
112 }
113 return true
114 }()
115 if !ok {
116 if err = f.Truncate(0); err != nil {
117 fatalf("failed to truncate trace file for writing: %v", err)
118 }
119 f.Seek(0, io.SeekStart)
120 f.WriteString("[\n")
121 }
122 } else {
123
124 f, err = os.Create(debugTrace)
125 if err != nil {
126 fatalf("opening trace file for write: %v", err)
127 }
128 f.WriteString("[\n")
129 }
130
131 enc := json.NewEncoder(f)
132 for _, ev := range distEvents {
133 if err := enc.Encode(ev); err != nil {
134 fatalf("marshaling trace event: %v", err)
135 }
136 f.WriteString(",")
137 }
138
139 for i, name := range debugTraces {
140 data, err := os.ReadFile(name)
141 if err != nil {
142 fatalf("reading trace file: %v", err)
143 }
144
145 events := strings.TrimSpace(string(data))
146 events = strings.TrimSuffix(strings.TrimPrefix(events, "["), "]")
147 f.WriteString(events)
148 if i != len(debugTraces)-1 {
149 f.WriteString(",")
150 }
151 }
152
153 f.WriteString("]\n")
154 if err := f.Close(); err != nil {
155 fatalf("closing trace file: %v", err)
156 }
157 }
158
View as plain text