Files
go-zero/core/prof/profilecenter.go

108 lines
1.9 KiB
Go
Raw Permalink Normal View History

2020-07-26 17:09:05 +08:00
package prof
import (
"fmt"
"strings"
2020-07-26 17:09:05 +08:00
"sync"
"sync/atomic"
"time"
"github.com/zeromicro/go-zero/core/logx"
"github.com/zeromicro/go-zero/core/threading"
2020-07-26 17:09:05 +08:00
)
type (
2021-02-22 10:20:54 +08:00
profileSlot struct {
2020-07-26 17:09:05 +08:00
lifecount int64
lastcount int64
lifecycle int64
lastcycle int64
}
2021-02-22 10:20:54 +08:00
profileCenter struct {
2020-07-26 17:09:05 +08:00
lock sync.RWMutex
2021-02-22 10:20:54 +08:00
slots map[string]*profileSlot
2020-07-26 17:09:05 +08:00
}
)
const flushInterval = 5 * time.Minute
var pc = &profileCenter{
slots: make(map[string]*profileSlot),
}
2020-07-26 17:09:05 +08:00
func init() {
flushRepeatedly()
2020-07-26 17:09:05 +08:00
}
func flushRepeatedly() {
2020-07-26 17:09:05 +08:00
threading.GoSafe(func() {
for {
time.Sleep(flushInterval)
logx.Stat(generateReport())
}
})
}
func report(name string, duration time.Duration) {
slot := loadOrStoreSlot(name, duration)
atomic.AddInt64(&slot.lifecount, 1)
atomic.AddInt64(&slot.lastcount, 1)
atomic.AddInt64(&slot.lifecycle, int64(duration))
atomic.AddInt64(&slot.lastcycle, int64(duration))
}
func loadOrStoreSlot(name string, duration time.Duration) *profileSlot {
pc.lock.RLock()
slot, ok := pc.slots[name]
pc.lock.RUnlock()
if ok {
return slot
}
pc.lock.Lock()
defer pc.lock.Unlock()
// double-check
if slot, ok = pc.slots[name]; ok {
return slot
}
slot = &profileSlot{}
pc.slots[name] = slot
return slot
}
2020-07-26 17:09:05 +08:00
func generateReport() string {
var builder strings.Builder
builder.WriteString("Profiling report\n")
builder.WriteString("QUEUE,LIFECOUNT,LIFECYCLE,LASTCOUNT,LASTCYCLE\n")
2020-07-26 17:09:05 +08:00
calcFn := func(total, count int64) string {
if count == 0 {
return "-"
}
2021-02-09 13:50:21 +08:00
return (time.Duration(total) / time.Duration(count)).String()
2020-07-26 17:09:05 +08:00
}
pc.lock.Lock()
for key, slot := range pc.slots {
builder.WriteString(fmt.Sprintf("%s,%d,%s,%d,%s\n",
key,
slot.lifecount,
calcFn(slot.lifecycle, slot.lifecount),
slot.lastcount,
calcFn(slot.lastcycle, slot.lastcount),
))
// reset last cycle stats
atomic.StoreInt64(&slot.lastcount, 0)
atomic.StoreInt64(&slot.lastcycle, 0)
}
pc.lock.Unlock()
2020-07-26 17:09:05 +08:00
return builder.String()
2020-07-26 17:09:05 +08:00
}