objects: move numa host and cell to objects

To continue objectification of numa, this commit move
numa host/cell related to objects.

Change-Id: I9fbc3ed6d9bd74840e42586faa9951d9672691c1
This commit is contained in:
Sahid Orentino Ferdjaoui 2014-11-24 12:04:19 -05:00
parent e18809359b
commit 57f6db96d5
14 changed files with 291 additions and 320 deletions

View File

@ -204,10 +204,10 @@ class Claim(NopClaim):
host_topology = resources.get('numa_topology')
requested_topology = self.numa_topology
if host_topology:
host_topology = hardware.VirtNUMAHostTopology.from_json(
host_topology = objects.NUMATopology.obj_from_db_obj(
host_topology)
instance_topology = (
hardware.VirtNUMAHostTopology.fit_instance_to_host(
hardware.numa_fit_instance_to_host(
host_topology, requested_topology,
limits_topology=limit))
if requested_topology and not instance_topology:

View File

@ -600,11 +600,11 @@ class ResourceTracker(object):
if itype:
host_topology = resources.get('numa_topology')
if host_topology:
host_topology = hardware.VirtNUMAHostTopology.from_json(
host_topology = objects.NUMATopology.obj_from_db_obj(
host_topology)
numa_topology = hardware.numa_get_constraints(itype, image_meta)
numa_topology = (
hardware.VirtNUMAHostTopology.fit_instance_to_host(
hardware.numa_fit_instance_to_host(
host_topology, numa_topology))
usage = self._get_usage_dict(
itype, numa_topology=numa_topology)

View File

@ -132,7 +132,7 @@ class ComputeNode(BASE, NovaBase):
stats = Column(Text, default='{}')
# json-encoded dict that contains NUMA topology as generated by
# nova.virt.hardware.VirtNUMAHostTopology.to_json()
# objects.NUMATopoloogy._to_json()
numa_topology = Column(Text)

View File

@ -80,6 +80,11 @@ class NUMATopology(base.NovaObject):
def _to_json(self):
return jsonutils.dumps(self.obj_to_primitive())
@classmethod
def obj_from_db_obj(cls, db_obj):
return cls.obj_from_primitive(
jsonutils.loads(db_obj))
def __len__(self):
"""Defined so that boolean testing works the same as for lists."""
return len(self.cells)

View File

@ -40,8 +40,7 @@ class NUMATopologyFilter(filters.BaseHostFilter):
cell.id, cell.cpuset, cell.memory,
max_cell_cpu, max_cell_memory))
limits = hardware.VirtNUMALimitTopology(cells=limit_cells)
instance_topology = (
hardware.VirtNUMAHostTopology.fit_instance_to_host(
instance_topology = (hardware.numa_fit_instance_to_host(
host_topology, requested_topology,
limits_topology=limits))
if not instance_topology:

View File

@ -121,10 +121,12 @@ class ClaimTestCase(test.NoDBTestCase):
'free_disk_gb': 20,
'vcpus': 2,
'vcpus_used': 0,
'numa_topology': hardware.VirtNUMAHostTopology(
cells=[hardware.VirtNUMATopologyCellUsage(1, [1, 2], 512),
hardware.VirtNUMATopologyCellUsage(2, [3, 4], 512)]
).to_json()
'numa_topology': objects.NUMATopology(
cells=[objects.NUMACell(id=1, cpuset=set([1, 2]), memory=512,
memory_usage=0, cpu_usage=0),
objects.NUMACell(id=2, cpuset=set([3, 4]), memory=512,
memory_usage=0, cpu_usage=0)]
)._to_json()
}
if values:
resources.update(values)

View File

@ -44,9 +44,11 @@ FAKE_VIRT_MEMORY_MB = 5
FAKE_VIRT_MEMORY_OVERHEAD = 1
FAKE_VIRT_MEMORY_WITH_OVERHEAD = (
FAKE_VIRT_MEMORY_MB + FAKE_VIRT_MEMORY_OVERHEAD)
FAKE_VIRT_NUMA_TOPOLOGY = hardware.VirtNUMAHostTopology(
cells=[hardware.VirtNUMATopologyCellUsage(0, set([1, 2]), 3072),
hardware.VirtNUMATopologyCellUsage(1, set([3, 4]), 3072)])
FAKE_VIRT_NUMA_TOPOLOGY = objects.NUMATopology(
cells=[objects.NUMACell(id=0, cpuset=set([1, 2]), memory=3072,
cpu_usage=0, memory_usage=0),
objects.NUMACell(id=1, cpuset=set([3, 4]), memory=3072,
cpu_usage=0, memory_usage=0)])
FAKE_VIRT_NUMA_TOPOLOGY_OVERHEAD = hardware.VirtNUMALimitTopology(
cells=[hardware.VirtNUMATopologyCellLimit(
0, set([1, 2]), 3072, 4, 10240),
@ -121,7 +123,7 @@ class FakeVirtDriver(driver.ComputeDriver):
'hypervisor_hostname': 'fakehost',
'cpu_info': '',
'numa_topology': (
self.numa_topology.to_json() if self.numa_topology else None),
self.numa_topology._to_json() if self.numa_topology else None),
}
if self.pci_support:
d['pci_passthrough_devices'] = jsonutils.dumps(self.pci_devices)
@ -585,7 +587,7 @@ class BaseTrackerTestCase(BaseTestCase):
if field == 'numa_topology':
self.assertEqualNUMAHostTopology(
value, hardware.VirtNUMAHostTopology.from_json(x))
value, objects.NUMATopology.obj_from_db_obj(x))
else:
self.assertEqual(value, x)
@ -729,12 +731,12 @@ class InstanceClaimTestCase(BaseTrackerTestCase):
if self.tracker.driver.numa_topology is None:
return None
mem = mem * 1024
return hardware.VirtNUMAHostTopology(
cells=[hardware.VirtNUMATopologyCellUsage(
0, set([1, 2]), 3072, cpu_usage=cpus,
return objects.NUMATopology(
cells=[objects.NUMACell(
id=0, cpuset=set([1, 2]), memory=3072, cpu_usage=cpus,
memory_usage=mem),
hardware.VirtNUMATopologyCellUsage(
1, set([3, 4]), 3072, cpu_usage=cpus,
objects.NUMACell(
id=1, cpuset=set([3, 4]), memory=3072, cpu_usage=cpus,
memory_usage=mem)])
@mock.patch('nova.objects.InstancePCIRequests.get_by_instance_uuid',
@ -792,7 +794,7 @@ class InstanceClaimTestCase(BaseTrackerTestCase):
self.assertEqual(FAKE_VIRT_MEMORY_MB - claim_mem_total,
self.compute["free_ram_mb"])
self.assertEqualNUMAHostTopology(
claim_topology, hardware.VirtNUMAHostTopology.from_json(
claim_topology, objects.NUMATopology.obj_from_db_obj(
self.compute['numa_topology']))
self.assertEqual(FAKE_VIRT_LOCAL_GB, self.compute["local_gb"])
@ -817,7 +819,7 @@ class InstanceClaimTestCase(BaseTrackerTestCase):
self.assertEqual(FAKE_VIRT_MEMORY_MB - claim_mem_total,
self.compute['free_ram_mb'])
self.assertEqualNUMAHostTopology(
claim_topology, hardware.VirtNUMAHostTopology.from_json(
claim_topology, objects.NUMATopology.obj_from_db_obj(
self.compute['numa_topology']))
self.assertEqual(claim_disk, self.compute['local_gb_used'])
@ -845,7 +847,7 @@ class InstanceClaimTestCase(BaseTrackerTestCase):
self.assertEqual(FAKE_VIRT_MEMORY_MB - claim_mem_total,
self.compute["free_ram_mb"])
self.assertEqualNUMAHostTopology(
claim_topology, hardware.VirtNUMAHostTopology.from_json(
claim_topology, objects.NUMATopology.obj_from_db_obj(
self.compute['numa_topology']))
self.assertEqual(claim_disk, self.compute["local_gb_used"])
@ -858,7 +860,7 @@ class InstanceClaimTestCase(BaseTrackerTestCase):
self.assertEqual(FAKE_VIRT_MEMORY_MB, self.compute["free_ram_mb"])
self.assertEqualNUMAHostTopology(
FAKE_VIRT_NUMA_TOPOLOGY,
hardware.VirtNUMAHostTopology.from_json(
objects.NUMATopology.obj_from_db_obj(
self.compute['numa_topology']))
self.assertEqual(0, self.compute["local_gb_used"])
@ -887,7 +889,7 @@ class InstanceClaimTestCase(BaseTrackerTestCase):
self.tracker.compute_node['memory_mb_used'])
self.assertEqualNUMAHostTopology(
claim_topology,
hardware.VirtNUMAHostTopology.from_json(
objects.NUMATopology.obj_from_db_obj(
self.compute['numa_topology']))
self.assertEqual(root_gb * 2,
self.tracker.compute_node['local_gb_used'])
@ -919,7 +921,7 @@ class InstanceClaimTestCase(BaseTrackerTestCase):
self.assertEqualNUMAHostTopology(
claim_topology,
hardware.VirtNUMAHostTopology.from_json(
objects.NUMATopology.obj_from_db_obj(
self.compute['numa_topology']))
@mock.patch('nova.objects.InstancePCIRequests.get_by_instance_uuid',
@ -939,7 +941,7 @@ class InstanceClaimTestCase(BaseTrackerTestCase):
self.assertEqual(0, self.compute['local_gb_used'])
self.assertEqualNUMAHostTopology(
FAKE_VIRT_NUMA_TOPOLOGY,
hardware.VirtNUMAHostTopology.from_json(
objects.NUMATopology.obj_from_db_obj(
self.compute['numa_topology']))
@mock.patch('nova.objects.InstancePCIRequests.get_by_instance_uuid',
@ -962,7 +964,7 @@ class InstanceClaimTestCase(BaseTrackerTestCase):
self.compute['memory_mb_used'])
self.assertEqualNUMAHostTopology(
claim_topology,
hardware.VirtNUMAHostTopology.from_json(
objects.NUMATopology.obj_from_db_obj(
self.compute['numa_topology']))
self.assertEqual(flavor['root_gb'] + flavor['ephemeral_gb'],
self.compute['local_gb_used'])
@ -978,7 +980,7 @@ class InstanceClaimTestCase(BaseTrackerTestCase):
self.compute['memory_mb_used'])
self.assertEqualNUMAHostTopology(
claim_topology,
hardware.VirtNUMAHostTopology.from_json(
objects.NUMATopology.obj_from_db_obj(
self.compute['numa_topology']))
self.assertEqual(flavor['root_gb'] + flavor['ephemeral_gb'],
self.compute['local_gb_used'])

View File

@ -18,11 +18,11 @@ from oslo.utils import timeutils
from nova import db
from nova import exception
from nova import objects
from nova.objects import compute_node
from nova.objects import hv_spec
from nova.objects import service
from nova.tests.unit.objects import test_objects
from nova.virt import hardware
NOW = timeutils.utcnow().replace(microsecond=0)
fake_stats = {'num_foo': '10'}
@ -30,10 +30,12 @@ fake_stats_db_format = jsonutils.dumps(fake_stats)
# host_ip is coerced from a string to an IPAddress
# but needs to be converted to a string for the database format
fake_host_ip = '127.0.0.1'
fake_numa_topology = hardware.VirtNUMAHostTopology(
cells=[hardware.VirtNUMATopologyCellUsage(0, set([1, 2]), 512),
hardware.VirtNUMATopologyCellUsage(1, set([3, 4]), 512)])
fake_numa_topology_db_format = fake_numa_topology.to_json()
fake_numa_topology = objects.NUMATopology(
cells=[objects.NUMACell(id=0, cpuset=set([1, 2]), memory=512,
cpu_usage=0, memory_usage=0),
objects.NUMACell(id=1, cpuset=set([3, 4]), memory=512,
cpu_usage=0, memory_usage=0)])
fake_numa_topology_db_format = fake_numa_topology._to_json()
fake_hv_spec = hv_spec.HVSpec(arch='foo', hv_type='bar', vm_mode='foobar')
fake_supported_hv_specs = [fake_hv_spec]
# for backward compatibility, each supported instance object

View File

@ -21,15 +21,17 @@ from oslo.serialization import jsonutils
from nova.compute import vm_states
from nova import db
from nova import objects
from nova.scheduler import filter_scheduler
from nova.scheduler import host_manager
from nova.virt import hardware
NUMA_TOPOLOGY = hardware.VirtNUMAHostTopology(
cells=[hardware.VirtNUMATopologyCellUsage(
0, set([1, 2]), 512),
hardware.VirtNUMATopologyCellUsage(
1, set([3, 4]), 512)])
NUMA_TOPOLOGY = objects.NUMATopology(
cells=[objects.NUMACell(
id=0, cpuset=set([1, 2]), memory=512,
cpu_usage=0, memory_usage=0),
objects.NUMACell(
id=1, cpuset=set([3, 4]), memory=512,
cpu_usage=0, memory_usage=0)])
COMPUTE_NODES = [
dict(id=1, local_gb=1024, memory_mb=1024, vcpus=1,
@ -49,7 +51,7 @@ COMPUTE_NODES = [
free_disk_gb=3072, local_gb_used=0, updated_at=None,
service=dict(host='host3', disabled=False),
hypervisor_hostname='node3', host_ip='127.0.0.1',
hypervisor_version=0, numa_topology=NUMA_TOPOLOGY.to_json()),
hypervisor_version=0, numa_topology=NUMA_TOPOLOGY._to_json()),
dict(id=4, local_gb=8192, memory_mb=8192, vcpus=8,
disk_available_least=8192, free_ram_mb=8192, vcpus_used=0,
free_disk_gb=8888, local_gb_used=0, updated_at=None,

View File

@ -26,13 +26,13 @@ from nova.compute import vm_states
from nova import db
from nova import exception
from nova.i18n import _LW
from nova import objects
from nova.scheduler import filters
from nova.scheduler import host_manager
from nova import test
from nova.tests.unit import matchers
from nova.tests.unit.scheduler import fakes
from nova import utils
from nova.virt import hardware
class FakeFilterClass1(filters.BaseHostFilter):
@ -319,7 +319,7 @@ class HostManagerTestCase(test.NoDBTestCase):
self.assertEqual(host_states_map[('host3', 'node3')].free_disk_mb,
3145728)
self.assertThat(
hardware.VirtNUMAHostTopology.from_json(
objects.NUMATopology.obj_from_db_obj(
host_states_map[('host3', 'node3')].numa_topology
)._to_dict(),
matchers.DictMatches(fakes.NUMA_TOPOLOGY._to_dict()))
@ -532,7 +532,7 @@ class HostStateTestCase(test.NoDBTestCase):
local_gb_used=0, free_ram_mb=0, vcpus=0, vcpus_used=0,
updated_at=None, host_ip='127.0.0.1',
hypervisor_version=hyper_ver_int,
numa_topology=fakes.NUMA_TOPOLOGY.to_json())
numa_topology=fakes.NUMA_TOPOLOGY._to_json())
host = host_manager.HostState("fakehost", "fakenode")
host.update_from_compute_node(compute)

View File

@ -10594,11 +10594,13 @@ class HostStateTestCase(test.NoDBTestCase):
"vendor_id": '8086',
"dev_type": 'type-PF',
"phys_function": None}]
numa_topology = hardware.VirtNUMAHostTopology(
cells=[hardware.VirtNUMATopologyCellUsage(
1, set([1, 2]), 1024),
hardware.VirtNUMATopologyCellUsage(
2, set([3, 4]), 1024)])
numa_topology = objects.NUMATopology(
cells=[objects.NUMACell(
id=1, cpuset=set([1, 2]), memory=1024,
cpu_usage=0, memory_usage=0),
objects.NUMACell(
id=2, cpuset=set([3, 4]), memory=1024,
cpu_usage=0, memory_usage=0)])
class FakeConnection(libvirt_driver.LibvirtDriver):
"""Fake connection object."""
@ -10676,7 +10678,7 @@ class HostStateTestCase(test.NoDBTestCase):
self.assertEqual(stats["disk_available_least"], 80)
self.assertEqual(jsonutils.loads(stats["pci_passthrough_devices"]),
HostStateTestCase.pci_devices)
self.assertThat(hardware.VirtNUMAHostTopology.from_json(
self.assertThat(objects.NUMATopology.obj_from_db_obj(
stats['numa_topology'])._to_dict(),
matchers.DictMatches(
HostStateTestCase.numa_topology._to_dict()))

View File

@ -893,10 +893,13 @@ class NUMATopologyTest(test.NoDBTestCase):
topology.cells[i].memory)
def test_host_usage_contiguous(self):
hosttopo = hw.VirtNUMAHostTopology([
hw.VirtNUMATopologyCellUsage(0, set([0, 1, 2, 3]), 1024),
hw.VirtNUMATopologyCellUsage(1, set([4, 6]), 512),
hw.VirtNUMATopologyCellUsage(2, set([5, 7]), 512),
hosttopo = objects.NUMATopology(cells=[
objects.NUMACell(id=0, cpuset=set([0, 1, 2, 3]), memory=1024,
cpu_usage=0, memory_usage=0),
objects.NUMACell(id=1, cpuset=set([4, 6]), memory=512,
cpu_usage=0, memory_usage=0),
objects.NUMACell(id=2, cpuset=set([5, 7]), memory=512,
cpu_usage=0, memory_usage=0),
])
instance1 = objects.InstanceNUMATopology(cells=[
objects.InstanceNUMACell(id=0, cpuset=set([0, 1, 2]), memory=256),
@ -907,13 +910,12 @@ class NUMATopologyTest(test.NoDBTestCase):
objects.InstanceNUMACell(id=1, cpuset=set([5, 7]), memory=256),
])
hostusage = hw.VirtNUMAHostTopology.usage_from_instances(
hostusage = hw.numa_usage_from_instances(
hosttopo, [instance1, instance2])
self.assertEqual(len(hosttopo), len(hostusage))
self.assertIsInstance(hostusage.cells[0],
hw.VirtNUMATopologyCellUsage)
self.assertIsInstance(hostusage.cells[0], objects.NUMACell)
self.assertEqual(hosttopo.cells[0].cpuset,
hostusage.cells[0].cpuset)
self.assertEqual(hosttopo.cells[0].memory,
@ -921,8 +923,7 @@ class NUMATopologyTest(test.NoDBTestCase):
self.assertEqual(hostusage.cells[0].cpu_usage, 5)
self.assertEqual(hostusage.cells[0].memory_usage, 512)
self.assertIsInstance(hostusage.cells[1],
hw.VirtNUMATopologyCellUsage)
self.assertIsInstance(hostusage.cells[1], objects.NUMACell)
self.assertEqual(hosttopo.cells[1].cpuset,
hostusage.cells[1].cpuset)
self.assertEqual(hosttopo.cells[1].memory,
@ -930,8 +931,7 @@ class NUMATopologyTest(test.NoDBTestCase):
self.assertEqual(hostusage.cells[1].cpu_usage, 3)
self.assertEqual(hostusage.cells[1].memory_usage, 512)
self.assertIsInstance(hostusage.cells[2],
hw.VirtNUMATopologyCellUsage)
self.assertIsInstance(hostusage.cells[2], objects.NUMACell)
self.assertEqual(hosttopo.cells[2].cpuset,
hostusage.cells[2].cpuset)
self.assertEqual(hosttopo.cells[2].memory,
@ -940,27 +940,31 @@ class NUMATopologyTest(test.NoDBTestCase):
self.assertEqual(hostusage.cells[2].memory_usage, 0)
def test_host_usage_sparse(self):
hosttopo = hw.VirtNUMAHostTopology([
hw.VirtNUMATopologyCellUsage(0, set([0, 1, 2, 3]), 1024),
hw.VirtNUMATopologyCellUsage(5, set([4, 6]), 512),
hw.VirtNUMATopologyCellUsage(6, set([5, 7]), 512),
hosttopo = objects.NUMATopology(cells=[
objects.NUMACell(id=0, cpuset=set([0, 1, 2, 3]), memory=1024,
cpu_usage=0, memory_usage=0),
objects.NUMACell(id=5, cpuset=set([4, 6]), memory=512,
cpu_usage=0, memory_usage=0),
objects.NUMACell(id=6, cpuset=set([5, 7]), memory=512,
cpu_usage=0, memory_usage=0),
])
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),
objects.InstanceNUMACell(id=5, cpuset=set([5, 7]), memory=256),
objects.InstanceNUMACell(id=0, cpuset=set([0, 1]), memory=256,
cpu_usage=0, memory_usage=0),
objects.InstanceNUMACell(id=5, cpuset=set([5, 7]), memory=256,
cpu_usage=0, memory_usage=0),
])
hostusage = hw.VirtNUMAHostTopology.usage_from_instances(
hostusage = hw.numa_usage_from_instances(
hosttopo, [instance1, instance2])
self.assertEqual(len(hosttopo), len(hostusage))
self.assertIsInstance(hostusage.cells[0],
hw.VirtNUMATopologyCellUsage)
self.assertIsInstance(hostusage.cells[0], objects.NUMACell)
self.assertEqual(hosttopo.cells[0].id,
hostusage.cells[0].id)
self.assertEqual(hosttopo.cells[0].cpuset,
@ -970,8 +974,7 @@ class NUMATopologyTest(test.NoDBTestCase):
self.assertEqual(hostusage.cells[0].cpu_usage, 5)
self.assertEqual(hostusage.cells[0].memory_usage, 512)
self.assertIsInstance(hostusage.cells[1],
hw.VirtNUMATopologyCellUsage)
self.assertIsInstance(hostusage.cells[1], objects.NUMACell)
self.assertEqual(hosttopo.cells[1].id,
hostusage.cells[1].id)
self.assertEqual(hosttopo.cells[1].cpuset,
@ -981,8 +984,7 @@ class NUMATopologyTest(test.NoDBTestCase):
self.assertEqual(hostusage.cells[1].cpu_usage, 2)
self.assertEqual(hostusage.cells[1].memory_usage, 256)
self.assertIsInstance(hostusage.cells[2],
hw.VirtNUMATopologyCellUsage)
self.assertIsInstance(hostusage.cells[2], objects.NUMACell)
self.assertEqual(hosttopo.cells[2].cpuset,
hostusage.cells[2].cpuset)
self.assertEqual(hosttopo.cells[2].memory,
@ -991,37 +993,35 @@ class NUMATopologyTest(test.NoDBTestCase):
self.assertEqual(hostusage.cells[2].memory_usage, 256)
def test_host_usage_culmulative_with_free(self):
hosttopo = hw.VirtNUMAHostTopology([
hw.VirtNUMATopologyCellUsage(
0, set([0, 1, 2, 3]), 1024, cpu_usage=2, memory_usage=512),
hw.VirtNUMATopologyCellUsage(
1, set([4, 6]), 512, cpu_usage=1, memory_usage=512),
hw.VirtNUMATopologyCellUsage(2, set([5, 7]), 256),
hosttopo = objects.NUMATopology(cells=[
objects.NUMACell(id=0, cpuset=set([0, 1, 2, 3]), memory=1024,
cpu_usage=2, memory_usage=512),
objects.NUMACell(id=1, cpuset=set([4, 6]), memory=512,
cpu_usage=1, memory_usage=512),
objects.NUMACell(id=2, cpuset=set([5, 7]), memory=256,
cpu_usage=0, memory_usage=0),
])
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.VirtNUMAHostTopology.usage_from_instances(
hostusage = hw.numa_usage_from_instances(
hosttopo, [instance1])
self.assertIsInstance(hostusage.cells[0],
hw.VirtNUMATopologyCellUsage)
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],
hw.VirtNUMATopologyCellUsage)
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],
hw.VirtNUMATopologyCellUsage)
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.VirtNUMAHostTopology.usage_from_instances(
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)
@ -1033,27 +1033,29 @@ class NUMATopologyTest(test.NoDBTestCase):
self.assertEqual(hostusage.cells[2].memory_usage, 0)
def test_topo_usage_none(self):
hosttopo = hw.VirtNUMAHostTopology([
hw.VirtNUMATopologyCellUsage(0, set([0, 1]), 512),
hw.VirtNUMATopologyCellUsage(1, set([2, 3]), 512),
hosttopo = objects.NUMATopology(cells=[
objects.NUMACell(id=0, cpuset=set([0, 1]), memory=512,
cpu_usage=0, memory_usage=0),
objects.NUMACell(id=1, cpuset=set([2, 3]), memory=512,
cpu_usage=0, memory_usage=0),
])
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.VirtNUMAHostTopology.usage_from_instances(
hostusage = hw.numa_usage_from_instances(
None, [instance1])
self.assertIsNone(hostusage)
hostusage = hw.VirtNUMAHostTopology.usage_from_instances(
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.VirtNUMAHostTopology.usage_from_instances(
hostusage = hw.numa_usage_from_instances(
hosttopo, None)
self.assertEqual(hostusage.cells[0].cpu_usage, 0)
self.assertEqual(hostusage.cells[0].memory_usage, 0)
@ -1062,7 +1064,7 @@ class NUMATopologyTest(test.NoDBTestCase):
def assertNUMACellMatches(self, expected_cell, got_cell):
attrs = ('cpuset', 'memory', 'id')
if isinstance(expected_cell, hw.VirtNUMAHostTopology):
if isinstance(expected_cell, objects.NUMATopology):
attrs += ('cpu_usage', 'memory_usage')
for attr in attrs:
@ -1070,13 +1072,13 @@ class NUMATopologyTest(test.NoDBTestCase):
getattr(got_cell, attr))
def test_json(self):
expected = hw.VirtNUMAHostTopology(
expected = objects.NUMATopology(
cells=[
hw.VirtNUMATopologyCellUsage(
1, set([1, 2]), 1024),
hw.VirtNUMATopologyCellUsage(
2, set([3, 4]), 1024)])
got = hw.VirtNUMAHostTopology.from_json(expected.to_json())
objects.NUMACell(id=1, cpuset=set([1, 2]), memory=1024,
cpu_usage=0, memory_usage=0),
objects.NUMACell(id=2, cpuset=set([3, 4]), memory=1024,
cpu_usage=0, memory_usage=0)])
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)
@ -1084,54 +1086,56 @@ class NUMATopologyTest(test.NoDBTestCase):
class VirtNUMATopologyCellUsageTestCase(test.NoDBTestCase):
def test_fit_instance_cell_success_no_limit(self):
host_cell = hw.VirtNUMATopologyCellUsage(4, set([1, 2]), 1024)
host_cell = objects.NUMACell(id=4, cpuset=set([1, 2]), memory=1024,
cpu_usage=0, memory_usage=0)
instance_cell = objects.InstanceNUMACell(
id=0, cpuset=set([1, 2]), memory=1024)
fitted_cell = host_cell.fit_instance_cell(host_cell, instance_cell)
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 = hw.VirtNUMATopologyCellUsage(4, set([1, 2]), 1024,
host_cell = objects.NUMACell(id=4, cpuset=set([1, 2]), memory=1024,
cpu_usage=2,
memory_usage=1024)
limit_cell = hw.VirtNUMATopologyCellLimit(
4, set([1, 2]), 1024,
4, cpuset=set([1, 2]), memory=1024,
cpu_limit=4, memory_limit=2048)
instance_cell = objects.InstanceNUMACell(
id=0, cpuset=set([1, 2]), memory=1024)
fitted_cell = host_cell.fit_instance_cell(
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 = hw.VirtNUMATopologyCellUsage(4, set([1, 2]), 1024)
host_cell = objects.NUMACell(id=4, cpuset=set([1, 2]), memory=1024,
cpu_usage=0, memory_usage=0)
limit_cell = hw.VirtNUMATopologyCellLimit(
4, set([1, 2]), 1024,
4, cpuset=set([1, 2]), memory=1024,
cpu_limit=4, memory_limit=2048)
instance_cell = objects.InstanceNUMACell(
id=0, cpuset=set([1, 2, 3]), memory=4096)
fitted_cell = host_cell.fit_instance_cell(
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 = hw.VirtNUMATopologyCellUsage(4, set([1, 2]), 1024,
host_cell = objects.NUMACell(id=4, cpuset=set([1, 2]), memory=1024,
cpu_usage=2,
memory_usage=1024)
limit_cell = hw.VirtNUMATopologyCellLimit(
4, set([1, 2]), 1024,
4, cpuset=set([1, 2]), memory=1024,
cpu_limit=4, memory_limit=2048)
instance_cell = objects.InstanceNUMACell(
id=0, cpuset=set([1, 2]), memory=4096)
fitted_cell = host_cell.fit_instance_cell(
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 = host_cell.fit_instance_cell(
fitted_cell = hw._numa_fit_instance_cell(
host_cell, instance_cell, limit_cell=limit_cell)
self.assertIsNone(fitted_cell)
@ -1140,22 +1144,20 @@ class VirtNUMAHostTopologyTestCase(test.NoDBTestCase):
def setUp(self):
super(VirtNUMAHostTopologyTestCase, self).setUp()
self.host = hw.VirtNUMAHostTopology(
self.host = objects.NUMATopology(
cells=[
hw.VirtNUMATopologyCellUsage(
1, set([1, 2]), 2048,
objects.NUMACell(id=1, cpuset=set([1, 2]), memory=2048,
cpu_usage=2, memory_usage=2048),
hw.VirtNUMATopologyCellUsage(
2, set([3, 4]), 2048,
objects.NUMACell(id=2, cpuset=set([3, 4]), memory=2048,
cpu_usage=2, memory_usage=2048)])
self.limits = hw.VirtNUMALimitTopology(
cells=[
hw.VirtNUMATopologyCellLimit(
1, set([1, 2]), 2048,
1, cpuset=set([1, 2]), memory=2048,
cpu_limit=4, memory_limit=4096),
hw.VirtNUMATopologyCellLimit(
2, set([3, 4]), 2048,
2, cpuset=set([3, 4]), memory=2048,
cpu_limit=4, memory_limit=3072)])
self.instance1 = objects.InstanceNUMATopology(
@ -1172,45 +1174,45 @@ class VirtNUMAHostTopologyTestCase(test.NoDBTestCase):
id=0, cpuset=set([1, 2]), memory=1024)])
def test_get_fitting_success_no_limits(self):
fitted_instance1 = hw.VirtNUMAHostTopology.fit_instance_to_host(
fitted_instance1 = hw.numa_fit_instance_to_host(
self.host, self.instance1)
self.assertIsInstance(fitted_instance1, objects.InstanceNUMATopology)
self.host = hw.VirtNUMAHostTopology.usage_from_instances(self.host,
self.host = hw.numa_usage_from_instances(self.host,
[fitted_instance1])
fitted_instance2 = hw.VirtNUMAHostTopology.fit_instance_to_host(
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.VirtNUMAHostTopology.fit_instance_to_host(
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.VirtNUMAHostTopology.fit_instance_to_host(
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.VirtNUMAHostTopology.fit_instance_to_host(
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.VirtNUMAHostTopology.usage_from_instances(self.host,
self.host = hw.numa_usage_from_instances(self.host,
[fitted_instance1])
fitted_instance2 = hw.VirtNUMAHostTopology.fit_instance_to_host(
fitted_instance2 = hw.numa_fit_instance_to_host(
self.host, self.instance1, self.limits)
self.assertIsNone(fitted_instance2)
def test_get_fitting_culmulative_success_limits(self):
fitted_instance1 = hw.VirtNUMAHostTopology.fit_instance_to_host(
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.VirtNUMAHostTopology.usage_from_instances(self.host,
self.host = hw.numa_usage_from_instances(self.host,
[fitted_instance1])
fitted_instance2 = hw.VirtNUMAHostTopology.fit_instance_to_host(
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)
@ -1263,9 +1265,11 @@ class NumberOfSerialPortsTest(test.NoDBTestCase):
class HelperMethodsTestCase(test.NoDBTestCase):
def setUp(self):
super(HelperMethodsTestCase, self).setUp()
self.hosttopo = hw.VirtNUMAHostTopology([
hw.VirtNUMATopologyCellUsage(0, set([0, 1]), 512),
hw.VirtNUMATopologyCellUsage(1, set([2, 3]), 512),
self.hosttopo = objects.NUMATopology(cells=[
objects.NUMACell(id=0, cpuset=set([0, 1]), memory=512,
memory_usage=0, cpu_usage=0),
objects.NUMACell(id=1, cpuset=set([2, 3]), memory=512,
memory_usage=0, cpu_usage=0),
])
self.instancetopo = objects.InstanceNUMATopology(
instance_uuid='fake-uuid',
@ -1285,19 +1289,19 @@ class HelperMethodsTestCase(test.NoDBTestCase):
self.assertEqual(256, host_usage.cells[1].memory_usage)
def test_dicts_json(self):
host = {'numa_topology': self.hosttopo.to_json()}
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(hw.VirtNUMAHostTopology.from_json(res))
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, hw.VirtNUMAHostTopology)
self.assertIsInstance(res, objects.NUMATopology)
self._check_usage(res)
def test_dicts_instance_json_old(self):
@ -1306,35 +1310,44 @@ class HelperMethodsTestCase(test.NoDBTestCase):
jsonutils.dumps(self.instancetopo._to_dict())}
res = hw.get_host_numa_usage_from_instance(host, instance)
self.assertIsInstance(res, hw.VirtNUMAHostTopology)
self.assertIsInstance(res, objects.NUMATopology)
self._check_usage(res)
def test_dicts_host_json(self):
host = {'numa_topology': self.hosttopo.to_json()}
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(hw.VirtNUMAHostTopology.from_json(res))
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())
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(hw.VirtNUMAHostTopology.from_json(res))
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())
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(hw.VirtNUMAHostTopology.from_json(res))
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())
host = objects.ComputeNode(numa_topology=self.hosttopo._to_json())
fake_uuid = str(uuid.uuid4())
instance = {'uuid': fake_uuid}
@ -1345,7 +1358,7 @@ class HelperMethodsTestCase(test.NoDBTestCase):
self.assertTrue(get_mock.called)
def test_object_instance_with_load(self):
host = objects.ComputeNode(numa_topology=self.hosttopo.to_json())
host = objects.ComputeNode(numa_topology=self.hosttopo._to_json())
fake_uuid = str(uuid.uuid4())
instance = objects.Instance(context=self.context, uuid=fake_uuid)
@ -1356,7 +1369,7 @@ class HelperMethodsTestCase(test.NoDBTestCase):
self.assertTrue(get_mock.called)
def test_instance_serialized_by_build_request_spec(self):
host = objects.ComputeNode(numa_topology=self.hosttopo.to_json())
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)
@ -1366,27 +1379,27 @@ class HelperMethodsTestCase(test.NoDBTestCase):
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(hw.VirtNUMAHostTopology.from_json(res))
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()
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(hw.VirtNUMAHostTopology.from_json(res))
self._check_usage(objects.NUMATopology.obj_from_db_obj(res))
def test_never_serialize_result(self):
host = {'numa_topology': self.hosttopo.to_json()}
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, hw.VirtNUMAHostTopology)
self.assertIsInstance(res, objects.NUMATopology)
self._check_usage(res)

View File

@ -652,84 +652,34 @@ class VirtNUMATopologyCellLimit(VirtNUMATopologyCell):
return cls(cell_id, cpuset, memory, cpu_limit, memory_limit)
class VirtNUMATopologyCellUsage(VirtNUMATopologyCell):
"""Class for reporting NUMA resources and usage in a cell
def _numa_fit_instance_cell(host_cell, instance_cell, limit_cell=None):
"""Check if a instance cell can fit and set it's cell id
The VirtNUMATopologyCellUsage class specializes
VirtNUMATopologyCell to include information about the
utilization of hardware resources in a NUMA cell.
:param host_cell: host cell to fit the instance cell onto
:param instance_cell: instance cell we want to fit
:param limit_cell: cell with limits of the host_cell if any
Make sure we can fit the instance cell onto a host cell and if so,
return a new objects.InstanceNUMACell with the id set to that of
the host, or None if the cell exceeds the limits of the host
:returns: a new instance cell or None
"""
# NOTE (ndipanov): do not allow an instance to overcommit against
# itself on any NUMA cell
if (instance_cell.memory > host_cell.memory or
len(instance_cell.cpuset) > len(host_cell.cpuset)):
return None
def __init__(self, id, cpuset, memory, cpu_usage=0, memory_usage=0):
"""Create a new NUMA Cell with usage
:param id: integer identifier of cell
:param cpuset: set containing list of CPU indexes
:param memory: RAM measured in MiB
:param cpu_usage: number of CPUs allocated
:param memory_usage: RAM allocated in MiB
Creates a new NUMA cell object to record the hardware
resources and utilization. The number of CPUs specified
by the @cpu_usage parameter may be larger than the number
of bits set in @cpuset if CPU overcommit is used. Likewise
the amount of RAM specified by the @memory_usage parameter
may be larger than the available RAM in @memory if RAM
overcommit is used.
:returns: a new NUMA cell object
"""
super(VirtNUMATopologyCellUsage, self).__init__(
id, cpuset, memory)
self.cpu_usage = cpu_usage
self.memory_usage = memory_usage
@classmethod
def fit_instance_cell(cls, host_cell, instance_cell, limit_cell=None):
"""Check if a instance cell can fit and set it's cell id
:param host_cell: host cell to fit the instance cell onto
:param instance_cell: instance cell we want to fit
:param limit_cell: cell with limits of the host_cell if any
Make sure we can fit the instance cell onto a host cell and if so,
return a new objects.InstanceNUMACell with the id set to that of
the host, or None if the cell exceeds the limits of the host
:returns: a new instance cell or None
"""
# NOTE (ndipanov): do not allow an instance to overcommit against
# itself on any NUMA cell
if (instance_cell.memory > host_cell.memory or
len(instance_cell.cpuset) > len(host_cell.cpuset)):
if limit_cell:
memory_usage = host_cell.memory_usage + instance_cell.memory
cpu_usage = host_cell.cpu_usage + len(instance_cell.cpuset)
if (memory_usage > limit_cell.memory_limit or
cpu_usage > limit_cell.cpu_limit):
return None
if limit_cell:
memory_usage = host_cell.memory_usage + instance_cell.memory
cpu_usage = host_cell.cpu_usage + len(instance_cell.cpuset)
if (memory_usage > limit_cell.memory_limit or
cpu_usage > limit_cell.cpu_limit):
return None
return objects.InstanceNUMACell(
id=host_cell.id, cpuset=instance_cell.cpuset,
memory=instance_cell.memory)
def _to_dict(self):
data_dict = super(VirtNUMATopologyCellUsage, self)._to_dict()
data_dict['mem']['used'] = self.memory_usage
data_dict['cpu_usage'] = self.cpu_usage
return data_dict
@classmethod
def _from_dict(cls, data_dict):
cpuset = parse_cpu_spec(data_dict.get('cpus', ''))
cpu_usage = data_dict.get('cpu_usage', 0)
memory = data_dict.get('mem', {}).get('total', 0)
memory_usage = data_dict.get('mem', {}).get('used', 0)
cell_id = data_dict.get('id')
return cls(cell_id, cpuset, memory, cpu_usage, memory_usage)
return objects.InstanceNUMACell(
id=host_cell.id, cpuset=instance_cell.cpuset,
memory=instance_cell.memory)
class VirtNUMATopology(object):
@ -903,93 +853,83 @@ class VirtNUMALimitTopology(VirtNUMATopology):
cell_class = VirtNUMATopologyCellLimit
class VirtNUMAHostTopology(VirtNUMATopology):
def numa_fit_instance_to_host(
host_topology, instance_topology, limits_topology=None):
"""Fit the instance topology onto the host topology given the limits
"""Class represents the NUMA configuration and utilization
of a compute node. As well as exposing the overall topology
it tracks the utilization of the resources by guest instances
:param host_topology: objects.NUMATopology object to fit an instance on
:param instance_topology: objects.InstanceNUMATopology to be fitted
:param limits_topology: VirtNUMALimitTopology that defines limits
Given a host and instance topology and optionally limits - this method
will attempt to fit instance cells onto all permutations of host cells
by calling the _numa_fit_instance_cell method, and return a new
InstanceNUMATopology with it's cell ids set to host cell id's of
the first successful permutation, or None.
"""
if (not (host_topology and instance_topology) or
len(host_topology) < len(instance_topology)):
return
else:
if limits_topology is None:
limits_topology_cells = itertools.repeat(
None, len(host_topology))
else:
limits_topology_cells = limits_topology.cells
# TODO(ndipanov): We may want to sort permutations differently
# depending on whether we want packing/spreading over NUMA nodes
for host_cell_perm in itertools.permutations(
zip(host_topology.cells, limits_topology_cells),
len(instance_topology)
):
cells = []
for (host_cell, limit_cell), instance_cell in zip(
host_cell_perm, instance_topology.cells):
got_cell = _numa_fit_instance_cell(
host_cell, instance_cell, limit_cell)
if got_cell is None:
break
cells.append(got_cell)
if len(cells) == len(host_cell_perm):
return objects.InstanceNUMATopology(cells=cells)
def numa_usage_from_instances(host, instances, free=False):
"""Get host topology usage
:param host: objects.NUMATopology with usage information
:param instances: list of objects.InstanceNUMATopology
:param free: If True usage of the host will be decreased
Sum the usage from all @instances to report the overall
host topology usage
:returns: objects.NUMATopology including usage information
"""
cell_class = VirtNUMATopologyCellUsage
if host is None:
return
@classmethod
def fit_instance_to_host(cls, host_topology, instance_topology,
limits_topology=None):
"""Fit the instance topology onto the host topology given the limits
instances = instances or []
cells = []
sign = -1 if free else 1
for hostcell in host.cells:
memory_usage = hostcell.memory_usage
cpu_usage = hostcell.cpu_usage
for instance in instances:
for instancecell in instance.cells:
if instancecell.id == hostcell.id:
memory_usage = (
memory_usage + sign * instancecell.memory)
cpu_usage = cpu_usage + sign * len(instancecell.cpuset)
:param host_topology: VirtNUMAHostTopology object to fit an instance on
:param instance_topology: objects.InstanceNUMATopology to be fitted
:param limits_topology: VirtNUMALimitTopology that defines limits
cell = objects.NUMACell(
id=hostcell.id, cpuset=hostcell.cpuset, memory=hostcell.memory,
cpu_usage=max(0, cpu_usage), memory_usage=max(0, memory_usage))
Given a host and instance topology and optionally limits - this method
will attempt to fit instance cells onto all permutations of host cells
by calling the fit_instance_cell method, and return a new
InstanceNUMATopology with it's cell ids set to host cell id's of
the first successful permutation, or None.
"""
if (not (host_topology and instance_topology) or
len(host_topology) < len(instance_topology)):
return
else:
if limits_topology is None:
limits_topology_cells = itertools.repeat(
None, len(host_topology))
else:
limits_topology_cells = limits_topology.cells
# TODO(ndipanov): We may want to sort permutations differently
# depending on whether we want packing/spreading over NUMA nodes
for host_cell_perm in itertools.permutations(
zip(host_topology.cells, limits_topology_cells),
len(instance_topology)
):
cells = []
for (host_cell, limit_cell), instance_cell in zip(
host_cell_perm, instance_topology.cells):
got_cell = cls.cell_class.fit_instance_cell(
host_cell, instance_cell, limit_cell)
if got_cell is None:
break
cells.append(got_cell)
if len(cells) == len(host_cell_perm):
return objects.InstanceNUMATopology(cells=cells)
cells.append(cell)
@classmethod
def usage_from_instances(cls, host, instances, free=False):
"""Get host topology usage
:param host: VirtNUMAHostTopology with usage information
:param instances: list of objects.InstanceNUMATopology
:param free: If True usage of the host will be decreased
Sum the usage from all @instances to report the overall
host topology usage
:returns: VirtNUMAHostTopology including usage information
"""
if host is None:
return
instances = instances or []
cells = []
sign = -1 if free else 1
for hostcell in host.cells:
memory_usage = hostcell.memory_usage
cpu_usage = hostcell.cpu_usage
for instance in instances:
for instancecell in instance.cells:
if instancecell.id == hostcell.id:
memory_usage = (
memory_usage + sign * instancecell.memory)
cpu_usage = cpu_usage + sign * len(instancecell.cpuset)
cell = cls.cell_class(
hostcell.id, hostcell.cpuset, hostcell.memory,
max(0, cpu_usage), max(0, memory_usage))
cells.append(cell)
return cls(cells)
return objects.NUMATopology(cells=cells)
# TODO(ndipanov): Remove when all code paths are using objects
@ -1055,7 +995,7 @@ def host_topology_and_format_from_host(host):
Since we may get a host as either a dict, a db object, or an actual
ComputeNode object, or an instance of HostState class, this makes sure we
get beck either None, or an instance of VirtNUMAHostTopology class.
get beck either None, or an instance of objects.NUMATopology class.
:returns: A two-tuple, first element is the topology itself or None, second
is a boolean set to True if topology was in json format.
@ -1069,7 +1009,9 @@ def host_topology_and_format_from_host(host):
if host_numa_topology is not None and isinstance(
host_numa_topology, six.string_types):
was_json = True
host_numa_topology = VirtNUMAHostTopology.from_json(host_numa_topology)
host_numa_topology = (objects.NUMATopology.obj_from_db_obj(
host_numa_topology))
return host_numa_topology, was_json
@ -1091,10 +1033,10 @@ def get_host_numa_usage_from_instance(host, instance, free=False,
:param free: if True the the returned topology will have it's usage
decreased instead.
:param never_serialize_result: if True result will always be an instance of
VirtNUMAHostTopology class.
objects.NUMATopology class.
:returns: numa_usage in the format it was on the host or
VirtNUMAHostTopology instance if never_serialize_result was True
objects.NUMATopology instance if never_serialize_result was True
"""
instance_numa_topology = instance_topology_from_instance(instance)
if instance_numa_topology:
@ -1104,11 +1046,11 @@ def get_host_numa_usage_from_instance(host, instance, free=False,
host)
updated_numa_topology = (
VirtNUMAHostTopology.usage_from_instances(
host_numa_topology, instance_numa_topology, free=free))
numa_usage_from_instances(
host_numa_topology, instance_numa_topology, free=free))
if updated_numa_topology is not None:
if jsonify_result and not never_serialize_result:
updated_numa_topology = updated_numa_topology.to_json()
updated_numa_topology = updated_numa_topology._to_json()
return updated_numa_topology

View File

@ -4912,11 +4912,13 @@ class LibvirtDriver(driver.ComputeDriver):
if topology is None or not topology.cells:
return
topology = hardware.VirtNUMAHostTopology(
cells=[hardware.VirtNUMATopologyCellUsage(
cell.id, set(cpu.id for cpu in cell.cpus),
cell.memory / units.Ki)
for cell in topology.cells])
topology = objects.NUMATopology(
cells=[objects.NUMACell(
id=cell.id,
cpuset=set(cpu.id for cpu in cell.cpus),
memory=cell.memory / units.Ki,
cpu_usage=0, memory_usage=0)
for cell in topology.cells])
allowed_cpus = hardware.get_vcpu_pin_set()
if allowed_cpus:
@ -5046,7 +5048,7 @@ class LibvirtDriver(driver.ComputeDriver):
numa_topology = self._get_host_numa_topology()
if numa_topology:
data['numa_topology'] = numa_topology.to_json()
data['numa_topology'] = numa_topology._to_json()
else:
data['numa_topology'] = None