Browse code

Refactor usage calc for CPU and system usage

Signed-off-by: Michael Crosby <crosbymichael@gmail.com>

Michael Crosby authored on 2015/01/20 07:07:21
Showing 8 changed files
... ...
@@ -2717,11 +2717,16 @@ func (cli *DockerCli) CmdStats(args ...string) error {
2717 2717
 }
2718 2718
 
2719 2719
 func calcuateCpuPercent(previousCpu, previousSystem uint64, v *stats.Stats) float64 {
2720
-	cpuPercent := 0.0
2721
-	cpuDelta := float64(v.CpuStats.CpuUsage.TotalUsage) - float64(previousCpu)
2722
-	systemDelta := float64(int(v.CpuStats.SystemUsage)/v.ClockTicks) - float64(int(previousSystem)/v.ClockTicks)
2723
-	if systemDelta > 0.0 {
2724
-		cpuPercent = (cpuDelta / systemDelta) * float64(v.ClockTicks*len(v.CpuStats.CpuUsage.PercpuUsage))
2720
+	var (
2721
+		cpuPercent = 0.0
2722
+		// calculate the change for the cpu usage of the container in between readings
2723
+		cpuDelta = float64(v.CpuStats.CpuUsage.TotalUsage - previousCpu)
2724
+		// calculate the change for the entire system between readings
2725
+		systemDelta = float64(v.CpuStats.SystemUsage - previousSystem)
2726
+	)
2727
+
2728
+	if systemDelta > 0.0 && cpuDelta > 0.0 {
2729
+		cpuPercent = (cpuDelta / systemDelta) * float64(len(v.CpuStats.CpuUsage.PercpuUsage)) * 100.0
2725 2730
 	}
2726 2731
 	return cpuPercent
2727 2732
 }
2728 2733
deleted file mode 100644
... ...
@@ -1,29 +0,0 @@
1
-package client
2
-
3
-import "sort"
4
-
5
-func sortStatsByName(cStats map[string]containerStats) []containerStats {
6
-	sStats := []containerStats{}
7
-	for _, s := range cStats {
8
-		sStats = append(sStats, s)
9
-	}
10
-	sorter := &statSorter{sStats}
11
-	sort.Sort(sorter)
12
-	return sStats
13
-}
14
-
15
-type statSorter struct {
16
-	stats []containerStats
17
-}
18
-
19
-func (s *statSorter) Len() int {
20
-	return len(s.stats)
21
-}
22
-
23
-func (s *statSorter) Swap(i, j int) {
24
-	s.stats[i], s.stats[j] = s.stats[j], s.stats[i]
25
-}
26
-
27
-func (s *statSorter) Less(i, j int) bool {
28
-	return s.stats[i].Name < s.stats[j].Name
29
-}
... ...
@@ -83,8 +83,6 @@ type Network struct {
83 83
 
84 84
 type Stats struct {
85 85
 	Read        time.Time   `json:"read"`
86
-	ClockTicks  int         `json:"clock_ticks"`
87
-	Interval    int         `json:"interval"` // in ms
88 86
 	Network     Network     `json:"network,omitempty"`
89 87
 	CpuStats    CpuStats    `json:"cpu_stats,omitempty"`
90 88
 	MemoryStats MemoryStats `json:"memory_stats,omitempty"`
... ...
@@ -107,7 +107,6 @@ type Resources struct {
107 107
 type ResourceStats struct {
108 108
 	*libcontainer.ContainerStats
109 109
 	Read        time.Time `json:"read"`
110
-	ClockTicks  int       `json:"clock_ticks"`
111 110
 	MemoryLimit int64     `json:"memory_limit"`
112 111
 	SystemUsage uint64    `json:"system_usage"`
113 112
 }
... ...
@@ -8,15 +8,9 @@ import (
8 8
 	"github.com/docker/docker/daemon/execdriver/lxc"
9 9
 	"github.com/docker/docker/daemon/execdriver/native"
10 10
 	"github.com/docker/docker/pkg/sysinfo"
11
-	"github.com/docker/docker/pkg/system"
12 11
 )
13 12
 
14 13
 func NewDriver(name, root, initPath string, sysInfo *sysinfo.SysInfo) (execdriver.Driver, error) {
15
-	meminfo, err := system.ReadMemInfo()
16
-	if err != nil {
17
-		return nil, err
18
-	}
19
-
20 14
 	switch name {
21 15
 	case "lxc":
22 16
 		// 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
24 24
 		// to be backwards compatible
25 25
 		return lxc.NewDriver(root, initPath, sysInfo.AppArmor)
26 26
 	case "native":
27
-		return native.NewDriver(path.Join(root, "execdriver", "native"), initPath, meminfo.MemTotal)
27
+		return native.NewDriver(path.Join(root, "execdriver", "native"), initPath)
28 28
 	}
29 29
 	return nil, fmt.Errorf("unknown exec driver %s", name)
30 30
 }
... ...
@@ -17,6 +17,7 @@ import (
17 17
 
18 18
 	log "github.com/Sirupsen/logrus"
19 19
 	"github.com/docker/docker/daemon/execdriver"
20
+	sysinfo "github.com/docker/docker/pkg/system"
20 21
 	"github.com/docker/docker/pkg/term"
21 22
 	"github.com/docker/libcontainer"
22 23
 	"github.com/docker/libcontainer/apparmor"
... ...
@@ -46,7 +47,12 @@ type driver struct {
46 46
 	sync.Mutex
47 47
 }
48 48
 
49
-func NewDriver(root, initPath string, machineMemory int64) (*driver, error) {
49
+func NewDriver(root, initPath string) (*driver, error) {
50
+	meminfo, err := sysinfo.ReadMemInfo()
51
+	if err != nil {
52
+		return nil, err
53
+	}
54
+
50 55
 	if err := os.MkdirAll(root, 0700); err != nil {
51 56
 		return nil, err
52 57
 	}
... ...
@@ -58,7 +64,7 @@ func NewDriver(root, initPath string, machineMemory int64) (*driver, error) {
58 58
 		root:             root,
59 59
 		initPath:         initPath,
60 60
 		activeContainers: make(map[string]*activeContainer),
61
-		machineMemory:    machineMemory,
61
+		machineMemory:    meminfo.MemTotal,
62 62
 	}, nil
63 63
 }
64 64
 
... ...
@@ -303,7 +309,6 @@ func (d *driver) Stats(id string) (*execdriver.ResourceStats, error) {
303 303
 	return &execdriver.ResourceStats{
304 304
 		Read:           now,
305 305
 		ContainerStats: stats,
306
-		ClockTicks:     system.GetClockTicks(),
307 306
 		MemoryLimit:    memoryLimit,
308 307
 	}, nil
309 308
 }
... ...
@@ -17,7 +17,6 @@ func (daemon *Daemon) ContainerStats(job *engine.Job) engine.Status {
17 17
 		ss := stats.ToStats(update.ContainerStats)
18 18
 		ss.MemoryStats.Limit = uint64(update.MemoryLimit)
19 19
 		ss.Read = update.Read
20
-		ss.ClockTicks = update.ClockTicks
21 20
 		ss.CpuStats.SystemUsage = update.SystemUsage
22 21
 		if err := enc.Encode(ss); err != nil {
23 22
 			// TODO: handle the specific broken pipe
... ...
@@ -11,6 +11,7 @@ import (
11 11
 
12 12
 	log "github.com/Sirupsen/logrus"
13 13
 	"github.com/docker/docker/daemon/execdriver"
14
+	"github.com/docker/libcontainer/system"
14 15
 )
15 16
 
16 17
 // newStatsCollector returns a new statsCollector that collections
... ...
@@ -21,6 +22,7 @@ func newStatsCollector(interval time.Duration) *statsCollector {
21 21
 	s := &statsCollector{
22 22
 		interval:   interval,
23 23
 		containers: make(map[string]*statsData),
24
+		clockTicks: uint64(system.GetClockTicks()),
24 25
 	}
25 26
 	s.start()
26 27
 	return s
... ...
@@ -36,6 +38,7 @@ type statsData struct {
36 36
 type statsCollector struct {
37 37
 	m          sync.Mutex
38 38
 	interval   time.Duration
39
+	clockTicks uint64
39 40
 	containers map[string]*statsData
40 41
 }
41 42
 
... ...
@@ -128,8 +131,10 @@ func (s *statsCollector) start() {
128 128
 	}()
129 129
 }
130 130
 
131
-// getSystemdCpuUSage returns the host system's cpu usage
132
-// in nanoseconds.
131
+const nanoSeconds = 1e9
132
+
133
+// getSystemdCpuUSage returns the host system's cpu usage in nanoseconds
134
+// for the system to match the cgroup readings are returned in the same format.
133 135
 func (s *statsCollector) getSystemCpuUsage() (uint64, error) {
134 136
 	f, err := os.Open("/proc/stat")
135 137
 	if err != nil {
... ...
@@ -144,17 +149,15 @@ func (s *statsCollector) getSystemCpuUsage() (uint64, error) {
144 144
 			if len(parts) < 8 {
145 145
 				return 0, fmt.Errorf("invalid number of cpu fields")
146 146
 			}
147
-			var total uint64
147
+			var sum uint64
148 148
 			for _, i := range parts[1:8] {
149 149
 				v, err := strconv.ParseUint(i, 10, 64)
150 150
 				if err != nil {
151
-					return 0.0, fmt.Errorf("Unable to convert value %s to int: %s", i, err)
151
+					return 0, fmt.Errorf("Unable to convert value %s to int: %s", i, err)
152 152
 				}
153
-				total += v
153
+				sum += v
154 154
 			}
155
-			return total * 1000000000, nil
156
-		default:
157
-			continue
155
+			return (sum * nanoSeconds) / s.clockTicks, nil
158 156
 		}
159 157
 	}
160 158
 	return 0, fmt.Errorf("invalid stat format")