1
2
3
4
5 package trace
6
7 import (
8 "fmt"
9 "internal/trace"
10 "internal/trace/traceviewer"
11 tracev2 "internal/trace/v2"
12 "io"
13 "log"
14 "net"
15 "net/http"
16 "os"
17
18 "internal/trace/v2/raw"
19
20 "cmd/internal/browser"
21 )
22
23
24 func Main(traceFile, httpAddr, pprof string, debug int) error {
25 tracef, err := os.Open(traceFile)
26 if err != nil {
27 return fmt.Errorf("failed to read trace file: %w", err)
28 }
29 defer tracef.Close()
30
31
32 switch debug {
33 case 1:
34 return debugProcessedEvents(tracef)
35 case 2:
36 return debugRawEvents(tracef)
37 }
38
39 ln, err := net.Listen("tcp", httpAddr)
40 if err != nil {
41 return fmt.Errorf("failed to create server socket: %w", err)
42 }
43 addr := "http://" + ln.Addr().String()
44
45 log.Print("Preparing trace for viewer...")
46 parsed, err := parseTrace(tracef)
47 if err != nil {
48 return err
49 }
50
51
52 tracef.Close()
53
54 log.Print("Splitting trace for viewer...")
55 ranges, err := splitTrace(parsed)
56 if err != nil {
57 return err
58 }
59
60 log.Printf("Opening browser. Trace viewer is listening on %s", addr)
61 browser.Open(addr)
62
63 mutatorUtil := func(flags trace.UtilFlags) ([][]trace.MutatorUtil, error) {
64 return trace.MutatorUtilizationV2(parsed.events, flags), nil
65 }
66
67 mux := http.NewServeMux()
68
69
70 mux.Handle("/", traceviewer.MainHandler([]traceviewer.View{
71 {Type: traceviewer.ViewProc, Ranges: ranges},
72
73
74
75 {Type: traceviewer.ViewThread, Ranges: ranges},
76 }))
77
78
79 mux.Handle("/trace", traceviewer.TraceHandler())
80 mux.Handle("/jsontrace", JSONTraceHandler(parsed))
81 mux.Handle("/static/", traceviewer.StaticHandler())
82
83
84 mux.HandleFunc("/goroutines", GoroutinesHandlerFunc(parsed.summary.Goroutines))
85 mux.HandleFunc("/goroutine", GoroutineHandler(parsed.summary.Goroutines))
86
87
88 mux.HandleFunc("/mmu", traceviewer.MMUHandlerFunc(ranges, mutatorUtil))
89
90
91 mux.HandleFunc("/io", traceviewer.SVGProfileHandlerFunc(pprofByGoroutine(computePprofIO(), parsed)))
92 mux.HandleFunc("/block", traceviewer.SVGProfileHandlerFunc(pprofByGoroutine(computePprofBlock(), parsed)))
93 mux.HandleFunc("/syscall", traceviewer.SVGProfileHandlerFunc(pprofByGoroutine(computePprofSyscall(), parsed)))
94 mux.HandleFunc("/sched", traceviewer.SVGProfileHandlerFunc(pprofByGoroutine(computePprofSched(), parsed)))
95
96
97 mux.HandleFunc("/regionio", traceviewer.SVGProfileHandlerFunc(pprofByRegion(computePprofIO(), parsed)))
98 mux.HandleFunc("/regionblock", traceviewer.SVGProfileHandlerFunc(pprofByRegion(computePprofBlock(), parsed)))
99 mux.HandleFunc("/regionsyscall", traceviewer.SVGProfileHandlerFunc(pprofByRegion(computePprofSyscall(), parsed)))
100 mux.HandleFunc("/regionsched", traceviewer.SVGProfileHandlerFunc(pprofByRegion(computePprofSched(), parsed)))
101
102
103 mux.HandleFunc("/userregions", UserRegionsHandlerFunc(parsed))
104 mux.HandleFunc("/userregion", UserRegionHandlerFunc(parsed))
105
106
107 mux.HandleFunc("/usertasks", UserTasksHandlerFunc(parsed))
108 mux.HandleFunc("/usertask", UserTaskHandlerFunc(parsed))
109
110 err = http.Serve(ln, mux)
111 return fmt.Errorf("failed to start http server: %w", err)
112 }
113
114 type parsedTrace struct {
115 events []tracev2.Event
116 summary *trace.Summary
117 }
118
119 func parseTrace(tr io.Reader) (*parsedTrace, error) {
120 r, err := tracev2.NewReader(tr)
121 if err != nil {
122 return nil, fmt.Errorf("failed to create trace reader: %w", err)
123 }
124 s := trace.NewSummarizer()
125 t := new(parsedTrace)
126 for {
127 ev, err := r.ReadEvent()
128 if err == io.EOF {
129 break
130 } else if err != nil {
131 return nil, fmt.Errorf("failed to read event: %w", err)
132 }
133 t.events = append(t.events, ev)
134 s.Event(&t.events[len(t.events)-1])
135 }
136 t.summary = s.Finalize()
137 return t, nil
138 }
139
140 func (t *parsedTrace) startTime() tracev2.Time {
141 return t.events[0].Time()
142 }
143
144 func (t *parsedTrace) endTime() tracev2.Time {
145 return t.events[len(t.events)-1].Time()
146 }
147
148
149
150 func splitTrace(parsed *parsedTrace) ([]traceviewer.Range, error) {
151
152
153 s, c := traceviewer.SplittingTraceConsumer(100 << 20)
154 if err := generateTrace(parsed, defaultGenOpts(), c); err != nil {
155 return nil, err
156 }
157 return s.Ranges, nil
158 }
159
160 func debugProcessedEvents(trace io.Reader) error {
161 tr, err := tracev2.NewReader(trace)
162 if err != nil {
163 return err
164 }
165 for {
166 ev, err := tr.ReadEvent()
167 if err == io.EOF {
168 return nil
169 } else if err != nil {
170 return err
171 }
172 fmt.Println(ev.String())
173 }
174 }
175
176 func debugRawEvents(trace io.Reader) error {
177 rr, err := raw.NewReader(trace)
178 if err != nil {
179 return err
180 }
181 for {
182 ev, err := rr.ReadEvent()
183 if err == io.EOF {
184 return nil
185 } else if err != nil {
186 return err
187 }
188 fmt.Println(ev.String())
189 }
190 }
191
View as plain text