github.com/llvm-mirror/llgo@v0.0.0-20190322182713-bf6f0a60fce1/third_party/gofrontend/libgo/go/net/http/pprof/pprof.go (about) 1 // Copyright 2010 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 pprof serves via its HTTP server runtime profiling data 6 // in the format expected by the pprof visualization tool. 7 // For more information about pprof, see 8 // http://code.google.com/p/google-perftools/. 9 // 10 // The package is typically only imported for the side effect of 11 // registering its HTTP handlers. 12 // The handled paths all begin with /debug/pprof/. 13 // 14 // To use pprof, link this package into your program: 15 // import _ "net/http/pprof" 16 // 17 // If your application is not already running an http server, you 18 // need to start one. Add "net/http" and "log" to your imports and 19 // the following code to your main function: 20 // 21 // go func() { 22 // log.Println(http.ListenAndServe("localhost:6060", nil)) 23 // }() 24 // 25 // Then use the pprof tool to look at the heap profile: 26 // 27 // go tool pprof http://localhost:6060/debug/pprof/heap 28 // 29 // Or to look at a 30-second CPU profile: 30 // 31 // go tool pprof http://localhost:6060/debug/pprof/profile 32 // 33 // Or to look at the goroutine blocking profile: 34 // 35 // go tool pprof http://localhost:6060/debug/pprof/block 36 // 37 // Or to collect a 5-second execution trace: 38 // 39 // wget http://localhost:6060/debug/pprof/trace?seconds=5 40 // 41 // To view all available profiles, open http://localhost:6060/debug/pprof/ 42 // in your browser. 43 // 44 // For a study of the facility in action, visit 45 // 46 // https://blog.golang.org/2011/06/profiling-go-programs.html 47 // 48 package pprof 49 50 import ( 51 "bufio" 52 "bytes" 53 "fmt" 54 "html/template" 55 "io" 56 "log" 57 "net/http" 58 "os" 59 "runtime" 60 "runtime/pprof" 61 "strconv" 62 "strings" 63 "time" 64 ) 65 66 func init() { 67 http.Handle("/debug/pprof/", http.HandlerFunc(Index)) 68 http.Handle("/debug/pprof/cmdline", http.HandlerFunc(Cmdline)) 69 http.Handle("/debug/pprof/profile", http.HandlerFunc(Profile)) 70 http.Handle("/debug/pprof/symbol", http.HandlerFunc(Symbol)) 71 http.Handle("/debug/pprof/trace", http.HandlerFunc(Trace)) 72 } 73 74 // Cmdline responds with the running program's 75 // command line, with arguments separated by NUL bytes. 76 // The package initialization registers it as /debug/pprof/cmdline. 77 func Cmdline(w http.ResponseWriter, r *http.Request) { 78 w.Header().Set("Content-Type", "text/plain; charset=utf-8") 79 fmt.Fprintf(w, strings.Join(os.Args, "\x00")) 80 } 81 82 // Profile responds with the pprof-formatted cpu profile. 83 // The package initialization registers it as /debug/pprof/profile. 84 func Profile(w http.ResponseWriter, r *http.Request) { 85 sec, _ := strconv.ParseInt(r.FormValue("seconds"), 10, 64) 86 if sec == 0 { 87 sec = 30 88 } 89 90 // Set Content Type assuming StartCPUProfile will work, 91 // because if it does it starts writing. 92 w.Header().Set("Content-Type", "application/octet-stream") 93 if err := pprof.StartCPUProfile(w); err != nil { 94 // StartCPUProfile failed, so no writes yet. 95 // Can change header back to text content 96 // and send error code. 97 w.Header().Set("Content-Type", "text/plain; charset=utf-8") 98 w.WriteHeader(http.StatusInternalServerError) 99 fmt.Fprintf(w, "Could not enable CPU profiling: %s\n", err) 100 return 101 } 102 time.Sleep(time.Duration(sec) * time.Second) 103 pprof.StopCPUProfile() 104 } 105 106 // Trace responds with the execution trace in binary form. 107 // Tracing lasts for duration specified in seconds GET parameter, or for 1 second if not specified. 108 // The package initialization registers it as /debug/pprof/trace. 109 func Trace(w http.ResponseWriter, r *http.Request) { 110 sec, _ := strconv.ParseInt(r.FormValue("seconds"), 10, 64) 111 if sec == 0 { 112 sec = 1 113 } 114 115 // Set Content Type assuming trace.Start will work, 116 // because if it does it starts writing. 117 w.Header().Set("Content-Type", "application/octet-stream") 118 w.Write([]byte("tracing not yet supported with gccgo")) 119 /* 120 if err := trace.Start(w); err != nil { 121 // trace.Start failed, so no writes yet. 122 // Can change header back to text content and send error code. 123 w.Header().Set("Content-Type", "text/plain; charset=utf-8") 124 w.WriteHeader(http.StatusInternalServerError) 125 fmt.Fprintf(w, "Could not enable tracing: %s\n", err) 126 return 127 } 128 time.Sleep(time.Duration(sec) * time.Second) 129 trace.Stop() 130 */ 131 } 132 133 // Symbol looks up the program counters listed in the request, 134 // responding with a table mapping program counters to function names. 135 // The package initialization registers it as /debug/pprof/symbol. 136 func Symbol(w http.ResponseWriter, r *http.Request) { 137 w.Header().Set("Content-Type", "text/plain; charset=utf-8") 138 139 // We have to read the whole POST body before 140 // writing any output. Buffer the output here. 141 var buf bytes.Buffer 142 143 // We don't know how many symbols we have, but we 144 // do have symbol information. Pprof only cares whether 145 // this number is 0 (no symbols available) or > 0. 146 fmt.Fprintf(&buf, "num_symbols: 1\n") 147 148 var b *bufio.Reader 149 if r.Method == "POST" { 150 b = bufio.NewReader(r.Body) 151 } else { 152 b = bufio.NewReader(strings.NewReader(r.URL.RawQuery)) 153 } 154 155 for { 156 word, err := b.ReadSlice('+') 157 if err == nil { 158 word = word[0 : len(word)-1] // trim + 159 } 160 pc, _ := strconv.ParseUint(string(word), 0, 64) 161 if pc != 0 { 162 f := runtime.FuncForPC(uintptr(pc)) 163 if f != nil { 164 fmt.Fprintf(&buf, "%#x %s\n", pc, f.Name()) 165 } 166 } 167 168 // Wait until here to check for err; the last 169 // symbol will have an err because it doesn't end in +. 170 if err != nil { 171 if err != io.EOF { 172 fmt.Fprintf(&buf, "reading request: %v\n", err) 173 } 174 break 175 } 176 } 177 178 w.Write(buf.Bytes()) 179 } 180 181 // Handler returns an HTTP handler that serves the named profile. 182 func Handler(name string) http.Handler { 183 return handler(name) 184 } 185 186 type handler string 187 188 func (name handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { 189 w.Header().Set("Content-Type", "text/plain; charset=utf-8") 190 debug, _ := strconv.Atoi(r.FormValue("debug")) 191 p := pprof.Lookup(string(name)) 192 if p == nil { 193 w.WriteHeader(404) 194 fmt.Fprintf(w, "Unknown profile: %s\n", name) 195 return 196 } 197 gc, _ := strconv.Atoi(r.FormValue("gc")) 198 if name == "heap" && gc > 0 { 199 runtime.GC() 200 } 201 p.WriteTo(w, debug) 202 return 203 } 204 205 // Index responds with the pprof-formatted profile named by the request. 206 // For example, "/debug/pprof/heap" serves the "heap" profile. 207 // Index responds to a request for "/debug/pprof/" with an HTML page 208 // listing the available profiles. 209 func Index(w http.ResponseWriter, r *http.Request) { 210 if strings.HasPrefix(r.URL.Path, "/debug/pprof/") { 211 name := strings.TrimPrefix(r.URL.Path, "/debug/pprof/") 212 if name != "" { 213 handler(name).ServeHTTP(w, r) 214 return 215 } 216 } 217 218 profiles := pprof.Profiles() 219 if err := indexTmpl.Execute(w, profiles); err != nil { 220 log.Print(err) 221 } 222 } 223 224 var indexTmpl = template.Must(template.New("index").Parse(`<html> 225 <head> 226 <title>/debug/pprof/</title> 227 </head> 228 <body> 229 /debug/pprof/<br> 230 <br> 231 profiles:<br> 232 <table> 233 {{range .}} 234 <tr><td align=right>{{.Count}}<td><a href="{{.Name}}?debug=1">{{.Name}}</a> 235 {{end}} 236 </table> 237 <br> 238 <a href="goroutine?debug=2">full goroutine stack dump</a><br> 239 </body> 240 </html> 241 `))