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{} cpu := &specs.LinuxCPU{}
hasLimits := false hasLimits := false
const cpuPeriod = 100000
if c.CPUS > 0 { if c.CPUS > 0 {
quota := int64(c.CPUS * cpuPeriod) period, quota := util.CoresToPeriodAndQuota(c.CPUS)
period := uint64(cpuPeriod)
cpu.Period = &period cpu.Period = &period
cpu.Quota = &quota 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 period := *c.config.Spec.Linux.Resources.CPU.Period
if quota > 0 && period > 0 { 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 // Kubernetes: precision finer than 1m is not allowed
if cpuLimitMilli >= 1 { if cpuLimitMilli >= 1 {

View File

@ -36,8 +36,6 @@ const (
kubeDirectoryPermission = 0755 kubeDirectoryPermission = 0755
// https://kubernetes.io/docs/concepts/storage/volumes/#hostpath // https://kubernetes.io/docs/concepts/storage/volumes/#hostpath
kubeFilePermission = 0644 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) { 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") return nil, errors.Wrap(err, "Failed to set CPU quota")
} }
if milliCPU > 0 { if milliCPU > 0 {
containerConfig.Resources.CPUPeriod = defaultCPUPeriod period, quota := util.CoresToPeriodAndQuota(float64(milliCPU) / 1000)
// CPU quota is a fraction of the period: milliCPU / 1000.0 * period containerConfig.Resources.CPUPeriod = period
// Or, without floating point math: containerConfig.Resources.CPUQuota = quota
containerConfig.Resources.CPUQuota = milliCPU * defaultCPUPeriod / 1000
} }
containerConfig.Resources.Memory, err = quantityToInt64(containerYAML.Resources.Limits.Memory()) containerConfig.Resources.Memory, err = quantityToInt64(containerYAML.Resources.Limits.Memory())

View File

@ -653,3 +653,26 @@ func CreateCidFile(cidfile string, id string) error {
cidFile.Close() cidFile.Close()
return nil 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) _, err := ValidateSysctls(strSlice)
assert.Error(t, err) 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)
}