From 5c59760ab3cb27849ea7075a696b821aa8466261 Mon Sep 17 00:00:00 2001 From: Julien Robert Date: Wed, 16 Oct 2024 21:36:51 +0200 Subject: [PATCH 1/3] feat(server/v2): enable pprof --- server/v2/commands.go | 40 +++++++++++++++++++++++++++++++++++----- server/v2/flags.go | 5 ++++- server/v2/server.go | 2 ++ simapp/app_di.go | 10 +++++----- 4 files changed, 46 insertions(+), 11 deletions(-) diff --git a/server/v2/commands.go b/server/v2/commands.go index 86f8e400467c..fa29f1b86cd4 100644 --- a/server/v2/commands.go +++ b/server/v2/commands.go @@ -6,6 +6,7 @@ import ( "os" "os/signal" "path/filepath" + "runtime/pprof" "strings" "syscall" @@ -13,6 +14,7 @@ import ( "github.com/spf13/viper" "cosmossdk.io/core/transaction" + "cosmossdk.io/log" ) // Execute executes the root command of an application. @@ -127,11 +129,9 @@ func createStartCommand[T transaction.Tx]( } }() - if err := server.Start(ctx); err != nil { - return err - } - - return nil + return wrapCPUProfile(l, v, func() error { + return server.Start(ctx) + }) }, } @@ -143,6 +143,36 @@ func createStartCommand[T transaction.Tx]( return cmd } +// wrapCPUProfile starts CPU profiling, if enabled, and executes the provided +// callbackFn in a separate goroutine, then will wait for that callback to return. +func wrapCPUProfile(logger log.Logger, v *viper.Viper, callbackFn func() error) error { + cpuProfileFile := v.GetString(FlagCPUProfiling) + if len(cpuProfileFile) == 0 { + // if cpu profiling is not enabled, just run the callback + return callbackFn() + } + + f, err := os.Create(cpuProfileFile) + if err != nil { + return err + } + + logger.Info("starting CPU profiler", "profile", cpuProfileFile) + if err := pprof.StartCPUProfile(f); err != nil { + return err + } + + defer func() { + logger.Info("stopping CPU profiler", "profile", cpuProfileFile) + pprof.StopCPUProfile() + if err := f.Close(); err != nil { + logger.Info("failed to close cpu-profile file", "profile", cpuProfileFile, "err", err.Error()) + } + }() + + return callbackFn() +} + // configHandle writes the default config to the home directory if it does not exist and sets the server context func configHandle[T transaction.Tx](s *Server[T], cmd *cobra.Command) error { home, err := cmd.Flags().GetString(FlagHome) diff --git a/server/v2/flags.go b/server/v2/flags.go index fc36cdcf2b4c..46925cc526e5 100644 --- a/server/v2/flags.go +++ b/server/v2/flags.go @@ -9,7 +9,10 @@ func prefix(f string) string { return fmt.Sprintf("%s.%s", serverName, f) } -var FlagMinGasPrices = prefix("minimum-gas-prices") +var ( + FlagMinGasPrices = prefix("minimum-gas-prices") + FlagCPUProfiling = prefix("cpu-profile") +) const ( // FlagHome specifies the home directory flag. diff --git a/server/v2/server.go b/server/v2/server.go index 486f5c0ceecb..980cb3e5fed2 100644 --- a/server/v2/server.go +++ b/server/v2/server.go @@ -181,6 +181,8 @@ func (s *Server[T]) Configs() map[string]any { func (s *Server[T]) StartCmdFlags() *pflag.FlagSet { flags := pflag.NewFlagSet(s.Name(), pflag.ExitOnError) flags.String(FlagMinGasPrices, "", "Minimum gas prices to accept for transactions; Any fee in a tx must meet this minimum (e.g. 0.01photino;0.0001stake)") + flags.String(FlagCPUProfiling, "", "Enable CPU profiling and write to the specified file") + return flags } diff --git a/simapp/app_di.go b/simapp/app_di.go index b26220892e0d..9602fbc3972c 100644 --- a/simapp/app_di.go +++ b/simapp/app_di.go @@ -231,11 +231,11 @@ func NewSimApp( // baseAppOptions = append(baseAppOptions, prepareOpt) // create and set dummy vote extension handler - voteExtOp := func(bApp *baseapp.BaseApp) { - voteExtHandler := NewVoteExtensionHandler() - voteExtHandler.SetHandlers(bApp) - } - baseAppOptions = append(baseAppOptions, voteExtOp, baseapp.SetOptimisticExecution()) + // voteExtOp := func(bApp *baseapp.BaseApp) { + // voteExtHandler := NewVoteExtensionHandler() + // voteExtHandler.SetHandlers(bApp) + // } + // baseAppOptions = append(baseAppOptions, voteExtOp, baseapp.SetOptimisticExecution()) app.App = appBuilder.Build(db, traceStore, baseAppOptions...) From 7d286598548e196f876ce8a6cdd186bb6effcc87 Mon Sep 17 00:00:00 2001 From: Julien Robert Date: Wed, 16 Oct 2024 21:37:32 +0200 Subject: [PATCH 2/3] revert --- simapp/app_di.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/simapp/app_di.go b/simapp/app_di.go index 9602fbc3972c..b26220892e0d 100644 --- a/simapp/app_di.go +++ b/simapp/app_di.go @@ -231,11 +231,11 @@ func NewSimApp( // baseAppOptions = append(baseAppOptions, prepareOpt) // create and set dummy vote extension handler - // voteExtOp := func(bApp *baseapp.BaseApp) { - // voteExtHandler := NewVoteExtensionHandler() - // voteExtHandler.SetHandlers(bApp) - // } - // baseAppOptions = append(baseAppOptions, voteExtOp, baseapp.SetOptimisticExecution()) + voteExtOp := func(bApp *baseapp.BaseApp) { + voteExtHandler := NewVoteExtensionHandler() + voteExtHandler.SetHandlers(bApp) + } + baseAppOptions = append(baseAppOptions, voteExtOp, baseapp.SetOptimisticExecution()) app.App = appBuilder.Build(db, traceStore, baseAppOptions...) From a976285923ae60af4650ef1e3608ad1ee6f53e66 Mon Sep 17 00:00:00 2001 From: Julien Robert Date: Wed, 16 Oct 2024 22:02:59 +0200 Subject: [PATCH 3/3] bot --- server/v2/commands.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/server/v2/commands.go b/server/v2/commands.go index fa29f1b86cd4..d5c202ade9f7 100644 --- a/server/v2/commands.go +++ b/server/v2/commands.go @@ -144,7 +144,7 @@ func createStartCommand[T transaction.Tx]( } // wrapCPUProfile starts CPU profiling, if enabled, and executes the provided -// callbackFn in a separate goroutine, then will wait for that callback to return. +// callbackFn, then waits for it to return. func wrapCPUProfile(logger log.Logger, v *viper.Viper, callbackFn func() error) error { cpuProfileFile := v.GetString(FlagCPUProfiling) if len(cpuProfileFile) == 0 { @@ -159,6 +159,7 @@ func wrapCPUProfile(logger log.Logger, v *viper.Viper, callbackFn func() error) logger.Info("starting CPU profiler", "profile", cpuProfileFile) if err := pprof.StartCPUProfile(f); err != nil { + _ = f.Close() return err }