# Copyright 2014 Red Hat, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. import uuid import mock from oslo_serialization import jsonutils import six from nova import context from nova import exception from nova import objects from nova.objects import base as base_obj from nova.pci import stats from nova import test from nova.virt import hardware as hw class InstanceInfoTests(test.NoDBTestCase): def test_instance_info_default(self): ii = hw.InstanceInfo() self.assertIsNone(ii.state) self.assertIsNone(ii.id) self.assertEqual(0, ii.max_mem_kb) self.assertEqual(0, ii.mem_kb) self.assertEqual(0, ii.num_cpu) self.assertEqual(0, ii.cpu_time_ns) def test_instance_info(self): ii = hw.InstanceInfo(state='fake-state', max_mem_kb=1, mem_kb=2, num_cpu=3, cpu_time_ns=4, id='fake-id') self.assertEqual('fake-state', ii.state) self.assertEqual('fake-id', ii.id) self.assertEqual(1, ii.max_mem_kb) self.assertEqual(2, ii.mem_kb) self.assertEqual(3, ii.num_cpu) self.assertEqual(4, ii.cpu_time_ns) def test_instance_infoi_equals(self): ii1 = hw.InstanceInfo(state='fake-state', max_mem_kb=1, mem_kb=2, num_cpu=3, cpu_time_ns=4, id='fake-id') ii2 = hw.InstanceInfo(state='fake-state', max_mem_kb=1, mem_kb=2, num_cpu=3, cpu_time_ns=4, id='fake-id') ii3 = hw.InstanceInfo(state='fake-estat', max_mem_kb=11, mem_kb=22, num_cpu=33, cpu_time_ns=44, id='fake-di') self.assertEqual(ii1, ii2) self.assertNotEqual(ii1, ii3) class CpuSetTestCase(test.NoDBTestCase): def test_get_vcpu_pin_set(self): self.flags(vcpu_pin_set="1-3,5,^2") cpuset_ids = hw.get_vcpu_pin_set() self.assertEqual(set([1, 3, 5]), cpuset_ids) def test_parse_cpu_spec_none_returns_none(self): self.flags(vcpu_pin_set=None) cpuset_ids = hw.get_vcpu_pin_set() self.assertIsNone(cpuset_ids) def test_parse_cpu_spec_valid_syntax_works(self): cpuset_ids = hw.parse_cpu_spec("1") self.assertEqual(set([1]), cpuset_ids) cpuset_ids = hw.parse_cpu_spec("1,2") self.assertEqual(set([1, 2]), cpuset_ids) cpuset_ids = hw.parse_cpu_spec(", , 1 , ,, 2, ,") self.assertEqual(set([1, 2]), cpuset_ids) cpuset_ids = hw.parse_cpu_spec("1-1") self.assertEqual(set([1]), cpuset_ids) cpuset_ids = hw.parse_cpu_spec(" 1 - 1, 1 - 2 , 1 -3") self.assertEqual(set([1, 2, 3]), cpuset_ids) cpuset_ids = hw.parse_cpu_spec("1,^2") self.assertEqual(set([1]), cpuset_ids) cpuset_ids = hw.parse_cpu_spec("1-2, ^1") self.assertEqual(set([2]), cpuset_ids) cpuset_ids = hw.parse_cpu_spec("1-3,5,^2") self.assertEqual(set([1, 3, 5]), cpuset_ids) cpuset_ids = hw.parse_cpu_spec(" 1 - 3 , ^2, 5") self.assertEqual(set([1, 3, 5]), cpuset_ids) cpuset_ids = hw.parse_cpu_spec(" 1,1, ^1") self.assertEqual(set([]), cpuset_ids) def test_parse_cpu_spec_invalid_syntax_raises(self): self.assertRaises(exception.Invalid, hw.parse_cpu_spec, " -1-3,5,^2") self.assertRaises(exception.Invalid, hw.parse_cpu_spec, "1-3-,5,^2") self.assertRaises(exception.Invalid, hw.parse_cpu_spec, "-3,5,^2") self.assertRaises(exception.Invalid, hw.parse_cpu_spec, "1-,5,^2") self.assertRaises(exception.Invalid, hw.parse_cpu_spec, "1-3,5,^2^") self.assertRaises(exception.Invalid, hw.parse_cpu_spec, "1-3,5,^2-") self.assertRaises(exception.Invalid, hw.parse_cpu_spec, "--13,^^5,^2") self.assertRaises(exception.Invalid, hw.parse_cpu_spec, "a-3,5,^2") self.assertRaises(exception.Invalid, hw.parse_cpu_spec, "1-a,5,^2") self.assertRaises(exception.Invalid, hw.parse_cpu_spec, "1-3,b,^2") self.assertRaises(exception.Invalid, hw.parse_cpu_spec, "1-3,5,^c") self.assertRaises(exception.Invalid, hw.parse_cpu_spec, "3 - 1, 5 , ^ 2 ") def test_format_cpu_spec(self): cpus = set([]) spec = hw.format_cpu_spec(cpus) self.assertEqual("", spec) cpus = [] spec = hw.format_cpu_spec(cpus) self.assertEqual("", spec) cpus = set([1, 3]) spec = hw.format_cpu_spec(cpus) self.assertEqual("1,3", spec) cpus = [1, 3] spec = hw.format_cpu_spec(cpus) self.assertEqual("1,3", spec) cpus = set([1, 2, 4, 6]) spec = hw.format_cpu_spec(cpus) self.assertEqual("1-2,4,6", spec) cpus = [1, 2, 4, 6] spec = hw.format_cpu_spec(cpus) self.assertEqual("1-2,4,6", spec) cpus = set([10, 11, 13, 14, 15, 16, 19, 20, 40, 42, 48]) spec = hw.format_cpu_spec(cpus) self.assertEqual("10-11,13-16,19-20,40,42,48", spec) cpus = [10, 11, 13, 14, 15, 16, 19, 20, 40, 42, 48] spec = hw.format_cpu_spec(cpus) self.assertEqual("10-11,13-16,19-20,40,42,48", spec) cpus = set([1, 2, 4, 6]) spec = hw.format_cpu_spec(cpus, allow_ranges=False) self.assertEqual("1,2,4,6", spec) cpus = [1, 2, 4, 6] spec = hw.format_cpu_spec(cpus, allow_ranges=False) self.assertEqual("1,2,4,6", spec) cpus = set([10, 11, 13, 14, 15, 16, 19, 20, 40, 42, 48]) spec = hw.format_cpu_spec(cpus, allow_ranges=False) self.assertEqual("10,11,13,14,15,16,19,20,40,42,48", spec) cpus = [10, 11, 13, 14, 15, 16, 19, 20, 40, 42, 48] spec = hw.format_cpu_spec(cpus, allow_ranges=False) self.assertEqual("10,11,13,14,15,16,19,20,40,42,48", spec) class VCPUTopologyTest(test.NoDBTestCase): def test_validate_config(self): testdata = [ { # Flavor sets preferred topology only "flavor": objects.Flavor(vcpus=16, memory_mb=2048, extra_specs={ "hw:cpu_sockets": "8", "hw:cpu_cores": "2", "hw:cpu_threads": "1", }), "image": { "properties": {} }, "expect": ( 8, 2, 1, 65536, 65536, 65536 ) }, { # Image topology overrides flavor "flavor": objects.Flavor(vcpus=16, memory_mb=2048, extra_specs={ "hw:cpu_sockets": "8", "hw:cpu_cores": "2", "hw:cpu_threads": "1", "hw:cpu_max_threads": "2", }), "image": { "properties": { "hw_cpu_sockets": "4", "hw_cpu_cores": "2", "hw_cpu_threads": "2", } }, "expect": ( 4, 2, 2, 65536, 65536, 2, ) }, { # Partial image topology overrides flavor "flavor": objects.Flavor(vcpus=16, memory_mb=2048, extra_specs={ "hw:cpu_sockets": "8", "hw:cpu_cores": "2", "hw:cpu_threads": "1", }), "image": { "properties": { "hw_cpu_sockets": "2", } }, "expect": ( 2, -1, -1, 65536, 65536, 65536, ) }, { # Restrict use of threads "flavor": objects.Flavor(vcpus=16, memory_mb=2048, extra_specs={ "hw:cpu_max_threads": "2", }), "image": { "properties": { "hw_cpu_max_threads": "1", } }, "expect": ( -1, -1, -1, 65536, 65536, 1, ) }, { # Force use of at least two sockets "flavor": objects.Flavor(vcpus=16, memory_mb=2048, extra_specs={ "hw:cpu_max_cores": "8", "hw:cpu_max_threads": "1", }), "image": { "properties": {} }, "expect": ( -1, -1, -1, 65536, 8, 1 ) }, { # Image limits reduce flavor "flavor": objects.Flavor(vcpus=16, memory_mb=2048, extra_specs={ "hw:cpu_max_cores": "8", "hw:cpu_max_threads": "1", }), "image": { "properties": { "hw_cpu_max_cores": "4", } }, "expect": ( -1, -1, -1, 65536, 4, 1 ) }, { # Image limits kill flavor preferred "flavor": objects.Flavor(vcpus=16, memory_mb=2048, extra_specs={ "hw:cpu_sockets": "2", "hw:cpu_cores": "8", "hw:cpu_threads": "1", }), "image": { "properties": { "hw_cpu_max_cores": "4", } }, "expect": ( -1, -1, -1, 65536, 4, 65536 ) }, { # Image limits cannot exceed flavor "flavor": objects.Flavor(vcpus=16, memory_mb=2048, extra_specs={ "hw:cpu_max_cores": "8", "hw:cpu_max_threads": "1", }), "image": { "properties": { "hw_cpu_max_cores": "16", } }, "expect": exception.ImageVCPULimitsRangeExceeded, }, { # Image preferred cannot exceed flavor "flavor": objects.Flavor(vcpus=16, memory_mb=2048, extra_specs={ "hw:cpu_max_cores": "8", "hw:cpu_max_threads": "1", }), "image": { "properties": { "hw_cpu_cores": "16", } }, "expect": exception.ImageVCPUTopologyRangeExceeded, }, ] for topo_test in testdata: if type(topo_test["expect"]) == tuple: (preferred, maximum) = hw._get_cpu_topology_constraints( topo_test["flavor"], topo_test["image"]) self.assertEqual(topo_test["expect"][0], preferred.sockets) self.assertEqual(topo_test["expect"][1], preferred.cores) self.assertEqual(topo_test["expect"][2], preferred.threads) self.assertEqual(topo_test["expect"][3], maximum.sockets) self.assertEqual(topo_test["expect"][4], maximum.cores) self.assertEqual(topo_test["expect"][5], maximum.threads) else: self.assertRaises(topo_test["expect"], hw._get_cpu_topology_constraints, topo_test["flavor"], topo_test["image"]) def test_possible_topologies(self): testdata = [ { "allow_threads": True, "vcpus": 8, "maxsockets": 8, "maxcores": 8, "maxthreads": 2, "expect": [ [8, 1, 1], [4, 2, 1], [2, 4, 1], [1, 8, 1], [4, 1, 2], [2, 2, 2], [1, 4, 2], ] }, { "allow_threads": False, "vcpus": 8, "maxsockets": 8, "maxcores": 8, "maxthreads": 2, "expect": [ [8, 1, 1], [4, 2, 1], [2, 4, 1], [1, 8, 1], ] }, { "allow_threads": True, "vcpus": 8, "maxsockets": 1024, "maxcores": 1024, "maxthreads": 2, "expect": [ [8, 1, 1], [4, 2, 1], [2, 4, 1], [1, 8, 1], [4, 1, 2], [2, 2, 2], [1, 4, 2], ] }, { "allow_threads": True, "vcpus": 8, "maxsockets": 1024, "maxcores": 1, "maxthreads": 2, "expect": [ [8, 1, 1], [4, 1, 2], ] }, { "allow_threads": True, "vcpus": 7, "maxsockets": 8, "maxcores": 8, "maxthreads": 2, "expect": [ [7, 1, 1], [1, 7, 1], ] }, { "allow_threads": True, "vcpus": 8, "maxsockets": 2, "maxcores": 1, "maxthreads": 1, "expect": exception.ImageVCPULimitsRangeImpossible, }, { "allow_threads": False, "vcpus": 8, "maxsockets": 2, "maxcores": 1, "maxthreads": 4, "expect": exception.ImageVCPULimitsRangeImpossible, }, ] for topo_test in testdata: if type(topo_test["expect"]) == list: actual = [] for topology in hw._get_possible_cpu_topologies( topo_test["vcpus"], objects.VirtCPUTopology( sockets=topo_test["maxsockets"], cores=topo_test["maxcores"], threads=topo_test["maxthreads"]), topo_test["allow_threads"]): actual.append([topology.sockets, topology.cores, topology.threads]) self.assertEqual(topo_test["expect"], actual) else: self.assertRaises(topo_test["expect"], hw._get_possible_cpu_topologies, topo_test["vcpus"], objects.VirtCPUTopology( sockets=topo_test["maxsockets"], cores=topo_test["maxcores"], threads=topo_test["maxthreads"]), topo_test["allow_threads"]) def test_sorting_topologies(self): testdata = [ { "allow_threads": True, "vcpus": 8, "maxsockets": 8, "maxcores": 8, "maxthreads": 2, "sockets": 4, "cores": 2, "threads": 1, "expect": [ [4, 2, 1], # score = 2 [8, 1, 1], # score = 1 [2, 4, 1], # score = 1 [1, 8, 1], # score = 1 [4, 1, 2], # score = 1 [2, 2, 2], # score = 1 [1, 4, 2], # score = 1 ] }, { "allow_threads": True, "vcpus": 8, "maxsockets": 1024, "maxcores": 1024, "maxthreads": 2, "sockets": -1, "cores": 4, "threads": -1, "expect": [ [2, 4, 1], # score = 1 [1, 4, 2], # score = 1 [8, 1, 1], # score = 0 [4, 2, 1], # score = 0 [1, 8, 1], # score = 0 [4, 1, 2], # score = 0 [2, 2, 2], # score = 0 ] }, { "allow_threads": True, "vcpus": 8, "maxsockets": 1024, "maxcores": 1, "maxthreads": 2, "sockets": -1, "cores": -1, "threads": 2, "expect": [ [4, 1, 2], # score = 1 [8, 1, 1], # score = 0 ] }, { "allow_threads": False, "vcpus": 8, "maxsockets": 1024, "maxcores": 1, "maxthreads": 2, "sockets": -1, "cores": -1, "threads": 2, "expect": [ [8, 1, 1], # score = 0 ] }, ] for topo_test in testdata: actual = [] possible = hw._get_possible_cpu_topologies( topo_test["vcpus"], objects.VirtCPUTopology(sockets=topo_test["maxsockets"], cores=topo_test["maxcores"], threads=topo_test["maxthreads"]), topo_test["allow_threads"]) tops = hw._sort_possible_cpu_topologies( possible, objects.VirtCPUTopology(sockets=topo_test["sockets"], cores=topo_test["cores"], threads=topo_test["threads"])) for topology in tops: actual.append([topology.sockets, topology.cores, topology.threads]) self.assertEqual(topo_test["expect"], actual) def test_best_config(self): testdata = [ { # Flavor sets preferred topology only "allow_threads": True, "flavor": objects.Flavor(vcpus=16, memory_mb=2048, extra_specs={ "hw:cpu_sockets": "8", "hw:cpu_cores": "2", "hw:cpu_threads": "1" }), "image": { "properties": {} }, "expect": [8, 2, 1], }, { # Image topology overrides flavor "allow_threads": True, "flavor": objects.Flavor(vcpus=16, memory_mb=2048, extra_specs={ "hw:cpu_sockets": "8", "hw:cpu_cores": "2", "hw:cpu_threads": "1", "hw:cpu_maxthreads": "2", }), "image": { "properties": { "hw_cpu_sockets": "4", "hw_cpu_cores": "2", "hw_cpu_threads": "2", } }, "expect": [4, 2, 2], }, { # Image topology overrides flavor "allow_threads": False, "flavor": objects.Flavor(vcpus=16, memory_mb=2048, extra_specs={ "hw:cpu_sockets": "8", "hw:cpu_cores": "2", "hw:cpu_threads": "1", "hw:cpu_maxthreads": "2", }), "image": { "properties": { "hw_cpu_sockets": "4", "hw_cpu_cores": "2", "hw_cpu_threads": "2", } }, "expect": [8, 2, 1], }, { # Partial image topology overrides flavor "allow_threads": True, "flavor": objects.Flavor(vcpus=16, memory_mb=2048, extra_specs={ "hw:cpu_sockets": "8", "hw:cpu_cores": "2", "hw:cpu_threads": "1" }), "image": { "properties": { "hw_cpu_sockets": "2" } }, "expect": [2, 8, 1], }, { # Restrict use of threads "allow_threads": True, "flavor": objects.Flavor(vcpus=16, memory_mb=2048, extra_specs={ "hw:cpu_max_threads": "1" }), "image": { "properties": {} }, "expect": [16, 1, 1] }, { # Force use of at least two sockets "allow_threads": True, "flavor": objects.Flavor(vcpus=16, memory_mb=2048, extra_specs={ "hw:cpu_max_cores": "8", "hw:cpu_max_threads": "1", }), "image": { "properties": {} }, "expect": [16, 1, 1] }, { # Image limits reduce flavor "allow_threads": True, "flavor": objects.Flavor(vcpus=16, memory_mb=2048, extra_specs={ "hw:cpu_max_sockets": "8", "hw:cpu_max_cores": "8", "hw:cpu_max_threads": "1", }), "image": { "properties": { "hw_cpu_max_sockets": 4, } }, "expect": [4, 4, 1] }, { # Image limits kill flavor preferred "allow_threads": True, "flavor": objects.Flavor(vcpus=16, memory_mb=2048, extra_specs={ "hw:cpu_sockets": "2", "hw:cpu_cores": "8", "hw:cpu_threads": "1", }), "image": { "properties": { "hw_cpu_max_cores": 4, } }, "expect": [16, 1, 1] }, { # NUMA needs threads, only cores requested by flavor "allow_threads": True, "flavor": objects.Flavor(vcpus=4, memory_mb=2048, extra_specs={ "hw:cpu_cores": "2", }), "image": { "properties": { "hw_cpu_max_cores": 2, } }, "numa_topology": objects.InstanceNUMATopology( cells=[ objects.InstanceNUMACell( id=0, cpuset=set([0, 1]), memory=1024, cpu_topology=objects.VirtCPUTopology( sockets=1, cores=1, threads=2)), objects.InstanceNUMACell( id=1, cpuset=set([2, 3]), memory=1024)]), "expect": [1, 2, 2] }, { # NUMA needs threads, but more than requested by flavor - the # least amount of threads wins "allow_threads": True, "flavor": objects.Flavor(vcpus=4, memory_mb=2048, extra_specs={ "hw:cpu_threads": "2", }), "image": { "properties": {} }, "numa_topology": objects.InstanceNUMATopology( cells=[ objects.InstanceNUMACell( id=0, cpuset=set([0, 1, 2, 3]), memory=2048, cpu_topology=objects.VirtCPUTopology( sockets=1, cores=1, threads=4))]), "expect": [2, 1, 2] }, { # NUMA needs threads, but more than limit in flavor - the # least amount of threads which divides into the vcpu # count wins. So with desired 4, max of 3, and # vcpu count of 4, we should get 2 threads. "allow_threads": True, "flavor": objects.Flavor(vcpus=4, memory_mb=2048, extra_specs={ "hw:cpu_max_sockets": "5", "hw:cpu_max_cores": "2", "hw:cpu_max_threads": "3", }), "image": { "properties": {} }, "numa_topology": objects.InstanceNUMATopology( cells=[ objects.InstanceNUMACell( id=0, cpuset=set([0, 1, 2, 3]), memory=2048, cpu_topology=objects.VirtCPUTopology( sockets=1, cores=1, threads=4))]), "expect": [2, 1, 2] }, { # NUMA needs threads, but thread count does not # divide into flavor vcpu count, so we must # reduce thread count to closest divisor "allow_threads": True, "flavor": objects.Flavor(vcpus=6, memory_mb=2048, extra_specs={ }), "image": { "properties": {} }, "numa_topology": objects.InstanceNUMATopology( cells=[ objects.InstanceNUMACell( id=0, cpuset=set([0, 1, 2, 3]), memory=2048, cpu_topology=objects.VirtCPUTopology( sockets=1, cores=1, threads=4))]), "expect": [2, 1, 3] }, { # NUMA needs different number of threads per cell - the least # amount of threads wins "allow_threads": True, "flavor": objects.Flavor(vcpus=8, memory_mb=2048, extra_specs={}), "image": { "properties": {} }, "numa_topology": objects.InstanceNUMATopology( cells=[ objects.InstanceNUMACell( id=0, cpuset=set([0, 1, 2, 3]), memory=1024, cpu_topology=objects.VirtCPUTopology( sockets=1, cores=2, threads=2)), objects.InstanceNUMACell( id=1, cpuset=set([4, 5, 6, 7]), memory=1024, cpu_topology=objects.VirtCPUTopology( sockets=1, cores=1, threads=4))]), "expect": [4, 1, 2] }, ] for topo_test in testdata: topology = hw._get_desirable_cpu_topologies( topo_test["flavor"], topo_test["image"], topo_test["allow_threads"], topo_test.get("numa_topology"))[0] self.assertEqual(topo_test["expect"][0], topology.sockets) self.assertEqual(topo_test["expect"][1], topology.cores) self.assertEqual(topo_test["expect"][2], topology.threads) class NUMATopologyTest(test.NoDBTestCase): def test_topology_constraints(self): testdata = [ { "flavor": objects.Flavor(vcpus=8, memory_mb=2048, extra_specs={ }), "image": { }, "expect": None, }, { "flavor": objects.Flavor(vcpus=8, memory_mb=2048, extra_specs={ "hw:numa_nodes": 2 }), "image": { }, "expect": objects.InstanceNUMATopology(cells= [ objects.InstanceNUMACell( id=0, cpuset=set([0, 1, 2, 3]), memory=1024), objects.InstanceNUMACell( id=1, cpuset=set([4, 5, 6, 7]), memory=1024), ]), }, { "flavor": objects.Flavor(vcpus=8, memory_mb=2048, extra_specs={ "hw:mem_page_size": 2048 }), "image": { }, "expect": objects.InstanceNUMATopology(cells=[ objects.InstanceNUMACell( id=0, cpuset=set([0, 1, 2, 3, 4, 5, 6, 7]), memory=2048, pagesize=2048) ]), }, { # vcpus is not a multiple of nodes, so it # is an error to not provide cpu/mem mapping "flavor": objects.Flavor(vcpus=8, memory_mb=2048, extra_specs={ "hw:numa_nodes": 3 }), "image": { }, "expect": exception.ImageNUMATopologyAsymmetric, }, { "flavor": objects.Flavor(vcpus=8, memory_mb=2048, extra_specs={ "hw:numa_nodes": 3, "hw:numa_cpus.0": "0-3", "hw:numa_mem.0": "1024", "hw:numa_cpus.1": "4,6", "hw:numa_mem.1": "512", "hw:numa_cpus.2": "5,7", "hw:numa_mem.2": "512", }), "image": { }, "expect": objects.InstanceNUMATopology(cells= [ objects.InstanceNUMACell( id=0, cpuset=set([0, 1, 2, 3]), memory=1024), objects.InstanceNUMACell( id=1, cpuset=set([4, 6]), memory=512), objects.InstanceNUMACell( id=2, cpuset=set([5, 7]), memory=512) ]), }, { # Request a CPU that is out of range # wrt vCPU count "flavor": objects.Flavor(vcpus=8, memory_mb=2048, extra_specs={ "hw:numa_nodes": 1, "hw:numa_cpus.0": "0-16", "hw:numa_mem.0": "2048", }), "image": { }, "expect": exception.ImageNUMATopologyCPUOutOfRange, }, { # Request the same CPU in two nodes "flavor": objects.Flavor(vcpus=8, memory_mb=2048, extra_specs={ "hw:numa_nodes": 2, "hw:numa_cpus.0": "0-7", "hw:numa_mem.0": "1024", "hw:numa_cpus.1": "0-7", "hw:numa_mem.1": "1024", }), "image": { }, "expect": exception.ImageNUMATopologyCPUDuplicates, }, { # Request with some CPUs not assigned "flavor": objects.Flavor(vcpus=8, memory_mb=2048, extra_specs={ "hw:numa_nodes": 2, "hw:numa_cpus.0": "0-2", "hw:numa_mem.0": "1024", "hw:numa_cpus.1": "3-4", "hw:numa_mem.1": "1024", }), "image": { }, "expect": exception.ImageNUMATopologyCPUsUnassigned, }, { # Request too little memory vs flavor total "flavor": objects.Flavor(vcpus=8, memory_mb=2048, extra_specs={ "hw:numa_nodes": 2, "hw:numa_cpus.0": "0-3", "hw:numa_mem.0": "512", "hw:numa_cpus.1": "4-7", "hw:numa_mem.1": "512", }), "image": { }, "expect": exception.ImageNUMATopologyMemoryOutOfRange, }, { # Request too much memory vs flavor total "flavor": objects.Flavor(vcpus=8, memory_mb=2048, extra_specs={ "hw:numa_nodes": 2, "hw:numa_cpus.0": "0-3", "hw:numa_mem.0": "1576", "hw:numa_cpus.1": "4-7", "hw:numa_mem.1": "1576", }), "image": { }, "expect": exception.ImageNUMATopologyMemoryOutOfRange, }, { # Request missing mem.0 "flavor": objects.Flavor(vcpus=8, memory_mb=2048, extra_specs={ "hw:numa_nodes": 2, "hw:numa_cpus.0": "0-3", "hw:numa_mem.1": "1576", }), "image": { }, "expect": exception.ImageNUMATopologyIncomplete, }, { # Request missing cpu.0 "flavor": objects.Flavor(vcpus=8, memory_mb=2048, extra_specs={ "hw:numa_nodes": 2, "hw:numa_mem.0": "1576", "hw:numa_cpus.1": "4-7", }), "image": { }, "expect": exception.ImageNUMATopologyIncomplete, }, { # Image attempts to override flavor "flavor": objects.Flavor(vcpus=8, memory_mb=2048, extra_specs={ "hw:numa_nodes": 2, }), "image": { "properties": { "hw_numa_nodes": 4} }, "expect": exception.ImageNUMATopologyForbidden, }, { # NUMA + CPU pinning requested in the flavor "flavor": objects.Flavor(vcpus=4, memory_mb=2048, extra_specs={ "hw:numa_nodes": 2, "hw:cpu_policy": "dedicated" }), "image": { }, "expect": objects.InstanceNUMATopology(cells= [ objects.InstanceNUMACell( id=0, cpuset=set([0, 1]), memory=1024, cpu_pinning={}), objects.InstanceNUMACell( id=1, cpuset=set([2, 3]), memory=1024, cpu_pinning={})]) }, { # no NUMA + CPU pinning requested in the flavor "flavor": objects.Flavor(vcpus=4, memory_mb=2048, extra_specs={ "hw:cpu_policy": "dedicated" }), "image": { }, "expect": objects.InstanceNUMATopology(cells= [ objects.InstanceNUMACell( id=0, cpuset=set([0, 1, 2, 3]), memory=2048, cpu_pinning={})]) }, { # NUMA + CPU pinning requested in the image "flavor": objects.Flavor(vcpus=4, memory_mb=2048, extra_specs={ "hw:numa_nodes": 2 }), "image": { "properties": { "hw_cpu_policy": "dedicated"} }, "expect": objects.InstanceNUMATopology(cells= [ objects.InstanceNUMACell( id=0, cpuset=set([0, 1]), memory=1024, cpu_pinning={}), objects.InstanceNUMACell( id=1, cpuset=set([2, 3]), memory=1024, cpu_pinning={})]) }, { # no NUMA + CPU pinning requested in the image "flavor": objects.Flavor(vcpus=4, memory_mb=2048, extra_specs={}), "image": { "properties": { "hw_cpu_policy": "dedicated"} }, "expect": objects.InstanceNUMATopology(cells= [ objects.InstanceNUMACell( id=0, cpuset=set([0, 1, 2, 3]), memory=2048, cpu_pinning={})]) }, { # Invalid CPU pinning override "flavor": objects.Flavor(vcpus=4, memory_mb=2048, extra_specs={ "hw:numa_nodes": 2, "hw:cpu_policy": "shared" }), "image": { "properties": { "hw_cpu_policy": "dedicated"} }, "expect": exception.ImageCPUPinningForbidden, }, ] for testitem in testdata: if testitem["expect"] is None: topology = hw.numa_get_constraints( testitem["flavor"], testitem["image"]) self.assertIsNone(topology) elif type(testitem["expect"]) == type: self.assertRaises(testitem["expect"], hw.numa_get_constraints, testitem["flavor"], testitem["image"]) else: topology = hw.numa_get_constraints( testitem["flavor"], testitem["image"]) self.assertEqual(len(testitem["expect"].cells), len(topology.cells)) for i in range(len(topology.cells)): self.assertEqual(testitem["expect"].cells[i].id, topology.cells[i].id) self.assertEqual(testitem["expect"].cells[i].cpuset, topology.cells[i].cpuset) self.assertEqual(testitem["expect"].cells[i].memory, topology.cells[i].memory) self.assertEqual(testitem["expect"].cells[i].pagesize, topology.cells[i].pagesize) self.assertEqual(testitem["expect"].cells[i].cpu_pinning, topology.cells[i].cpu_pinning) def test_host_usage_contiguous(self): hpages0_4K = objects.NUMAPagesTopology(size_kb=4, total=256, used=0) hpages0_2M = objects.NUMAPagesTopology(size_kb=2048, total=0, used=1) hpages1_4K = objects.NUMAPagesTopology(size_kb=4, total=128, used=2) hpages1_2M = objects.NUMAPagesTopology(size_kb=2048, total=0, used=3) hosttopo = objects.NUMATopology(cells=[ objects.NUMACell(id=0, cpuset=set([0, 1, 2, 3]), memory=1024, cpu_usage=0, memory_usage=0, mempages=[ hpages0_4K, hpages0_2M], siblings=[], pinned_cpus=set([])), objects.NUMACell(id=1, cpuset=set([4, 6]), memory=512, cpu_usage=0, memory_usage=0, mempages=[ hpages1_4K, hpages1_2M], siblings=[], pinned_cpus=set([])), objects.NUMACell(id=2, cpuset=set([5, 7]), memory=512, cpu_usage=0, memory_usage=0, mempages=[], siblings=[], pinned_cpus=set([])), ]) instance1 = objects.InstanceNUMATopology(cells=[ objects.InstanceNUMACell(id=0, cpuset=set([0, 1, 2]), memory=256), objects.InstanceNUMACell(id=1, cpuset=set([4]), memory=256), ]) instance2 = objects.InstanceNUMATopology(cells=[ objects.InstanceNUMACell(id=0, cpuset=set([0, 1]), memory=256), objects.InstanceNUMACell(id=1, cpuset=set([5, 7]), memory=256), ]) hostusage = hw.numa_usage_from_instances( hosttopo, [instance1, instance2]) self.assertEqual(len(hosttopo), len(hostusage)) self.assertIsInstance(hostusage.cells[0], objects.NUMACell) self.assertEqual(hosttopo.cells[0].cpuset, hostusage.cells[0].cpuset) self.assertEqual(hosttopo.cells[0].memory, hostusage.cells[0].memory) self.assertEqual(hostusage.cells[0].cpu_usage, 5) self.assertEqual(hostusage.cells[0].memory_usage, 512) self.assertEqual(hostusage.cells[0].mempages, [ hpages0_4K, hpages0_2M]) self.assertIsInstance(hostusage.cells[1], objects.NUMACell) self.assertEqual(hosttopo.cells[1].cpuset, hostusage.cells[1].cpuset) self.assertEqual(hosttopo.cells[1].memory, hostusage.cells[1].memory) self.assertEqual(hostusage.cells[1].cpu_usage, 3) self.assertEqual(hostusage.cells[1].memory_usage, 512) self.assertEqual(hostusage.cells[1].mempages, [ hpages1_4K, hpages1_2M]) self.assertEqual(256, hpages0_4K.total) self.assertEqual(0, hpages0_4K.used) self.assertEqual(0, hpages0_2M.total) self.assertEqual(1, hpages0_2M.used) self.assertIsInstance(hostusage.cells[2], objects.NUMACell) self.assertEqual(hosttopo.cells[2].cpuset, hostusage.cells[2].cpuset) self.assertEqual(hosttopo.cells[2].memory, hostusage.cells[2].memory) self.assertEqual(hostusage.cells[2].cpu_usage, 0) self.assertEqual(hostusage.cells[2].memory_usage, 0) self.assertEqual(128, hpages1_4K.total) self.assertEqual(2, hpages1_4K.used) self.assertEqual(0, hpages1_2M.total) self.assertEqual(3, hpages1_2M.used) def test_host_usage_sparse(self): hosttopo = objects.NUMATopology(cells=[ objects.NUMACell(id=0, cpuset=set([0, 1, 2, 3]), memory=1024, cpu_usage=0, memory_usage=0, mempages=[], siblings=[], pinned_cpus=set([])), objects.NUMACell(id=5, cpuset=set([4, 6]), memory=512, cpu_usage=0, memory_usage=0, mempages=[], siblings=[], pinned_cpus=set([])), objects.NUMACell(id=6, cpuset=set([5, 7]), memory=512, cpu_usage=0, memory_usage=0, mempages=[], siblings=[], pinned_cpus=set([])), ]) instance1 = objects.InstanceNUMATopology(cells=[ objects.InstanceNUMACell(id=0, cpuset=set([0, 1, 2]), memory=256), objects.InstanceNUMACell(id=6, cpuset=set([4]), memory=256), ]) instance2 = objects.InstanceNUMATopology(cells=[ objects.InstanceNUMACell(id=0, cpuset=set([0, 1]), memory=256, cpu_usage=0, memory_usage=0, mempages=[]), objects.InstanceNUMACell(id=5, cpuset=set([5, 7]), memory=256, cpu_usage=0, memory_usage=0, mempages=[]), ]) hostusage = hw.numa_usage_from_instances( hosttopo, [instance1, instance2]) self.assertEqual(len(hosttopo), len(hostusage)) self.assertIsInstance(hostusage.cells[0], objects.NUMACell) self.assertEqual(hosttopo.cells[0].id, hostusage.cells[0].id) self.assertEqual(hosttopo.cells[0].cpuset, hostusage.cells[0].cpuset) self.assertEqual(hosttopo.cells[0].memory, hostusage.cells[0].memory) self.assertEqual(hostusage.cells[0].cpu_usage, 5) self.assertEqual(hostusage.cells[0].memory_usage, 512) self.assertIsInstance(hostusage.cells[1], objects.NUMACell) self.assertEqual(hosttopo.cells[1].id, hostusage.cells[1].id) self.assertEqual(hosttopo.cells[1].cpuset, hostusage.cells[1].cpuset) self.assertEqual(hosttopo.cells[1].memory, hostusage.cells[1].memory) self.assertEqual(hostusage.cells[1].cpu_usage, 2) self.assertEqual(hostusage.cells[1].memory_usage, 256) self.assertIsInstance(hostusage.cells[2], objects.NUMACell) self.assertEqual(hosttopo.cells[2].cpuset, hostusage.cells[2].cpuset) self.assertEqual(hosttopo.cells[2].memory, hostusage.cells[2].memory) self.assertEqual(hostusage.cells[2].cpu_usage, 1) self.assertEqual(hostusage.cells[2].memory_usage, 256) def test_host_usage_culmulative_with_free(self): hosttopo = objects.NUMATopology(cells=[ objects.NUMACell(id=0, cpuset=set([0, 1, 2, 3]), memory=1024, cpu_usage=2, memory_usage=512, mempages=[], siblings=[], pinned_cpus=set([])), objects.NUMACell(id=1, cpuset=set([4, 6]), memory=512, cpu_usage=1, memory_usage=512, mempages=[], siblings=[], pinned_cpus=set([])), objects.NUMACell(id=2, cpuset=set([5, 7]), memory=256, cpu_usage=0, memory_usage=0, mempages=[], siblings=[], pinned_cpus=set([])), ]) instance1 = objects.InstanceNUMATopology(cells=[ objects.InstanceNUMACell(id=0, cpuset=set([0, 1, 2]), memory=512), objects.InstanceNUMACell(id=1, cpuset=set([3]), memory=256), objects.InstanceNUMACell(id=2, cpuset=set([4]), memory=256)]) hostusage = hw.numa_usage_from_instances( hosttopo, [instance1]) self.assertIsInstance(hostusage.cells[0], objects.NUMACell) self.assertEqual(hostusage.cells[0].cpu_usage, 5) self.assertEqual(hostusage.cells[0].memory_usage, 1024) self.assertIsInstance(hostusage.cells[1], objects.NUMACell) self.assertEqual(hostusage.cells[1].cpu_usage, 2) self.assertEqual(hostusage.cells[1].memory_usage, 768) self.assertIsInstance(hostusage.cells[2], objects.NUMACell) self.assertEqual(hostusage.cells[2].cpu_usage, 1) self.assertEqual(hostusage.cells[2].memory_usage, 256) # Test freeing of resources hostusage = hw.numa_usage_from_instances( hostusage, [instance1], free=True) self.assertEqual(hostusage.cells[0].cpu_usage, 2) self.assertEqual(hostusage.cells[0].memory_usage, 512) self.assertEqual(hostusage.cells[1].cpu_usage, 1) self.assertEqual(hostusage.cells[1].memory_usage, 512) self.assertEqual(hostusage.cells[2].cpu_usage, 0) self.assertEqual(hostusage.cells[2].memory_usage, 0) def test_topo_usage_none(self): hosttopo = objects.NUMATopology(cells=[ objects.NUMACell(id=0, cpuset=set([0, 1]), memory=512, cpu_usage=0, memory_usage=0, mempages=[], siblings=[], pinned_cpus=set([])), objects.NUMACell(id=1, cpuset=set([2, 3]), memory=512, cpu_usage=0, memory_usage=0, mempages=[], siblings=[], pinned_cpus=set([])), ]) instance1 = objects.InstanceNUMATopology(cells=[ objects.InstanceNUMACell(id=0, cpuset=set([0, 1]), memory=256), objects.InstanceNUMACell(id=2, cpuset=set([2]), memory=256), ]) hostusage = hw.numa_usage_from_instances( None, [instance1]) self.assertIsNone(hostusage) hostusage = hw.numa_usage_from_instances( hosttopo, []) self.assertEqual(hostusage.cells[0].cpu_usage, 0) self.assertEqual(hostusage.cells[0].memory_usage, 0) self.assertEqual(hostusage.cells[1].cpu_usage, 0) self.assertEqual(hostusage.cells[1].memory_usage, 0) hostusage = hw.numa_usage_from_instances( hosttopo, None) self.assertEqual(hostusage.cells[0].cpu_usage, 0) self.assertEqual(hostusage.cells[0].memory_usage, 0) self.assertEqual(hostusage.cells[1].cpu_usage, 0) self.assertEqual(hostusage.cells[1].memory_usage, 0) def assertNUMACellMatches(self, expected_cell, got_cell): attrs = ('cpuset', 'memory', 'id') if isinstance(expected_cell, objects.NUMATopology): attrs += ('cpu_usage', 'memory_usage') for attr in attrs: self.assertEqual(getattr(expected_cell, attr), getattr(got_cell, attr)) def test_json(self): expected = objects.NUMATopology( cells=[ objects.NUMACell(id=1, cpuset=set([1, 2]), memory=1024, cpu_usage=0, memory_usage=0, mempages=[], siblings=[], pinned_cpus=set([])), objects.NUMACell(id=2, cpuset=set([3, 4]), memory=1024, cpu_usage=0, memory_usage=0, mempages=[], siblings=[], pinned_cpus=set([]))]) got = objects.NUMATopology.obj_from_db_obj(expected._to_json()) for exp_cell, got_cell in zip(expected.cells, got.cells): self.assertNUMACellMatches(exp_cell, got_cell) class VirtNUMATopologyCellUsageTestCase(test.NoDBTestCase): def test_fit_instance_cell_success_no_limit(self): host_cell = objects.NUMACell(id=4, cpuset=set([1, 2]), memory=1024, cpu_usage=0, memory_usage=0, mempages=[], siblings=[], pinned_cpus=set([])) instance_cell = objects.InstanceNUMACell( id=0, cpuset=set([1, 2]), memory=1024) fitted_cell = hw._numa_fit_instance_cell(host_cell, instance_cell) self.assertIsInstance(fitted_cell, objects.InstanceNUMACell) self.assertEqual(host_cell.id, fitted_cell.id) def test_fit_instance_cell_success_w_limit(self): host_cell = objects.NUMACell(id=4, cpuset=set([1, 2]), memory=1024, cpu_usage=2, memory_usage=1024, mempages=[], siblings=[], pinned_cpus=set([])) limit_cell = objects.NUMATopologyLimits( cpu_allocation_ratio=2, ram_allocation_ratio=2) instance_cell = objects.InstanceNUMACell( id=0, cpuset=set([1, 2]), memory=1024) fitted_cell = hw._numa_fit_instance_cell( host_cell, instance_cell, limit_cell=limit_cell) self.assertIsInstance(fitted_cell, objects.InstanceNUMACell) self.assertEqual(host_cell.id, fitted_cell.id) def test_fit_instance_cell_self_overcommit(self): host_cell = objects.NUMACell(id=4, cpuset=set([1, 2]), memory=1024, cpu_usage=0, memory_usage=0, mempages=[], siblings=[], pinned_cpus=set([])) limit_cell = objects.NUMATopologyLimits( cpu_allocation_ratio=2, ram_allocation_ratio=2) instance_cell = objects.InstanceNUMACell( id=0, cpuset=set([1, 2, 3]), memory=4096) fitted_cell = hw._numa_fit_instance_cell( host_cell, instance_cell, limit_cell=limit_cell) self.assertIsNone(fitted_cell) def test_fit_instance_cell_fail_w_limit(self): host_cell = objects.NUMACell(id=4, cpuset=set([1, 2]), memory=1024, cpu_usage=2, memory_usage=1024, mempages=[], siblings=[], pinned_cpus=set([])) instance_cell = objects.InstanceNUMACell( id=0, cpuset=set([1, 2]), memory=4096) limit_cell = objects.NUMATopologyLimits( cpu_allocation_ratio=2, ram_allocation_ratio=2) fitted_cell = hw._numa_fit_instance_cell( host_cell, instance_cell, limit_cell=limit_cell) self.assertIsNone(fitted_cell) instance_cell = objects.InstanceNUMACell( id=0, cpuset=set([1, 2, 3, 4, 5]), memory=1024) fitted_cell = hw._numa_fit_instance_cell( host_cell, instance_cell, limit_cell=limit_cell) self.assertIsNone(fitted_cell) class VirtNUMAHostTopologyTestCase(test.NoDBTestCase): def setUp(self): super(VirtNUMAHostTopologyTestCase, self).setUp() self.host = objects.NUMATopology( cells=[ objects.NUMACell(id=1, cpuset=set([1, 2]), memory=2048, cpu_usage=2, memory_usage=2048, mempages=[], siblings=[], pinned_cpus=set([])), objects.NUMACell(id=2, cpuset=set([3, 4]), memory=2048, cpu_usage=2, memory_usage=2048, mempages=[], siblings=[], pinned_cpus=set([]))]) self.limits = objects.NUMATopologyLimits( cpu_allocation_ratio=2, ram_allocation_ratio=2) self.instance1 = objects.InstanceNUMATopology( cells=[ objects.InstanceNUMACell( id=0, cpuset=set([1, 2]), memory=2048)]) self.instance2 = objects.InstanceNUMATopology( cells=[ objects.InstanceNUMACell( id=0, cpuset=set([1, 2, 3, 4]), memory=1024)]) self.instance3 = objects.InstanceNUMATopology( cells=[ objects.InstanceNUMACell( id=0, cpuset=set([1, 2]), memory=1024)]) def test_get_fitting_success_no_limits(self): fitted_instance1 = hw.numa_fit_instance_to_host( self.host, self.instance1) self.assertIsInstance(fitted_instance1, objects.InstanceNUMATopology) self.host = hw.numa_usage_from_instances(self.host, [fitted_instance1]) fitted_instance2 = hw.numa_fit_instance_to_host( self.host, self.instance3) self.assertIsInstance(fitted_instance2, objects.InstanceNUMATopology) def test_get_fitting_success_limits(self): fitted_instance = hw.numa_fit_instance_to_host( self.host, self.instance3, self.limits) self.assertIsInstance(fitted_instance, objects.InstanceNUMATopology) self.assertEqual(1, fitted_instance.cells[0].id) def test_get_fitting_fails_no_limits(self): fitted_instance = hw.numa_fit_instance_to_host( self.host, self.instance2, self.limits) self.assertIsNone(fitted_instance) def test_get_fitting_culmulative_fails_limits(self): fitted_instance1 = hw.numa_fit_instance_to_host( self.host, self.instance1, self.limits) self.assertIsInstance(fitted_instance1, objects.InstanceNUMATopology) self.assertEqual(1, fitted_instance1.cells[0].id) self.host = hw.numa_usage_from_instances(self.host, [fitted_instance1]) fitted_instance2 = hw.numa_fit_instance_to_host( self.host, self.instance2, self.limits) self.assertIsNone(fitted_instance2) def test_get_fitting_culmulative_success_limits(self): fitted_instance1 = hw.numa_fit_instance_to_host( self.host, self.instance1, self.limits) self.assertIsInstance(fitted_instance1, objects.InstanceNUMATopology) self.assertEqual(1, fitted_instance1.cells[0].id) self.host = hw.numa_usage_from_instances(self.host, [fitted_instance1]) fitted_instance2 = hw.numa_fit_instance_to_host( self.host, self.instance3, self.limits) self.assertIsInstance(fitted_instance2, objects.InstanceNUMATopology) self.assertEqual(2, fitted_instance2.cells[0].id) def test_get_fitting_pci_success(self): pci_request = objects.InstancePCIRequest(count=1, spec=[{'vendor_id': '8086'}]) pci_reqs = [pci_request] pci_stats = stats.PciDeviceStats() with mock.patch.object(stats.PciDeviceStats, 'support_requests', return_value= True): fitted_instance1 = hw.numa_fit_instance_to_host(self.host, self.instance1, pci_requests=pci_reqs, pci_stats=pci_stats) self.assertIsInstance(fitted_instance1, objects.InstanceNUMATopology) def test_get_fitting_pci_fail(self): pci_request = objects.InstancePCIRequest(count=1, spec=[{'vendor_id': '8086'}]) pci_reqs = [pci_request] pci_stats = stats.PciDeviceStats() with mock.patch.object(stats.PciDeviceStats, 'support_requests', return_value= False): fitted_instance1 = hw.numa_fit_instance_to_host( self.host, self.instance1, pci_requests=pci_reqs, pci_stats=pci_stats) self.assertIsNone(fitted_instance1) class NumberOfSerialPortsTest(test.NoDBTestCase): def test_flavor(self): flavor = objects.Flavor(vcpus=8, memory_mb=2048, extra_specs={"hw:serial_port_count": 3}) num_ports = hw.get_number_of_serial_ports(flavor, None) self.assertEqual(3, num_ports) def test_image_meta(self): flavor = objects.Flavor(vcpus=8, memory_mb=2048, extra_specs={}) image_meta = {"properties": {"hw_serial_port_count": 2}} num_ports = hw.get_number_of_serial_ports(flavor, image_meta) self.assertEqual(2, num_ports) def test_flavor_invalid_value(self): flavor = objects.Flavor(vcpus=8, memory_mb=2048, extra_specs={"hw:serial_port_count": 'foo'}) image_meta = {"properties": {}} self.assertRaises(exception.ImageSerialPortNumberInvalid, hw.get_number_of_serial_ports, flavor, image_meta) def test_image_meta_invalid_value(self): flavor = objects.Flavor(vcpus=8, memory_mb=2048, extra_specs={}) image_meta = {"properties": {"hw_serial_port_count": 'bar'}} self.assertRaises(exception.ImageSerialPortNumberInvalid, hw.get_number_of_serial_ports, flavor, image_meta) def test_image_meta_smaller_than_flavor(self): flavor = objects.Flavor(vcpus=8, memory_mb=2048, extra_specs={"hw:serial_port_count": 3}) image_meta = {"properties": {"hw_serial_port_count": 2}} num_ports = hw.get_number_of_serial_ports(flavor, image_meta) self.assertEqual(2, num_ports) def test_flavor_smaller_than_image_meta(self): flavor = objects.Flavor(vcpus=8, memory_mb=2048, extra_specs={"hw:serial_port_count": 3}) image_meta = {"properties": {"hw_serial_port_count": 4}} self.assertRaises(exception.ImageSerialPortNumberExceedFlavorValue, hw.get_number_of_serial_ports, flavor, image_meta) class HelperMethodsTestCase(test.NoDBTestCase): def setUp(self): super(HelperMethodsTestCase, self).setUp() self.hosttopo = objects.NUMATopology(cells=[ objects.NUMACell(id=0, cpuset=set([0, 1]), memory=512, memory_usage=0, cpu_usage=0, mempages=[], siblings=[], pinned_cpus=set([])), objects.NUMACell(id=1, cpuset=set([2, 3]), memory=512, memory_usage=0, cpu_usage=0, mempages=[], siblings=[], pinned_cpus=set([])), ]) self.instancetopo = objects.InstanceNUMATopology( instance_uuid='fake-uuid', cells=[ objects.InstanceNUMACell( id=0, cpuset=set([0, 1]), memory=256, pagesize=2048, cpu_pinning={1: 3, 0: 4}), objects.InstanceNUMACell( id=1, cpuset=set([2]), memory=256, pagesize=2048, cpu_pinning={2: 5}), ]) self.context = context.RequestContext('fake-user', 'fake-project') def _check_usage(self, host_usage): self.assertEqual(2, host_usage.cells[0].cpu_usage) self.assertEqual(256, host_usage.cells[0].memory_usage) self.assertEqual(1, host_usage.cells[1].cpu_usage) self.assertEqual(256, host_usage.cells[1].memory_usage) def test_dicts_json(self): host = {'numa_topology': self.hosttopo._to_json()} instance = {'numa_topology': self.instancetopo._to_json()} res = hw.get_host_numa_usage_from_instance(host, instance) self.assertIsInstance(res, six.string_types) self._check_usage(objects.NUMATopology.obj_from_db_obj(res)) def test_dicts_instance_json(self): host = {'numa_topology': self.hosttopo} instance = {'numa_topology': self.instancetopo._to_json()} res = hw.get_host_numa_usage_from_instance(host, instance) self.assertIsInstance(res, objects.NUMATopology) self._check_usage(res) def test_dicts_instance_json_old(self): host = {'numa_topology': self.hosttopo} instance = {'numa_topology': jsonutils.dumps(self.instancetopo._to_dict())} res = hw.get_host_numa_usage_from_instance(host, instance) self.assertIsInstance(res, objects.NUMATopology) self._check_usage(res) def test_dicts_host_json(self): host = {'numa_topology': self.hosttopo._to_json()} instance = {'numa_topology': self.instancetopo} res = hw.get_host_numa_usage_from_instance(host, instance) self.assertIsInstance(res, six.string_types) self._check_usage(objects.NUMATopology.obj_from_db_obj(res)) def test_dicts_host_json_old(self): host = {'numa_topology': jsonutils.dumps( self.hosttopo._to_dict())} instance = {'numa_topology': self.instancetopo} res = hw.get_host_numa_usage_from_instance(host, instance) self.assertIsInstance(res, six.string_types) self._check_usage(objects.NUMATopology.obj_from_db_obj(res)) def test_object_host_instance_json(self): host = objects.ComputeNode(numa_topology=self.hosttopo._to_json()) instance = {'numa_topology': self.instancetopo._to_json()} res = hw.get_host_numa_usage_from_instance(host, instance) self.assertIsInstance(res, six.string_types) self._check_usage(objects.NUMATopology.obj_from_db_obj(res)) def test_object_host_instance(self): host = objects.ComputeNode(numa_topology=self.hosttopo._to_json()) instance = {'numa_topology': self.instancetopo} res = hw.get_host_numa_usage_from_instance(host, instance) self.assertIsInstance(res, six.string_types) self._check_usage(objects.NUMATopology.obj_from_db_obj(res)) def test_instance_with_fetch(self): host = objects.ComputeNode(numa_topology=self.hosttopo._to_json()) fake_uuid = str(uuid.uuid4()) instance = {'uuid': fake_uuid} with mock.patch.object(objects.InstanceNUMATopology, 'get_by_instance_uuid', return_value=None) as get_mock: res = hw.get_host_numa_usage_from_instance(host, instance) self.assertIsInstance(res, six.string_types) self.assertTrue(get_mock.called) def test_object_instance_with_load(self): host = objects.ComputeNode(numa_topology=self.hosttopo._to_json()) fake_uuid = str(uuid.uuid4()) instance = objects.Instance(context=self.context, uuid=fake_uuid) with mock.patch.object(objects.InstanceNUMATopology, 'get_by_instance_uuid', return_value=None) as get_mock: res = hw.get_host_numa_usage_from_instance(host, instance) self.assertIsInstance(res, six.string_types) self.assertTrue(get_mock.called) def test_instance_serialized_by_build_request_spec(self): host = objects.ComputeNode(numa_topology=self.hosttopo._to_json()) fake_uuid = str(uuid.uuid4()) instance = objects.Instance(context=self.context, id=1, uuid=fake_uuid, numa_topology=self.instancetopo) # NOTE (ndipanov): This emulates scheduler.utils.build_request_spec # We can remove this test once we no longer use that method. instance_raw = jsonutils.to_primitive( base_obj.obj_to_primitive(instance)) res = hw.get_host_numa_usage_from_instance(host, instance_raw) self.assertIsInstance(res, six.string_types) self._check_usage(objects.NUMATopology.obj_from_db_obj(res)) def test_attr_host(self): class Host(object): def __init__(obj): obj.numa_topology = self.hosttopo._to_json() host = Host() instance = {'numa_topology': self.instancetopo._to_json()} res = hw.get_host_numa_usage_from_instance(host, instance) self.assertIsInstance(res, six.string_types) self._check_usage(objects.NUMATopology.obj_from_db_obj(res)) def test_never_serialize_result(self): host = {'numa_topology': self.hosttopo._to_json()} instance = {'numa_topology': self.instancetopo} res = hw.get_host_numa_usage_from_instance(host, instance, never_serialize_result=True) self.assertIsInstance(res, objects.NUMATopology) self._check_usage(res) def test_dict_numa_topology_to_obj(self): fake_uuid = str(uuid.uuid4()) instance = objects.Instance(context=self.context, id=1, uuid=fake_uuid, numa_topology=self.instancetopo) instance_dict = base_obj.obj_to_primitive(instance) instance_numa_topo = hw.instance_topology_from_instance(instance_dict) for expected_cell, actual_cell in zip(self.instancetopo.cells, instance_numa_topo.cells): for k in expected_cell.fields: self.assertEqual(getattr(expected_cell, k), getattr(actual_cell, k)) class VirtMemoryPagesTestCase(test.NoDBTestCase): def test_cell_instance_pagesize(self): cell = objects.InstanceNUMACell( id=0, cpuset=set([0]), memory=1024, pagesize=2048) self.assertEqual(0, cell.id) self.assertEqual(set([0]), cell.cpuset) self.assertEqual(1024, cell.memory) self.assertEqual(2048, cell.pagesize) def test_numa_pagesize_usage_from_cell(self): instcell = objects.InstanceNUMACell( id=0, cpuset=set([0]), memory=512, pagesize=2048) hostcell = objects.NUMACell( id=0, cpuset=set([0]), memory=1024, cpu_usage=0, memory_usage=0, mempages=[objects.NUMAPagesTopology( size_kb=2048, total=512, used=0)], siblings=[], pinned_cpus=set([])) topo = hw._numa_pagesize_usage_from_cell(hostcell, instcell, 1) self.assertEqual(2048, topo[0].size_kb) self.assertEqual(512, topo[0].total) self.assertEqual(256, topo[0].used) def _test_get_requested_mempages_pagesize(self, spec=None, props=None): flavor = objects.Flavor(vcpus=16, memory_mb=2048, extra_specs=spec or {}) image_meta = {"properties": props or {}} return hw._numa_get_pagesize_constraints(flavor, image_meta) def test_get_requested_mempages_pagesize_from_flavor_swipe(self): self.assertEqual( hw.MEMPAGES_SMALL, self._test_get_requested_mempages_pagesize( spec={"hw:mem_page_size": "small"})) self.assertEqual( hw.MEMPAGES_LARGE, self._test_get_requested_mempages_pagesize( spec={"hw:mem_page_size": "large"})) self.assertEqual( hw.MEMPAGES_ANY, self._test_get_requested_mempages_pagesize( spec={"hw:mem_page_size": "any"})) def test_get_requested_mempages_pagesize_from_flavor_specific(self): self.assertEqual( 2048, self._test_get_requested_mempages_pagesize( spec={"hw:mem_page_size": "2048"})) def test_get_requested_mempages_pagesize_from_flavor_invalid(self): self.assertRaises( exception.MemoryPageSizeInvalid, self._test_get_requested_mempages_pagesize, {"hw:mem_page_size": "foo"}) def test_get_requested_mempages_pagesize_from_image_flavor_any(self): self.assertEqual( 2048, self._test_get_requested_mempages_pagesize( spec={"hw:mem_page_size": "any"}, props={"hw_mem_page_size": "2048"})) def test_get_requested_mempages_pagesize_from_image_flavor_large(self): self.assertEqual( 2048, self._test_get_requested_mempages_pagesize( spec={"hw:mem_page_size": "large"}, props={"hw_mem_page_size": "2048"})) def test_get_requested_mempages_pagesize_from_image_forbidden(self): self.assertRaises( exception.MemoryPageSizeForbidden, self._test_get_requested_mempages_pagesize, {"hw:mem_page_size": "small"}, {"hw_mem_page_size": "2048"}) def test_get_requested_mempages_pagesize_from_image_forbidden2(self): self.assertRaises( exception.MemoryPageSizeForbidden, self._test_get_requested_mempages_pagesize, {}, {"hw_mem_page_size": "2048"}) def test_cell_accepts_request_wipe(self): host_cell = objects.NUMACell( id=0, cpuset=set([0]), memory=1024, mempages=[ objects.NUMAPagesTopology(size_kb=4, total=262144, used=0), ], siblings=[], pinned_cpus=set([])) inst_cell = objects.InstanceNUMACell( id=0, cpuset=set([0]), memory=1024, pagesize=hw.MEMPAGES_SMALL) self.assertEqual( 4, hw._numa_cell_supports_pagesize_request(host_cell, inst_cell)) inst_cell = objects.InstanceNUMACell( id=0, cpuset=set([0]), memory=1024, pagesize=hw.MEMPAGES_ANY) self.assertEqual( 4, hw._numa_cell_supports_pagesize_request(host_cell, inst_cell)) inst_cell = objects.InstanceNUMACell( id=0, cpuset=set([0]), memory=1024, pagesize=hw.MEMPAGES_LARGE) self.assertIsNone(hw._numa_cell_supports_pagesize_request( host_cell, inst_cell)) def test_cell_accepts_request_large_pass(self): inst_cell = objects.InstanceNUMACell( id=0, cpuset=set([0]), memory=1024, pagesize=hw.MEMPAGES_LARGE) host_cell = objects.NUMACell( id=0, cpuset=set([0]), memory=1024, mempages=[ objects.NUMAPagesTopology(size_kb=4, total=256, used=0), objects.NUMAPagesTopology(size_kb=2048, total=512, used=0) ], siblings=[], pinned_cpus=set([])) self.assertEqual( 2048, hw._numa_cell_supports_pagesize_request(host_cell, inst_cell)) def test_cell_accepts_request_custom_pass(self): inst_cell = objects.InstanceNUMACell( id=0, cpuset=set([0]), memory=1024, pagesize=2048) host_cell = objects.NUMACell( id=0, cpuset=set([0]), memory=1024, mempages=[ objects.NUMAPagesTopology(size_kb=4, total=256, used=0), objects.NUMAPagesTopology(size_kb=2048, total=512, used=0) ], siblings=[], pinned_cpus=set([])) self.assertEqual( 2048, hw._numa_cell_supports_pagesize_request(host_cell, inst_cell)) class _CPUPinningTestCaseBase(object): def assertEqualTopology(self, expected, got): for attr in ('sockets', 'cores', 'threads'): self.assertEqual(getattr(expected, attr), getattr(got, attr), "Mismatch on %s" % attr) def assertInstanceCellPinned(self, instance_cell, cell_ids=None): default_cell_id = 0 self.assertIsNotNone(instance_cell) if cell_ids is None: self.assertEqual(default_cell_id, instance_cell.id) else: self.assertIn(instance_cell.id, cell_ids) self.assertEqual(len(instance_cell.cpuset), len(instance_cell.cpu_pinning)) class CPUPinningCellTestCase(test.NoDBTestCase, _CPUPinningTestCaseBase): def test_get_pinning_inst_too_large_cpu(self): host_pin = objects.NUMACell(id=0, cpuset=set([0, 1, 2]), memory=2048, memory_usage=0, siblings=[], mempages=[], pinned_cpus=set([])) inst_pin = objects.InstanceNUMACell(cpuset=set([0, 1, 2, 3]), memory=2048) inst_pin = hw._numa_fit_instance_cell_with_pinning(host_pin, inst_pin) self.assertIsNone(inst_pin) def test_get_pinning_inst_too_large_mem(self): host_pin = objects.NUMACell(id=0, cpuset=set([0, 1, 2]), memory=2048, memory_usage=1024, siblings=[], mempages=[], pinned_cpus=set([])) inst_pin = objects.InstanceNUMACell(cpuset=set([0, 1, 2]), memory=2048) inst_pin = hw._numa_fit_instance_cell_with_pinning(host_pin, inst_pin) self.assertIsNone(inst_pin) def test_get_pinning_inst_not_avail(self): host_pin = objects.NUMACell(id=0, cpuset=set([0, 1, 2, 3]), memory=2048, memory_usage=0, pinned_cpus=set([0]), siblings=[], mempages=[]) inst_pin = objects.InstanceNUMACell(cpuset=set([0, 1, 2, 3]), memory=2048) inst_pin = hw._numa_fit_instance_cell_with_pinning(host_pin, inst_pin) self.assertIsNone(inst_pin) def test_get_pinning_no_sibling_fits_empty(self): host_pin = objects.NUMACell(id=0, cpuset=set([0, 1, 2]), memory=2048, memory_usage=0, siblings=[], mempages=[], pinned_cpus=set([])) inst_pin = objects.InstanceNUMACell(cpuset=set([0, 1, 2]), memory=2048) inst_pin = hw._numa_fit_instance_cell_with_pinning(host_pin, inst_pin) self.assertInstanceCellPinned(inst_pin) def test_get_pinning_no_sibling_fits_w_usage(self): host_pin = objects.NUMACell(id=0, cpuset=set([0, 1, 2, 3]), memory=2048, memory_usage=0, pinned_cpus=set([1]), mempages=[], siblings=[]) inst_pin = objects.InstanceNUMACell(cpuset=set([0, 1, 2]), memory=1024) inst_pin = hw._numa_fit_instance_cell_with_pinning(host_pin, inst_pin) self.assertInstanceCellPinned(inst_pin) def test_get_pinning_instance_siblings_fits(self): host_pin = objects.NUMACell(id=0, cpuset=set([0, 1, 2, 3]), memory=2048, memory_usage=0, siblings=[], mempages=[], pinned_cpus=set([])) topo = objects.VirtCPUTopology(sockets=1, cores=2, threads=2) inst_pin = objects.InstanceNUMACell( cpuset=set([0, 1, 2, 3]), memory=2048, cpu_topology=topo) inst_pin = hw._numa_fit_instance_cell_with_pinning(host_pin, inst_pin) self.assertInstanceCellPinned(inst_pin) self.assertEqualTopology(topo, inst_pin.cpu_topology) def test_get_pinning_instance_siblings_host_siblings_fits_empty(self): host_pin = objects.NUMACell(id=0, cpuset=set([0, 1, 2, 3]), memory=2048, memory_usage=0, siblings=[set([0, 1]), set([2, 3])], mempages=[], pinned_cpus=set([])) topo = objects.VirtCPUTopology(sockets=1, cores=2, threads=2) inst_pin = objects.InstanceNUMACell( cpuset=set([0, 1, 2, 3]), memory=2048, cpu_topology=topo) inst_pin = hw._numa_fit_instance_cell_with_pinning(host_pin, inst_pin) self.assertInstanceCellPinned(inst_pin) self.assertEqualTopology(topo, inst_pin.cpu_topology) def test_get_pinning_instance_siblings_host_siblings_fits_w_usage(self): host_pin = objects.NUMACell( id=0, cpuset=set([0, 1, 2, 3, 4, 5, 6, 7]), memory=4096, memory_usage=0, pinned_cpus=set([1, 2, 5, 6]), siblings=[set([0, 1, 2, 3]), set([4, 5, 6, 7])], mempages=[]) topo = objects.VirtCPUTopology(sockets=1, cores=2, threads=2) inst_pin = objects.InstanceNUMACell( cpuset=set([0, 1, 2, 3]), memory=2048, cpu_topology=topo) inst_pin = hw._numa_fit_instance_cell_with_pinning(host_pin, inst_pin) self.assertInstanceCellPinned(inst_pin) self.assertEqualTopology(topo, inst_pin.cpu_topology) def test_get_pinning_instance_siblings_host_siblings_fails(self): host_pin = objects.NUMACell( id=0, cpuset=set([0, 1, 2, 3, 4, 5, 6, 7]), memory=4096, memory_usage=0, siblings=[set([0, 1]), set([2, 3]), set([4, 5]), set([6, 7])], mempages=[], pinned_cpus=set([])) topo = objects.VirtCPUTopology(sockets=1, cores=2, threads=4) inst_pin = objects.InstanceNUMACell( cpuset=set([0, 1, 2, 3, 4, 5, 6, 7]), memory=2048, cpu_topology=topo) inst_pin = hw._numa_fit_instance_cell_with_pinning(host_pin, inst_pin) self.assertIsNone(inst_pin) def test_get_pinning_host_siblings_fit_single_core(self): host_pin = objects.NUMACell( id=0, cpuset=set([0, 1, 2, 3, 4, 5, 6, 7]), memory=4096, memory_usage=0, siblings=[set([0, 1, 2, 3]), set([4, 5, 6, 7])], mempages=[], pinned_cpus=set([])) inst_pin = objects.InstanceNUMACell(cpuset=set([0, 1, 2, 3]), memory=2048) inst_pin = hw._numa_fit_instance_cell_with_pinning(host_pin, inst_pin) self.assertInstanceCellPinned(inst_pin) got_topo = objects.VirtCPUTopology(sockets=1, cores=1, threads=4) self.assertEqualTopology(got_topo, inst_pin.cpu_topology) def test_get_pinning_host_siblings_fit(self): host_pin = objects.NUMACell(id=0, cpuset=set([0, 1, 2, 3]), memory=4096, memory_usage=0, siblings=[set([0, 1]), set([2, 3])], mempages=[], pinned_cpus=set([])) inst_pin = objects.InstanceNUMACell(cpuset=set([0, 1, 2, 3]), memory=2048) inst_pin = hw._numa_fit_instance_cell_with_pinning(host_pin, inst_pin) self.assertInstanceCellPinned(inst_pin) got_topo = objects.VirtCPUTopology(sockets=1, cores=2, threads=2) self.assertEqualTopology(got_topo, inst_pin.cpu_topology) class CPUPinningTestCase(test.NoDBTestCase, _CPUPinningTestCaseBase): def test_host_numa_fit_instance_to_host_single_cell(self): host_topo = objects.NUMATopology( cells=[objects.NUMACell(id=0, cpuset=set([0, 1]), memory=2048, memory_usage=0, siblings=[], mempages=[], pinned_cpus=set([])), objects.NUMACell(id=1, cpuset=set([2, 3]), memory=2048, memory_usage=0, siblings=[], mempages=[], pinned_cpus=set([]))] ) inst_topo = objects.InstanceNUMATopology( cells=[objects.InstanceNUMACell( cpuset=set([0, 1]), memory=2048, cpu_pinning={})]) inst_topo = hw.numa_fit_instance_to_host(host_topo, inst_topo) for cell in inst_topo.cells: self.assertInstanceCellPinned(cell, cell_ids=(0, 1)) def test_host_numa_fit_instance_to_host_single_cell_w_usage(self): host_topo = objects.NUMATopology( cells=[objects.NUMACell(id=0, cpuset=set([0, 1]), pinned_cpus=set([0]), memory=2048, memory_usage=0, siblings=[], mempages=[]), objects.NUMACell(id=1, cpuset=set([2, 3]), memory=2048, memory_usage=0, siblings=[], mempages=[], pinned_cpus=set([]))]) inst_topo = objects.InstanceNUMATopology( cells=[objects.InstanceNUMACell( cpuset=set([0, 1]), memory=2048, cpu_pinning={})]) inst_topo = hw.numa_fit_instance_to_host(host_topo, inst_topo) for cell in inst_topo.cells: self.assertInstanceCellPinned(cell, cell_ids=(1,)) def test_host_numa_fit_instance_to_host_single_cell_fail(self): host_topo = objects.NUMATopology( cells=[objects.NUMACell(id=0, cpuset=set([0, 1]), memory=2048, pinned_cpus=set([0]), memory_usage=0, siblings=[], mempages=[]), objects.NUMACell(id=1, cpuset=set([2, 3]), memory=2048, pinned_cpus=set([2]), memory_usage=0, siblings=[], mempages=[])]) inst_topo = objects.InstanceNUMATopology( cells=[objects.InstanceNUMACell(cpuset=set([0, 1]), memory=2048, cpu_pinning={})]) inst_topo = hw.numa_fit_instance_to_host(host_topo, inst_topo) self.assertIsNone(inst_topo) def test_host_numa_fit_instance_to_host_fit(self): host_topo = objects.NUMATopology( cells=[objects.NUMACell(id=0, cpuset=set([0, 1, 2, 3]), memory=2048, memory_usage=0, siblings=[], mempages=[], pinned_cpus=set([])), objects.NUMACell(id=1, cpuset=set([4, 5, 6, 7]), memory=2048, memory_usage=0, siblings=[], mempages=[], pinned_cpus=set([]))]) inst_topo = objects.InstanceNUMATopology( cells=[objects.InstanceNUMACell(cpuset=set([0, 1]), memory=2048, cpu_pinning={}), objects.InstanceNUMACell(cpuset=set([2, 3]), memory=2048, cpu_pinning={})]) inst_topo = hw.numa_fit_instance_to_host(host_topo, inst_topo) for cell in inst_topo.cells: self.assertInstanceCellPinned(cell, cell_ids=(0, 1)) def test_host_numa_fit_instance_to_host_barely_fit(self): host_topo = objects.NUMATopology( cells=[objects.NUMACell(id=0, cpuset=set([0, 1, 2, 3]), memory=2048, pinned_cpus=set([0]), siblings=[], mempages=[], memory_usage=0), objects.NUMACell(id=1, cpuset=set([4, 5, 6, 7]), memory=2048, memory_usage=0, siblings=[], mempages=[], pinned_cpus=set([4, 5, 6])), objects.NUMACell(id=2, cpuset=set([8, 9, 10, 11]), memory=2048, memory_usage=0, siblings=[], mempages=[], pinned_cpus=set([10, 11]))]) inst_topo = objects.InstanceNUMATopology( cells=[objects.InstanceNUMACell(cpuset=set([0, 1]), memory=2048, cpu_pinning={}), objects.InstanceNUMACell(cpuset=set([2, 3]), memory=2048, cpu_pinning={})]) inst_topo = hw.numa_fit_instance_to_host(host_topo, inst_topo) for cell in inst_topo.cells: self.assertInstanceCellPinned(cell, cell_ids=(0, 2)) def test_host_numa_fit_instance_to_host_fail_capacity(self): host_topo = objects.NUMATopology( cells=[objects.NUMACell(id=0, cpuset=set([0, 1, 2, 3]), memory=4096, memory_usage=0, mempages=[], siblings=[], pinned_cpus=set([0])), objects.NUMACell(id=1, cpuset=set([4, 5, 6, 7]), memory=4096, memory_usage=0, siblings=[], mempages=[], pinned_cpus=set([4, 5, 6]))]) inst_topo = objects.InstanceNUMATopology( cells=[objects.InstanceNUMACell(cpuset=set([0, 1]), memory=2048, cpu_pinning={}), objects.InstanceNUMACell(cpuset=set([2, 3]), memory=2048, cpu_pinning={})]) inst_topo = hw.numa_fit_instance_to_host(host_topo, inst_topo) self.assertIsNone(inst_topo) def test_host_numa_fit_instance_to_host_fail_topology(self): host_topo = objects.NUMATopology( cells=[objects.NUMACell(id=0, cpuset=set([0, 1, 2, 3]), memory=4096, memory_usage=0, siblings=[], mempages=[], pinned_cpus=set([])), objects.NUMACell(id=1, cpuset=set([4, 5, 6, 7]), memory=4096, memory_usage=0, siblings=[], mempages=[], pinned_cpus=set([]))]) inst_topo = objects.InstanceNUMATopology( cells=[objects.InstanceNUMACell(cpuset=set([0, 1]), memory=1024, cpu_pinning={}), objects.InstanceNUMACell(cpuset=set([2, 3]), memory=1024, cpu_pinning={}), objects.InstanceNUMACell(cpuset=set([4, 5]), memory=1024, cpu_pinning={})]) inst_topo = hw.numa_fit_instance_to_host(host_topo, inst_topo) self.assertIsNone(inst_topo) def test_cpu_pinning_usage_from_instances(self): host_pin = objects.NUMATopology( cells=[objects.NUMACell(id=0, cpuset=set([0, 1, 2, 3]), memory=4096, cpu_usage=0, memory_usage=0, siblings=[], mempages=[], pinned_cpus=set([]))]) inst_pin_1 = objects.InstanceNUMATopology( cells=[objects.InstanceNUMACell( cpuset=set([0, 1]), id=0, cpu_pinning={0: 0, 1: 3}, memory=2048)]) inst_pin_2 = objects.InstanceNUMATopology( cells = [objects.InstanceNUMACell( cpuset=set([0, 1]), id=0, cpu_pinning={0: 1, 1: 2}, memory=2048)]) host_pin = hw.numa_usage_from_instances( host_pin, [inst_pin_1, inst_pin_2]) self.assertEqual(set([0, 1, 2, 3]), host_pin.cells[0].pinned_cpus) def test_cpu_pinning_usage_from_instances_free(self): host_pin = objects.NUMATopology( cells=[objects.NUMACell(id=0, cpuset=set([0, 1, 2, 3]), memory=4096, cpu_usage=0, memory_usage=0, siblings=[], mempages=[], pinned_cpus=set([0, 1, 3]))]) inst_pin_1 = objects.InstanceNUMATopology( cells=[objects.InstanceNUMACell( cpuset=set([0]), memory=1024, cpu_pinning={0: 1}, id=0)]) inst_pin_2 = objects.InstanceNUMATopology( cells=[objects.InstanceNUMACell( cpuset=set([0, 1]), memory=1024, id=0, cpu_pinning={0: 0, 1: 3})]) host_pin = hw.numa_usage_from_instances( host_pin, [inst_pin_1, inst_pin_2], free=True) self.assertEqual(set(), host_pin.cells[0].pinned_cpus) def test_host_usage_from_instances_fail(self): host_pin = objects.NUMATopology( cells=[objects.NUMACell(id=0, cpuset=set([0, 1, 2, 3]), memory=4096, cpu_usage=0, memory_usage=0, siblings=[], mempages=[], pinned_cpus=set([]))]) inst_pin_1 = objects.InstanceNUMATopology( cells=[objects.InstanceNUMACell( cpuset=set([0, 1]), memory=2048, id=0, cpu_pinning={0: 0, 1: 3})]) inst_pin_2 = objects.InstanceNUMATopology( cells = [objects.InstanceNUMACell( cpuset=set([0, 1]), id=0, memory=2048, cpu_pinning={0: 0, 1: 2})]) self.assertRaises(exception.CPUPinningInvalid, hw.numa_usage_from_instances, host_pin, [inst_pin_1, inst_pin_2])