Merge pull request #8207 from xordspar0/common-period-quota

Centralize cores and period/quota conversion code
This commit is contained in:
OpenShift Merge Robot
2020-11-02 16:02:55 +01:00
committed by GitHub
5 changed files with 48 additions and 11 deletions

View File

@ -25,11 +25,8 @@ func getCPULimits(c *ContainerCLIOpts) *specs.LinuxCPU {
cpu := &specs.LinuxCPU{}
hasLimits := false
const cpuPeriod = 100000
if c.CPUS > 0 {
quota := int64(c.CPUS * cpuPeriod)
period := uint64(cpuPeriod)
period, quota := util.CoresToPeriodAndQuota(c.CPUS)
cpu.Period = &period
cpu.Quota = &quota

View File

@ -327,7 +327,7 @@ func containerToV1Container(c *Container) (v1.Container, []v1.Volume, error) {
period := *c.config.Spec.Linux.Resources.CPU.Period
if quota > 0 && period > 0 {
cpuLimitMilli := int64(1000 * float64(quota) / float64(period))
cpuLimitMilli := int64(1000 * util.PeriodAndQuotaToCores(period, quota))
// Kubernetes: precision finer than 1m is not allowed
if cpuLimitMilli >= 1 {

View File

@ -36,8 +36,6 @@ const (
kubeDirectoryPermission = 0755
// https://kubernetes.io/docs/concepts/storage/volumes/#hostpath
kubeFilePermission = 0644
// Kubernetes sets CPUPeriod to 100000us (100ms): https://kubernetes.io/docs/reference/command-line-tools-reference/kubelet/
defaultCPUPeriod = 100000
)
func (ic *ContainerEngine) PlayKube(ctx context.Context, path string, options entities.PlayKubeOptions) (*entities.PlayKubeReport, error) {
@ -515,10 +513,9 @@ func kubeContainerToCreateConfig(ctx context.Context, containerYAML v1.Container
return nil, errors.Wrap(err, "Failed to set CPU quota")
}
if milliCPU > 0 {
containerConfig.Resources.CPUPeriod = defaultCPUPeriod
// CPU quota is a fraction of the period: milliCPU / 1000.0 * period
// Or, without floating point math:
containerConfig.Resources.CPUQuota = milliCPU * defaultCPUPeriod / 1000
period, quota := util.CoresToPeriodAndQuota(float64(milliCPU) / 1000)
containerConfig.Resources.CPUPeriod = period
containerConfig.Resources.CPUQuota = quota
}
containerConfig.Resources.Memory, err = quantityToInt64(containerYAML.Resources.Limits.Memory())

View File

@ -653,3 +653,26 @@ func CreateCidFile(cidfile string, id string) error {
cidFile.Close()
return nil
}
// DefaultCPUPeriod is the default CPU period is 100us, which is the same default
// as Kubernetes.
const DefaultCPUPeriod uint64 = 100000
// CoresToPeriodAndQuota converts a fraction of cores to the equivalent
// Completely Fair Scheduler (CFS) parameters period and quota.
//
// Cores is a fraction of the CFS period that a container may use. Period and
// Quota are in microseconds.
func CoresToPeriodAndQuota(cores float64) (uint64, int64) {
return DefaultCPUPeriod, int64(cores * float64(DefaultCPUPeriod))
}
// PeriodAndQuotaToCores takes the CFS parameters period and quota and returns
// a fraction that represents the limit to the number of cores that can be
// utilized over the scheduling period.
//
// Cores is a fraction of the CFS period that a container may use. Period and
// Quota are in microseconds.
func PeriodAndQuotaToCores(period uint64, quota int64) float64 {
return float64(quota) / float64(period)
}

View File

@ -257,3 +257,23 @@ func TestValidateSysctlBadSysctl(t *testing.T) {
_, err := ValidateSysctls(strSlice)
assert.Error(t, err)
}
func TestCoresToPeriodAndQuota(t *testing.T) {
cores := 1.0
expectedPeriod := DefaultCPUPeriod
expectedQuota := int64(DefaultCPUPeriod)
actualPeriod, actualQuota := CoresToPeriodAndQuota(cores)
assert.Equal(t, actualPeriod, expectedPeriod, "Period does not match")
assert.Equal(t, actualQuota, expectedQuota, "Quota does not match")
}
func TestPeriodAndQuotaToCores(t *testing.T) {
var (
period uint64 = 100000
quota int64 = 50000
expectedCores = 0.5
)
assert.Equal(t, PeriodAndQuotaToCores(period, quota), expectedCores)
}