github.com/bigzoro/my_simplechain@v0.0.0-20240315012955-8ad0a2a29bb9/internal/debug/api.go (about) 1 // Copyright 2016 The go-simplechain Authors 2 // This file is part of the go-simplechain library. 3 // 4 // The go-simplechain 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-simplechain 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-simplechain 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 "bytes" 25 "errors" 26 "io" 27 "os" 28 "os/user" 29 "path/filepath" 30 "runtime" 31 "runtime/debug" 32 "runtime/pprof" 33 "strings" 34 "sync" 35 "time" 36 37 "github.com/bigzoro/my_simplechain/log" 38 ) 39 40 func GetLogVerbosity() log.Lvl { 41 return glogger.GetVerbosity() 42 } 43 44 // Handler is the global debugging handler. 45 var Handler = new(HandlerT) 46 47 // HandlerT implements the debugging API. 48 // Do not create values of this type, use the one 49 // in the Handler variable instead. 50 type HandlerT struct { 51 mu sync.Mutex 52 cpuW io.WriteCloser 53 cpuFile string 54 traceW io.WriteCloser 55 traceFile string 56 } 57 58 // Verbosity sets the log verbosity ceiling. The verbosity of individual packages 59 // and source files can be raised using Vmodule. 60 func (*HandlerT) Verbosity(level int) { 61 glogger.Verbosity(log.Lvl(level)) 62 } 63 64 // Vmodule sets the log verbosity pattern. See package log for details on the 65 // pattern syntax. 66 func (*HandlerT) Vmodule(pattern string) error { 67 return glogger.Vmodule(pattern) 68 } 69 70 // BacktraceAt sets the log backtrace location. See package log for details on 71 // the pattern syntax. 72 func (*HandlerT) BacktraceAt(location string) error { 73 return glogger.BacktraceAt(location) 74 } 75 76 // MemStats returns detailed runtime memory statistics. 77 func (*HandlerT) MemStats() *runtime.MemStats { 78 s := new(runtime.MemStats) 79 runtime.ReadMemStats(s) 80 return s 81 } 82 83 // GcStats returns GC statistics. 84 func (*HandlerT) GcStats() *debug.GCStats { 85 s := new(debug.GCStats) 86 debug.ReadGCStats(s) 87 return s 88 } 89 90 // CpuProfile turns on CPU profiling for nsec seconds and writes 91 // profile data to file. 92 func (h *HandlerT) CpuProfile(file string, nsec uint) error { 93 if err := h.StartCPUProfile(file); err != nil { 94 return err 95 } 96 time.Sleep(time.Duration(nsec) * time.Second) 97 h.StopCPUProfile() 98 return nil 99 } 100 101 // StartCPUProfile turns on CPU profiling, writing to the given file. 102 func (h *HandlerT) StartCPUProfile(file string) error { 103 h.mu.Lock() 104 defer h.mu.Unlock() 105 if h.cpuW != nil { 106 return errors.New("CPU profiling already in progress") 107 } 108 f, err := os.Create(expandHome(file)) 109 if err != nil { 110 return err 111 } 112 if err := pprof.StartCPUProfile(f); err != nil { 113 f.Close() 114 return err 115 } 116 h.cpuW = f 117 h.cpuFile = file 118 log.Info("CPU profiling started", "dump", h.cpuFile) 119 return nil 120 } 121 122 // StopCPUProfile stops an ongoing CPU profile. 123 func (h *HandlerT) StopCPUProfile() error { 124 h.mu.Lock() 125 defer h.mu.Unlock() 126 pprof.StopCPUProfile() 127 if h.cpuW == nil { 128 return errors.New("CPU profiling not in progress") 129 } 130 log.Info("Done writing CPU profile", "dump", h.cpuFile) 131 h.cpuW.Close() 132 h.cpuW = nil 133 h.cpuFile = "" 134 return nil 135 } 136 137 // GoTrace turns on tracing for nsec seconds and writes 138 // trace data to file. 139 func (h *HandlerT) GoTrace(file string, nsec uint) error { 140 if err := h.StartGoTrace(file); err != nil { 141 return err 142 } 143 time.Sleep(time.Duration(nsec) * time.Second) 144 h.StopGoTrace() 145 return nil 146 } 147 148 // BlockProfile turns on goroutine profiling for nsec seconds and writes profile data to 149 // file. It uses a profile rate of 1 for most accurate information. If a different rate is 150 // desired, set the rate and write the profile manually. 151 func (*HandlerT) BlockProfile(file string, nsec uint) error { 152 runtime.SetBlockProfileRate(1) 153 time.Sleep(time.Duration(nsec) * time.Second) 154 defer runtime.SetBlockProfileRate(0) 155 return writeProfile("block", file) 156 } 157 158 // SetBlockProfileRate sets the rate of goroutine block profile data collection. 159 // rate 0 disables block profiling. 160 func (*HandlerT) SetBlockProfileRate(rate int) { 161 runtime.SetBlockProfileRate(rate) 162 } 163 164 // WriteBlockProfile writes a goroutine blocking profile to the given file. 165 func (*HandlerT) WriteBlockProfile(file string) error { 166 return writeProfile("block", file) 167 } 168 169 // MutexProfile turns on mutex profiling for nsec seconds and writes profile data to file. 170 // It uses a profile rate of 1 for most accurate information. If a different rate is 171 // desired, set the rate and write the profile manually. 172 func (*HandlerT) MutexProfile(file string, nsec uint) error { 173 runtime.SetMutexProfileFraction(1) 174 time.Sleep(time.Duration(nsec) * time.Second) 175 defer runtime.SetMutexProfileFraction(0) 176 return writeProfile("mutex", file) 177 } 178 179 // SetMutexProfileFraction sets the rate of mutex profiling. 180 func (*HandlerT) SetMutexProfileFraction(rate int) { 181 runtime.SetMutexProfileFraction(rate) 182 } 183 184 // WriteMutexProfile writes a goroutine blocking profile to the given file. 185 func (*HandlerT) WriteMutexProfile(file string) error { 186 return writeProfile("mutex", file) 187 } 188 189 // WriteMemProfile writes an allocation profile to the given file. 190 // Note that the profiling rate cannot be set through the API, 191 // it must be set on the command line. 192 func (*HandlerT) WriteMemProfile(file string) error { 193 return writeProfile("heap", file) 194 } 195 196 // Stacks returns a printed representation of the stacks of all goroutines. 197 func (*HandlerT) Stacks() string { 198 buf := new(bytes.Buffer) 199 pprof.Lookup("goroutine").WriteTo(buf, 2) 200 return buf.String() 201 } 202 203 // FreeOSMemory returns unused memory to the OS. 204 func (*HandlerT) FreeOSMemory() { 205 debug.FreeOSMemory() 206 } 207 208 // SetGCPercent sets the garbage collection target percentage. It returns the previous 209 // setting. A negative value disables GC. 210 func (*HandlerT) SetGCPercent(v int) int { 211 return debug.SetGCPercent(v) 212 } 213 214 func writeProfile(name, file string) error { 215 p := pprof.Lookup(name) 216 log.Info("Writing profile records", "count", p.Count(), "type", name, "dump", file) 217 f, err := os.Create(expandHome(file)) 218 if err != nil { 219 return err 220 } 221 defer f.Close() 222 return p.WriteTo(f, 0) 223 } 224 225 // expands home directory in file paths. 226 // ~someuser/tmp will not be expanded. 227 func expandHome(p string) string { 228 if strings.HasPrefix(p, "~/") || strings.HasPrefix(p, "~\\") { 229 home := os.Getenv("HOME") 230 if home == "" { 231 if usr, err := user.Current(); err == nil { 232 home = usr.HomeDir 233 } 234 } 235 if home != "" { 236 p = home + p[1:] 237 } 238 } 239 return filepath.Clean(p) 240 }