api.go 5.8 KB

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