1
0
Fork 0
mirror of https://github.com/moby/moby.git synced 2022-11-09 12:21:53 -05:00

Refactor usage calc for CPU and system usage

Signed-off-by: Michael Crosby <crosbymichael@gmail.com>
This commit is contained in:
Michael Crosby 2015-01-19 14:07:21 -08:00
parent cc658804c0
commit 2d4fc1de05
8 changed files with 30 additions and 56 deletions

View file

@ -2717,11 +2717,16 @@ func (cli *DockerCli) CmdStats(args ...string) error {
} }
func calcuateCpuPercent(previousCpu, previousSystem uint64, v *stats.Stats) float64 { func calcuateCpuPercent(previousCpu, previousSystem uint64, v *stats.Stats) float64 {
cpuPercent := 0.0 var (
cpuDelta := float64(v.CpuStats.CpuUsage.TotalUsage) - float64(previousCpu) cpuPercent = 0.0
systemDelta := float64(int(v.CpuStats.SystemUsage)/v.ClockTicks) - float64(int(previousSystem)/v.ClockTicks) // calculate the change for the cpu usage of the container in between readings
if systemDelta > 0.0 { cpuDelta = float64(v.CpuStats.CpuUsage.TotalUsage - previousCpu)
cpuPercent = (cpuDelta / systemDelta) * float64(v.ClockTicks*len(v.CpuStats.CpuUsage.PercpuUsage)) // calculate the change for the entire system between readings
systemDelta = float64(v.CpuStats.SystemUsage - previousSystem)
)
if systemDelta > 0.0 && cpuDelta > 0.0 {
cpuPercent = (cpuDelta / systemDelta) * float64(len(v.CpuStats.CpuUsage.PercpuUsage)) * 100.0
} }
return cpuPercent return cpuPercent
} }

View file

@ -1,29 +0,0 @@
package client
import "sort"
func sortStatsByName(cStats map[string]containerStats) []containerStats {
sStats := []containerStats{}
for _, s := range cStats {
sStats = append(sStats, s)
}
sorter := &statSorter{sStats}
sort.Sort(sorter)
return sStats
}
type statSorter struct {
stats []containerStats
}
func (s *statSorter) Len() int {
return len(s.stats)
}
func (s *statSorter) Swap(i, j int) {
s.stats[i], s.stats[j] = s.stats[j], s.stats[i]
}
func (s *statSorter) Less(i, j int) bool {
return s.stats[i].Name < s.stats[j].Name
}

View file

