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.
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/.
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/.
14
// To use pprof, link this package into your program:
15
// import _ "net/http/pprof"
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:
22
// log.Println(http.ListenAndServe("localhost:6060", nil))
25
// Then use the pprof tool to look at the heap profile:
27
// go tool pprof http://localhost:6060/debug/pprof/heap
29
// Or to look at a 30-second CPU profile:
31
// go tool pprof http://localhost:6060/debug/pprof/profile
33
// Or to look at the goroutine blocking profile:
35
// go tool pprof http://localhost:6060/debug/pprof/block
37
// To view all available profiles, open http://localhost:6060/debug/pprof/
40
// For a study of the facility in action, visit
42
// http://blog.golang.org/2011/06/profiling-go-programs.html
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))
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"))
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)
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)
97
time.Sleep(time.Duration(sec) * time.Second)
98
pprof.StopCPUProfile()
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")
107
// We have to read the whole POST body before
108
// writing any output. Buffer the output here.
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")
117
if r.Method == "POST" {
118
b = bufio.NewReader(r.Body)
120
b = bufio.NewReader(strings.NewReader(r.URL.RawQuery))
124
word, err := b.ReadSlice('+')
126
word = word[0 : len(word)-1] // trim +
128
pc, _ := strconv.ParseUint(string(word), 0, 64)
130
f := runtime.FuncForPC(uintptr(pc))
132
fmt.Fprintf(&buf, "%#x %s\n", pc, f.Name())
136
// Wait until here to check for err; the last
137
// symbol will have an err because it doesn't end in +.
140
fmt.Fprintf(&buf, "reading request: %v\n", err)
149
// Handler returns an HTTP handler that serves the named profile.
150
func Handler(name string) http.Handler {
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))
162
fmt.Fprintf(w, "Unknown profile: %s\n", name)
165
gc, _ := strconv.Atoi(r.FormValue("gc"))
166
if name == "heap" && gc > 0 {
173
// Index responds with the pprof-formatted profile named by the request.
174
// For example, "/debug/pprof/heap" serves the "heap" profile.
175
// Index responds to a request for "/debug/pprof/" with an HTML page
176
// listing the available profiles.
177
func Index(w http.ResponseWriter, r *http.Request) {
178
index("/debug/pprof/").ServeHTTP(w, r)
181
var indexTmpl = template.Must(template.New("index").Parse(`<!DOCTYPE html>
192
<td style="text-align: right;">{{.Count}}</td>
193
<td><a href="{{.Name}}?debug=1">{{.Name}}</a></td>
197
<p><a href="goroutine?debug=2">full goroutine stack dump</a></p>
202
// IndexAtRoot returns a handler that responds to an HTTP request
203
// at the given root path with an HTML page listing the available profiles.
204
// A trailing '/' will be added to root if there is not one already there.
205
func IndexAtRoot(root string) http.Handler {
206
if !strings.HasSuffix(root, "/") {
212
// index is an http.Handler that is functionally equivilent to Index except
213
// that an arbitrary prefix may be used.
216
// ServeHTTP implements http.Handler. ServeHTTP responds with the pprof-
217
// formatted profile named by the request after the prefix specified in index
218
// has been stripped.
219
func (i index) ServeHTTP(w http.ResponseWriter, r *http.Request) {
220
if strings.HasPrefix(r.URL.Path, string(i)) {
221
name := strings.TrimPrefix(r.URL.Path, string(i))
223
handler(name).ServeHTTP(w, r)
227
if err := indexTmpl.Execute(w, pprof.Profiles()); err != nil {