github.com/MangoDowner/go-gm@v0.0.0-20180818020936-8baa2bd4408c/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 46 Note that while the various profiles available when launching 47 'go tool trace' work on every browser, the trace viewer itself 48 (the 'view trace' page) comes from the Chrome/Chromium project 49 and is only actively tested on that browser. 50 ` 51 52 var ( 53 httpFlag = flag.String("http", "localhost:0", "HTTP service address (e.g., ':6060')") 54 pprofFlag = flag.String("pprof", "", "print a pprof-like profile instead") 55 56 // The binary file name, left here for serveSVGProfile. 57 programBinary string 58 traceFile string 59 ) 60 61 func main() { 62 flag.Usage = func() { 63 fmt.Fprintln(os.Stderr, usageMessage) 64 os.Exit(2) 65 } 66 flag.Parse() 67 68 // Go 1.7 traces embed symbol info and does not require the binary. 69 // But we optionally accept binary as first arg for Go 1.5 traces. 70 switch flag.NArg() { 71 case 1: 72 traceFile = flag.Arg(0) 73 case 2: 74 programBinary = flag.Arg(0) 75 traceFile = flag.Arg(1) 76 default: 77 flag.Usage() 78 } 79 80 var pprofFunc func(io.Writer) error 81 switch *pprofFlag { 82 case "net": 83 pprofFunc = pprofIO 84 case "sync": 85 pprofFunc = pprofBlock 86 case "syscall": 87 pprofFunc = pprofSyscall 88 case "sched": 89 pprofFunc = pprofSched 90 } 91 if pprofFunc != nil { 92 if err := pprofFunc(os.Stdout); err != nil { 93 dief("failed to generate pprof: %v\n", err) 94 } 95 os.Exit(0) 96 } 97 if *pprofFlag != "" { 98 dief("unknown pprof type %s\n", *pprofFlag) 99 } 100 101 ln, err := net.Listen("tcp", *httpFlag) 102 if err != nil { 103 dief("failed to create server socket: %v\n", err) 104 } 105 106 log.Printf("Parsing trace...") 107 events, err := parseEvents() 108 if err != nil { 109 dief("%v\n", err) 110 } 111 112 log.Printf("Serializing trace...") 113 params := &traceParams{ 114 events: events, 115 endTime: int64(1<<63 - 1), 116 } 117 data, err := generateTrace(params) 118 if err != nil { 119 dief("%v\n", err) 120 } 121 122 log.Printf("Splitting trace...") 123 ranges = splitTrace(data) 124 125 log.Printf("Opening browser") 126 if !browser.Open("http://" + ln.Addr().String()) { 127 fmt.Fprintf(os.Stderr, "Trace viewer is listening on http://%s\n", ln.Addr().String()) 128 } 129 130 // Start http server. 131 http.HandleFunc("/", httpMain) 132 err = http.Serve(ln, nil) 133 dief("failed to start http server: %v\n", err) 134 } 135 136 var ranges []Range 137 138 var loader struct { 139 once sync.Once 140 events []*trace.Event 141 err error 142 } 143 144 func parseEvents() ([]*trace.Event, error) { 145 loader.once.Do(func() { 146 tracef, err := os.Open(traceFile) 147 if err != nil { 148 loader.err = fmt.Errorf("failed to open trace file: %v", err) 149 return 150 } 151 defer tracef.Close() 152 153 // Parse and symbolize. 154 events, err := trace.Parse(bufio.NewReader(tracef), programBinary) 155 if err != nil { 156 loader.err = fmt.Errorf("failed to parse trace: %v", err) 157 return 158 } 159 loader.events = events 160 }) 161 return loader.events, loader.err 162 } 163 164 // httpMain serves the starting page. 165 func httpMain(w http.ResponseWriter, r *http.Request) { 166 if err := templMain.Execute(w, ranges); err != nil { 167 http.Error(w, err.Error(), http.StatusInternalServerError) 168 return 169 } 170 } 171 172 var templMain = template.Must(template.New("").Parse(` 173 <html> 174 <body> 175 {{if $}} 176 {{range $e := $}} 177 <a href="/trace?start={{$e.Start}}&end={{$e.End}}">View trace ({{$e.Name}})</a><br> 178 {{end}} 179 <br> 180 {{else}} 181 <a href="/trace">View trace</a><br> 182 {{end}} 183 <a href="/goroutines">Goroutine analysis</a><br> 184 <a href="/io">Network blocking profile</a><br> 185 <a href="/block">Synchronization blocking profile</a><br> 186 <a href="/syscall">Syscall blocking profile</a><br> 187 <a href="/sched">Scheduler latency profile</a><br> 188 </body> 189 </html> 190 `)) 191 192 func dief(msg string, args ...interface{}) { 193 fmt.Fprintf(os.Stderr, msg, args...) 194 os.Exit(1) 195 }