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