mirror of
https://github.com/containers/podman.git
synced 2025-06-22 01:48:54 +08:00
Merge pull request #8207 from xordspar0/common-period-quota
Centralize cores and period/quota conversion code
This commit is contained in:
@ -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 = "a
|
cpu.Quota = "a
|
||||||
|
@ -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 {
|
||||||
|
@ -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())
|
||||||
|
@ -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)
|
||||||
|
}
|
||||||
|
@ -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)
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user