github.com/linapex/ethereum-dpos-chinese@v0.0.0-20190316121959-b78b3a4a1ece/internal/debug/api.go (about) 1 2 //<developer> 3 // <name>linapex 曹一峰</name> 4 // <email>linapex@163.com</email> 5 // <wx>superexc</wx> 6 // <qqgroup>128148617</qqgroup> 7 // <url>https://jsq.ink</url> 8 // <role>pku engineer</role> 9 // <date>2019-03-16 12:09:40</date> 10 //</624342640623620096> 11 12 13 //包调试接口转到运行时调试工具。 14 //这个包主要是胶水代码使这些设施可用 15 //通过cli和rpc子系统。如果你想从Go代码中使用它们, 16 //改用包运行时。 17 package debug 18 19 import ( 20 "bytes" 21 "errors" 22 "io" 23 "os" 24 "os/user" 25 "path/filepath" 26 "runtime" 27 "runtime/debug" 28 "runtime/pprof" 29 "strings" 30 "sync" 31 "time" 32 33 "github.com/ethereum/go-ethereum/log" 34 ) 35 36 //处理程序是全局调试处理程序。 37 var Handler = new(HandlerT) 38 39 //handlert实现调试API。 40 //不要创建此类型的值,请使用 41 //而是在处理程序变量中。 42 type HandlerT struct { 43 mu sync.Mutex 44 cpuW io.WriteCloser 45 cpuFile string 46 traceW io.WriteCloser 47 traceFile string 48 } 49 50 //冗长设置了原木冗长的天花板。单个包装的冗长程度 51 //源文件可以使用vmodule来提升。 52 func (*HandlerT) Verbosity(level int) { 53 glogger.Verbosity(log.Lvl(level)) 54 } 55 56 //vmodule设置日志冗长模式。有关 57 //模式语法。 58 func (*HandlerT) Vmodule(pattern string) error { 59 return glogger.Vmodule(pattern) 60 } 61 62 //backtraceat设置日志backtrace位置。有关详细信息,请参阅包日志 63 //模式语法。 64 func (*HandlerT) BacktraceAt(location string) error { 65 return glogger.BacktraceAt(location) 66 } 67 68 //MEMSTATS返回详细的运行时内存统计信息。 69 func (*HandlerT) MemStats() *runtime.MemStats { 70 s := new(runtime.MemStats) 71 runtime.ReadMemStats(s) 72 return s 73 } 74 75 //gcstats返回gc统计信息。 76 func (*HandlerT) GcStats() *debug.GCStats { 77 s := new(debug.GCStats) 78 debug.ReadGCStats(s) 79 return s 80 } 81 82 //cpuprofile打开cpu配置文件达nsec秒并写入 83 //配置文件数据到文件。 84 func (h *HandlerT) CpuProfile(file string, nsec uint) error { 85 if err := h.StartCPUProfile(file); err != nil { 86 return err 87 } 88 time.Sleep(time.Duration(nsec) * time.Second) 89 h.StopCPUProfile() 90 return nil 91 } 92 93 //startcpuprofile打开CPU配置文件,写入给定文件。 94 func (h *HandlerT) StartCPUProfile(file string) error { 95 h.mu.Lock() 96 defer h.mu.Unlock() 97 if h.cpuW != nil { 98 return errors.New("CPU profiling already in progress") 99 } 100 f, err := os.Create(expandHome(file)) 101 if err != nil { 102 return err 103 } 104 if err := pprof.StartCPUProfile(f); err != nil { 105 f.Close() 106 return err 107 } 108 h.cpuW = f 109 h.cpuFile = file 110 log.Info("CPU profiling started", "dump", h.cpuFile) 111 return nil 112 } 113 114 //stopcupprofile停止正在进行的CPU配置文件。 115 func (h *HandlerT) StopCPUProfile() error { 116 h.mu.Lock() 117 defer h.mu.Unlock() 118 pprof.StopCPUProfile() 119 if h.cpuW == nil { 120 return errors.New("CPU profiling not in progress") 121 } 122 log.Info("Done writing CPU profile", "dump", h.cpuFile) 123 h.cpuW.Close() 124 h.cpuW = nil 125 h.cpuFile = "" 126 return nil 127 } 128 129 //gotrace打开对nsec秒的跟踪并写入 130 //将数据跟踪到文件。 131 func (h *HandlerT) GoTrace(file string, nsec uint) error { 132 if err := h.StartGoTrace(file); err != nil { 133 return err 134 } 135 time.Sleep(time.Duration(nsec) * time.Second) 136 h.StopGoTrace() 137 return nil 138 } 139 140 //BoeStand将GOOTONE配置文件转换为NSEC秒,并将配置文件数据写入 141 //文件。它使用1的配置率来获取最准确的信息。如果不同的利率是 142 //需要时,设置速率并手动写入配置文件。 143 func (*HandlerT) BlockProfile(file string, nsec uint) error { 144 runtime.SetBlockProfileRate(1) 145 time.Sleep(time.Duration(nsec) * time.Second) 146 defer runtime.SetBlockProfileRate(0) 147 return writeProfile("block", file) 148 } 149 150 //setBlockProfileRate设置goroutine块配置文件数据收集的速率。 151 //速率0禁用块分析。 152 func (*HandlerT) SetBlockProfileRate(rate int) { 153 runtime.SetBlockProfileRate(rate) 154 } 155 156 //WriteBlockProfile将goroutine阻塞配置文件写入给定文件。 157 func (*HandlerT) WriteBlockProfile(file string) error { 158 return writeProfile("block", file) 159 } 160 161 //mutex profile打开mutex配置文件达nsec秒,并将配置文件数据写入文件。 162 //它使用1的配置率来获取最准确的信息。如果不同的利率是 163 //需要时,设置速率并手动写入配置文件。 164 func (*HandlerT) MutexProfile(file string, nsec uint) error { 165 runtime.SetMutexProfileFraction(1) 166 time.Sleep(time.Duration(nsec) * time.Second) 167 defer runtime.SetMutexProfileFraction(0) 168 return writeProfile("mutex", file) 169 } 170 171 //setmutexprofilefraction设置mutex分析的速率。 172 func (*HandlerT) SetMutexProfileFraction(rate int) { 173 runtime.SetMutexProfileFraction(rate) 174 } 175 176 //writemutexprofile将goroutine阻塞配置文件写入给定文件。 177 func (*HandlerT) WriteMutexProfile(file string) error { 178 return writeProfile("mutex", file) 179 } 180 181 //WriteMemProfile将分配配置文件写入给定文件。 182 //请注意,无法通过API设置分析速率, 183 //必须在命令行上设置。 184 func (*HandlerT) WriteMemProfile(file string) error { 185 return writeProfile("heap", file) 186 } 187 188 //Stacks返回所有goroutine堆栈的打印表示。 189 func (*HandlerT) Stacks() string { 190 buf := new(bytes.Buffer) 191 pprof.Lookup("goroutine").WriteTo(buf, 2) 192 return buf.String() 193 } 194 195 //FreeosMemory将未使用的内存返回给操作系统。 196 func (*HandlerT) FreeOSMemory() { 197 debug.FreeOSMemory() 198 } 199 200 //setgcPercent设置垃圾收集目标百分比。它返回上一个 201 //设置。负值将禁用gc。 202 func (*HandlerT) SetGCPercent(v int) int { 203 return debug.SetGCPercent(v) 204 } 205 206 func writeProfile(name, file string) error { 207 p := pprof.Lookup(name) 208 log.Info("Writing profile records", "count", p.Count(), "type", name, "dump", file) 209 f, err := os.Create(expandHome(file)) 210 if err != nil { 211 return err 212 } 213 defer f.Close() 214 return p.WriteTo(f, 0) 215 } 216 217 //在文件路径中展开主目录。 218 //~someuser/tmp将不会扩展。 219 func expandHome(p string) string { 220 if strings.HasPrefix(p, "~/") || strings.HasPrefix(p, "~\\") { 221 home := os.Getenv("HOME") 222 if home == "" { 223 if usr, err := user.Current(); err == nil { 224 home = usr.HomeDir 225 } 226 } 227 if home != "" { 228 p = home + p[1:] 229 } 230 } 231 return filepath.Clean(p) 232 } 233