sandbox: consider cpusets if quota is not enforced

CPUSet cgroup allows for pinning the memory associated with a cpuset to
a given numa node. Similar to cpuset.cpus, we should take cpuset.mems
into account for the sandbox-cgroup that Kata creates.

Signed-off-by: Eric Ernst <eric.g.ernst@gmail.com>
This commit is contained in:
Eric Ernst 2020-10-12 21:15:55 -07:00 committed by Eric Ernst
parent 77a463e57a
commit 88cd712876
2 changed files with 34 additions and 8 deletions

View File

@ -1897,7 +1897,10 @@ func (s *Sandbox) updateResources() error {
return fmt.Errorf("sandbox config is nil")
}
sandboxVCPUs := s.calculateSandboxCPUs()
sandboxVCPUs, err := s.calculateSandboxCPUs()
if err != nil {
return err
}
// Add default vcpus for sandbox
sandboxVCPUs += s.hypervisor.hypervisorConfig().NumVCPUs
@ -1959,8 +1962,9 @@ func (s *Sandbox) calculateSandboxMemory() int64 {
return memorySandbox
}
func (s *Sandbox) calculateSandboxCPUs() uint32 {
func (s *Sandbox) calculateSandboxCPUs() (uint32, error) {
mCPU := uint32(0)
cpusetCount := int(0)
for _, c := range s.config.Containers {
// Do not hot add again non-running containers resources
@ -1974,9 +1978,22 @@ func (s *Sandbox) calculateSandboxCPUs() uint32 {
mCPU += utils.CalculateMilliCPUs(*cpu.Quota, *cpu.Period)
}
set, err := cpuset.Parse(cpu.Cpus)
if err != nil {
return 0, nil
}
cpusetCount += set.Size()
}
}
return utils.CalculateVCpusFromMilliCpus(mCPU)
// If we aren't being constrained, then we could have two scenarios:
// 1. BestEffort QoS: no proper support today in Kata.
// 2. We could be constrained only by CPUSets. Check for this:
if mCPU == 0 && cpusetCount > 0 {
return uint32(cpusetCount), nil
}
return utils.CalculateVCpusFromMilliCpus(mCPU), nil
}
// GetHypervisorType is used for getting Hypervisor name currently used.
@ -2313,11 +2330,11 @@ func (s *Sandbox) getSandboxCPUSet() (string, string, error) {
memResult := cpuset.NewCPUSet()
for _, ctr := range s.config.Containers {
if ctr.Resources.CPU != nil {
currCpuSet, err := cpuset.Parse(ctr.Resources.CPU.Cpus)
currCPUSet, err := cpuset.Parse(ctr.Resources.CPU.Cpus)
if err != nil {
return "", "", fmt.Errorf("unable to parse CPUset.cpus for container %s: %v", ctr.ID, err)
}
cpuResult = cpuResult.Union(currCpuSet)
cpuResult = cpuResult.Union(currCPUSet)
currMemSet, err := cpuset.Parse(ctr.Resources.CPU.Mems)
if err != nil {

View File

@ -106,12 +106,18 @@ func TestCreateMockSandbox(t *testing.T) {
func TestCalculateSandboxCPUs(t *testing.T) {
sandbox := &Sandbox{}
sandbox.config = &SandboxConfig{}
unconstrained := newTestContainerConfigNoop("cont-00001")
constrained := newTestContainerConfigNoop("cont-00001")
constrained := newTestContainerConfigNoop("cont-00002")
unconstrainedCpusets0_1 := newTestContainerConfigNoop("cont-00003")
unconstrainedCpusets2 := newTestContainerConfigNoop("cont-00004")
constrainedCpusets0_7 := newTestContainerConfigNoop("cont-00005")
quota := int64(4000)
period := uint64(1000)
constrained.Resources.CPU = &specs.LinuxCPU{Period: &period, Quota: &quota}
unconstrainedCpusets0_1.Resources.CPU = &specs.LinuxCPU{Cpus: "0-1"}
unconstrainedCpusets2.Resources.CPU = &specs.LinuxCPU{Cpus: "2"}
constrainedCpusets0_7.Resources.CPU = &specs.LinuxCPU{Period: &period, Quota: &quota, Cpus: "0-7"}
tests := []struct {
name string
containers []ContainerConfig
@ -123,11 +129,14 @@ func TestCalculateSandboxCPUs(t *testing.T) {
{"2-constrained", []ContainerConfig{constrained, constrained}, 8},
{"3-mix-constraints", []ContainerConfig{unconstrained, constrained, constrained}, 8},
{"3-constrained", []ContainerConfig{constrained, constrained, constrained}, 12},
{"unconstrained-1-cpuset", []ContainerConfig{unconstrained, unconstrained, unconstrainedCpusets0_1}, 2},
{"unconstrained-2-cpuset", []ContainerConfig{unconstrainedCpusets0_1, unconstrainedCpusets2}, 3},
{"constrained-cpuset", []ContainerConfig{constrainedCpusets0_7}, 4},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
sandbox.config.Containers = tt.containers
got := sandbox.calculateSandboxCPUs()
got, _ := sandbox.calculateSandboxCPUs()
assert.Equal(t, got, tt.want)
})
}