github.com/bcskill/bcschain/v3@v3.4.9-beta2/internal/debug/api.go (about) 1 // Copyright 2016 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 // Package debug interfaces Go runtime debugging facilities. 18 // This package is mostly glue code making these facilities available 19 // through the CLI and RPC subsystem. If you want to use them from Go code, 20 // use package runtime instead. 21 package debug 22 23 import ( 24 "errors" 25 "io" 26 "os" 27 "os/user" 28 "path/filepath" 29 "runtime" 30 "runtime/debug" 31 "runtime/pprof" 32 "strings" 33 "sync" 34 "time" 35 36 "github.com/bcskill/bcschain/v3/log" 37 ) 38 39 // Handler is the global debugging handler. 40 var Handler = new(HandlerT) 41 42 // HandlerT implements the debugging API. 43 // Do not create values of this type, use the one 44 // in the Handler variable instead. 45 type HandlerT struct { 46 mu sync.Mutex 47 cpuW io.WriteCloser 48 cpuFile string 49 traceW io.WriteCloser 50 traceFile string 51 } 52 53 // Verbosity sets the log verbosity ceiling. The verbosity of individual packages 54 // and source files can be raised using Vmodule. 55 func (*HandlerT) Verbosity(level int) { 56 glogger.Verbosity(log.Lvl(level)) 57 } 58 59 // Vmodule sets the log verbosity pattern. See package log for details on the 60 // pattern syntax. 61 func (*HandlerT) Vmodule(pattern string) error { 62 return glogger.Vmodule(pattern) 63 } 64 65 // BacktraceAt sets the log backtrace location. See package log for details on 66 // the pattern syntax. 67 func (*HandlerT) BacktraceAt(location string) error { 68 return glogger.BacktraceAt(location) 69 } 70 71 // MemStats returns detailed runtime memory statistics. 72 func (*HandlerT) MemStats() *runtime.MemStats { 73 s := new(runtime.MemStats) 74 runtime.ReadMemStats(s) 75 return s 76 } 77 78 // GcStats returns GC statistics. 79 func (*HandlerT) GcStats() *debug.GCStats { 80 s := new(debug.GCStats) 81 debug.ReadGCStats(s) 82 return s 83 } 84 85 // CpuProfile turns on CPU profiling for nsec seconds and writes 86 // profile data to file. 87 func (h *HandlerT) CpuProfile(file string, nsec uint) error { 88 if err := h.StartCPUProfile(file); err != nil { 89 return err 90 } 91 time.Sleep(time.Duration(nsec) * time.Second) 92 h.StopCPUProfile() 93 return nil 94 } 95 96 // StartCPUProfile turns on CPU profiling, writing to the given file. 97 func (h *HandlerT) StartCPUProfile(file string) error { 98 h.mu.Lock() 99 defer h.mu.Unlock() 100 if h.cpuW != nil { 101 return errors.New("CPU profiling already in progress") 102 } 103 f, err := os.Create(expandHome(file)) 104 if err != nil { 105 return err 106 } 107 if err := pprof.StartCPUProfile(f); err != nil { 108 f.Close() 109 return err 110 } 111 h.cpuW = f 112 h.cpuFile = file 113 log.Info("CPU profiling started", "dump", h.cpuFile) 114 return nil 115 } 116 117 // StopCPUProfile stops an ongoing CPU profile. 118 func (h *HandlerT) StopCPUProfile() error { 119 h.mu.Lock() 120 defer h.mu.Unlock() 121 pprof.StopCPUProfile() 122 if h.cpuW == nil { 123 return errors.New("CPU profiling not in progress") 124 } 125 log.Info("Done writing CPU profile", "dump", h.cpuFile) 126 h.cpuW.Close() 127 h.cpuW = nil 128 h.cpuFile = "" 129 return nil 130 } 131 132 // GoTrace turns on tracing for nsec seconds and writes 133 // trace data to file. 134 func (h *HandlerT) GoTrace(file string, nsec uint) error { 135 if err := h.StartGoTrace(file); err != nil { 136 return err 137 } 138 time.Sleep(time.Duration(nsec) * time.Second) 139 h.StopGoTrace() 140 return nil 141 } 142 143 // BlockProfile turns on goroutine profiling for nsec seconds and writes profile data to 144 // file. It uses a profile rate of 1 for most accurate information. If a different rate is 145 // desired, set the rate and write the profile manually. 146 func (*HandlerT) BlockProfile(file string, nsec uint) error { 147 runtime.SetBlockProfileRate(1) 148 time.Sleep(time.Duration(nsec) * time.Second) 149 defer runtime.SetBlockProfileRate(0) 150 return writeProfile("block", file) 151 } 152 153 // SetBlockProfileRate sets the rate of goroutine block profile data collection. 154 // rate 0 disables block profiling. 155 func (*HandlerT) SetBlockProfileRate(rate int) { 156 runtime.SetBlockProfileRate(rate) 157 } 158 159 // WriteBlockProfile writes a goroutine blocking profile to the given file. 160 func (*HandlerT) WriteBlockProfile(file string) error { 161 return writeProfile("block", file) 162 } 163 164 // MutexProfile turns on mutex profiling for nsec seconds and writes profile data to file. 165 // It uses a profile rate of 1 for most accurate information. If a different rate is 166 // desired, set the rate and write the profile manually. 167 func (*HandlerT) MutexProfile(file string, nsec uint) error { 168 runtime.SetMutexProfileFraction(1) 169 time.Sleep(time.Duration(nsec) * time.Second) 170 defer runtime.SetMutexProfileFraction(0) 171 return writeProfile("mutex", file) 172 } 173 174 // SetMutexProfileFraction sets the rate of mutex profiling. 175 func (*HandlerT) SetMutexProfileFraction(rate int) { 176 runtime.SetMutexProfileFraction(rate) 177 } 178 179 // WriteMutexProfile writes a goroutine blocking profile to the given file. 180 func (*HandlerT) WriteMutexProfile(file string) error { 181 return writeProfile("mutex", file) 182 } 183 184 // WriteMemProfile writes an allocation profile to the given file. 185 // Note that the profiling rate cannot be set through the API, 186 // it must be set on the command line. 187 func (*HandlerT) WriteMemProfile(file string) error { 188 return writeProfile("heap", file) 189 } 190 191 // Stacks returns a printed representation of the stacks of all goroutines. 192 func (*HandlerT) Stacks() string { 193 buf := make([]byte, 1024*1024) 194 buf = buf[:runtime.Stack(buf, true)] 195 return string(buf) 196 } 197 198 // FreeOSMemory returns unused memory to the OS. 199 func (*HandlerT) FreeOSMemory() { 200 debug.FreeOSMemory() 201 } 202 203 // SetGCPercent sets the garbage collection target percentage. It returns the previous 204 // setting. A negative value disables GC. 205 func (*HandlerT) SetGCPercent(v int) int { 206 return debug.SetGCPercent(v) 207 } 208 209 func writeProfile(name, file string) error { 210 p := pprof.Lookup(name) 211 log.Info("Writing profile records", "count", p.Count(), "type", name, "dump", file) 212 f, err := os.Create(expandHome(file)) 213 if err != nil { 214 return err 215 } 216 defer f.Close() 217 return p.WriteTo(f, 0) 218 } 219 220 // expands home directory in file paths. 221 // ~someuser/tmp will not be expanded. 222 func expandHome(p string) string { 223 if strings.HasPrefix(p, "~/") || strings.HasPrefix(p, "~\\") { 224 home := os.Getenv("HOME") 225 if home == "" { 226 if usr, err := user.Current(); err == nil { 227 home = usr.HomeDir 228 } 229 } 230 if home != "" { 231 p = home + p[1:] 232 } 233 } 234 return filepath.Clean(p) 235 }