github.com/whoyao/protocol@v0.0.0-20230519045905-2d8ace718ca5/utils/cpu.go (about) 1 package utils 2 3 import ( 4 "time" 5 6 "github.com/frostbyte73/core" 7 "go.uber.org/atomic" 8 9 "github.com/whoyao/protocol/logger" 10 ) 11 12 // This object returns cgroup quota aware cpu stats. On other systems than Linux, 13 // it falls back to full system stats 14 15 type platformCPUMonitor interface { 16 getCPUIdle() (float64, error) 17 numCPU() int 18 } 19 20 type CPUStats struct { 21 idleCPUs atomic.Float64 22 platform platformCPUMonitor 23 24 updateCallback func(idle float64) 25 warningThrottle core.Throttle 26 closeChan chan struct{} 27 } 28 29 func NewCPUStats(updateCallback func(idle float64)) (*CPUStats, error) { 30 p, err := newPlatformCPUMonitor() 31 if err != nil { 32 return nil, err 33 } 34 35 c := &CPUStats{ 36 platform: p, 37 warningThrottle: core.NewThrottle(time.Minute), 38 updateCallback: updateCallback, 39 closeChan: make(chan struct{}), 40 } 41 42 go c.monitorCPULoad() 43 44 return c, nil 45 } 46 47 func (c *CPUStats) GetCPUIdle() float64 { 48 return c.idleCPUs.Load() 49 } 50 51 func (c *CPUStats) NumCPU() int { 52 return c.platform.numCPU() 53 } 54 55 func (c *CPUStats) Stop() { 56 close(c.closeChan) 57 } 58 59 func (c *CPUStats) monitorCPULoad() { 60 ticker := time.NewTicker(time.Second) 61 defer ticker.Stop() 62 63 for { 64 select { 65 case <-c.closeChan: 66 return 67 case <-ticker.C: 68 idle, err := c.platform.getCPUIdle() 69 if err != nil { 70 logger.Errorw("failed retrieving CPU idle", err) 71 continue 72 } 73 74 c.idleCPUs.Store(idle) 75 idleRatio := idle / float64(c.platform.numCPU()) 76 77 if idleRatio < 0.1 { 78 c.warningThrottle(func() { logger.Infow("high cpu load", "load", 1-idleRatio) }) 79 } 80 81 if c.updateCallback != nil { 82 c.updateCallback(idle) 83 } 84 } 85 } 86 }