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 is a fork of net/http/pprof modified to communicate
8
// Changes from the original version
10
// - This fork does not automatically register itself with the default
12
// - To start the pprof handler, see the Start method in socket.go.
13
// - For compatability with Go 1.2.1, support for obtaining trace data
16
// ---------------------------------------------------------------
18
// Package pprof serves via its HTTP server runtime profiling data
19
// in the format expected by the pprof visualization tool.
20
// For more information about pprof, see
21
// http://code.google.com/p/google-perftools/.
23
// The package is typically only imported for the side effect of
24
// registering its HTTP handlers.
25
// The handled paths all begin with /debug/pprof/.
27
// To use pprof, link this package into your program:
28
// import _ "net/http/pprof"
30
// If your application is not already running an http server, you
31
// need to start one. Add "net/http" and "log" to your imports and
32
// the following code to your main function:
35
// log.Println(http.ListenAndServe("localhost:6060", nil))
38
// Then use the pprof tool to look at the heap profile:
40
// go tool pprof http://localhost:6060/debug/pprof/heap
42
// Or to look at a 30-second CPU profile:
44
// go tool pprof http://localhost:6060/debug/pprof/profile
46
// Or to look at the goroutine blocking profile:
48
// go tool pprof http://localhost:6060/debug/pprof/block
50
// To view all available profiles, open http://localhost:6060/debug/pprof/
53
// For a study of the facility in action, visit
55
// https://blog.golang.org/2011/06/profiling-go-programs.html
75
// Cmdline responds with the running program's
76
// command line, with arguments separated by NUL bytes.
77
// The package initialization registers it as /debug/pprof/cmdline.
78
func Cmdline(w http.ResponseWriter, r *http.Request) {
79
w.Header().Set("Content-Type", "text/plain; charset=utf-8")
80
fmt.Fprintf(w, strings.Join(os.Args, "\x00"))
83
func sleep(w http.ResponseWriter, d time.Duration) {
84
var clientGone <-chan bool
85
if cn, ok := w.(http.CloseNotifier); ok {
86
clientGone = cn.CloseNotify()
94
// Profile responds with the pprof-formatted cpu profile.
95
// The package initialization registers it as /debug/pprof/profile.
96
func Profile(w http.ResponseWriter, r *http.Request) {
97
sec, _ := strconv.ParseInt(r.FormValue("seconds"), 10, 64)
102
// Set Content Type assuming StartCPUProfile will work,
103
// because if it does it starts writing.
104
w.Header().Set("Content-Type", "application/octet-stream")
105
if err := pprof.StartCPUProfile(w); err != nil {
106
// StartCPUProfile failed, so no writes yet.
107
// Can change header back to text content
108
// and send error code.
109
w.Header().Set("Content-Type", "text/plain; charset=utf-8")
110
w.WriteHeader(http.StatusInternalServerError)
111
fmt.Fprintf(w, "Could not enable CPU profiling: %s\n", err)
114
sleep(w, time.Duration(sec)*time.Second)
115
pprof.StopCPUProfile()
118
// Symbol looks up the program counters listed in the request,
119
// responding with a table mapping program counters to function names.
120
// The package initialization registers it as /debug/pprof/symbol.
121
func Symbol(w http.ResponseWriter, r *http.Request) {
122
w.Header().Set("Content-Type", "text/plain; charset=utf-8")
124
// We have to read the whole POST body before
125
// writing any output. Buffer the output here.
128
// We don't know how many symbols we have, but we
129
// do have symbol information. Pprof only cares whether
130
// this number is 0 (no symbols available) or > 0.
131
fmt.Fprintf(&buf, "num_symbols: 1\n")
134
if r.Method == "POST" {
135
b = bufio.NewReader(r.Body)
137
b = bufio.NewReader(strings.NewReader(r.URL.RawQuery))
141
word, err := b.ReadSlice('+')
143
word = word[0 : len(word)-1] // trim +
145
pc, _ := strconv.ParseUint(string(word), 0, 64)
147
f := runtime.FuncForPC(uintptr(pc))
149
fmt.Fprintf(&buf, "%#x %s\n", pc, f.Name())
153
// Wait until here to check for err; the last
154
// symbol will have an err because it doesn't end in +.
157
fmt.Fprintf(&buf, "reading request: %v\n", err)
166
// Handler returns an HTTP handler that serves the named profile.
167
func Handler(name string) http.Handler {
173
func (name handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
174
w.Header().Set("Content-Type", "text/plain; charset=utf-8")
175
debug, _ := strconv.Atoi(r.FormValue("debug"))
176
p := pprof.Lookup(string(name))
179
fmt.Fprintf(w, "Unknown profile: %s\n", name)
182
gc, _ := strconv.Atoi(r.FormValue("gc"))
183
if name == "heap" && gc > 0 {
190
// Index responds with the pprof-formatted profile named by the request.
191
// For example, "/debug/pprof/heap" serves the "heap" profile.
192
// Index responds to a request for "/debug/pprof/" with an HTML page
193
// listing the available profiles.
194
func Index(w http.ResponseWriter, r *http.Request) {
195
if strings.HasPrefix(r.URL.Path, "/debug/pprof/") {
196
name := strings.TrimPrefix(r.URL.Path, "/debug/pprof/")
198
handler(name).ServeHTTP(w, r)
203
profiles := pprof.Profiles()
204
if err := indexTmpl.Execute(w, profiles); err != nil {
209
var indexTmpl = template.Must(template.New("index").Parse(`<html>
211
<title>/debug/pprof/</title>
219
<tr><td align=right>{{.Count}}<td><a href="{{.Name}}?debug=1">{{.Name}}</a>
223
<a href="goroutine?debug=2">full goroutine stack dump</a><br>