Skip to content

Commit df87a2b

Browse files
docker: calculate zero cpu percent correctly (#26902) (#26915)
* docker: calculate zero cpu percent correctly Corrects the guard clause in the docker driver `CalculateCPUPercent` to return zero if the two uint64 values can't be subtracted, by checking if the value being subtracted isn't larger than the other. This has to be done prior to subtracting the values, because subtracting two uint64 values will never result in a value lower than zero, which is what the original clause checked, but instead wraps around on itself. These values are used in metrics, where it would appear that a docker container/alloc that was shutting down would use all of the cpu at the time of shutdown. This was manifesting in strange DAS autoscaling behavior during development while deploying new jobs. * add changelog Co-authored-by: Allison Larson <[email protected]>
1 parent 353ecb1 commit df87a2b

File tree

3 files changed

+72
-3
lines changed

3 files changed

+72
-3
lines changed

.changelog/26902.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
```release-note:bug
2+
docker: Fixed a bug where cpu usage percentage was incorrectly measured when container was stopped
3+
```

drivers/docker/util/util.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@
44
package util
55

66
func CalculateCPUPercent(newSample, oldSample, newTotal, oldTotal uint64, cores int) float64 {
7-
numerator := newSample - oldSample
8-
denom := newTotal - oldTotal
9-
if numerator <= 0 || denom <= 0 {
7+
if (newSample <= oldSample) || (newTotal <= oldTotal) {
108
return 0.0
119
}
10+
numerator := newSample - oldSample
11+
denom := newTotal - oldTotal
1212

1313
return (float64(numerator) / float64(denom)) * float64(cores) * 100.0
1414
}

drivers/docker/util/util_test.go

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
// Copyright (c) HashiCorp, Inc.
2+
// SPDX-License-Identifier: BUSL-1.1
3+
4+
package util
5+
6+
import (
7+
"testing"
8+
9+
"github.com/shoenig/test/must"
10+
)
11+
12+
func TestCalculateCPUPercent(t *testing.T) {
13+
tests := []struct {
14+
name string
15+
newSample uint64
16+
oldSample uint64
17+
newTotal uint64
18+
oldTotal uint64
19+
cores int
20+
expected float64
21+
}{
22+
{
23+
name: "valid case",
24+
newSample: 100,
25+
oldSample: 50,
26+
newTotal: 200,
27+
oldTotal: 100,
28+
cores: 4,
29+
expected: 200.0,
30+
},
31+
{
32+
name: "zero denominator",
33+
newSample: 100,
34+
oldSample: 50,
35+
newTotal: 100,
36+
oldTotal: 100,
37+
cores: 4,
38+
expected: 0.0,
39+
},
40+
{
41+
name: "zero numerator",
42+
newSample: 100,
43+
oldSample: 100,
44+
newTotal: 100,
45+
oldTotal: 50,
46+
cores: 4,
47+
expected: 0.0,
48+
},
49+
{
50+
name: "negative case",
51+
newSample: 50,
52+
oldSample: 100,
53+
newTotal: 100,
54+
oldTotal: 200,
55+
cores: 4,
56+
expected: 0.0,
57+
},
58+
}
59+
60+
for _, tt := range tests {
61+
t.Run(tt.name, func(t *testing.T) {
62+
result := CalculateCPUPercent(tt.newSample, tt.oldSample, tt.newTotal, tt.oldTotal, tt.cores)
63+
must.Eq(t, tt.expected, result)
64+
})
65+
}
66+
}

0 commit comments

Comments
 (0)