From 479fd7078ee24c5ec39457d954cb7cc82ee7236a Mon Sep 17 00:00:00 2001 From: Eric Ernst Date: Thu, 17 Sep 2020 16:28:07 -0700 Subject: [PATCH] sandbox: consider cpusets if quota is not enforced If quota is not being enforced on any containers but CPUsets are specified, take the number of CPU sets into account when sizing the virtual machine. Fixes: #2971 Signed-off-by: Eric Ernst --- virtcontainers/sandbox.go | 24 +++++++++++++++++++++--- virtcontainers/sandbox_test.go | 15 ++++++++++++--- 2 files changed, 33 insertions(+), 6 deletions(-) diff --git a/virtcontainers/sandbox.go b/virtcontainers/sandbox.go index c7ae0f60bc..f1c9d8dafc 100644 --- a/virtcontainers/sandbox.go +++ b/virtcontainers/sandbox.go @@ -1863,7 +1863,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 @@ -1923,8 +1926,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 @@ -1938,9 +1942,23 @@ func (s *Sandbox) calculateSandboxCPUs() uint32 { mCPU += utils.CalculateMilliCPUs(*cpu.Quota, *cpu.Period) } + //todo we should handle error + 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. diff --git a/virtcontainers/sandbox_test.go b/virtcontainers/sandbox_test.go index bfc340ccf7..4681e70773 100644 --- a/virtcontainers/sandbox_test.go +++ b/virtcontainers/sandbox_test.go @@ -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") + unconstrained_cpusets0_1 := newTestContainerConfigNoop("cont-00003") + unconstrained_cpusets2 := newTestContainerConfigNoop("cont-00004") + constrained_cpusets0_7 := newTestContainerConfigNoop("cont-00005") quota := int64(4000) period := uint64(1000) constrained.Resources.CPU = &specs.LinuxCPU{Period: &period, Quota: "a} - + unconstrained_cpusets0_1.Resources.CPU = &specs.LinuxCPU{Cpus: "0-1"} + unconstrained_cpusets2.Resources.CPU = &specs.LinuxCPU{Cpus: "2"} + constrained_cpusets0_7.Resources.CPU = &specs.LinuxCPU{Period: &period, Quota: "a, 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, unconstrained_cpusets0_1}, 2}, + {"unconstrained-2-cpuset", []ContainerConfig{unconstrained_cpusets0_1, unconstrained_cpusets2}, 3}, + {"constrained-cpuset", []ContainerConfig{constrained_cpusets0_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) }) }