Merge "Make numa_usage_from_instances consider CPU pinning"

This commit is contained in:
Jenkins 2015-01-16 18:28:14 +00:00 committed by Gerrit Code Review
commit 5bbb97f7be
7 changed files with 126 additions and 9 deletions

View File

@ -1822,3 +1822,8 @@ class MemoryPageSizeForbidden(Invalid):
class MemoryPageSizeNotSupported(Invalid):
msg_fmt = _("Page size %(pagesize)s is not supported by the host.")
class CPUPinningInvalid(Invalid):
msg_fmt = _("Cannot pin/unpin cpus %(requested)s from the following "
"pinned set %(pinned)s")

View File

@ -92,6 +92,10 @@ class InstanceNUMACell(base.NovaObject,
return map(set, zip(*[iter(cpu_list)] * threads))
@property
def cpu_pinning_requested(self):
return self.cpu_pinning is not None
def pin(self, vcpu, pcpu):
if vcpu not in self.cpuset:
return
@ -202,3 +206,7 @@ class InstanceNUMATopology(base.NovaObject,
return cls(cells=[
InstanceNUMACell._from_dict(cell_dict)
for cell_dict in data_dict.get('cells', [])])
@property
def cpu_pinning_requested(self):
return all(cell.cpu_pinning_requested for cell in self.cells)

View File

@ -67,6 +67,18 @@ class NUMACell(base.NovaObject,
def avail_memory(self):
return self.memory - self.memory_usage
def pin_cpus(self, cpus):
if self.pinned_cpus & cpus:
raise exception.CPUPinningInvalid(requested=list(cpus),
pinned=list(self.pinned_cpus))
self.pinned_cpus |= cpus
def unpin_cpus(self, cpus):
if (self.pinned_cpus & cpus) != cpus:
raise exception.CPUPinningInvalid(requested=list(cpus),
pinned=list(self.pinned_cpus))
self.pinned_cpus -= cpus
def _to_dict(self):
return {
'id': self.id,

View File

@ -10,6 +10,7 @@
# License for the specific language governing permissions and limitations
# under the License.
import copy
import uuid
import mock
@ -140,6 +141,20 @@ class _TestInstanceNUMATopology(object):
inst_cell = objects.InstanceNUMACell()
self.assertEqual(0, len(inst_cell.obj_get_changes()))
def test_cpu_pinning_requested_cell(self):
inst_cell = objects.InstanceNUMACell(cpuset=set([0, 1, 2, 3]),
cpu_pinning=None)
self.assertFalse(inst_cell.cpu_pinning_requested)
inst_cell.cpu_pinning = {}
self.assertTrue(inst_cell.cpu_pinning_requested)
def test_cpu_pinning_requested(self):
fake_topo_obj = copy.deepcopy(fake_obj_numa_topology)
self.assertFalse(fake_topo_obj.cpu_pinning_requested)
for cell in fake_topo_obj.cells:
cell.cpu_pinning = dict(zip(*map(list, [cell.cpuset] * 2)))
self.assertTrue(fake_topo_obj.cpu_pinning_requested)
class TestInstanceNUMATopology(test_objects._LocalTest,
_TestInstanceNUMATopology):

View File

@ -33,7 +33,7 @@ class _TestNUMA(object):
self.assertEqual(d1, d2)
def test_pinning_logic(self):
def test_free_cpus(self):
obj = objects.NUMATopology(cells=[
objects.NUMACell(
id=0, cpuset=set([1, 2]), memory=512,
@ -48,6 +48,21 @@ class _TestNUMA(object):
self.assertEqual(set([2]), obj.cells[0].free_cpus)
self.assertEqual(set([3, 4]), obj.cells[1].free_cpus)
def test_pinning_logic(self):
numacell = objects.NUMACell(id=0, cpuset=set([1, 2, 3, 4]), memory=512,
cpu_usage=2, memory_usage=256,
pinned_cpus=set([1]))
numacell.pin_cpus(set([2, 3]))
self.assertEqual(set([4]), numacell.free_cpus)
self.assertRaises(exception.CPUPinningInvalid,
numacell.pin_cpus, set([1, 4]))
self.assertRaises(exception.CPUPinningInvalid,
numacell.pin_cpus, set([1, 6]))
self.assertRaises(exception.CPUPinningInvalid,
numacell.unpin_cpus, set([1, 4]))
numacell.unpin_cpus(set([1, 2, 3]))
self.assertEqual(set([1, 2, 3, 4]), numacell.free_cpus)
def test_pages_topology_wipe(self):
pages_topology = objects.NUMAPagesTopology(
size_kb=2048, total=1024, used=512)

View File

@ -1828,3 +1828,56 @@ class CPUPinningTestCase(test.NoDBTestCase, _CPUPinningTestCaseBase):
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)])
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,
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)])
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])

View File

@ -779,7 +779,7 @@ def _numa_fit_instance_cell(host_cell, instance_cell, limit_cell=None):
len(instance_cell.cpuset) > len(host_cell.cpuset)):
return None
if instance_cell.cpu_pinning is not None:
if instance_cell.cpu_pinning_requested:
new_instance_cell = _numa_fit_instance_cell_with_pinning(
host_cell, instance_cell)
if not new_instance_cell:
@ -1121,7 +1121,12 @@ def numa_usage_from_instances(host, instances, free=False):
for hostcell in host.cells:
memory_usage = hostcell.memory_usage
cpu_usage = hostcell.cpu_usage
mempages = hostcell.mempages
newcell = objects.NUMACell(
id=hostcell.id, cpuset=hostcell.cpuset, memory=hostcell.memory,
cpu_usage=0, memory_usage=0,
pinned_cpus=hostcell.pinned_cpus, siblings=hostcell.siblings)
for instance in instances:
for instancecell in instance.cells:
if instancecell.id == hostcell.id:
@ -1129,15 +1134,19 @@ def numa_usage_from_instances(host, instances, free=False):
memory_usage + sign * instancecell.memory)
cpu_usage = cpu_usage + sign * len(instancecell.cpuset)
if instancecell.pagesize and instancecell.pagesize > 0:
mempages = _numa_pagesize_usage_from_cell(
newcell.mempages = _numa_pagesize_usage_from_cell(
hostcell, instancecell, sign)
if instance.cpu_pinning_requested:
pinned_cpus = set(instancecell.cpu_pinning.values())
if free:
newcell.unpin_cpus(pinned_cpus)
else:
newcell.pin_cpus(pinned_cpus)
cell = objects.NUMACell(
id=hostcell.id, cpuset=hostcell.cpuset, memory=hostcell.memory,
cpu_usage=max(0, cpu_usage), memory_usage=max(0, memory_usage),
mempages=mempages)
newcell.cpu_usage = max(0, cpu_usage)
newcell.memory_usage = max(0, memory_usage)
cells.append(cell)
cells.append(newcell)
return objects.NUMATopology(cells=cells)