profile.go 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. package profile
  2. import (
  3. "os"
  4. "path/filepath"
  5. "runtime"
  6. "runtime/pprof"
  7. "bet24.com/log"
  8. )
  9. const (
  10. cpuMode = iota
  11. memMode
  12. mutexMode
  13. blockMode
  14. traceMode
  15. goroutineMode
  16. threadCreateMode
  17. )
  18. type Profile struct {
  19. // 分析模式
  20. mode int
  21. path string
  22. //内存配置文件采样速率,分析器将会在每分配指定的字节数量后对内存使用情况进行取样
  23. memProfileRate int
  24. closer func()
  25. stopped uint32
  26. namePrefix string
  27. }
  28. func NamePrefix(name string) func(*Profile) {
  29. return func(p *Profile) {
  30. p.namePrefix = name
  31. }
  32. }
  33. // CPUProfile enables cpu profiling.
  34. // It disables any previous profiling settings.
  35. func CPUProfile(p *Profile) { p.mode = cpuMode }
  36. // DefaultMemProfileRate is the default memory profiling rate.
  37. const DefaultMemProfileRate = 4096
  38. // MemProfile enables memory profiling.
  39. // It disables any previous profiling settings.
  40. func MemProfile(p *Profile) {
  41. p.memProfileRate = DefaultMemProfileRate
  42. p.mode = memMode
  43. }
  44. //GoRTProfile enables goroutine profiling
  45. func GoRTProfile(p *Profile) { p.mode = goroutineMode }
  46. //block enables goroutine profiling
  47. func BlockProfile(p *Profile) { p.mode = blockMode }
  48. //MutexProfile enables goroutine profiling
  49. func MutexProfile(p *Profile) { p.mode = mutexMode }
  50. // ProfilePath controls the base path where various profiling
  51. // files are written. If blank, the base path will be generated
  52. // by os.MkdirTemp.
  53. func ProfilePath(path string) func(*Profile) {
  54. return func(p *Profile) {
  55. p.path = path
  56. }
  57. }
  58. // Stop stops the profile and flushes any unwritten data.
  59. func (p *Profile) Stop() {
  60. p.closer()
  61. }
  62. // Start starts a new profiling session.
  63. // The caller should call the Stop method on the value returned
  64. // to cleanly stop profiling.
  65. func Start(options ...func(*Profile)) interface {
  66. Stop()
  67. } {
  68. var prof Profile
  69. for _, option := range options {
  70. option(&prof)
  71. }
  72. path, err := func() (string, error) {
  73. if p := prof.path; p != "" {
  74. return p, os.MkdirAll(p, 0777)
  75. }
  76. return os.MkdirTemp("", "profile")
  77. }()
  78. if err != nil {
  79. log.Fatal("profile: could not create initial output directory: %v", err)
  80. }
  81. logf := func(format string, args ...interface{}) {
  82. log.Debug(format, args...)
  83. }
  84. switch prof.mode {
  85. case cpuMode:
  86. fn := filepath.Join(path, prof.namePrefix+"cpu.pprof")
  87. f, err := os.Create(fn)
  88. if err != nil {
  89. log.Fatal("profile: could not create cpu profile %q: %v", fn, err)
  90. }
  91. logf("profile: cpu profiling enabled, %s", fn)
  92. pprof.StartCPUProfile(f)
  93. prof.closer = func() {
  94. pprof.StopCPUProfile()
  95. f.Close()
  96. logf("profile: cpu profiling disabled, %s", fn)
  97. }
  98. case memMode:
  99. fn := filepath.Join(path, prof.namePrefix+"mem.pprof")
  100. f, err := os.Create(fn)
  101. if err != nil {
  102. log.Fatal("profile: could not create memory profile %q: %v", fn, err)
  103. }
  104. old := runtime.MemProfileRate
  105. runtime.MemProfileRate = prof.memProfileRate
  106. logf("profile: memory profiling enabled (rate %d), %s", runtime.MemProfileRate, fn)
  107. prof.closer = func() {
  108. pprof.Lookup("heap").WriteTo(f, 0)
  109. f.Close()
  110. runtime.MemProfileRate = old
  111. logf("profile: memory profiling disabled, %s", fn)
  112. }
  113. case goroutineMode:
  114. fn := filepath.Join(path, prof.namePrefix+"goroutine.pprof")
  115. f, err := os.Create(fn)
  116. if err != nil {
  117. log.Fatal("profile: could not create goroutine profile %q: %v", fn, err)
  118. }
  119. logf("profile: goroutine profiling enabled, %s", fn)
  120. prof.closer = func() {
  121. pprof.Lookup("goroutine").WriteTo(f, 0)
  122. f.Close()
  123. logf("profile: goroutine profiling disabled, %s", fn)
  124. }
  125. case blockMode:
  126. fn := filepath.Join(path, prof.namePrefix+"block.pprof")
  127. f, err := os.Create(fn)
  128. if err != nil {
  129. log.Fatal("profile: could not create block profile %q: %v", fn, err)
  130. }
  131. logf("profile: block profiling enabled, %s", fn)
  132. prof.closer = func() {
  133. pprof.Lookup("block").WriteTo(f, 0)
  134. f.Close()
  135. logf("profile: block profiling disabled, %s", fn)
  136. }
  137. case mutexMode:
  138. fn := filepath.Join(path, prof.namePrefix+"mutex.pprof")
  139. f, err := os.Create(fn)
  140. if err != nil {
  141. log.Fatal("profile: could not create mutex profile %q: %v", fn, err)
  142. }
  143. logf("profile: mutex profiling enabled, %s", fn)
  144. prof.closer = func() {
  145. pprof.Lookup("mutex").WriteTo(f, 0)
  146. f.Close()
  147. logf("profile: mutex profiling disabled, %s", fn)
  148. }
  149. }
  150. return &prof
  151. }