From 9bb732d9816a0de6f7e5d1a8de50406b0d23f7fe Mon Sep 17 00:00:00 2001 From: Frank Mueller Date: Fri, 23 Mar 2018 14:58:40 +0100 Subject: [PATCH] Add profiling with pprof (#754) --- cmd/statusd/main.go | 9 +++++++++ profiling/profiler.go | 40 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+) create mode 100644 profiling/profiler.go diff --git a/cmd/statusd/main.go b/cmd/statusd/main.go index f1fcae9dc..9b639bb5e 100644 --- a/cmd/statusd/main.go +++ b/cmd/statusd/main.go @@ -18,6 +18,7 @@ import ( "github.com/status-im/status-go/geth/params" "github.com/status-im/status-go/metrics" nodemetrics "github.com/status-im/status-go/metrics/node" + "github.com/status-im/status-go/profiling" ) var ( @@ -41,6 +42,8 @@ var ( ipcEnabled = flag.Bool("ipc", false, "Enable IPC RPC endpoint") cliEnabled = flag.Bool("cli", false, "Enable debugging CLI server") cliPort = flag.String("cliport", debug.CLIPort, "CLI server's listening port") + pprofEnabled = flag.Bool("pprof", false, "Enable runtime profiling via pprof") + pprofPort = flag.Int("pprofport", 52525, "Port for runtime profiling via pprof") logLevel = flag.String("log", "INFO", `Log level, one of: "ERROR", "WARN", "INFO", "DEBUG", and "TRACE"`) logFile = flag.String("logfile", "", "Path to the log file") version = flag.Bool("version", false, "Print version") @@ -127,6 +130,7 @@ func main() { // handle interrupt signals interruptCh := haltOnInterruptSignal(backend.NodeManager()) + // Check if debugging CLI connection shall be enabled. if *cliEnabled { err := startDebug(backend) @@ -136,6 +140,11 @@ func main() { } } + // Check if profiling shall be enabled. + if *pprofEnabled { + profiling.NewProfiler(*pprofPort).Go() + } + // Run stats server. if *statsEnabled { go startCollectingStats(interruptCh, backend.NodeManager()) diff --git a/profiling/profiler.go b/profiling/profiler.go new file mode 100644 index 000000000..8f7be0dc4 --- /dev/null +++ b/profiling/profiler.go @@ -0,0 +1,40 @@ +package profiling + +import ( + "fmt" + "net/http" + hpprof "net/http/pprof" + + "github.com/ethereum/go-ethereum/log" +) + +// Profiler runs and controls a HTTP pprof interface. +type Profiler struct { + server *http.Server +} + +// NewProfiler creates an instance of the profiler with +// the given port. +func NewProfiler(port int) *Profiler { + mux := http.NewServeMux() + mux.HandleFunc("/debug/pprof/", hpprof.Index) + mux.HandleFunc("/debug/pprof/cmdline", hpprof.Cmdline) + mux.HandleFunc("/debug/pprof/profile", hpprof.Profile) + mux.HandleFunc("/debug/pprof/symbol", hpprof.Symbol) + mux.HandleFunc("/debug/pprof/trace", hpprof.Trace) + p := Profiler{ + server: &http.Server{ + Addr: fmt.Sprintf(":%d", port), + Handler: mux, + }, + } + return &p +} + +// Go starts the HTTP pprof in the background. +func (p *Profiler) Go() { + go func() { + log.Info("debug server stopped", "err", p.server.ListenAndServe()) + }() + log.Info("debug server started") +}