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:
parent
cc658804c0
commit
2d4fc1de05
8 changed files with 30 additions and 56 deletions
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
|
||||||
}
|
|
|
@ -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"`
|
||||||
|
|
|
@ -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"`
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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")
|
||||||
|
|
Loading…
Add table
Reference in a new issue