github.com/tickoalcantara12/micro/v3@v3.0.0-20221007104245-9d75b9bcbab9/service/debug/profile/pprof/pprof.go (about) 1 // Licensed under the Apache License, Version 2.0 (the "License"); 2 // you may not use this file except in compliance with the License. 3 // You may obtain a copy of the License at 4 // 5 // https://www.apache.org/licenses/LICENSE-2.0 6 // 7 // Unless required by applicable law or agreed to in writing, software 8 // distributed under the License is distributed on an "AS IS" BASIS, 9 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 // See the License for the specific language governing permissions and 11 // limitations under the License. 12 // 13 // Original source: github.com/micro/go-micro/v3/debug/profile/pprof/pprof.go 14 15 // Package pprof provides a pprof profiler which writes output to /tmp/[name].{cpu,mem}.pprof 16 package pprof 17 18 import ( 19 "os" 20 "path/filepath" 21 "runtime" 22 "runtime/pprof" 23 "sync" 24 "time" 25 26 "github.com/tickoalcantara12/micro/v3/service/debug/profile" 27 ) 28 29 type profiler struct { 30 opts profile.Options 31 32 sync.Mutex 33 running bool 34 exit chan bool 35 36 // where the cpu profile is written 37 cpuFile *os.File 38 // where the mem profile is written 39 memFile *os.File 40 } 41 42 func (p *profiler) writeHeap(f *os.File) { 43 defer f.Close() 44 45 t := time.NewTicker(time.Second * 30) 46 defer t.Stop() 47 48 for { 49 select { 50 case <-t.C: 51 runtime.GC() 52 pprof.WriteHeapProfile(f) 53 case <-p.exit: 54 return 55 } 56 } 57 } 58 59 func (p *profiler) Start() error { 60 p.Lock() 61 defer p.Unlock() 62 63 if p.running { 64 return nil 65 } 66 67 // create exit channel 68 p.exit = make(chan bool) 69 70 cpuFile := filepath.Join("/tmp", "cpu.pprof") 71 memFile := filepath.Join("/tmp", "mem.pprof") 72 73 if len(p.opts.Name) > 0 { 74 cpuFile = filepath.Join("/tmp", p.opts.Name+".cpu.pprof") 75 memFile = filepath.Join("/tmp", p.opts.Name+".mem.pprof") 76 } 77 78 f1, err := os.Create(cpuFile) 79 if err != nil { 80 return err 81 } 82 83 f2, err := os.Create(memFile) 84 if err != nil { 85 return err 86 } 87 88 // start cpu profiling 89 if err := pprof.StartCPUProfile(f1); err != nil { 90 return err 91 } 92 93 // write the heap periodically 94 go p.writeHeap(f2) 95 96 // set cpu file 97 p.cpuFile = f1 98 // set mem file 99 p.memFile = f2 100 101 p.running = true 102 103 return nil 104 } 105 106 func (p *profiler) Stop() error { 107 p.Lock() 108 defer p.Unlock() 109 110 select { 111 case <-p.exit: 112 return nil 113 default: 114 close(p.exit) 115 pprof.StopCPUProfile() 116 p.cpuFile.Close() 117 p.running = false 118 p.cpuFile = nil 119 p.memFile = nil 120 return nil 121 } 122 } 123 124 func (p *profiler) String() string { 125 return "pprof" 126 } 127 128 func NewProfile(opts ...profile.Option) profile.Profile { 129 var options profile.Options 130 for _, o := range opts { 131 o(&options) 132 } 133 p := new(profiler) 134 p.opts = options 135 return p 136 }