On linux, this will report the amount of idle CPU relative to the cgroup defined quota. On other OSs, the idle cpu for the whole host is reported
78 lines
1.4 KiB
Go
78 lines
1.4 KiB
Go
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)
|
|
}
|
|
}
|
|
}
|
|
}
|