/third_party/gofrontend/libgo/go/net/http/pprof/pprof.go
Go | 241 lines | 132 code | 21 blank | 88 comment | 30 complexity | 78cb1b5f915fe05d616be96a1c88fd58 MD5 | raw file
Possible License(s): BSD-3-Clause, MIT
- // Copyright 2010 The Go Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style
- // license that can be found in the LICENSE file.
- // Package pprof serves via its HTTP server runtime profiling data
- // in the format expected by the pprof visualization tool.
- // For more information about pprof, see
- // http://code.google.com/p/google-perftools/.
- //
- // The package is typically only imported for the side effect of
- // registering its HTTP handlers.
- // The handled paths all begin with /debug/pprof/.
- //
- // To use pprof, link this package into your program:
- // import _ "net/http/pprof"
- //
- // If your application is not already running an http server, you
- // need to start one. Add "net/http" and "log" to your imports and
- // the following code to your main function:
- //
- // go func() {
- // log.Println(http.ListenAndServe("localhost:6060", nil))
- // }()
- //
- // Then use the pprof tool to look at the heap profile:
- //
- // go tool pprof http://localhost:6060/debug/pprof/heap
- //
- // Or to look at a 30-second CPU profile:
- //
- // go tool pprof http://localhost:6060/debug/pprof/profile
- //
- // Or to look at the goroutine blocking profile:
- //
- // go tool pprof http://localhost:6060/debug/pprof/block
- //
- // Or to collect a 5-second execution trace:
- //
- // wget http://localhost:6060/debug/pprof/trace?seconds=5
- //
- // To view all available profiles, open http://localhost:6060/debug/pprof/
- // in your browser.
- //
- // For a study of the facility in action, visit
- //
- // https://blog.golang.org/2011/06/profiling-go-programs.html
- //
- package pprof
- import (
- "bufio"
- "bytes"
- "fmt"
- "html/template"
- "io"
- "log"
- "net/http"
- "os"
- "runtime"
- "runtime/pprof"
- "strconv"
- "strings"
- "time"
- )
- func init() {
- http.Handle("/debug/pprof/", http.HandlerFunc(Index))
- http.Handle("/debug/pprof/cmdline", http.HandlerFunc(Cmdline))
- http.Handle("/debug/pprof/profile", http.HandlerFunc(Profile))
- http.Handle("/debug/pprof/symbol", http.HandlerFunc(Symbol))
- http.Handle("/debug/pprof/trace", http.HandlerFunc(Trace))
- }
- // Cmdline responds with the running program's
- // command line, with arguments separated by NUL bytes.
- // The package initialization registers it as /debug/pprof/cmdline.
- func Cmdline(w http.ResponseWriter, r *http.Request) {
- w.Header().Set("Content-Type", "text/plain; charset=utf-8")
- fmt.Fprintf(w, strings.Join(os.Args, "\x00"))
- }
- // Profile responds with the pprof-formatted cpu profile.
- // The package initialization registers it as /debug/pprof/profile.
- func Profile(w http.ResponseWriter, r *http.Request) {
- sec, _ := strconv.ParseInt(r.FormValue("seconds"), 10, 64)
- if sec == 0 {
- sec = 30
- }
- // Set Content Type assuming StartCPUProfile will work,
- // because if it does it starts writing.
- w.Header().Set("Content-Type", "application/octet-stream")
- if err := pprof.StartCPUProfile(w); err != nil {
- // StartCPUProfile failed, so no writes yet.
- // Can change header back to text content
- // and send error code.
- w.Header().Set("Content-Type", "text/plain; charset=utf-8")
- w.WriteHeader(http.StatusInternalServerError)
- fmt.Fprintf(w, "Could not enable CPU profiling: %s\n", err)
- return
- }
- time.Sleep(time.Duration(sec) * time.Second)
- pprof.StopCPUProfile()
- }
- // Trace responds with the execution trace in binary form.
- // Tracing lasts for duration specified in seconds GET parameter, or for 1 second if not specified.
- // The package initialization registers it as /debug/pprof/trace.
- func Trace(w http.ResponseWriter, r *http.Request) {
- sec, _ := strconv.ParseInt(r.FormValue("seconds"), 10, 64)
- if sec == 0 {
- sec = 1
- }
- // Set Content Type assuming trace.Start will work,
- // because if it does it starts writing.
- w.Header().Set("Content-Type", "application/octet-stream")
- w.Write([]byte("tracing not yet supported with gccgo"))
- /*
- if err := trace.Start(w); err != nil {
- // trace.Start failed, so no writes yet.
- // Can change header back to text content and send error code.
- w.Header().Set("Content-Type", "text/plain; charset=utf-8")
- w.WriteHeader(http.StatusInternalServerError)
- fmt.Fprintf(w, "Could not enable tracing: %s\n", err)
- return
- }
- time.Sleep(time.Duration(sec) * time.Second)
- trace.Stop()
- */
- }
- // Symbol looks up the program counters listed in the request,
- // responding with a table mapping program counters to function names.
- // The package initialization registers it as /debug/pprof/symbol.
- func Symbol(w http.ResponseWriter, r *http.Request) {
- w.Header().Set("Content-Type", "text/plain; charset=utf-8")
- // We have to read the whole POST body before
- // writing any output. Buffer the output here.
- var buf bytes.Buffer
- // We don't know how many symbols we have, but we
- // do have symbol information. Pprof only cares whether
- // this number is 0 (no symbols available) or > 0.
- fmt.Fprintf(&buf, "num_symbols: 1\n")
- var b *bufio.Reader
- if r.Method == "POST" {
- b = bufio.NewReader(r.Body)
- } else {
- b = bufio.NewReader(strings.NewReader(r.URL.RawQuery))
- }
- for {
- word, err := b.ReadSlice('+')
- if err == nil {
- word = word[0 : len(word)-1] // trim +
- }
- pc, _ := strconv.ParseUint(string(word), 0, 64)
- if pc != 0 {
- f := runtime.FuncForPC(uintptr(pc))
- if f != nil {
- fmt.Fprintf(&buf, "%#x %s\n", pc, f.Name())
- }
- }
- // Wait until here to check for err; the last
- // symbol will have an err because it doesn't end in +.
- if err != nil {
- if err != io.EOF {
- fmt.Fprintf(&buf, "reading request: %v\n", err)
- }
- break
- }
- }
- w.Write(buf.Bytes())
- }
- // Handler returns an HTTP handler that serves the named profile.
- func Handler(name string) http.Handler {
- return handler(name)
- }
- type handler string
- func (name handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
- w.Header().Set("Content-Type", "text/plain; charset=utf-8")
- debug, _ := strconv.Atoi(r.FormValue("debug"))
- p := pprof.Lookup(string(name))
- if p == nil {
- w.WriteHeader(404)
- fmt.Fprintf(w, "Unknown profile: %s\n", name)
- return
- }
- gc, _ := strconv.Atoi(r.FormValue("gc"))
- if name == "heap" && gc > 0 {
- runtime.GC()
- }
- p.WriteTo(w, debug)
- return
- }
- // Index responds with the pprof-formatted profile named by the request.
- // For example, "/debug/pprof/heap" serves the "heap" profile.
- // Index responds to a request for "/debug/pprof/" with an HTML page
- // listing the available profiles.
- func Index(w http.ResponseWriter, r *http.Request) {
- if strings.HasPrefix(r.URL.Path, "/debug/pprof/") {
- name := strings.TrimPrefix(r.URL.Path, "/debug/pprof/")
- if name != "" {
- handler(name).ServeHTTP(w, r)
- return
- }
- }
- profiles := pprof.Profiles()
- if err := indexTmpl.Execute(w, profiles); err != nil {
- log.Print(err)
- }
- }
- var indexTmpl = template.Must(template.New("index").Parse(`<html>
- <head>
- <title>/debug/pprof/</title>
- </head>
- <body>
- /debug/pprof/<br>
- <br>
- profiles:<br>
- <table>
- {{range .}}
- <tr><td align=right>{{.Count}}<td><a href="{{.Name}}?debug=1">{{.Name}}</a>
- {{end}}
- </table>
- <br>
- <a href="goroutine?debug=2">full goroutine stack dump</a><br>
- </body>
- </html>
- `))