package utils import ( "runtime" "time" "github.com/frostbyte73/go-throttle" "github.com/livekit/protocol/logger" "go.uber.org/atomic" ) // This object returns cgroup quota aware cpu stats. On other systems than Linux, // it falls back to full system stats type CPUStats struct { idleCPUs atomic.Float64 platform *platformCPUMonitor updateCallback func(idle float64) warningThrottle func(func()) closeChan chan struct{} } func NewCPUStats(updateCallback func(idle float64)) (*CPUStats, error) { p, err := newPlatformCPUMonitor() if err != nil { return nil, err } c := &CPUStats{ platform: p, warningThrottle: throttle.New(time.Minute), updateCallback: updateCallback, closeChan: make(chan struct{}), } go c.monitorCPULoad() return c, nil } func (c *CPUStats) GetCPUIdle() float64 { return c.idleCPUs.Load() } func (c *CPUStats) Stop() { close(c.closeChan) } func (c *CPUStats) monitorCPULoad() { ticker := time.NewTicker(time.Second) defer ticker.Stop() for { select { case <-c.closeChan: return case <-ticker.C: idle, err := c.platform.getCPUIdle() if err != nil { logger.Errorw("failed retrieving CPU idle", err) continue } c.idleCPUs.Store(idle) idleRatio := idle / float64(runtime.NumCPU()) if idleRatio < 0.1 { c.warningThrottle(func() { logger.Infow("high cpu load", "load", 1-idleRatio) }) } if c.updateCallback != nil { c.updateCallback(idle) } } } }