Signed-off-by: Lei Jitang <leijitang@huawei.com>
| ... | ... |
@@ -46,7 +46,6 @@ func (s *containerStats) Collect(cli *DockerCli, streamStats bool) {
|
| 46 | 46 |
var ( |
| 47 | 47 |
previousCPU uint64 |
| 48 | 48 |
previousSystem uint64 |
| 49 |
- start = true |
|
| 50 | 49 |
dec = json.NewDecoder(stream) |
| 51 | 50 |
u = make(chan error, 1) |
| 52 | 51 |
) |
| ... | ... |
@@ -61,10 +60,9 @@ func (s *containerStats) Collect(cli *DockerCli, streamStats bool) {
|
| 61 | 61 |
memPercent = float64(v.MemoryStats.Usage) / float64(v.MemoryStats.Limit) * 100.0 |
| 62 | 62 |
cpuPercent = 0.0 |
| 63 | 63 |
) |
| 64 |
- if !start {
|
|
| 65 |
- cpuPercent = calculateCPUPercent(previousCPU, previousSystem, v) |
|
| 66 |
- } |
|
| 67 |
- start = false |
|
| 64 |
+ previousCPU = v.PreCpuStats.CpuUsage.TotalUsage |
|
| 65 |
+ previousSystem = v.PreCpuStats.SystemUsage |
|
| 66 |
+ cpuPercent = calculateCPUPercent(previousCPU, previousSystem, v) |
|
| 68 | 67 |
s.mu.Lock() |
| 69 | 68 |
s.CPUPercentage = cpuPercent |
| 70 | 69 |
s.Memory = float64(v.MemoryStats.Usage) |
| ... | ... |
@@ -73,8 +71,6 @@ func (s *containerStats) Collect(cli *DockerCli, streamStats bool) {
|
| 73 | 73 |
s.NetworkRx = float64(v.Network.RxBytes) |
| 74 | 74 |
s.NetworkTx = float64(v.Network.TxBytes) |
| 75 | 75 |
s.mu.Unlock() |
| 76 |
- previousCPU = v.CpuStats.CpuUsage.TotalUsage |
|
| 77 |
- previousSystem = v.CpuStats.SystemUsage |
|
| 78 | 76 |
u <- nil |
| 79 | 77 |
if !streamStats {
|
| 80 | 78 |
return |
| ... | ... |
@@ -151,7 +147,7 @@ func (cli *DockerCli) CmdStats(args ...string) error {
|
| 151 | 151 |
} |
| 152 | 152 |
// do a quick pause so that any failed connections for containers that do not exist are able to be |
| 153 | 153 |
// evicted before we display the initial or default values. |
| 154 |
- time.Sleep(500 * time.Millisecond) |
|
| 154 |
+ time.Sleep(1500 * time.Millisecond) |
|
| 155 | 155 |
var errs []string |
| 156 | 156 |
for _, c := range cStats {
|
| 157 | 157 |
c.mu.Lock() |
| ... | ... |
@@ -84,6 +84,7 @@ type Network struct {
|
| 84 | 84 |
type Stats struct {
|
| 85 | 85 |
Read time.Time `json:"read"` |
| 86 | 86 |
Network Network `json:"network,omitempty"` |
| 87 |
+ PreCpuStats CpuStats `json:"precpu_stats,omitempty"` |
|
| 87 | 88 |
CpuStats CpuStats `json:"cpu_stats,omitempty"` |
| 88 | 89 |
MemoryStats MemoryStats `json:"memory_stats,omitempty"` |
| 89 | 90 |
BlkioStats BlkioStats `json:"blkio_stats,omitempty"` |
| ... | ... |
@@ -2,9 +2,9 @@ package daemon |
| 2 | 2 |
|
| 3 | 3 |
import ( |
| 4 | 4 |
"encoding/json" |
| 5 |
- "io" |
|
| 6 |
- |
|
| 5 |
+ "github.com/docker/docker/api/types" |
|
| 7 | 6 |
"github.com/docker/docker/daemon/execdriver" |
| 7 |
+ "io" |
|
| 8 | 8 |
) |
| 9 | 9 |
|
| 10 | 10 |
func (daemon *Daemon) ContainerStats(name string, stream bool, out io.Writer) error {
|
| ... | ... |
@@ -12,13 +12,23 @@ func (daemon *Daemon) ContainerStats(name string, stream bool, out io.Writer) er |
| 12 | 12 |
if err != nil {
|
| 13 | 13 |
return err |
| 14 | 14 |
} |
| 15 |
+ var pre_cpu_stats types.CpuStats |
|
| 16 |
+ for first_v := range updates {
|
|
| 17 |
+ first_update := first_v.(*execdriver.ResourceStats) |
|
| 18 |
+ first_stats := convertToAPITypes(first_update.Stats) |
|
| 19 |
+ pre_cpu_stats = first_stats.CpuStats |
|
| 20 |
+ pre_cpu_stats.SystemUsage = first_update.SystemUsage |
|
| 21 |
+ break |
|
| 22 |
+ } |
|
| 15 | 23 |
enc := json.NewEncoder(out) |
| 16 | 24 |
for v := range updates {
|
| 17 | 25 |
update := v.(*execdriver.ResourceStats) |
| 18 | 26 |
ss := convertToAPITypes(update.Stats) |
| 27 |
+ ss.PreCpuStats = pre_cpu_stats |
|
| 19 | 28 |
ss.MemoryStats.Limit = uint64(update.MemoryLimit) |
| 20 | 29 |
ss.Read = update.Read |
| 21 | 30 |
ss.CpuStats.SystemUsage = update.SystemUsage |
| 31 |
+ pre_cpu_stats = ss.CpuStats |
|
| 22 | 32 |
if err := enc.Encode(ss); err != nil {
|
| 23 | 33 |
// TODO: handle the specific broken pipe |
| 24 | 34 |
daemon.UnsubscribeToContainerStats(name, updates) |
| 25 | 35 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,48 @@ |
| 0 |
+package main |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ "encoding/json" |
|
| 4 |
+ "fmt" |
|
| 5 |
+ "github.com/docker/docker/api/types" |
|
| 6 |
+ "github.com/go-check/check" |
|
| 7 |
+ "strings" |
|
| 8 |
+ "time" |
|
| 9 |
+) |
|
| 10 |
+ |
|
| 11 |
+func (s *DockerSuite) TestCliStatsNoStreamGetCpu(c *check.C) {
|
|
| 12 |
+ out, _ := dockerCmd(c, "run", "-d", "--cpu-quota=2000", "busybox", "/bin/sh", "-c", "while true;do echo 'Hello';done") |
|
| 13 |
+ |
|
| 14 |
+ id := strings.TrimSpace(out) |
|
| 15 |
+ if err := waitRun(id); err != nil {
|
|
| 16 |
+ c.Fatal(err) |
|
| 17 |
+ } |
|
| 18 |
+ ch := make(chan error) |
|
| 19 |
+ var v *types.Stats |
|
| 20 |
+ go func() {
|
|
| 21 |
+ _, body, err := sockRequestRaw("GET", fmt.Sprintf("/containers/%s/stats?stream=1", id), nil, "")
|
|
| 22 |
+ if err != nil {
|
|
| 23 |
+ ch <- err |
|
| 24 |
+ } |
|
| 25 |
+ dec := json.NewDecoder(body) |
|
| 26 |
+ if err := dec.Decode(&v); err != nil {
|
|
| 27 |
+ ch <- err |
|
| 28 |
+ } |
|
| 29 |
+ ch <- nil |
|
| 30 |
+ }() |
|
| 31 |
+ select {
|
|
| 32 |
+ case e := <-ch: |
|
| 33 |
+ if e == nil {
|
|
| 34 |
+ var cpuPercent = 0.0 |
|
| 35 |
+ cpuDelta := float64(v.CpuStats.CpuUsage.TotalUsage - v.PreCpuStats.CpuUsage.TotalUsage) |
|
| 36 |
+ systemDelta := float64(v.CpuStats.SystemUsage - v.PreCpuStats.SystemUsage) |
|
| 37 |
+ cpuPercent = (cpuDelta / systemDelta) * float64(len(v.CpuStats.CpuUsage.PercpuUsage)) * 100.0 |
|
| 38 |
+ if cpuPercent < 1.8 || cpuPercent > 2.2 {
|
|
| 39 |
+ c.Fatal("docker stats with no-stream get cpu usage failed")
|
|
| 40 |
+ } |
|
| 41 |
+ |
|
| 42 |
+ } |
|
| 43 |
+ case <-time.After(4 * time.Second): |
|
| 44 |
+ c.Fatal("docker stats with no-stream timeout")
|
|
| 45 |
+ } |
|
| 46 |
+ |
|
| 47 |
+} |
| ... | ... |
@@ -29,7 +29,7 @@ func (s *DockerSuite) TestCliStatsNoStream(c *check.C) {
|
| 29 | 29 |
if err != nil {
|
| 30 | 30 |
c.Fatalf("Error running stats: %v", err)
|
| 31 | 31 |
} |
| 32 |
- case <-time.After(2 * time.Second): |
|
| 32 |
+ case <-time.After(3 * time.Second): |
|
| 33 | 33 |
statsCmd.Process.Kill() |
| 34 | 34 |
c.Fatalf("stats did not return immediately when not streaming")
|
| 35 | 35 |
} |