Skip to content

Commit

Permalink
helpers: fix reading cpu stats on cgroup v2
Browse files Browse the repository at this point in the history
read quota and limit from cpu.max, and convert cpu.weight to the range
expected with cgroup v1.

Signed-off-by: Giuseppe Scrivano <[email protected]>
(cherry picked from commit 56ced55)
Signed-off-by: Kir Kolyshkin <[email protected]>
  • Loading branch information
giuseppe authored and Paweł Szulik committed May 31, 2021
1 parent 1ec141b commit 51a94f6
Show file tree
Hide file tree
Showing 2 changed files with 114 additions and 11 deletions.
79 changes: 68 additions & 11 deletions container/common/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,17 +103,43 @@ func GetSpec(cgroupPaths map[string]string, machineInfoFactory info.MachineInfoF
cpuRoot, ok := cgroupPaths["cpu"]
if ok {
if utils.FileExists(cpuRoot) {
spec.HasCpu = true
spec.Cpu.Limit = readUInt64(cpuRoot, "cpu.shares")
spec.Cpu.Period = readUInt64(cpuRoot, "cpu.cfs_period_us")
quota := readString(cpuRoot, "cpu.cfs_quota_us")

if quota != "" && quota != "-1" {
val, err := strconv.ParseUint(quota, 10, 64)
if err != nil {
klog.Errorf("GetSpec: Failed to parse CPUQuota from %q: %s", path.Join(cpuRoot, "cpu.cfs_quota_us"), err)
} else {
spec.Cpu.Quota = val
if cgroups.IsCgroup2UnifiedMode() {
spec.HasCpu = true

weight := readUInt64(cpuRoot, "cpu.weight")
if weight > 0 {
limit, err := convertCPUWeightToCPULimit(weight)
if err != nil {
klog.Errorf("GetSpec: Failed to read CPULimit from %q: %s", path.Join(cpuRoot, "cpu.weight"), err)
} else {
spec.Cpu.Limit = limit
}
}
max := readString(cpuRoot, "cpu.max")
if max != "" {
splits := strings.SplitN(max, " ", 2)
if len(splits) != 2 {
klog.Errorf("GetSpec: Failed to parse CPUmax from %q", path.Join(cpuRoot, "cpu.max"))
} else {
if splits[0] != "max" {
spec.Cpu.Quota = parseUint64String(splits[0])
}
spec.Cpu.Period = parseUint64String(splits[1])
}
}
} else {
spec.HasCpu = true
spec.Cpu.Limit = readUInt64(cpuRoot, "cpu.shares")
spec.Cpu.Period = readUInt64(cpuRoot, "cpu.cfs_period_us")
quota := readString(cpuRoot, "cpu.cfs_quota_us")

if quota != "" && quota != "-1" {
val, err := strconv.ParseUint(quota, 10, 64)
if err != nil {
klog.Errorf("GetSpec: Failed to parse CPUQuota from %q: %s", path.Join(cpuRoot, "cpu.cfs_quota_us"), err)
} else {
spec.Cpu.Quota = val
}
}
}
}
Expand Down Expand Up @@ -201,6 +227,37 @@ func readString(dirpath string, file string) string {
return strings.TrimSpace(string(out))
}

// Convert from [1-10000] to [2-262144]
func convertCPUWeightToCPULimit(weight uint64) (uint64, error) {
const (
// minWeight is the lowest value possible for cpu.weight
minWeight = 1
// maxWeight is the highest value possible for cpu.weight
maxWeight = 10000
)
if weight < minWeight || weight > maxWeight {
return 0, fmt.Errorf("convertCPUWeightToCPULimit: invalid cpu weight: %v", weight)
}
return 2 + ((weight-1)*262142)/9999, nil
}

func parseUint64String(strValue string) uint64 {
if strValue == "max" {
return math.MaxUint64
}
if strValue == "" {
return 0
}

val, err := strconv.ParseUint(strValue, 10, 64)
if err != nil {
klog.Errorf("parseUint64String: Failed to parse int %q: %s", strValue, err)
return 0
}

return val
}

func readUInt64(dirpath string, file string) uint64 {
out := readString(dirpath, file)
if out == "max" {
Expand Down
46 changes: 46 additions & 0 deletions container/common/helpers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,49 @@ func BenchmarkListDirectories(b *testing.B) {
}
}
}

func TestConvertCpuWeightToCpuLimit(t *testing.T) {
limit, err := convertCPUWeightToCPULimit(1)
if err != nil {
t.Fatalf("Error in convertCPUWeightToCPULimit: %s", err)
}
if limit != 2 {
t.Fatalf("convertCPUWeightToCPULimit(1) != 2")
}
limit, err = convertCPUWeightToCPULimit(10000)
if err != nil {
t.Fatalf("Error in convertCPUWeightToCPULimit: %s", err)
}
if limit != 262144 {
t.Fatalf("convertCPUWeightToCPULimit(10000) != 262144")
}
_, err = convertCPUWeightToCPULimit(0)
if err == nil {
t.Fatalf("convertCPUWeightToCPULimit(0) must raise an error")
}
_, err = convertCPUWeightToCPULimit(10001)
if err == nil {
t.Fatalf("convertCPUWeightToCPULimit(10001) must raise an error")
}
}

func TestParseUint64String(t *testing.T) {
if parseUint64String("1000") != 1000 {
t.Fatalf("parseUint64String(\"1000\") != 1000")
}
if parseUint64String("-1") != 0 {
t.Fatalf("parseUint64String(\"-1\") != 0")
}
if parseUint64String("0") != 0 {
t.Fatalf("parseUint64String(\"0\") != 0")
}
if parseUint64String("not-a-number") != 0 {
t.Fatalf("parseUint64String(\"not-a-number\") != 0")
}
if parseUint64String(" 1000 ") != 0 {
t.Fatalf("parseUint64String(\" 1000 \") != 0")
}
if parseUint64String("18446744073709551615") != 18446744073709551615 {
t.Fatalf("parseUint64String(\"18446744073709551615\") != 18446744073709551615")
}
}

0 comments on commit 51a94f6

Please sign in to comment.