github.com/c9s/go@v0.0.0-20180120015821-984e81f64e0c/src/cmd/trace/main.go (about) 1 // Copyright 2014 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package main 6 7 import ( 8 "bufio" 9 "cmd/internal/browser" 10 "flag" 11 "fmt" 12 "html/template" 13 "internal/trace" 14 "io" 15 "log" 16 "net" 17 "net/http" 18 "os" 19 "sync" 20 ) 21 22 const usageMessage = "" + 23 `Usage of 'go tool trace': 24 Given a trace file produced by 'go test': 25 go test -trace=trace.out pkg 26 27 Open a web browser displaying trace: 28 go tool trace [flags] [pkg.test] trace.out 29 30 Generate a pprof-like profile from the trace: 31 go tool trace -pprof=TYPE [pkg.test] trace.out 32 33 [pkg.test] argument is required for traces produced by Go 1.6 and below. 34 Go 1.7 does not require the binary argument. 35 36 Supported profile types are: 37 - net: network blocking profile 38 - sync: synchronization blocking profile 39 - syscall: syscall blocking profile 40 - sched: scheduler latency profile 41 42 Flags: 43 -http=addr: HTTP service address (e.g., ':6060') 44 -pprof=type: print a pprof-like profile instead 45 -d: print debug info such as parsed events 46 47 Note that while the various profiles available when launching 48 'go tool trace' work on every browser, the trace viewer itself 49 (the 'view trace' page) comes from the Chrome/Chromium project 50 and is only actively tested on that browser. 51 ` 52 53 var ( 54 httpFlag = flag.String("http", "localhost:0", "HTTP service address (e.g., ':6060')") 55 pprofFlag = flag.String("pprof", "", "print a pprof-like profile instead") 56 debugFlag = flag.Bool("d", false, "print debug information such as parsed events list") 57 58 // The binary file name, left here for serveSVGProfile. 59 programBinary string 60 traceFile string 61 ) 62 63 func main() { 64 flag.Usage = func() { 65 fmt.Fprintln(os.Stderr, usageMessage) 66 os.Exit(2) 67 } 68 flag.Parse() 69 70 // Go 1.7 traces embed symbol info and does not require the binary. 71 // But we optionally accept binary as first arg for Go 1.5 traces. 72 switch flag.NArg() { 73 case 1: 74 traceFile = flag.Arg(0) 75 case 2: 76 programBinary = flag.Arg(0) 77 traceFile = flag.Arg(1) 78 default: 79 flag.Usage() 80 } 81 82 var pprofFunc func(io.Writer, string) error 83 switch *pprofFlag { 84 case "net": 85 pprofFunc = pprofIO 86 case "sync": 87 pprofFunc = pprofBlock 88 case "syscall": 89 pprofFunc = pprofSyscall 90 case "sched": 91 pprofFunc = pprofSched 92 } 93 if pprofFunc != nil { 94 if err := pprofFunc(os.Stdout, ""); err != nil { 95 dief("failed to generate pprof: %v\n", err) 96 } 97 os.Exit(0) 98 } 99 if *pprofFlag != "" { 100 dief("unknown pprof type %s\n", *pprofFlag) 101 } 102 103 ln, err := net.Listen("tcp", *httpFlag) 104 if err != nil { 105 dief("failed to create server socket: %v\n", err) 106 } 107 108 log.Print("Parsing trace...") 109 res, err := parseTrace() 110 if err != nil { 111 dief("%v\n", err) 112 } 113 114 if *debugFlag { 115 trace.Print(res.Events) 116 os.Exit(0) 117 } 118 119 log.Print("Serializing trace...") 120 params := &traceParams{ 121 parsed: res, 122 endTime: int64(1<<63 - 1), 123 } 124 data, err := generateTrace(params) 125 if err != nil { 126 dief("%v\n", err) 127 } 128 129 log.Print("Splitting trace...") 130 ranges = splitTrace(data) 131 132 addr := "http://" + ln.Addr().String() 133 log.Printf("Opening browser. Trace viewer is listening on %s", addr) 134 browser.Open(addr) 135 136 // Start http server. 137 http.HandleFunc("/", httpMain) 138 err = http.Serve(ln, nil) 139 dief("failed to start http server: %v\n", err) 140 } 141 142 var ranges []Range 143 144 var loader struct { 145 once sync.Once 146 res trace.ParseResult 147 err error 148 } 149 150 // parseEvents is a compatibility wrapper that returns only 151 // the Events part of trace.ParseResult returned by parseTrace. 152 func parseEvents() ([]*trace.Event, error) { 153 res, err := parseTrace() 154 if err != nil { 155 return nil, err 156 } 157 return res.Events, err 158 } 159 160 func parseTrace() (trace.ParseResult, error) { 161 loader.once.Do(func() { 162 tracef, err := os.Open(traceFile) 163 if err != nil { 164 loader.err = fmt.Errorf("failed to open trace file: %v", err) 165 return 166 } 167 defer tracef.Close() 168 169 // Parse and symbolize. 170 res, err := trace.Parse(bufio.NewReader(tracef), programBinary) 171 if err != nil { 172 loader.err = fmt.Errorf("failed to parse trace: %v", err) 173 return 174 } 175 loader.res = res 176 }) 177 return loader.res, loader.err 178 } 179 180 // httpMain serves the starting page. 181 func httpMain(w http.ResponseWriter, r *http.Request) { 182 if err := templMain.Execute(w, ranges); err != nil { 183 http.Error(w, err.Error(), http.StatusInternalServerError) 184 return 185 } 186 } 187 188 var templMain = template.Must(template.New("").Parse(` 189 <html> 190 <body> 191 {{if $}} 192 {{range $e := $}} 193 <a href="/trace?start={{$e.Start}}&end={{$e.End}}">View trace ({{$e.Name}})</a><br> 194 {{end}} 195 <br> 196 {{else}} 197 <a href="/trace">View trace</a><br> 198 {{end}} 199 <a href="/goroutines">Goroutine analysis</a><br> 200 <a href="/io">Network blocking profile</a> (<a href="/io?raw=1" download="io.profile">⬇</a>)<br> 201 <a href="/block">Synchronization blocking profile</a> (<a href="/block?raw=1" download="block.profile">⬇</a>)<br> 202 <a href="/syscall">Syscall blocking profile</a> (<a href="/syscall?raw=1" download="syscall.profile">⬇</a>)<br> 203 <a href="/sched">Scheduler latency profile</a> (<a href="/sche?raw=1" download="sched.profile">⬇</a>)<br> 204 </body> 205 </html> 206 `)) 207 208 func dief(msg string, args ...interface{}) { 209 fmt.Fprintf(os.Stderr, msg, args...) 210 os.Exit(1) 211 }