github.com/ader1990/go@v0.0.0-20140630135419-8c24447fa791/src/pkg/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 // To view all available profiles, open http://localhost:6060/debug/pprof/ 38 // in your browser. 39 // 40 // For a study of the facility in action, visit 41 // 42 // http://blog.golang.org/2011/06/profiling-go-programs.html 43 // 44 package pprof 45 46 import ( 47 "bufio" 48 "bytes" 49 "fmt" 50 "html/template" 51 "io" 52 "log" 53 "net/http" 54 "os" 55 "runtime" 56 "runtime/pprof" 57 "strconv" 58 "strings" 59 "time" 60 ) 61 62 func init() { 63 http.Handle("/debug/pprof/", http.HandlerFunc(Index)) 64 http.Handle("/debug/pprof/cmdline", http.HandlerFunc(Cmdline)) 65 http.Handle("/debug/pprof/profile", http.HandlerFunc(Profile)) 66 http.Handle("/debug/pprof/symbol", http.HandlerFunc(Symbol)) 67 } 68 69 // Cmdline responds with the running program's 70 // command line, with arguments separated by NUL bytes. 71 // The package initialization registers it as /debug/pprof/cmdline. 72 func Cmdline(w http.ResponseWriter, r *http.Request) { 73 w.Header().Set("Content-Type", "text/plain; charset=utf-8") 74 fmt.Fprintf(w, strings.Join(os.Args, "\x00")) 75 } 76 77 // Profile responds with the pprof-formatted cpu profile. 78 // The package initialization registers it as /debug/pprof/profile. 79 func Profile(w http.ResponseWriter, r *http.Request) { 80 sec, _ := strconv.ParseInt(r.FormValue("seconds"), 10, 64) 81 if sec == 0 { 82 sec = 30 83 } 84 85 // Set Content Type assuming StartCPUProfile will work, 86 // because if it does it starts writing. 87 w.Header().Set("Content-Type", "application/octet-stream") 88 if err := pprof.StartCPUProfile(w); err != nil { 89 // StartCPUProfile failed, so no writes yet. 90 // Can change header back to text content 91 // and send error code. 92 w.Header().Set("Content-Type", "text/plain; charset=utf-8") 93 w.WriteHeader(http.StatusInternalServerError) 94 fmt.Fprintf(w, "Could not enable CPU profiling: %s\n", err) 95 return 96 } 97 time.Sleep(time.Duration(sec) * time.Second) 98 pprof.StopCPUProfile() 99 } 100 101 // Symbol looks up the program counters listed in the request, 102 // responding with a table mapping program counters to function names. 103 // The package initialization registers it as /debug/pprof/symbol. 104 func Symbol(w http.ResponseWriter, r *http.Request) { 105 w.Header().Set("Content-Type", "text/plain; charset=utf-8") 106 107 // We have to read the whole POST body before 108 // writing any output. Buffer the output here. 109 var buf bytes.Buffer 110 111 // We don't know how many symbols we have, but we 112 // do have symbol information. Pprof only cares whether 113 // this number is 0 (no symbols available) or > 0. 114 fmt.Fprintf(&buf, "num_symbols: 1\n") 115 116 var b *bufio.Reader 117 if r.Method == "POST" { 118 b = bufio.NewReader(r.Body) 119 } else { 120 b = bufio.NewReader(strings.NewReader(r.URL.RawQuery)) 121 } 122 123 for { 124 word, err := b.ReadSlice('+') 125 if err == nil { 126 word = word[0 : len(word)-1] // trim + 127 } 128 pc, _ := strconv.ParseUint(string(word), 0, 64) 129 if pc != 0 { 130 f := runtime.FuncForPC(uintptr(pc)) 131 if f != nil { 132 fmt.Fprintf(&buf, "%#x %s\n", pc, f.Name()) 133 } 134 } 135 136 // Wait until here to check for err; the last 137 // symbol will have an err because it doesn't end in +. 138 if err != nil { 139 if err != io.EOF { 140 fmt.Fprintf(&buf, "reading request: %v\n", err) 141 } 142 break 143 } 144 } 145 146 w.Write(buf.Bytes()) 147 } 148 149 // Handler returns an HTTP handler that serves the named profile. 150 func Handler(name string) http.Handler { 151 return handler(name) 152 } 153 154 type handler string 155 156 func (name handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { 157 w.Header().Set("Content-Type", "text/plain; charset=utf-8") 158 debug, _ := strconv.Atoi(r.FormValue("debug")) 159 p := pprof.Lookup(string(name)) 160 if p == nil { 161 w.WriteHeader(404) 162 fmt.Fprintf(w, "Unknown profile: %s\n", name) 163 return 164 } 165 p.WriteTo(w, debug) 166 return 167 } 168 169 // Index responds with the pprof-formatted profile named by the request. 170 // For example, "/debug/pprof/heap" serves the "heap" profile. 171 // Index responds to a request for "/debug/pprof/" with an HTML page 172 // listing the available profiles. 173 func Index(w http.ResponseWriter, r *http.Request) { 174 if strings.HasPrefix(r.URL.Path, "/debug/pprof/") { 175 name := strings.TrimPrefix(r.URL.Path, "/debug/pprof/") 176 if name != "" { 177 handler(name).ServeHTTP(w, r) 178 return 179 } 180 } 181 182 profiles := pprof.Profiles() 183 if err := indexTmpl.Execute(w, profiles); err != nil { 184 log.Print(err) 185 } 186 } 187 188 var indexTmpl = template.Must(template.New("index").Parse(`<html> 189 <head> 190 <title>/debug/pprof/</title> 191 </head> 192 /debug/pprof/<br> 193 <br> 194 <body> 195 profiles:<br> 196 <table> 197 {{range .}} 198 <tr><td align=right>{{.Count}}<td><a href="/debug/pprof/{{.Name}}?debug=1">{{.Name}}</a> 199 {{end}} 200 </table> 201 <br> 202 <a href="/debug/pprof/goroutine?debug=2">full goroutine stack dump</a><br> 203 </body> 204 </html> 205 `))