浏览代码

Refactor usage calc for CPU and system usage

Signed-off-by: Michael Crosby <crosbymichael@gmail.com>
Michael Crosby 10 年之前
父节点
当前提交
2d4fc1de05

+ 10 - 5
api/client/commands.go

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

+ 0 - 29
api/client/sort.go

@@ -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
-}

+ 0 - 2
api/stats/stats.go

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

+ 0 - 1
daemon/execdriver/driver.go

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

+ 1 - 7
daemon/execdriver/execdrivers/execdrivers.go

@@ -8,15 +8,9 @@ import (
 	"github.com/docker/docker/daemon/execdriver/lxc"
 	"github.com/docker/docker/daemon/execdriver/native"
 	"github.com/docker/docker/pkg/sysinfo"
-	"github.com/docker/docker/pkg/system"
 )
 
 func NewDriver(name, root, initPath string, sysInfo *sysinfo.SysInfo) (execdriver.Driver, error) {
-	meminfo, err := system.ReadMemInfo()
-	if err != nil {
-		return nil, err
-	}
-
 	switch name {
 	case "lxc":
 		// 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
 		return lxc.NewDriver(root, initPath, sysInfo.AppArmor)
 	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)
 }

+ 8 - 3
daemon/execdriver/native/driver.go

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

+ 0 - 1
daemon/stats.go

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

+ 11 - 8
daemon/stats_collector.go

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