github.com/digdeepmining/go-atheios@v1.5.13-0.20180902133602-d5687a2e6f43/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/atheioschain/go-atheios/logger" 37 "github.com/atheioschain/go-atheios/logger/glog" 38 ) 39 40 // Handler is the global debugging handler. 41 var Handler = new(HandlerT) 42 43 // HandlerT implements the debugging API. 44 // Do not create values of this type, use the one 45 // in the Handler variable instead. 46 type HandlerT struct { 47 mu sync.Mutex 48 cpuW io.WriteCloser 49 cpuFile string 50 traceW io.WriteCloser 51 traceFile string 52 } 53 54 // Verbosity sets the glog verbosity ceiling. 55 // The verbosity of individual packages and source files 56 // can be raised using Vmodule. 57 func (*HandlerT) Verbosity(level int) { 58 glog.SetV(level) 59 } 60 61 // Vmodule sets the glog verbosity pattern. See package 62 // glog for details on pattern syntax. 63 func (*HandlerT) Vmodule(pattern string) error { 64 return glog.GetVModule().Set(pattern) 65 } 66 67 // BacktraceAt sets the glog backtrace location. 68 // See package glog for details on pattern syntax. 69 func (*HandlerT) BacktraceAt(location string) error { 70 return glog.GetTraceLocation().Set(location) 71 } 72 73 // MemStats returns detailed runtime memory statistics. 74 func (*HandlerT) MemStats() *runtime.MemStats { 75 s := new(runtime.MemStats) 76 runtime.ReadMemStats(s) 77 return s 78 } 79 80 // GcStats returns GC statistics. 81 func (*HandlerT) GcStats() *debug.GCStats { 82 s := new(debug.GCStats) 83 debug.ReadGCStats(s) 84 return s 85 } 86 87 // CpuProfile turns on CPU profiling for nsec seconds and writes 88 // profile data to file. 89 func (h *HandlerT) CpuProfile(file string, nsec uint) error { 90 if err := h.StartCPUProfile(file); err != nil { 91 return err 92 } 93 time.Sleep(time.Duration(nsec) * time.Second) 94 h.StopCPUProfile() 95 return nil 96 } 97 98 // StartCPUProfile turns on CPU profiling, writing to the given file. 99 func (h *HandlerT) StartCPUProfile(file string) error { 100 h.mu.Lock() 101 defer h.mu.Unlock() 102 if h.cpuW != nil { 103 return errors.New("CPU profiling already in progress") 104 } 105 f, err := os.Create(expandHome(file)) 106 if err != nil { 107 return err 108 } 109 if err := pprof.StartCPUProfile(f); err != nil { 110 f.Close() 111 return err 112 } 113 h.cpuW = f 114 h.cpuFile = file 115 glog.V(logger.Info).Infoln("CPU profiling started, writing to", h.cpuFile) 116 return nil 117 } 118 119 // StopCPUProfile stops an ongoing CPU profile. 120 func (h *HandlerT) StopCPUProfile() error { 121 h.mu.Lock() 122 defer h.mu.Unlock() 123 pprof.StopCPUProfile() 124 if h.cpuW == nil { 125 return errors.New("CPU profiling not in progress") 126 } 127 glog.V(logger.Info).Infoln("done writing CPU profile to", h.cpuFile) 128 h.cpuW.Close() 129 h.cpuW = nil 130 h.cpuFile = "" 131 return nil 132 } 133 134 // GoTrace turns on tracing for nsec seconds and writes 135 // trace data to file. 136 func (h *HandlerT) GoTrace(file string, nsec uint) error { 137 if err := h.StartGoTrace(file); err != nil { 138 return err 139 } 140 time.Sleep(time.Duration(nsec) * time.Second) 141 h.StopGoTrace() 142 return nil 143 } 144 145 // BlockProfile turns on CPU profiling for nsec seconds and writes 146 // profile data to file. It uses a profile rate of 1 for most accurate 147 // information. If a different rate is desired, set the rate 148 // and write the profile manually. 149 func (*HandlerT) BlockProfile(file string, nsec uint) error { 150 runtime.SetBlockProfileRate(1) 151 time.Sleep(time.Duration(nsec) * time.Second) 152 defer runtime.SetBlockProfileRate(0) 153 return writeProfile("block", file) 154 } 155 156 // SetBlockProfileRate sets the rate of goroutine block profile data collection. 157 // rate 0 disables block profiling. 158 func (*HandlerT) SetBlockProfileRate(rate int) { 159 runtime.SetBlockProfileRate(rate) 160 } 161 162 // WriteBlockProfile writes a goroutine blocking profile to the given file. 163 func (*HandlerT) WriteBlockProfile(file string) error { 164 return writeProfile("block", file) 165 } 166 167 // WriteMemProfile writes an allocation profile to the given file. 168 // Note that the profiling rate cannot be set through the API, 169 // it must be set on the command line. 170 func (*HandlerT) WriteMemProfile(file string) error { 171 return writeProfile("heap", file) 172 } 173 174 // Stacks returns a printed representation of the stacks of all goroutines. 175 func (*HandlerT) Stacks() string { 176 buf := make([]byte, 1024*1024) 177 buf = buf[:runtime.Stack(buf, true)] 178 return string(buf) 179 } 180 181 func writeProfile(name, file string) error { 182 p := pprof.Lookup(name) 183 glog.V(logger.Info).Infof("writing %d %s profile records to %s", p.Count(), name, file) 184 f, err := os.Create(expandHome(file)) 185 if err != nil { 186 return err 187 } 188 defer f.Close() 189 return p.WriteTo(f, 0) 190 } 191 192 // expands home directory in file paths. 193 // ~someuser/tmp will not be expanded. 194 func expandHome(p string) string { 195 if strings.HasPrefix(p, "~/") || strings.HasPrefix(p, "~\\") { 196 home := os.Getenv("HOME") 197 if home == "" { 198 if usr, err := user.Current(); err == nil { 199 home = usr.HomeDir 200 } 201 } 202 if home != "" { 203 p = home + p[1:] 204 } 205 } 206 return filepath.Clean(p) 207 }