profilecenter.go 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. package prof
  2. import (
  3. "bytes"
  4. "strconv"
  5. "sync"
  6. "sync/atomic"
  7. "time"
  8. "github.com/olekukonko/tablewriter"
  9. "github.com/tal-tech/go-zero/core/logx"
  10. "github.com/tal-tech/go-zero/core/threading"
  11. )
  12. type (
  13. Slot struct {
  14. lifecount int64
  15. lastcount int64
  16. lifecycle int64
  17. lastcycle int64
  18. }
  19. ProfileCenter struct {
  20. lock sync.RWMutex
  21. slots map[string]*Slot
  22. }
  23. )
  24. const flushInterval = 5 * time.Minute
  25. var (
  26. profileCenter = &ProfileCenter{
  27. slots: make(map[string]*Slot),
  28. }
  29. once sync.Once
  30. )
  31. func report(name string, duration time.Duration) {
  32. updated := func() bool {
  33. profileCenter.lock.RLock()
  34. defer profileCenter.lock.RUnlock()
  35. slot, ok := profileCenter.slots[name]
  36. if ok {
  37. atomic.AddInt64(&slot.lifecount, 1)
  38. atomic.AddInt64(&slot.lastcount, 1)
  39. atomic.AddInt64(&slot.lifecycle, int64(duration))
  40. atomic.AddInt64(&slot.lastcycle, int64(duration))
  41. }
  42. return ok
  43. }()
  44. if !updated {
  45. func() {
  46. profileCenter.lock.Lock()
  47. defer profileCenter.lock.Unlock()
  48. profileCenter.slots[name] = &Slot{
  49. lifecount: 1,
  50. lastcount: 1,
  51. lifecycle: int64(duration),
  52. lastcycle: int64(duration),
  53. }
  54. }()
  55. }
  56. once.Do(flushRepeatly)
  57. }
  58. func flushRepeatly() {
  59. threading.GoSafe(func() {
  60. for {
  61. time.Sleep(flushInterval)
  62. logx.Stat(generateReport())
  63. }
  64. })
  65. }
  66. func generateReport() string {
  67. var buffer bytes.Buffer
  68. buffer.WriteString("Profiling report\n")
  69. var data [][]string
  70. calcFn := func(total, count int64) string {
  71. if count == 0 {
  72. return "-"
  73. } else {
  74. return (time.Duration(total) / time.Duration(count)).String()
  75. }
  76. }
  77. func() {
  78. profileCenter.lock.Lock()
  79. defer profileCenter.lock.Unlock()
  80. for key, slot := range profileCenter.slots {
  81. data = append(data, []string{
  82. key,
  83. strconv.FormatInt(slot.lifecount, 10),
  84. calcFn(slot.lifecycle, slot.lifecount),
  85. strconv.FormatInt(slot.lastcount, 10),
  86. calcFn(slot.lastcycle, slot.lastcount),
  87. })
  88. // reset the data for last cycle
  89. slot.lastcount = 0
  90. slot.lastcycle = 0
  91. }
  92. }()
  93. table := tablewriter.NewWriter(&buffer)
  94. table.SetHeader([]string{"QUEUE", "LIFECOUNT", "LIFECYCLE", "LASTCOUNT", "LASTCYCLE"})
  95. table.SetBorder(false)
  96. table.AppendBulk(data)
  97. table.Render()
  98. return buffer.String()
  99. }