profilecenter.go 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. package prof
  2. import (
  3. "bytes"
  4. "strconv"
  5. "sync"
  6. "sync/atomic"
  7. "time"
  8. "git.i2edu.net/i2/go-zero/core/logx"
  9. "git.i2edu.net/i2/go-zero/core/threading"
  10. "github.com/olekukonko/tablewriter"
  11. )
  12. type (
  13. profileSlot 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]*profileSlot
  22. }
  23. )
  24. const flushInterval = 5 * time.Minute
  25. var (
  26. pc = &profileCenter{
  27. slots: make(map[string]*profileSlot),
  28. }
  29. once sync.Once
  30. )
  31. func report(name string, duration time.Duration) {
  32. updated := func() bool {
  33. pc.lock.RLock()
  34. defer pc.lock.RUnlock()
  35. slot, ok := pc.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. pc.lock.Lock()
  47. defer pc.lock.Unlock()
  48. pc.slots[name] = &profileSlot{
  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. }
  74. return (time.Duration(total) / time.Duration(count)).String()
  75. }
  76. func() {
  77. pc.lock.Lock()
  78. defer pc.lock.Unlock()
  79. for key, slot := range pc.slots {
  80. data = append(data, []string{
  81. key,
  82. strconv.FormatInt(slot.lifecount, 10),
  83. calcFn(slot.lifecycle, slot.lifecount),
  84. strconv.FormatInt(slot.lastcount, 10),
  85. calcFn(slot.lastcycle, slot.lastcount),
  86. })
  87. // reset the data for last cycle
  88. slot.lastcount = 0
  89. slot.lastcycle = 0
  90. }
  91. }()
  92. table := tablewriter.NewWriter(&buffer)
  93. table.SetHeader([]string{"QUEUE", "LIFECOUNT", "LIFECYCLE", "LASTCOUNT", "LASTCYCLE"})
  94. table.SetBorder(false)
  95. table.AppendBulk(data)
  96. table.Render()
  97. return buffer.String()
  98. }