github.com/megatontech/mynoteforgo@v0.0.0-20200507084910-5d0c6ea6e890/源码/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 "runtime" 20 "runtime/debug" 21 "sync" 22 23 _ "net/http/pprof" // Required to use pprof 24 ) 25 26 const usageMessage = "" + 27 `Usage of 'go tool trace': 28 Given a trace file produced by 'go test': 29 go test -trace=trace.out pkg 30 31 Open a web browser displaying trace: 32 go tool trace [flags] [pkg.test] trace.out 33 34 Generate a pprof-like profile from the trace: 35 go tool trace -pprof=TYPE [pkg.test] trace.out 36 37 [pkg.test] argument is required for traces produced by Go 1.6 and below. 38 Go 1.7 does not require the binary argument. 39 40 Supported profile types are: 41 - net: network blocking profile 42 - sync: synchronization blocking profile 43 - syscall: syscall blocking profile 44 - sched: scheduler latency profile 45 46 Flags: 47 -http=addr: HTTP service address (e.g., ':6060') 48 -pprof=type: print a pprof-like profile instead 49 -d: print debug info such as parsed events 50 51 Note that while the various profiles available when launching 52 'go tool trace' work on every browser, the trace viewer itself 53 (the 'view trace' page) comes from the Chrome/Chromium project 54 and is only actively tested on that browser. 55 ` 56 57 var ( 58 httpFlag = flag.String("http", "localhost:0", "HTTP service address (e.g., ':6060')") 59 pprofFlag = flag.String("pprof", "", "print a pprof-like profile instead") 60 debugFlag = flag.Bool("d", false, "print debug information such as parsed events list") 61 62 // The binary file name, left here for serveSVGProfile. 63 programBinary string 64 traceFile string 65 ) 66 67 func main() { 68 flag.Usage = func() { 69 fmt.Fprintln(os.Stderr, usageMessage) 70 os.Exit(2) 71 } 72 flag.Parse() 73 74 // Go 1.7 traces embed symbol info and does not require the binary. 75 // But we optionally accept binary as first arg for Go 1.5 traces. 76 switch flag.NArg() { 77 case 1: 78 traceFile = flag.Arg(0) 79 case 2: 80 programBinary = flag.Arg(0) 81 traceFile = flag.Arg(1) 82 default: 83 flag.Usage() 84 } 85 86 var pprofFunc func(io.Writer, *http.Request) error 87 switch *pprofFlag { 88 case "net": 89 pprofFunc = pprofByGoroutine(computePprofIO) 90 case "sync": 91 pprofFunc = pprofByGoroutine(computePprofBlock) 92 case "syscall": 93 pprofFunc = pprofByGoroutine(computePprofSyscall) 94 case "sched": 95 pprofFunc = pprofByGoroutine(computePprofSched) 96 } 97 if pprofFunc != nil { 98 if err := pprofFunc(os.Stdout, &http.Request{}); err != nil { 99 dief("failed to generate pprof: %v\n", err) 100 } 101 os.Exit(0) 102 } 103 if *pprofFlag != "" { 104 dief("unknown pprof type %s\n", *pprofFlag) 105 } 106 107 ln, err := net.Listen("tcp", *httpFlag) 108 if err != nil { 109 dief("failed to create server socket: %v\n", err) 110 } 111 112 log.Print("Parsing trace...") 113 res, err := parseTrace() 114 if err != nil { 115 dief("%v\n", err) 116 } 117 118 if *debugFlag { 119 trace.Print(res.Events) 120 os.Exit(0) 121 } 122 reportMemoryUsage("after parsing trace") 123 debug.FreeOSMemory() 124 125 log.Print("Splitting trace...") 126 ranges = splitTrace(res) 127 reportMemoryUsage("after spliting trace") 128 debug.FreeOSMemory() 129 130 addr := "http://" + ln.Addr().String() 131 log.Printf("Opening browser. Trace viewer is listening on %s", addr) 132 browser.Open(addr) 133 134 // Start http server. 135 http.HandleFunc("/", httpMain) 136 err = http.Serve(ln, nil) 137 dief("failed to start http server: %v\n", err) 138 } 139 140 var ranges []Range 141 142 var loader struct { 143 once sync.Once 144 res trace.ParseResult 145 err error 146 } 147 148 // parseEvents is a compatibility wrapper that returns only 149 // the Events part of trace.ParseResult returned by parseTrace. 150 func parseEvents() ([]*trace.Event, error) { 151 res, err := parseTrace() 152 if err != nil { 153 return nil, err 154 } 155 return res.Events, err 156 } 157 158 func parseTrace() (trace.ParseResult, error) { 159 loader.once.Do(func() { 160 tracef, err := os.Open(traceFile) 161 if err != nil { 162 loader.err = fmt.Errorf("failed to open trace file: %v", err) 163 return 164 } 165 defer tracef.Close() 166 167 // Parse and symbolize. 168 res, err := trace.Parse(bufio.NewReader(tracef), programBinary) 169 if err != nil { 170 loader.err = fmt.Errorf("failed to parse trace: %v", err) 171 return 172 } 173 loader.res = res 174 }) 175 return loader.res, loader.err 176 } 177 178 // httpMain serves the starting page. 179 func httpMain(w http.ResponseWriter, r *http.Request) { 180 if err := templMain.Execute(w, ranges); err != nil { 181 http.Error(w, err.Error(), http.StatusInternalServerError) 182 return 183 } 184 } 185 186 var templMain = template.Must(template.New("").Parse(` 187 <html> 188 <body> 189 {{if $}} 190 {{range $e := $}} 191 <a href="{{$e.URL}}">View trace ({{$e.Name}})</a><br> 192 {{end}} 193 <br> 194 {{else}} 195 <a href="/trace">View trace</a><br> 196 {{end}} 197 <a href="/goroutines">Goroutine analysis</a><br> 198 <a href="/io">Network blocking profile</a> (<a href="/io?raw=1" download="io.profile">⬇</a>)<br> 199 <a href="/block">Synchronization blocking profile</a> (<a href="/block?raw=1" download="block.profile">⬇</a>)<br> 200 <a href="/syscall">Syscall blocking profile</a> (<a href="/syscall?raw=1" download="syscall.profile">⬇</a>)<br> 201 <a href="/sched">Scheduler latency profile</a> (<a href="/sche?raw=1" download="sched.profile">⬇</a>)<br> 202 <a href="/usertasks">User-defined tasks</a><br> 203 <a href="/userregions">User-defined regions</a><br> 204 <a href="/mmu">Minimum mutator utilization</a><br> 205 </body> 206 </html> 207 `)) 208 209 func dief(msg string, args ...interface{}) { 210 fmt.Fprintf(os.Stderr, msg, args...) 211 os.Exit(1) 212 } 213 214 var debugMemoryUsage bool 215 216 func init() { 217 v := os.Getenv("DEBUG_MEMORY_USAGE") 218 debugMemoryUsage = v != "" 219 } 220 221 func reportMemoryUsage(msg string) { 222 if !debugMemoryUsage { 223 return 224 } 225 var s runtime.MemStats 226 runtime.ReadMemStats(&s) 227 w := os.Stderr 228 fmt.Fprintf(w, "%s\n", msg) 229 fmt.Fprintf(w, " Alloc:\t%d Bytes\n", s.Alloc) 230 fmt.Fprintf(w, " Sys:\t%d Bytes\n", s.Sys) 231 fmt.Fprintf(w, " HeapReleased:\t%d Bytes\n", s.HeapReleased) 232 fmt.Fprintf(w, " HeapSys:\t%d Bytes\n", s.HeapSys) 233 fmt.Fprintf(w, " HeapInUse:\t%d Bytes\n", s.HeapInuse) 234 fmt.Fprintf(w, " HeapAlloc:\t%d Bytes\n", s.HeapAlloc) 235 var dummy string 236 fmt.Printf("Enter to continue...") 237 fmt.Scanf("%s", &dummy) 238 }