pci manager: replace node_id parameter with compute_node

To implement the `socket` PCI NUMA affinity policy, we'll need to
track the host NUMA topology in the PCI stats code. To achieve this,
PCI stats will need to know the compute node it's running on. Prepare
for this by replacing the node_id parameter with compute_node. Node_id
was previously optional, but that looks to have been only to
facilitate testing, as that's the only place where it was not passed
it. We use compute_node (instead of just making node_id mandatory)
because it allows for an optimization later on wherein the PCI manager
does not need to pull the ComputeNode object from the database
needlessly.

Implements: blueprint pci-socket-affinity
Change-Id: Idc839312d1449e9327ee7e3793d53ed080a44d0c
This commit is contained in:
Artom Lifshitz 2021-03-04 09:41:51 -05:00
parent dc6667c211
commit 6c3175d3ee
5 changed files with 47 additions and 38 deletions

View File

@ -763,8 +763,7 @@ class ResourceTracker(object):
def _setup_pci_tracker(self, context, compute_node, resources):
if not self.pci_tracker:
n_id = compute_node.id
self.pci_tracker = pci_manager.PciDevTracker(context, node_id=n_id)
self.pci_tracker = pci_manager.PciDevTracker(context, compute_node)
if 'pci_passthrough_devices' in resources:
dev_json = resources.pop('pci_passthrough_devices')
self.pci_tracker.update_devices_from_hypervisor_resources(

View File

@ -51,25 +51,22 @@ class PciDevTracker(object):
are saved.
"""
def __init__(self, context, node_id=None):
def __init__(self, context, compute_node):
"""Create a pci device tracker.
If a node_id is passed in, it will fetch pci devices information
from database, otherwise, it will create an empty devices list
and the resource tracker will update the node_id information later.
:param context: The request context.
:param compute_node: The object.ComputeNode whose PCI devices we're
tracking.
"""
super(PciDevTracker, self).__init__()
self.stale = {}
self.node_id = node_id
self.node_id = compute_node.id
self.dev_filter = whitelist.Whitelist(CONF.pci.passthrough_whitelist)
self.stats = stats.PciDeviceStats(dev_filter=self.dev_filter)
self._context = context
if node_id:
self.pci_devs = objects.PciDeviceList.get_by_compute_node(
context, node_id)
else:
self.pci_devs = objects.PciDeviceList(objects=[])
self.pci_devs = objects.PciDeviceList.get_by_compute_node(
context, self.node_id)
self._build_device_tree(self.pci_devs)
self._initial_instance_usage()

View File

@ -56,7 +56,12 @@ class DummyTracker(object):
def new_pci_tracker(self):
ctxt = context.RequestContext('testuser', 'testproject')
self.pci_tracker = pci_manager.PciDevTracker(ctxt)
with mock.patch.object(
objects.PciDeviceList, 'get_by_compute_node',
return_value=objects.PciDeviceList()
):
self.pci_tracker = pci_manager.PciDevTracker(
ctxt, objects.ComputeNode(id=1))
class ClaimTestCase(test.NoDBTestCase):

View File

@ -2113,7 +2113,12 @@ class TestInstanceClaim(BaseTestCase):
# TODO(jaypipes): Remove once the PCI tracker is always created
# upon the resource tracker being initialized...
self.rt.pci_tracker = pci_manager.PciDevTracker(mock.sentinel.ctx)
with mock.patch.object(
objects.PciDeviceList, 'get_by_compute_node',
return_value=objects.PciDeviceList()
):
self.rt.pci_tracker = pci_manager.PciDevTracker(
mock.sentinel.ctx, _COMPUTE_NODE_FIXTURES[0])
pci_dev = pci_device.PciDevice.create(
None, fake_pci_device.dev_dict)
@ -2478,7 +2483,6 @@ class TestResize(BaseTestCase):
pci_get_by_instance_mock,
is_bfv_mock,
revert=False):
self.flags(reserved_host_disk_mb=0,
reserved_host_memory_mb=0)
virt_resources = copy.deepcopy(_VIRT_DRIVER_AVAIL_RESOURCES)
@ -2652,7 +2656,8 @@ class TestResize(BaseTestCase):
# TODO(jaypipes): Remove once the PCI tracker is always created
# upon the resource tracker being initialized...
self.rt.pci_tracker = pci_manager.PciDevTracker(mock.sentinel.ctx)
self.rt.pci_tracker = pci_manager.PciDevTracker(
mock.sentinel.ctx, _COMPUTE_NODE_FIXTURES[0])
pci_dev = pci_device.PciDevice.create(
None, fake_pci_device.dev_dict)
@ -2743,7 +2748,12 @@ class TestResize(BaseTestCase):
# TODO(jaypipes): Remove once the PCI tracker is always created
# upon the resource tracker being initialized...
self.rt.pci_tracker = pci_manager.PciDevTracker(mock.sentinel.ctx)
with mock.patch.object(
objects.PciDeviceList, 'get_by_compute_node',
return_value=objects.PciDeviceList()
):
self.rt.pci_tracker = pci_manager.PciDevTracker(
mock.sentinel.ctx, cn)
pci_dev = pci_device.PciDevice.create(
None, fake_pci_device.dev_dict)
@ -3030,7 +3040,12 @@ class TestLiveMigration(BaseTestCase):
migration = objects.Migration(id=42, migration_type='live-migration',
status='accepted')
image_meta = objects.ImageMeta(properties=objects.ImageMetaProps())
self.rt.pci_tracker = pci_manager.PciDevTracker(mock.sentinel.ctx)
with mock.patch.object(
objects.PciDeviceList, 'get_by_compute_node',
return_value=objects.PciDeviceList()
):
self.rt.pci_tracker = pci_manager.PciDevTracker(
mock.sentinel.ctx, _COMPUTE_NODE_FIXTURES[0])
with test.nested(
mock.patch.object(objects.ImageMeta, 'from_instance',
return_value=image_meta),

View File

@ -19,7 +19,6 @@ import mock
from oslo_serialization import jsonutils
from oslo_utils.fixture import uuidsentinel
import nova
from nova.compute import vm_states
from nova import context
from nova import objects
@ -144,7 +143,8 @@ class PciDevTrackerTestCase(test.NoDBTestCase):
def _create_tracker(self, fake_devs):
self.fake_devs = fake_devs
self.tracker = manager.PciDevTracker(self.fake_context, 1)
self.tracker = manager.PciDevTracker(
self.fake_context, objects.ComputeNode(id=1))
def setUp(self):
super(PciDevTrackerTestCase, self).setUp()
@ -216,25 +216,15 @@ class PciDevTrackerTestCase(test.NoDBTestCase):
self.assertIsNone(vf.parent_device)
self.assertEqual([], vf.child_devices)
@mock.patch.object(nova.objects.PciDeviceList, 'get_by_compute_node')
def test_pcidev_tracker_create_no_nodeid(self, mock_get_cn):
self.tracker = manager.PciDevTracker(self.fake_context)
self.assertEqual(len(self.tracker.pci_devs), 0)
self.assertFalse(mock_get_cn.called)
@mock.patch.object(nova.objects.PciDeviceList, 'get_by_compute_node')
def test_pcidev_tracker_create_with_nodeid(self, mock_get_cn):
self.tracker = manager.PciDevTracker(self.fake_context, node_id=1)
mock_get_cn.assert_called_once_with(self.fake_context, 1)
@mock.patch('nova.pci.whitelist.Whitelist.device_assignable',
return_value=True)
def test_update_devices_from_hypervisor_resources(self, _mock_dev_assign):
fake_pci_devs = [copy.deepcopy(fake_pci), copy.deepcopy(fake_pci_2)]
fake_pci_devs = [copy.deepcopy(fake_pci_4), copy.deepcopy(fake_pci_5)]
fake_pci_devs_json = jsonutils.dumps(fake_pci_devs)
tracker = manager.PciDevTracker(self.fake_context)
tracker = manager.PciDevTracker(
self.fake_context, objects.ComputeNode(id=1))
tracker.update_devices_from_hypervisor_resources(fake_pci_devs_json)
self.assertEqual(2, len(tracker.pci_devs))
self.assertEqual(5, len(tracker.pci_devs))
@mock.patch("nova.pci.manager.LOG.debug")
def test_update_devices_from_hypervisor_resources_32bit_domain(
@ -260,10 +250,12 @@ class PciDevTrackerTestCase(test.NoDBTestCase):
fake_pci_devs = [fake_pci]
fake_pci_devs_json = jsonutils.dumps(fake_pci_devs)
tracker = manager.PciDevTracker(self.fake_context)
# We expect that the device with 32bit PCI domain is ignored
tracker = manager.PciDevTracker(
self.fake_context, objects.ComputeNode(id=1))
# We expect that the device with 32bit PCI domain is ignored, so we'll
# have only the 3 original fake devs
tracker.update_devices_from_hypervisor_resources(fake_pci_devs_json)
self.assertEqual(0, len(tracker.pci_devs))
self.assertEqual(3, len(tracker.pci_devs))
mock_debug.assert_called_once_with(
'Skipping PCI device %s reported by the hypervisor: %s',
{'address': '10000:00:02.0', 'parent_addr': None},
@ -433,7 +425,8 @@ class PciDevTrackerTestCase(test.NoDBTestCase):
fake_db_dev_3 = dict(fake_db_dev_1, id=4, address='0000:00:00.4')
fake_devs_numa = copy.deepcopy(fake_db_devs)
fake_devs_numa.append(fake_db_dev_3)
self.tracker = manager.PciDevTracker(1)
self.tracker = manager.PciDevTracker(
mock.sentinel.context, objects.ComputeNode(id=1))
self.tracker._set_hvdevs(fake_devs_numa)
pci_requests = copy.deepcopy(fake_pci_requests)[:1]
pci_requests[0]['count'] = 2