Skip to content

Commit fd95216

Browse files
committed
ConvertCPUSharesToCgroupV2Value: improve
The old formula, while correctly converting the cgroup v1 range to cgroup v2 range, had a few issues: 1. When cgroup v1 value is out of range, it returned invalid cgroup v2 value, leading to vague errors down the line (see [1]). 2. Default value cgroup v1 shares of 1024 is converted to 39, which is much less than the cgroup v2 default weight of 100 (see [2], [3]). The new conversion formula fixes both issues (see discussion in [2] for more details). Amend the test case accordingly. [1]: opencontainers/runc#4755 [2]: kubernetes/kubernetes#131216 [3]: opencontainers/runc#4772 Signed-off-by: Kir Kolyshkin <[email protected]>
1 parent 9657f5a commit fd95216

File tree

2 files changed

+39
-9
lines changed

2 files changed

+39
-9
lines changed

utils.go

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"errors"
66
"fmt"
77
"io"
8+
"math"
89
"os"
910
"path/filepath"
1011
"strconv"
@@ -413,16 +414,30 @@ func WriteCgroupProc(dir string, pid int) error {
413414
return err
414415
}
415416

416-
// Since the OCI spec is designed for cgroup v1, in some cases
417-
// there is need to convert from the cgroup v1 configuration to cgroup v2
418-
// the formula for cpuShares is y = (1 + ((x - 2) * 9999) / 262142)
419-
// convert from [2-262144] to [1-10000]
420-
// 262144 comes from Linux kernel definition "#define MAX_SHARES (1UL << 18)"
417+
// ConvertCPUSharesToCgroupV2Value converts CPU shares, used by cgroup v1,
418+
// to CPU weight, used by cgroup v2.
419+
//
420+
// Cgroup v1 CPU shares has a range of [2^1...2^18], i.e. [2...262144],
421+
// and the default value is 1024.
422+
//
423+
// Cgroup v2 CPU weight has a range of [10^0...10^4], i.e. [1...10000],
424+
// and the default value is 100.
421425
func ConvertCPUSharesToCgroupV2Value(cpuShares uint64) uint64 {
426+
// The value of 0 means "unset".
422427
if cpuShares == 0 {
423428
return 0
424429
}
425-
return (1 + ((cpuShares-2)*9999)/262142)
430+
if cpuShares <= 2 {
431+
return 1
432+
}
433+
if cpuShares >= 262144 {
434+
return 10000
435+
}
436+
l := math.Log2(float64(cpuShares))
437+
// Quadratic function which fits min, max, and default.
438+
exponent := (l*l+125*l)/612.0 - 7.0/34.0
439+
440+
return uint64(math.Ceil(math.Pow(10, exponent)))
426441
}
427442

428443
// ConvertMemorySwapToCgroupV2Value converts MemorySwap value from OCI spec

utils_test.go

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -535,10 +535,25 @@ func TestGetHugePageSizeImpl(t *testing.T) {
535535
}
536536

537537
func TestConvertCPUSharesToCgroupV2Value(t *testing.T) {
538+
const (
539+
sharesMin = 2
540+
sharesMax = 262144
541+
sharesDef = 1024
542+
weightMin = 1
543+
weightMax = 10000
544+
weightDef = 100
545+
unset = 0
546+
)
538547
cases := map[uint64]uint64{
539-
0: 0,
540-
2: 1,
541-
262144: 10000,
548+
unset: unset,
549+
550+
sharesMin - 1: weightMin, // Below the minimum (out of range).
551+
sharesMin: weightMin, // Minimum.
552+
sharesMin + 1: weightMin + 1, // Just above the minimum.
553+
sharesDef: weightDef, // Default.
554+
sharesMax - 1: weightMax, // Just below the maximum.
555+
sharesMax: weightMax, // Maximum.
556+
sharesMax + 1: weightMax, // Above the maximum (out of range).
542557
}
543558
for i, expected := range cases {
544559
got := ConvertCPUSharesToCgroupV2Value(i)

0 commit comments

Comments
 (0)