Skip to content

Commit

Permalink
add go pprof capabilities
Browse files Browse the repository at this point in the history
  • Loading branch information
jchappelow committed Dec 17, 2024
1 parent 64a1843 commit 0dee852
Show file tree
Hide file tree
Showing 3 changed files with 102 additions and 2 deletions.
93 changes: 93 additions & 0 deletions app/node/prof.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package node

import (
"fmt"
"net/http"
_ "net/http/pprof"
"os"
"runtime"
"runtime/pprof"
"time"
)

type profMode string

const (
profModeDisabled profMode = ""
profModeHTTP profMode = "http"
profModeCPU profMode = "cpu"
profModeMem profMode = "mem"
profModeBlock profMode = "block"
profModeMutex profMode = "mutex"
)

func startProfilers(mode profMode, pprofFile string) (func(), error) {
if pprofFile == "" {
pprofFile = fmt.Sprintf("kwild-%s.pprof", mode)
}

switch mode {
case profModeHTTP:
// http pprof uses http.DefaultServeMux, so we register a redirect
// handler with the root path on the default mux.
http.Handle("/", http.RedirectHandler("/debug/pprof/", http.StatusSeeOther))
go func() {
if err := http.ListenAndServe("localhost:6060", nil); err != nil {
fmt.Printf("http.ListenAndServe: %v\n", err)
}
}()
return func() {}, nil
case profModeCPU:
f, err := os.Create(pprofFile)
if err != nil {
return nil, err
}
err = pprof.StartCPUProfile(f)
if err != nil {
return nil, fmt.Errorf("error starting CPU profiler: %w", err)
}
return pprof.StopCPUProfile, nil
case profModeMem:
f, err := os.Create(pprofFile)
if err != nil {
return nil, err
}
timer := time.NewTimer(time.Second * 15)
go func() {
<-timer.C
if err = pprof.WriteHeapProfile(f); err != nil {
fmt.Printf("WriteHeapProfile: %v\n", err)
}
f.Close()
}()
return func() { timer.Reset(0) }, nil
case profModeBlock:
f, err := os.Create(pprofFile)
if err != nil {
return nil, fmt.Errorf("could not create block profile file %q: %v", pprofFile, err)
}
runtime.SetBlockProfileRate(1)
return func() {
pprof.Lookup("block").WriteTo(f, 0)
f.Close()
runtime.SetBlockProfileRate(0)
}, nil
case profModeMutex:
f, err := os.Create(pprofFile)
if err != nil {
return nil, fmt.Errorf("could not create mutex profile file %q: %v", pprofFile, err)
}
runtime.SetMutexProfileFraction(1)
return func() {
if mp := pprof.Lookup("mutex"); mp != nil {
mp.WriteTo(f, 0)
}
f.Close()
runtime.SetMutexProfileFraction(0)
}, nil
case profModeDisabled:
return func() {}, nil
default:
return nil, fmt.Errorf("unknown profile mode %s", mode)
}
}
7 changes: 7 additions & 0 deletions app/node/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,13 @@ func StartCmd() *cobra.Command {
return string(rawToml)
}))

stopProfiler, err := startProfilers(profMode(cfg.ProfileMode), cfg.ProfileFile)
if err != nil {
cmd.Usage()
return err
}
defer stopProfiler()

return runNode(cmd.Context(), rootDir, cfg)
},
}
Expand Down
4 changes: 2 additions & 2 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -208,8 +208,8 @@ type Config struct {
LogFormat log.Format `toml:"log_format" comment:"log format\npossible values: 'json', 'text' (kv), and 'plain' (fmt-style)"`
// LogOutput []string `toml:"log_output" comment:"output paths for the log"`

// ProfileMode string `toml:"profile_mode"`
// ProfileFile string `toml:"profile_file"`
ProfileMode string `toml:"profile_mode,commented" comment:"profile mode (http, cpu, mem, mutex, or block)"`
ProfileFile string `toml:"profile_file,commented" comment:"profile output file path (e.g. cpu.pprof)"`

P2P PeerConfig `toml:"p2p" comment:"P2P related configuration"`
Consensus ConsensusConfig `toml:"consensus" comment:"Consensus related configuration"`
Expand Down

0 comments on commit 0dee852

Please sign in to comment.