From 67d7a653fdd4c4fa489e319a7748e5b69b96ae83 Mon Sep 17 00:00:00 2001 From: Sascha Grunert Date: Thu, 14 Nov 2024 11:29:54 +0100 Subject: [PATCH] Add `--profile-{cpu,mem}` flags The flags allow debugging `crictl` with respect to CPU and memory consumption. Signed-off-by: Sascha Grunert --- .golangci.yml | 4 ++- cmd/crictl/main.go | 65 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+), 1 deletion(-) diff --git a/.golangci.yml b/.golangci.yml index 38f21a3058..dc42dfa72c 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -122,6 +122,8 @@ linters-settings: disabled: true nestif: min-complexity: 17 + maintidx: + under: 10 godox: keywords: - BUG @@ -132,7 +134,7 @@ linters-settings: cyclop: max-complexity: 37 gocognit: - min-complexity: 53 + min-complexity: 71 gci: sections: - standard diff --git a/cmd/crictl/main.go b/cmd/crictl/main.go index 9924264928..7002f8893b 100644 --- a/cmd/crictl/main.go +++ b/cmd/crictl/main.go @@ -21,7 +21,9 @@ import ( "errors" "fmt" "os" + "path/filepath" "runtime" + "runtime/pprof" "slices" "sort" "strings" @@ -270,12 +272,47 @@ func main() { Usage: "Address to which the gRPC tracing collector will send spans to.", Value: "127.0.0.1:4317", }, + &cli.StringFlag{ + Name: "profile-cpu", + Usage: "Write a pprof CPU profile to the provided path.", + }, + &cli.StringFlag{ + Name: "profile-mem", + Usage: "Write a pprof memory profile to the provided path.", + }, } + var cpuProfile *os.File + defer func() { + if cpuProfile != nil { + pprof.StopCPUProfile() + cpuProfile.Close() + } + }() + app.Before = func(context *cli.Context) (err error) { var config *common.ServerConfiguration var exePath string + cpuProfilePath := context.String("profile-cpu") + if cpuProfilePath != "" { + cpuProfilePath, err = filepath.Abs(cpuProfilePath) + if err != nil { + return fmt.Errorf("unable to get absolute memory profile path: %w", err) + } + + logrus.Infof("Creating CPU profile in: %s", cpuProfilePath) + + cpuProfile, err = os.Create(cpuProfilePath) + if err != nil { + return fmt.Errorf("could not create CPU profile %q: %w", cpuProfilePath, err) + } + + if err := pprof.StartCPUProfile(cpuProfile); err != nil { + return fmt.Errorf("could not start CPU profiling in %q: %w", cpuProfilePath, err) + } + } + if exePath, err = os.Executable(); err != nil { logrus.Fatal(err) } @@ -355,6 +392,34 @@ func main() { return nil } + + app.After = func(ctx *cli.Context) (err error) { + memProfilePath := ctx.String("profile-mem") + if memProfilePath != "" { + memProfilePath, err = filepath.Abs(memProfilePath) + if err != nil { + return fmt.Errorf("unable to get absolute memory profile path: %w", err) + } + + logrus.Infof("Creating memory profile in: %s", memProfilePath) + + file, err := os.Create(memProfilePath) + if err != nil { + return fmt.Errorf("could not create memory profile %q: %w", memProfilePath, err) + } + defer file.Close() + + // Ensure up to date data + runtime.GC() + + if err := pprof.WriteHeapProfile(file); err != nil { + return fmt.Errorf("could not write memory profile in %q: %w", memProfilePath, err) + } + } + + return nil + } + // sort all flags for _, cmd := range app.Commands { sort.Sort(cli.FlagsByName(cmd.Flags))