aboutsummaryrefslogtreecommitdiff
path: root/libgo/go/net/http/pprof/pprof.go
diff options
context:
space:
mode:
Diffstat (limited to 'libgo/go/net/http/pprof/pprof.go')
-rw-r--r--libgo/go/net/http/pprof/pprof.go51
1 files changed, 39 insertions, 12 deletions
diff --git a/libgo/go/net/http/pprof/pprof.go b/libgo/go/net/http/pprof/pprof.go
index 05d0890fdf3..12c7599ab0f 100644
--- a/libgo/go/net/http/pprof/pprof.go
+++ b/libgo/go/net/http/pprof/pprof.go
@@ -37,6 +37,11 @@
//
// wget http://localhost:6060/debug/pprof/trace?seconds=5
//
+// Or to look at the holders of contended mutexes, after calling
+// runtime.SetMutexProfileFraction in your program:
+//
+// go tool pprof http://localhost:6060/debug/pprof/mutex
+//
// To view all available profiles, open http://localhost:6060/debug/pprof/
// in your browser.
//
@@ -57,6 +62,7 @@ import (
"os"
"runtime"
"runtime/pprof"
+ "runtime/trace"
"strconv"
"strings"
"time"
@@ -89,6 +95,11 @@ func sleep(w http.ResponseWriter, d time.Duration) {
}
}
+func durationExceedsWriteTimeout(r *http.Request, seconds float64) bool {
+ srv, ok := r.Context().Value(http.ServerContextKey).(*http.Server)
+ return ok && srv.WriteTimeout != 0 && seconds >= srv.WriteTimeout.Seconds()
+}
+
// 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) {
@@ -97,6 +108,14 @@ func Profile(w http.ResponseWriter, r *http.Request) {
sec = 30
}
+ if durationExceedsWriteTimeout(r, float64(sec)) {
+ w.Header().Set("Content-Type", "text/plain; charset=utf-8")
+ w.Header().Set("X-Go-Pprof", "1")
+ w.WriteHeader(http.StatusBadRequest)
+ fmt.Fprintln(w, "profile duration exceeds server's WriteTimeout")
+ return
+ }
+
// Set Content Type assuming StartCPUProfile will work,
// because if it does it starts writing.
w.Header().Set("Content-Type", "application/octet-stream")
@@ -105,6 +124,7 @@ func Profile(w http.ResponseWriter, r *http.Request) {
// Can change header back to text content
// and send error code.
w.Header().Set("Content-Type", "text/plain; charset=utf-8")
+ w.Header().Set("X-Go-Pprof", "1")
w.WriteHeader(http.StatusInternalServerError)
fmt.Fprintf(w, "Could not enable CPU profiling: %s\n", err)
return
@@ -122,20 +142,28 @@ func Trace(w http.ResponseWriter, r *http.Request) {
sec = 1
}
+ if durationExceedsWriteTimeout(r, sec) {
+ w.Header().Set("Content-Type", "text/plain; charset=utf-8")
+ w.Header().Set("X-Go-Pprof", "1")
+ w.WriteHeader(http.StatusBadRequest)
+ fmt.Fprintln(w, "profile duration exceeds server's WriteTimeout")
+ return
+ }
+
// 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
- // }
- // sleep(w, time.Duration(sec*float64(time.Second)))
- // trace.Stop()
+ 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.Header().Set("X-Go-Pprof", "1")
+ w.WriteHeader(http.StatusInternalServerError)
+ fmt.Fprintf(w, "Could not enable tracing: %s\n", err)
+ return
+ }
+ sleep(w, time.Duration(sec*float64(time.Second)))
+ trace.Stop()
}
// Symbol looks up the program counters listed in the request,
@@ -207,7 +235,6 @@ func (name handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
runtime.GC()
}
p.WriteTo(w, debug)
- return
}
// Index responds with the pprof-formatted profile named by the request.