@ -83,8 +83,6 @@ type Network struct {
type Stats struct { type Stats struct {
Read time.Time `json:"read"` Read time.Time `json:"read"`
ClockTicks int `json:"clock_ticks"`
Interval int `json:"interval"` // in ms
Network Network `json:"network,omitempty"` Network Network `json:"network,omitempty"`
CpuStats CpuStats `json:"cpu_stats,omitempty"` CpuStats CpuStats `json:"cpu_stats,omitempty"`
MemoryStats MemoryStats `json:"memory_stats,omitempty"` MemoryStats MemoryStats `json:"memory_stats,omitempty"`

View file

@ -107,7 +107,6 @@ type Resources struct {
type ResourceStats struct { type ResourceStats struct {
*libcontainer.ContainerStats *libcontainer.ContainerStats
Read time.Time `json:"read"` Read time.Time `json:"read"`
ClockTicks int `json:"clock_ticks"`
MemoryLimit int64 `json:"memory_limit"` MemoryLimit int64 `json:"memory_limit"`
SystemUsage uint64 `json:"system_usage"` SystemUsage uint64 `json:"system_usage"`
} }

View file

@ -8,15 +8,9 @@ import (
"github.com/docker/docker/daemon/execdriver/lxc" "github.com/docker/docker/daemon/execdriver/lxc"
"github.com/docker/docker/daemon/execdriver/native" "github.com/docker/docker/daemon/execdriver/native"
"github.com/docker/docker/pkg/sysinfo" "github.com/docker/docker/pkg/sysinfo"
"github.com/docker/docker/pkg/system"
) )
func NewDriver(name, root, initPath string, sysInfo *sysinfo.SysInfo) (execdriver.Driver, error) { func NewDriver(name, root, initPath string, sysInfo *sysinfo.SysInfo) (execdriver.Driver, error) {
meminfo, err := system.ReadMemInfo()
if err != nil {
return nil, err
}
switch name { switch name {
case "lxc": case "lxc":
// we want to give the lxc driver the full docker root because it needs // we want to give the lxc driver the full docker root because it needs
@ -24,7 +18,7 @@ func NewDriver(name, root, initPath string, sysInfo *sysinfo.SysInfo) (execdrive
// to be backwards compatible // to be backwards compatible
return lxc.NewDriver(root, initPath, sysInfo.AppArmor) return lxc.NewDriver(root, initPath, sysInfo.AppArmor)
case "native": case "native":
return native.NewDriver(path.Join(root, "execdriver", "native"), initPath, meminfo.MemTotal) return native.NewDriver(path.Join(root, "execdriver", "native"), initPath)
} }
return nil, fmt.Errorf("unknown exec driver %s", name) return nil, fmt.Errorf("unknown exec driver %s", name)
} }

View file

@ -17,6 +17,7 @@ import (
log "github.com/Sirupsen/logrus" log "github.com/Sirupsen/logrus"
"github.com/docker/docker/daemon/execdriver" "github.com/docker/docker/daemon/execdriver"
sysinfo "github.com/docker/docker/pkg/system"
"github.com/docker/docker/pkg/term" "github.com/docker/docker/pkg/term"
"github.com/docker/libcontainer" "github.com/docker/libcontainer"
"github.com/docker/libcontainer/apparmor" "github.com/docker/libcontainer/apparmor"
@ -46,7 +47,12 @@ type driver struct {
sync.Mutex sync.Mutex
} }
func NewDriver(root, initPath string, machineMemory int64) (*driver, error) { func NewDriver(root, initPath string) (*driver, error) {
meminfo, err := sysinfo.ReadMemInfo()
if err != nil {
return nil, err
}
if err := os.MkdirAll(root, 0700); err != nil { if err := os.MkdirAll(root, 0700); err != nil {
return nil, err return nil, err
} }
@ -58,7 +64,7 @@ func NewDriver(root, initPath string, machineMemory int64) (*driver, error) {
root: root, root: root,
initPath: initPath, initPath: initPath,
activeContainers: make(map[string]*activeContainer), activeContainers: make(map[string]*activeContainer),
machineMemory: machineMemory, machineMemory: meminfo.MemTotal,
}, nil }, nil
} }
@ -303,7 +309,6 @@ func (d *driver) Stats(id string) (*execdriver.ResourceStats, error) {
return &execdriver.ResourceStats{ return &execdriver.ResourceStats{
Read: now, Read: now,
ContainerStats: stats, ContainerStats: stats,
ClockTicks: system.GetClockTicks(),
MemoryLimit: memoryLimit, MemoryLimit: memoryLimit,
}, nil }, nil
} }

View file

@ -17,7 +17,6 @@ func (daemon *Daemon) ContainerStats(job *engine.Job) engine.Status {
ss := stats.ToStats(update.ContainerStats) ss := stats.ToStats(update.ContainerStats)
ss.MemoryStats.Limit = uint64(update.MemoryLimit) ss.MemoryStats.Limit = uint64(update.MemoryLimit)
ss.Read = update.Read ss.Read = update.Read
ss.ClockTicks = update.ClockTicks
ss.CpuStats.SystemUsage = update.SystemUsage ss.CpuStats.SystemUsage = update.SystemUsage
if err := enc.Encode(ss); err != nil { if err := enc.Encode(ss); err != nil {
// TODO: handle the specific broken pipe // TODO: handle the specific broken pipe

View file

@ -11,6 +11,7 @@ import (
log "github.com/Sirupsen/logrus" log "github.com/Sirupsen/logrus"
"github.com/docker/docker/daemon/execdriver" "github.com/docker/docker/daemon/execdriver"
"github.com/docker/libcontainer/system"
) )
// newStatsCollector returns a new statsCollector that collections // newStatsCollector returns a new statsCollector that collections
@ -21,6 +22,7 @@ func newStatsCollector(interval time.Duration) *statsCollector {
s := &statsCollector{ s := &statsCollector{
interval: interval, interval: interval,
containers: make(map[string]*statsData), containers: make(map[string]*statsData),
clockTicks: uint64(system.GetClockTicks()),
} }
s.start() s.start()
return s return s
@ -36,6 +38,7 @@ type statsData struct {
type statsCollector struct { type statsCollector struct {
m sync.Mutex m sync.Mutex
interval time.Duration interval time.Duration
clockTicks uint64
containers map[string]*statsData containers map[string]*statsData
} }
@ -128,8 +131,10 @@ func (s *statsCollector) start() {
}() }()
} }
// getSystemdCpuUSage returns the host system's cpu usage const nanoSeconds = 1e9
// in nanoseconds.
// getSystemdCpuUSage returns the host system's cpu usage in nanoseconds
// for the system to match the cgroup readings are returned in the same format.
func (s *statsCollector) getSystemCpuUsage() (uint64, error) { func (s *statsCollector) getSystemCpuUsage() (uint64, error) {
f, err := os.Open("/proc/stat") f, err := os.Open("/proc/stat")
if err != nil { if err != nil {
@ -144,17 +149,15 @@ func (s *statsCollector) getSystemCpuUsage() (uint64, error) {
if len(parts) < 8 { if len(parts) < 8 {
return 0, fmt.Errorf("invalid number of cpu fields") return 0, fmt.Errorf("invalid number of cpu fields")
} }
var total uint64 var sum uint64
for _, i := range parts[1:8] { for _, i := range parts[1:8] {
v, err := strconv.ParseUint(i, 10, 64) v, err := strconv.ParseUint(i, 10, 64)
if err != nil { if err != nil {
return 0.0, fmt.Errorf("Unable to convert value %s to int: %s", i, err) return 0, fmt.Errorf("Unable to convert value %s to int: %s", i, err)
} }
total += v sum += v
} }
return total * 1000000000, nil return (sum * nanoSeconds) / s.clockTicks, nil
default:
continue
} }
} }
return 0, fmt.Errorf("invalid stat format") return 0, fmt.Errorf("invalid stat format")