Compute smoothed cpu load for containers.
This commit is contained in:
parent
c26ca15cc7
commit
33c2cac71d
@ -197,6 +197,8 @@ type CpuStats struct {
|
|||||||
// Unit: nanoseconds
|
// Unit: nanoseconds
|
||||||
System uint64 `json:"system"`
|
System uint64 `json:"system"`
|
||||||
} `json:"usage"`
|
} `json:"usage"`
|
||||||
|
// Smoothed average of number of runnable threads x 1000.
|
||||||
|
// We multiply by thousand to avoid using floats, but preserving precision.
|
||||||
Load int32 `json:"load"`
|
Load int32 `json:"load"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,6 +17,7 @@ package manager
|
|||||||
import (
|
import (
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"math"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -33,6 +34,9 @@ var HousekeepingInterval = flag.Duration("housekeeping_interval", 1*time.Second,
|
|||||||
var maxHousekeepingInterval = flag.Duration("max_housekeeping_interval", 60*time.Second, "Largest interval to allow between container housekeepings")
|
var maxHousekeepingInterval = flag.Duration("max_housekeeping_interval", 60*time.Second, "Largest interval to allow between container housekeepings")
|
||||||
var allowDynamicHousekeeping = flag.Bool("allow_dynamic_housekeeping", true, "Whether to allow the housekeeping interval to be dynamic")
|
var allowDynamicHousekeeping = flag.Bool("allow_dynamic_housekeeping", true, "Whether to allow the housekeeping interval to be dynamic")
|
||||||
|
|
||||||
|
// Decay value used for load average smoothing. Interval length of 10 seconds is used.
|
||||||
|
var loadDecay = math.Exp(float64(-1 * (*HousekeepingInterval).Seconds() / 10))
|
||||||
|
|
||||||
type containerInfo struct {
|
type containerInfo struct {
|
||||||
info.ContainerReference
|
info.ContainerReference
|
||||||
Subcontainers []info.ContainerReference
|
Subcontainers []info.ContainerReference
|
||||||
@ -45,6 +49,7 @@ type containerData struct {
|
|||||||
storageDriver storage.StorageDriver
|
storageDriver storage.StorageDriver
|
||||||
lock sync.Mutex
|
lock sync.Mutex
|
||||||
loadReader cpuload.CpuLoadReader
|
loadReader cpuload.CpuLoadReader
|
||||||
|
loadAvg float64 // smoothed load average seen so far.
|
||||||
housekeepingInterval time.Duration
|
housekeepingInterval time.Duration
|
||||||
lastUpdatedTime time.Time
|
lastUpdatedTime time.Time
|
||||||
lastErrorTime time.Time
|
lastErrorTime time.Time
|
||||||
@ -111,6 +116,7 @@ func newContainerData(containerName string, driver storage.StorageDriver, handle
|
|||||||
housekeepingInterval: *HousekeepingInterval,
|
housekeepingInterval: *HousekeepingInterval,
|
||||||
loadReader: loadReader,
|
loadReader: loadReader,
|
||||||
logUsage: logUsage,
|
logUsage: logUsage,
|
||||||
|
loadAvg: -1.0, // negative value indicates uninitialized.
|
||||||
stop: make(chan bool, 1),
|
stop: make(chan bool, 1),
|
||||||
}
|
}
|
||||||
cont.info.ContainerReference = ref
|
cont.info.ContainerReference = ref
|
||||||
@ -225,6 +231,18 @@ func (c *containerData) updateSpec() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Calculate new smoothed load average using the new sample of runnable threads.
|
||||||
|
// The decay used ensures that the load will stabilize on a new constant value within
|
||||||
|
// 10 seconds.
|
||||||
|
func (c *containerData) updateLoad(newLoad uint64) {
|
||||||
|
if c.loadAvg < 0 {
|
||||||
|
c.loadAvg = float64(newLoad) // initialize to the first seen sample for faster stabilization.
|
||||||
|
} else {
|
||||||
|
c.loadAvg = c.loadAvg*loadDecay + float64(newLoad)*(1.0-loadDecay)
|
||||||
|
}
|
||||||
|
glog.V(3).Infof("New load for %q: %v. latest sample: %d", c.info.Name, c.loadAvg, newLoad)
|
||||||
|
}
|
||||||
|
|
||||||
func (c *containerData) updateStats() error {
|
func (c *containerData) updateStats() error {
|
||||||
stats, err := c.handler.GetStats()
|
stats, err := c.handler.GetStats()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -243,9 +261,11 @@ func (c *containerData) updateStats() error {
|
|||||||
loadStats, err := c.loadReader.GetCpuLoad(c.info.Name, path)
|
loadStats, err := c.loadReader.GetCpuLoad(c.info.Name, path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to get load stat for %q - path %q, error %s", c.info.Name, path, err)
|
return fmt.Errorf("failed to get load stat for %q - path %q, error %s", c.info.Name, path, err)
|
||||||
} else {
|
|
||||||
stats.TaskStats = loadStats
|
|
||||||
}
|
}
|
||||||
|
stats.TaskStats = loadStats
|
||||||
|
c.updateLoad(loadStats.NrRunning)
|
||||||
|
// convert to 'milliLoad' to avoid floats and preserve precision.
|
||||||
|
stats.Cpu.Load = int32(c.loadAvg * 1000)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ref, err := c.handler.ContainerReference()
|
ref, err := c.handler.ContainerReference()
|
||||||
|
Loading…
Reference in New Issue
Block a user