github.com/hlts2/go@v0.0.0-20170904000733-812b34efaed8/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) 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 events, err := parseEvents() 110 if err != nil { 111 dief("%v\n", err) 112 } 113 114 if *debugFlag { 115 trace.Print(events) 116 os.Exit(0) 117 } 118 119 log.Print("Serializing trace...") 120 params := &traceParams{ 121 events: events, 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 events []*trace.Event 147 err error 148 } 149 150 func parseEvents() ([]*trace.Event, error) { 151 loader.once.Do(func() { 152 tracef, err := os.Open(traceFile) 153 if err != nil { 154 loader.err = fmt.Errorf("failed to open trace file: %v", err) 155 return 156 } 157 defer tracef.Close() 158 159 // Parse and symbolize. 160 events, err := trace.Parse(bufio.NewReader(tracef), programBinary) 161 if err != nil { 162 loader.err = fmt.Errorf("failed to parse trace: %v", err) 163 return 164 } 165 loader.events = events 166 }) 167 return loader.events, loader.err 168 } 169 170 // httpMain serves the starting page. 171 func httpMain(w http.ResponseWriter, r *http.Request) { 172 if err := templMain.Execute(w, ranges); err != nil { 173 http.Error(w, err.Error(), http.StatusInternalServerError) 174 return 175 } 176 } 177 178 var templMain = template.Must(template.New("").Parse(` 179 <html> 180 <body> 181 {{if $}} 182 {{range $e := $}} 183 <a href="/trace?start={{$e.Start}}&end={{$e.End}}">View trace ({{$e.Name}})</a><br> 184 {{end}} 185 <br> 186 {{else}} 187 <a href="/trace">View trace</a><br> 188 {{end}} 189 <a href="/goroutines">Goroutine analysis</a><br> 190 <a href="/io">Network blocking profile</a><br> 191 <a href="/block">Synchronization blocking profile</a><br> 192 <a href="/syscall">Syscall blocking profile</a><br> 193 <a href="/sched">Scheduler latency profile</a><br> 194 </body> 195 </html> 196 `)) 197 198 func dief(msg string, args ...interface{}) { 199 fmt.Fprintf(os.Stderr, msg, args...) 200 os.Exit(1) 201 }