...
1
16
17 package cmd
18
19 import (
20 "fmt"
21 "os"
22 "os/signal"
23 "runtime"
24 "runtime/pprof"
25
26 "github.com/spf13/pflag"
27 )
28
29 var (
30 profileName string
31 profileOutput string
32 )
33
34 func addProfilingFlags(flags *pflag.FlagSet) {
35 flags.StringVar(&profileName, "profile", "none", "Name of profile to capture. One of (none|cpu|heap|goroutine|threadcreate|block|mutex)")
36 flags.StringVar(&profileOutput, "profile-output", "profile.pprof", "Name of the file to write the profile to")
37 }
38
39 func initProfiling() error {
40 var (
41 f *os.File
42 err error
43 )
44 switch profileName {
45 case "none":
46 return nil
47 case "cpu":
48 f, err = os.Create(profileOutput)
49 if err != nil {
50 return err
51 }
52 err = pprof.StartCPUProfile(f)
53 if err != nil {
54 return err
55 }
56
57
58 case "block":
59 runtime.SetBlockProfileRate(1)
60 case "mutex":
61 runtime.SetMutexProfileFraction(1)
62 default:
63
64 if profile := pprof.Lookup(profileName); profile == nil {
65 return fmt.Errorf("unknown profile '%s'", profileName)
66 }
67 }
68
69
70
71 c := make(chan os.Signal, 1)
72 signal.Notify(c, os.Interrupt)
73 go func() {
74 <-c
75 f.Close()
76 flushProfiling()
77 os.Exit(0)
78 }()
79
80 return nil
81 }
82
83 func flushProfiling() error {
84 switch profileName {
85 case "none":
86 return nil
87 case "cpu":
88 pprof.StopCPUProfile()
89 case "heap":
90 runtime.GC()
91 fallthrough
92 default:
93 profile := pprof.Lookup(profileName)
94 if profile == nil {
95 return nil
96 }
97 f, err := os.Create(profileOutput)
98 if err != nil {
99 return err
100 }
101 defer f.Close()
102 profile.WriteTo(f, 0)
103 }
104
105 return nil
106 }
107
View as plain text