mirror of
https://github.com/k3s-io/kubernetes.git
synced 2026-07-17 20:00:07 +00:00
Merge pull request #131076 from tallclair/quota-cleanup
Deduplicate MilliCPUToQuota function & constants
This commit is contained in:
@@ -26,48 +26,13 @@ import (
|
||||
"k8s.io/kubernetes/pkg/kubelet/cm"
|
||||
)
|
||||
|
||||
const (
|
||||
milliCPUToCPU = 1000
|
||||
|
||||
// 100000 microseconds is equivalent to 100ms
|
||||
quotaPeriod = 100000
|
||||
// 1000 microseconds is equivalent to 1ms
|
||||
// defined here:
|
||||
// https://github.com/torvalds/linux/blob/cac03ac368fabff0122853de2422d4e17a32de08/kernel/sched/core.c#L10546
|
||||
minQuotaPeriod = 1000
|
||||
)
|
||||
|
||||
// milliCPUToQuota converts milliCPU to CFS quota and period values
|
||||
// Input parameters and resulting value is number of microseconds.
|
||||
func milliCPUToQuota(milliCPU int64, period int64) (quota int64) {
|
||||
// CFS quota is measured in two values:
|
||||
// - cfs_period_us=100ms (the amount of time to measure usage across)
|
||||
// - cfs_quota=20ms (the amount of cpu time allowed to be used across a period)
|
||||
// so in the above example, you are limited to 20% of a single CPU
|
||||
// for multi-cpu environments, you just scale equivalent amounts
|
||||
// see https://www.kernel.org/doc/Documentation/scheduler/sched-bwc.txt for details
|
||||
if milliCPU == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
// we then convert your milliCPU to a value normalized over a period
|
||||
quota = (milliCPU * period) / milliCPUToCPU
|
||||
|
||||
// quota needs to be a minimum of 1ms.
|
||||
if quota < minQuotaPeriod {
|
||||
quota = minQuotaPeriod
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// sharesToMilliCPU converts CpuShares (cpu.shares) to milli-CPU value
|
||||
// TODO(vinaykul,InPlacePodVerticalScaling): Address issue that sets min req/limit to 2m/10m before beta
|
||||
// See: https://github.com/kubernetes/kubernetes/pull/102884#discussion_r662552642
|
||||
func sharesToMilliCPU(shares int64) int64 {
|
||||
milliCPU := int64(0)
|
||||
if shares >= int64(cm.MinShares) {
|
||||
milliCPU = int64(math.Ceil(float64(shares*milliCPUToCPU) / float64(cm.SharesPerCPU)))
|
||||
milliCPU = int64(math.Ceil(float64(shares*cm.MilliCPUToCPU) / float64(cm.SharesPerCPU)))
|
||||
}
|
||||
return milliCPU
|
||||
}
|
||||
@@ -77,7 +42,7 @@ func quotaToMilliCPU(quota int64, period int64) int64 {
|
||||
if quota == -1 {
|
||||
return int64(0)
|
||||
}
|
||||
return (quota * milliCPUToCPU) / period
|
||||
return (quota * cm.MilliCPUToCPU) / period
|
||||
}
|
||||
|
||||
func subtractOverheadFromResourceConfig(resCfg *cm.ResourceConfig, pod *v1.Pod) *cm.ResourceConfig {
|
||||
|
||||
@@ -25,10 +25,7 @@ import (
|
||||
|
||||
v1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/api/resource"
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
featuregatetesting "k8s.io/component-base/featuregate/testing"
|
||||
runtimeapi "k8s.io/cri-api/pkg/apis/runtime/v1"
|
||||
"k8s.io/kubernetes/pkg/features"
|
||||
"k8s.io/kubernetes/pkg/kubelet/cm"
|
||||
)
|
||||
|
||||
@@ -36,184 +33,6 @@ func seccompLocalhostRef(profileName string) string {
|
||||
return filepath.Join(fakeSeccompProfileRoot, profileName)
|
||||
}
|
||||
|
||||
func TestMilliCPUToQuota(t *testing.T) {
|
||||
for _, testCase := range []struct {
|
||||
msg string
|
||||
input int64
|
||||
expected int64
|
||||
period uint64
|
||||
}{
|
||||
{
|
||||
msg: "all-zero",
|
||||
input: int64(0),
|
||||
expected: int64(0),
|
||||
period: uint64(0),
|
||||
},
|
||||
{
|
||||
msg: "5 input default quota and period",
|
||||
input: int64(5),
|
||||
expected: int64(1000),
|
||||
period: uint64(100000),
|
||||
},
|
||||
{
|
||||
msg: "9 input default quota and period",
|
||||
input: int64(9),
|
||||
expected: int64(1000),
|
||||
period: uint64(100000),
|
||||
},
|
||||
{
|
||||
msg: "10 input default quota and period",
|
||||
input: int64(10),
|
||||
expected: int64(1000),
|
||||
period: uint64(100000),
|
||||
},
|
||||
{
|
||||
msg: "200 input 20k quota and default period",
|
||||
input: int64(200),
|
||||
expected: int64(20000),
|
||||
period: uint64(100000),
|
||||
},
|
||||
{
|
||||
msg: "500 input 50k quota and default period",
|
||||
input: int64(500),
|
||||
expected: int64(50000),
|
||||
period: uint64(100000),
|
||||
},
|
||||
{
|
||||
msg: "1k input 100k quota and default period",
|
||||
input: int64(1000),
|
||||
expected: int64(100000),
|
||||
period: uint64(100000),
|
||||
},
|
||||
{
|
||||
msg: "1500 input 150k quota and default period",
|
||||
input: int64(1500),
|
||||
expected: int64(150000),
|
||||
period: uint64(100000),
|
||||
}} {
|
||||
t.Run(testCase.msg, func(t *testing.T) {
|
||||
quota := milliCPUToQuota(testCase.input, int64(testCase.period))
|
||||
if quota != testCase.expected {
|
||||
t.Errorf("Input %v and %v, expected quota %v, but got quota %v", testCase.input, testCase.period, testCase.expected, quota)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestMilliCPUToQuotaWithCustomCPUCFSQuotaPeriod(t *testing.T) {
|
||||
featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CPUCFSQuotaPeriod, true)
|
||||
|
||||
for _, testCase := range []struct {
|
||||
msg string
|
||||
input int64
|
||||
expected int64
|
||||
period uint64
|
||||
}{
|
||||
{
|
||||
msg: "all-zero",
|
||||
input: int64(0),
|
||||
expected: int64(0),
|
||||
period: uint64(0),
|
||||
},
|
||||
{
|
||||
msg: "5 input default quota and period",
|
||||
input: int64(5),
|
||||
expected: minQuotaPeriod,
|
||||
period: uint64(100000),
|
||||
},
|
||||
{
|
||||
msg: "9 input default quota and period",
|
||||
input: int64(9),
|
||||
expected: minQuotaPeriod,
|
||||
period: uint64(100000),
|
||||
},
|
||||
{
|
||||
msg: "10 input default quota and period",
|
||||
input: int64(10),
|
||||
expected: minQuotaPeriod,
|
||||
period: uint64(100000),
|
||||
},
|
||||
{
|
||||
msg: "200 input 20k quota and default period",
|
||||
input: int64(200),
|
||||
expected: int64(20000),
|
||||
period: uint64(100000),
|
||||
},
|
||||
{
|
||||
msg: "500 input 50k quota and default period",
|
||||
input: int64(500),
|
||||
expected: int64(50000),
|
||||
period: uint64(100000),
|
||||
},
|
||||
{
|
||||
msg: "1k input 100k quota and default period",
|
||||
input: int64(1000),
|
||||
expected: int64(100000),
|
||||
period: uint64(100000),
|
||||
},
|
||||
{
|
||||
msg: "1500 input 150k quota and default period",
|
||||
input: int64(1500),
|
||||
expected: int64(150000),
|
||||
period: uint64(100000),
|
||||
},
|
||||
{
|
||||
msg: "5 input 10k period and default quota expected",
|
||||
input: int64(5),
|
||||
period: uint64(10000),
|
||||
expected: minQuotaPeriod,
|
||||
},
|
||||
{
|
||||
msg: "5 input 5k period and default quota expected",
|
||||
input: int64(5),
|
||||
period: uint64(5000),
|
||||
expected: minQuotaPeriod,
|
||||
},
|
||||
{
|
||||
msg: "9 input 10k period and default quota expected",
|
||||
input: int64(9),
|
||||
period: uint64(10000),
|
||||
expected: minQuotaPeriod,
|
||||
},
|
||||
{
|
||||
msg: "10 input 200k period and 2000 quota expected",
|
||||
input: int64(10),
|
||||
period: uint64(200000),
|
||||
expected: int64(2000),
|
||||
},
|
||||
{
|
||||
msg: "200 input 200k period and 40k quota",
|
||||
input: int64(200),
|
||||
period: uint64(200000),
|
||||
expected: int64(40000),
|
||||
},
|
||||
{
|
||||
msg: "500 input 20k period and 20k expected quota",
|
||||
input: int64(500),
|
||||
period: uint64(20000),
|
||||
expected: int64(10000),
|
||||
},
|
||||
{
|
||||
msg: "1000 input 10k period and 10k expected quota",
|
||||
input: int64(1000),
|
||||
period: uint64(10000),
|
||||
expected: int64(10000),
|
||||
},
|
||||
{
|
||||
msg: "1500 input 5000 period and 7500 expected quota",
|
||||
input: int64(1500),
|
||||
period: uint64(5000),
|
||||
expected: int64(7500),
|
||||
}} {
|
||||
t.Run(testCase.msg, func(t *testing.T) {
|
||||
quota := milliCPUToQuota(testCase.input, int64(testCase.period))
|
||||
if quota != testCase.expected {
|
||||
t.Errorf("Input %v and %v, expected quota %v, but got quota %v", testCase.input, testCase.period, testCase.expected, quota)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetSeccompProfile(t *testing.T) {
|
||||
_, _, m, err := createTestRuntimeManager()
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -294,13 +294,13 @@ func (m *kubeGenericRuntimeManager) calculateLinuxResources(cpuRequest, cpuLimit
|
||||
if m.cpuCFSQuota {
|
||||
// if cpuLimit.Amount is nil, then the appropriate default value is returned
|
||||
// to allow full usage of cpu resource.
|
||||
cpuPeriod := int64(quotaPeriod)
|
||||
cpuPeriod := int64(cm.QuotaPeriod)
|
||||
if utilfeature.DefaultFeatureGate.Enabled(kubefeatures.CPUCFSQuotaPeriod) {
|
||||
// kubeGenericRuntimeManager.cpuCFSQuotaPeriod is provided in time.Duration,
|
||||
// but we need to convert it to number of microseconds which is used by kernel.
|
||||
cpuPeriod = int64(m.cpuCFSQuotaPeriod.Duration / time.Microsecond)
|
||||
}
|
||||
cpuQuota := milliCPUToQuota(cpuLimit.MilliValue(), cpuPeriod)
|
||||
cpuQuota := cm.MilliCPUToQuota(cpuLimit.MilliValue(), cpuPeriod)
|
||||
resources.CpuQuota = cpuQuota
|
||||
if disableCPUQuota {
|
||||
resources.CpuQuota = int64(-1)
|
||||
|
||||
Reference in New Issue
Block a user