nova/nova/tests/unit/scheduler/filters/test_numa_topology_filters.py

332 lines
15 KiB
Python

# 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 itertools
from oslo_utils.fixture import uuidsentinel as uuids
from nova import objects
from nova.objects import fields
from nova.scheduler.filters import numa_topology_filter
from nova import test
from nova.tests.unit.scheduler import fakes
class TestNUMATopologyFilter(test.NoDBTestCase):
def setUp(self):
super(TestNUMATopologyFilter, self).setUp()
self.filt_cls = numa_topology_filter.NUMATopologyFilter()
def _get_spec_obj(self, numa_topology, network_metadata=None):
image_meta = objects.ImageMeta(properties=objects.ImageMetaProps())
spec_obj = objects.RequestSpec(numa_topology=numa_topology,
pci_requests=None,
instance_uuid=uuids.fake,
flavor=objects.Flavor(extra_specs={}),
image=image_meta)
if network_metadata:
spec_obj.network_metadata = network_metadata
return spec_obj
def test_numa_topology_filter_pass(self):
instance_topology = objects.InstanceNUMATopology(cells=[
objects.InstanceNUMACell(id=0, cpuset=set([1]), pcpuset=set(),
memory=512),
objects.InstanceNUMACell(id=1, cpuset=set([3]), pcpuset=set(),
memory=512),
])
spec_obj = self._get_spec_obj(numa_topology=instance_topology)
host = fakes.FakeHostState('host1', 'node1',
{'numa_topology': fakes.NUMA_TOPOLOGY,
'pci_stats': None,
'cpu_allocation_ratio': 16.0,
'ram_allocation_ratio': 1.5})
self.assertTrue(self.filt_cls.host_passes(host, spec_obj))
def test_numa_topology_filter_numa_instance_no_numa_host_fail(self):
instance_topology = objects.InstanceNUMATopology(cells=[
objects.InstanceNUMACell(id=0, cpuset=set([1]), pcpuset=set(),
memory=512),
objects.InstanceNUMACell(id=1, cpuset=set([3]), pcpuset=set(),
memory=512),
])
spec_obj = self._get_spec_obj(numa_topology=instance_topology)
host = fakes.FakeHostState('host1', 'node1', {'pci_stats': None})
self.assertFalse(self.filt_cls.host_passes(host, spec_obj))
def test_numa_topology_filter_numa_host_no_numa_instance_pass(self):
spec_obj = self._get_spec_obj(numa_topology=None)
host = fakes.FakeHostState('host1', 'node1',
{'numa_topology': fakes.NUMA_TOPOLOGY})
self.assertTrue(self.filt_cls.host_passes(host, spec_obj))
def test_numa_topology_filter_fail_fit(self):
instance_topology = objects.InstanceNUMATopology(cells=[
objects.InstanceNUMACell(id=0, cpuset=set([1]), pcpuset=set(),
memory=512),
objects.InstanceNUMACell(id=1, cpuset=set([2]), pcpuset=set(),
memory=512),
objects.InstanceNUMACell(id=2, cpuset=set([3]), pcpuset=set(),
memory=512),
])
spec_obj = self._get_spec_obj(numa_topology=instance_topology)
host = fakes.FakeHostState('host1', 'node1',
{'numa_topology': fakes.NUMA_TOPOLOGY,
'pci_stats': None,
'cpu_allocation_ratio': 16.0,
'ram_allocation_ratio': 1.5})
self.assertFalse(self.filt_cls.host_passes(host, spec_obj))
def test_numa_topology_filter_fail_memory(self):
instance_topology = objects.InstanceNUMATopology(cells=[
objects.InstanceNUMACell(id=0, cpuset=set([1]), pcpuset=set(),
memory=1024),
objects.InstanceNUMACell(id=1, cpuset=set([3]), pcpuset=set(),
memory=512),
])
spec_obj = self._get_spec_obj(numa_topology=instance_topology)
host = fakes.FakeHostState('host1', 'node1',
{'numa_topology': fakes.NUMA_TOPOLOGY,
'pci_stats': None,
'cpu_allocation_ratio': 16.0,
'ram_allocation_ratio': 1})
self.assertFalse(self.filt_cls.host_passes(host, spec_obj))
def test_numa_topology_filter_fail_cpu(self):
instance_topology = objects.InstanceNUMATopology(cells=[
objects.InstanceNUMACell(id=0, cpuset=set([1]), pcpuset=set(),
memory=512),
objects.InstanceNUMACell(id=1, cpuset=set([3, 4, 5]),
pcpuset=set(), memory=512)])
spec_obj = self._get_spec_obj(numa_topology=instance_topology)
host = fakes.FakeHostState('host1', 'node1',
{'numa_topology': fakes.NUMA_TOPOLOGY,
'pci_stats': None,
'cpu_allocation_ratio': 1,
'ram_allocation_ratio': 1.5})
self.assertFalse(self.filt_cls.host_passes(host, spec_obj))
def test_numa_topology_filter_pass_set_limit(self):
instance_topology = objects.InstanceNUMATopology(cells=[
objects.InstanceNUMACell(id=0, cpuset=set([1]), pcpuset=set(),
memory=512),
objects.InstanceNUMACell(id=1, cpuset=set([3]), pcpuset=set(),
memory=512),
])
spec_obj = self._get_spec_obj(numa_topology=instance_topology)
host = fakes.FakeHostState('host1', 'node1',
{'numa_topology': fakes.NUMA_TOPOLOGY,
'pci_stats': None,
'cpu_allocation_ratio': 21,
'ram_allocation_ratio': 1.3})
self.assertTrue(self.filt_cls.host_passes(host, spec_obj))
limits = host.limits['numa_topology']
self.assertEqual(limits.cpu_allocation_ratio, 21)
self.assertEqual(limits.ram_allocation_ratio, 1.3)
def _do_test_numa_topology_filter_cpu_policy(
self, numa_topology, cpu_policy, cpu_thread_policy, passes):
instance_topology = objects.InstanceNUMATopology(cells=[
objects.InstanceNUMACell(
id=0,
cpuset=set(),
pcpuset=set([1]),
memory=512,
cpu_policy=cpu_policy,
cpu_thread_policy=cpu_thread_policy,
),
objects.InstanceNUMACell(
id=1,
cpuset=set(),
pcpuset=set([3]),
memory=512,
cpu_policy=cpu_policy,
cpu_thread_policy=cpu_thread_policy,
),
])
spec_obj = objects.RequestSpec(numa_topology=instance_topology,
pci_requests=None,
instance_uuid=uuids.fake)
extra_specs = [
{},
{
'hw:cpu_policy': cpu_policy,
'hw:cpu_thread_policy': cpu_thread_policy,
}
]
image_props = [
{},
{
'hw_cpu_policy': cpu_policy,
'hw_cpu_thread_policy': cpu_thread_policy,
}
]
host = fakes.FakeHostState('host1', 'node1', {
'numa_topology': numa_topology,
'pci_stats': None,
'cpu_allocation_ratio': 1,
'ram_allocation_ratio': 1.5})
assertion = self.assertTrue if passes else self.assertFalse
# test combinations of image properties and extra specs
for specs, props in itertools.product(extra_specs, image_props):
# ...except for the one where no policy is specified
if specs == props == {}:
continue
fake_flavor = objects.Flavor(memory_mb=1024, extra_specs=specs)
fake_image_props = objects.ImageMetaProps(**props)
fake_image = objects.ImageMeta(properties=fake_image_props)
spec_obj.image = fake_image
spec_obj.flavor = fake_flavor
assertion(self.filt_cls.host_passes(host, spec_obj))
self.assertIsNone(spec_obj.numa_topology.cells[0].cpu_pinning)
def test_numa_topology_filter_fail_cpu_thread_policy_require(self):
cpu_policy = fields.CPUAllocationPolicy.DEDICATED
cpu_thread_policy = fields.CPUThreadAllocationPolicy.REQUIRE
numa_topology = fakes.NUMA_TOPOLOGY
self._do_test_numa_topology_filter_cpu_policy(
numa_topology, cpu_policy, cpu_thread_policy, False)
def test_numa_topology_filter_pass_cpu_thread_policy_require(self):
cpu_policy = fields.CPUAllocationPolicy.DEDICATED
cpu_thread_policy = fields.CPUThreadAllocationPolicy.REQUIRE
for numa_topology in fakes.NUMA_TOPOLOGIES_W_HT:
self._do_test_numa_topology_filter_cpu_policy(
numa_topology, cpu_policy, cpu_thread_policy, True)
def test_numa_topology_filter_pass_cpu_thread_policy_others(self):
cpu_policy = fields.CPUAllocationPolicy.DEDICATED
numa_topology = fakes.NUMA_TOPOLOGY
for cpu_thread_policy in [
fields.CPUThreadAllocationPolicy.PREFER,
fields.CPUThreadAllocationPolicy.ISOLATE]:
self._do_test_numa_topology_filter_cpu_policy(
numa_topology, cpu_policy, cpu_thread_policy, True)
def test_numa_topology_filter_pass_mempages(self):
instance_topology = objects.InstanceNUMATopology(cells=[
objects.InstanceNUMACell(
id=0, cpuset=set([3]), pcpuset=set(), memory=128, pagesize=4),
objects.InstanceNUMACell(
id=1, cpuset=set([1]), pcpuset=set(), memory=128, pagesize=16),
])
spec_obj = self._get_spec_obj(numa_topology=instance_topology)
host = fakes.FakeHostState('host1', 'node1',
{'numa_topology': fakes.NUMA_TOPOLOGY,
'pci_stats': None,
'cpu_allocation_ratio': 16.0,
'ram_allocation_ratio': 1.5})
self.assertTrue(self.filt_cls.host_passes(host, spec_obj))
def test_numa_topology_filter_fail_mempages(self):
instance_topology = objects.InstanceNUMATopology(cells=[
objects.InstanceNUMACell(
id=0, cpuset=set([3]), pcpuset=set(), memory=128, pagesize=8),
objects.InstanceNUMACell(
id=1, cpuset=set([1]), pcpuset=set(), memory=128, pagesize=16),
])
spec_obj = self._get_spec_obj(numa_topology=instance_topology)
host = fakes.FakeHostState('host1', 'node1',
{'numa_topology': fakes.NUMA_TOPOLOGY,
'pci_stats': None,
'cpu_allocation_ratio': 16.0,
'ram_allocation_ratio': 1.5})
self.assertFalse(self.filt_cls.host_passes(host, spec_obj))
def _get_fake_host_state_with_networks(self):
network_a = objects.NetworkMetadata(physnets=set(['foo', 'bar']),
tunneled=False)
network_b = objects.NetworkMetadata(physnets=set(), tunneled=True)
host_topology = objects.NUMATopology(cells=[
objects.NUMACell(
id=1,
cpuset=set([1, 2]),
pcpuset=set(),
memory=2048,
cpu_usage=2,
memory_usage=2048,
mempages=[],
siblings=[set([1]), set([2])],
pinned_cpus=set(),
network_metadata=network_a),
objects.NUMACell(
id=2,
cpuset=set([3, 4]),
pcpuset=set(),
memory=2048,
cpu_usage=2,
memory_usage=2048,
mempages=[],
siblings=[set([3]), set([4])],
pinned_cpus=set(),
network_metadata=network_b)])
return fakes.FakeHostState('host1', 'node1', {
'numa_topology': host_topology,
'pci_stats': None,
'cpu_allocation_ratio': 16.0,
'ram_allocation_ratio': 1.5})
def test_numa_topology_filter_pass_networks(self):
host = self._get_fake_host_state_with_networks()
instance_topology = objects.InstanceNUMATopology(cells=[
objects.InstanceNUMACell(id=0, cpuset=set([1]), pcpuset=set(),
memory=512),
objects.InstanceNUMACell(id=1, cpuset=set([3]), pcpuset=set(),
memory=512),
])
network_metadata = objects.NetworkMetadata(
physnets=set(['foo']), tunneled=False)
spec_obj = self._get_spec_obj(numa_topology=instance_topology,
network_metadata=network_metadata)
self.assertTrue(self.filt_cls.host_passes(host, spec_obj))
# this should pass because while the networks are affined to different
# host NUMA nodes, our guest itself has multiple NUMA nodes
network_metadata = objects.NetworkMetadata(
physnets=set(['foo', 'bar']), tunneled=True)
spec_obj = self._get_spec_obj(numa_topology=instance_topology,
network_metadata=network_metadata)
self.assertTrue(self.filt_cls.host_passes(host, spec_obj))
def test_numa_topology_filter_fail_networks(self):
host = self._get_fake_host_state_with_networks()
instance_topology = objects.InstanceNUMATopology(cells=[
objects.InstanceNUMACell(id=0, cpuset=set([1]), pcpuset=set(),
memory=512),
])
# this should fail because the networks are affined to different host
# NUMA nodes but our guest only has a single NUMA node
network_metadata = objects.NetworkMetadata(
physnets=set(['foo']), tunneled=True)
spec_obj = self._get_spec_obj(numa_topology=instance_topology,
network_metadata=network_metadata)
self.assertFalse(self.filt_cls.host_passes(host, spec_obj))