diff --git a/daemons/compute/server/main.go b/daemons/compute/server/main.go index f1f3920e..8af24435 100644 --- a/daemons/compute/server/main.go +++ b/daemons/compute/server/main.go @@ -20,6 +20,7 @@ package main import ( + "bufio" "flag" "fmt" "log" @@ -27,7 +28,9 @@ import ( "os" "os/signal" "runtime" + "runtime/pprof" "syscall" + "time" "github.com/takama/daemon" "google.golang.org/grpc" @@ -99,6 +102,42 @@ func (service *Service) Manage() (string, error) { return fmt.Sprintf("Failed to set permissions on socket %s", *socketAddr), err } + if len(options.CpuProfile) > 0 { + filename := options.CpuProfile + "-" + time.Now().UTC().Format(time.RFC3339) + f, err := os.Create(filename) + if err != nil { + errlog.Fatal("could not create CPU profile: ", err) + } + defer func() { + cerr := f.Close() + if err == nil { + err = cerr + } + }() + + b := bufio.NewWriter(f) + + if err := pprof.StartCPUProfile(f); err != nil { + errlog.Fatal("could not start CPU profile: ", err) + } + errlog.Printf("CPU profiling enabled (%s)\n", filename) + defer pprof.StopCPUProfile() + + go func() { + for { + select { + case <-interrupt: + return + case <-time.After(5 * time.Second): + if err = b.Flush(); err != nil { + errlog.Fatal("could not write to cpu profile", err) + } + } + } + + }() + } + go service.Run(server, listener) for { diff --git a/daemons/compute/server/servers/server.go b/daemons/compute/server/servers/server.go index 11c3e66a..1eba358a 100644 --- a/daemons/compute/server/servers/server.go +++ b/daemons/compute/server/servers/server.go @@ -35,7 +35,7 @@ type ServerOptions struct { name string nodeName string sysConfig string - cpuProfile string + CpuProfile string simulated bool k8sQPS int @@ -50,7 +50,7 @@ func GetOptions() (*ServerOptions, error) { nodeName: os.Getenv("NNF_NODE_NAME"), tokenFile: os.Getenv("NNF_DATA_MOVEMENT_SERVICE_TOKEN_FILE"), certFile: os.Getenv("NNF_DATA_MOVEMENT_SERVICE_CERT_FILE"), - cpuProfile: os.Getenv("NNF_DATA_MOVEMENT_SERVICE_CPU_PROFILE"), + CpuProfile: os.Getenv("NNF_DATA_MOVEMENT_SERVICE_CPU_PROFILE"), simulated: false, // These options adjust the client-side rate-limiting for k8s. The new defaults are 50 and @@ -70,7 +70,7 @@ func GetOptions() (*ServerOptions, error) { flag.BoolVar(&opts.simulated, "simulated", opts.simulated, "Run in simulation mode where no requests are sent to the server") flag.IntVar(&opts.k8sQPS, "kubernetes-qps", opts.k8sQPS, "Kubernetes client queries per second (QPS)") flag.IntVar(&opts.k8sBurst, "kubernetes-burst", opts.k8sBurst, "Kubernetes client additional concurrent calls above QPS") - flag.StringVar(&opts.cpuProfile, "cpu-profile", opts.cpuProfile, "Enable and dump CPU profiling data to this file") + flag.StringVar(&opts.CpuProfile, "cpu-profile", opts.CpuProfile, "Enable and dump CPU profiling data to this file") flag.Parse() return &opts, nil }