github.com/euank/go@v0.0.0-20160829210321-495514729181/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 /* 6 Trace is a tool for viewing trace files. 7 8 Trace files can be generated with: 9 - runtime/trace.Start 10 - net/http/pprof package 11 - go test -trace 12 13 Example usage: 14 Generate a trace file with 'go test': 15 go test -trace trace.out pkg 16 View the trace in a web browser: 17 go tool trace trace.out 18 */ 19 package main 20 21 import ( 22 "bufio" 23 "flag" 24 "fmt" 25 "html/template" 26 "internal/trace" 27 "log" 28 "net" 29 "net/http" 30 "os" 31 "os/exec" 32 "runtime" 33 "sync" 34 ) 35 36 const usageMessage = "" + 37 `Usage of 'go tool trace': 38 Given a trace file produced by 'go test': 39 go test -trace=trace.out pkg 40 41 Open a web browser displaying trace: 42 go tool trace [flags] [pkg.test] trace.out 43 [pkg.test] argument is required for traces produced by Go 1.6 and below. 44 Go 1.7 does not require the binary argument. 45 46 Flags: 47 -http=addr: HTTP service address (e.g., ':6060') 48 ` 49 50 var ( 51 httpFlag = flag.String("http", "localhost:0", "HTTP service address (e.g., ':6060')") 52 53 // The binary file name, left here for serveSVGProfile. 54 programBinary string 55 traceFile string 56 ) 57 58 func main() { 59 flag.Usage = func() { 60 fmt.Fprintln(os.Stderr, usageMessage) 61 os.Exit(2) 62 } 63 flag.Parse() 64 65 // Go 1.7 traces embed symbol info and does not require the binary. 66 // But we optionally accept binary as first arg for Go 1.5 traces. 67 switch flag.NArg() { 68 case 1: 69 traceFile = flag.Arg(0) 70 case 2: 71 programBinary = flag.Arg(0) 72 traceFile = flag.Arg(1) 73 default: 74 flag.Usage() 75 } 76 77 ln, err := net.Listen("tcp", *httpFlag) 78 if err != nil { 79 dief("failed to create server socket: %v\n", err) 80 } 81 82 log.Printf("Parsing trace...") 83 events, err := parseEvents() 84 if err != nil { 85 dief("%v\n", err) 86 } 87 88 log.Printf("Serializing trace...") 89 params := &traceParams{ 90 events: events, 91 endTime: int64(1<<63 - 1), 92 } 93 data := generateTrace(params) 94 95 log.Printf("Splitting trace...") 96 ranges = splitTrace(data) 97 98 log.Printf("Opening browser") 99 if !startBrowser("http://" + ln.Addr().String()) { 100 fmt.Fprintf(os.Stderr, "Trace viewer is listening on http://%s\n", ln.Addr().String()) 101 } 102 103 // Start http server. 104 http.HandleFunc("/", httpMain) 105 err = http.Serve(ln, nil) 106 dief("failed to start http server: %v\n", err) 107 } 108 109 var ranges []Range 110 111 var loader struct { 112 once sync.Once 113 events []*trace.Event 114 err error 115 } 116 117 func parseEvents() ([]*trace.Event, error) { 118 loader.once.Do(func() { 119 tracef, err := os.Open(traceFile) 120 if err != nil { 121 loader.err = fmt.Errorf("failed to open trace file: %v", err) 122 return 123 } 124 defer tracef.Close() 125 126 // Parse and symbolize. 127 events, err := trace.Parse(bufio.NewReader(tracef), programBinary) 128 if err != nil { 129 loader.err = fmt.Errorf("failed to parse trace: %v", err) 130 return 131 } 132 loader.events = events 133 }) 134 return loader.events, loader.err 135 } 136 137 // httpMain serves the starting page. 138 func httpMain(w http.ResponseWriter, r *http.Request) { 139 if err := templMain.Execute(w, ranges); err != nil { 140 http.Error(w, err.Error(), http.StatusInternalServerError) 141 return 142 } 143 } 144 145 var templMain = template.Must(template.New("").Parse(` 146 <html> 147 <body> 148 {{if $}} 149 {{range $e := $}} 150 <a href="/trace?start={{$e.Start}}&end={{$e.End}}">View trace ({{$e.Name}})</a><br> 151 {{end}} 152 <br> 153 {{else}} 154 <a href="/trace">View trace</a><br> 155 {{end}} 156 <a href="/goroutines">Goroutine analysis</a><br> 157 <a href="/io">Network blocking profile</a><br> 158 <a href="/block">Synchronization blocking profile</a><br> 159 <a href="/syscall">Syscall blocking profile</a><br> 160 <a href="/sched">Scheduler latency profile</a><br> 161 </body> 162 </html> 163 `)) 164 165 // startBrowser tries to open the URL in a browser 166 // and reports whether it succeeds. 167 // Note: copied from x/tools/cmd/cover/html.go 168 func startBrowser(url string) bool { 169 // try to start the browser 170 var args []string 171 switch runtime.GOOS { 172 case "darwin": 173 args = []string{"open"} 174 case "windows": 175 args = []string{"cmd", "/c", "start"} 176 default: 177 args = []string{"xdg-open"} 178 } 179 cmd := exec.Command(args[0], append(args[1:], url)...) 180 return cmd.Start() == nil 181 } 182 183 func dief(msg string, args ...interface{}) { 184 fmt.Fprintf(os.Stderr, msg, args...) 185 os.Exit(1) 186 }