Skip empty cpu pinning and hugepages

If there is no specified hugepages or CPU pinning
distributors shouldn't be called. Also changed
initialization of custom_hugepages type.

Change-Id: Iedb819b1da7dcb3877a6a94b9e7cfb93aa949a9e
Closes-Bug: #1594443
(cherry picked from commit 661ce479a6)
This commit is contained in:
Artur Svechnikov 2016-07-13 11:42:08 +03:00 committed by Georgy Kibardin
parent 7184b2229e
commit a6434023f1
7 changed files with 111 additions and 32 deletions

View File

@ -464,6 +464,10 @@ class NodeAttributesValidator(base.BasicAttributesValidator):
@classmethod
def _validate_cpu_pinning(cls, node, attrs):
if not objects.NodeAttributes.is_cpu_pinning_enabled(
node, attributes=attrs):
return
pining_info = objects.NodeAttributes.node_cpu_pinning_info(node, attrs)
# check that we have at least one CPU for operating system
@ -477,6 +481,28 @@ class NodeAttributesValidator(base.BasicAttributesValidator):
@classmethod
def _validate_hugepages(cls, node, attrs):
if not objects.NodeAttributes.is_hugepages_enabled(
node, attributes=attrs):
return
hugepage_sizes = set(
objects.NodeAttributes.total_hugepages(node, attributes=attrs)
)
supported_hugepages = set(
str(page)
for page in node.meta['numa_topology']['supported_hugepages']
)
if not hugepage_sizes.issubset(supported_hugepages):
raise errors.InvalidData(
"Node {0} doesn't support {1} Huge Page(s), supported Huge"
" Page(s): {2}.".format(
node.id,
", ".join(hugepage_sizes - supported_hugepages),
", ".join(supported_hugepages)
)
)
try:
objects.NodeAttributes.distribute_hugepages(node, attrs)
except ValueError as exc:

View File

@ -1095,14 +1095,16 @@ class Node(NailgunObject):
kernel_params += ' amd_iommu=on'
break
if 'hugepages' not in kernel_params:
if ('hugepages' not in kernel_params
and NodeAttributes.is_hugepages_enabled(instance)):
kernel_params += NodeAttributes.hugepages_kernel_opts(instance)
isolated_cpus = NodeAttributes.distribute_node_cpus(
instance)['isolated_cpus']
if isolated_cpus and 'isolcpus' not in kernel_params:
kernel_params += " isolcpus={0}".format(
",".join(six.moves.map(str, isolated_cpus)))
if NodeAttributes.is_cpu_pinning_enabled(instance):
isolated_cpus = NodeAttributes.distribute_node_cpus(
instance)['isolated_cpus']
if isolated_cpus and 'isolcpus' not in kernel_params:
kernel_params += " isolcpus={0}".format(
",".join(six.moves.map(str, isolated_cpus)))
return kernel_params
@ -1413,14 +1415,15 @@ class NodeAttributes(object):
@classmethod
def set_default_hugepages(cls, node):
supported_hugepages = node.meta['numa_topology']['supported_hugepages']
hugepages = cls._safe_get_hugepages(node)
if not hugepages:
return
sizes = [x[0] for x in consts.HUGE_PAGES_SIZE_MAP]
for attrs in six.itervalues(hugepages):
if attrs.get('type') == 'custom_hugepages':
attrs['value'] = dict.fromkeys(supported_hugepages, 0)
attrs['value'] = dict.fromkeys(sizes, 0)
Node.update_attributes(node, {'hugepages': hugepages})
@ -1457,11 +1460,6 @@ class NodeAttributes(object):
return {'total_required_cpus': total_required_cpus,
'components': components}
@classmethod
def is_nova_cpu_pinning_enabled(cls, node):
cpu_pinning = cls._safe_get_cpu_pinning(node)
return 'nova' in cpu_pinning and bool(cpu_pinning['nova']['value'])
@staticmethod
def pages_per_numa_node(size):
"""Convert memory size to 2 MiB pages count.
@ -1473,7 +1471,7 @@ class NodeAttributes(object):
return int(math.ceil(float(size) / 2))
@classmethod
def total_hugepages(cls, node):
def total_hugepages(cls, node, attributes=None):
"""Return total hugepages for the node
Iterate over hugepages attributes and sum them
@ -1490,7 +1488,9 @@ class NodeAttributes(object):
hugepages = collections.defaultdict(int)
numa_count = len(node.meta['numa_topology']['numa_nodes'])
hugepages_attributes = cls._safe_get_hugepages(node)
hugepages_attributes = cls._safe_get_hugepages(
node, attributes=attributes)
for name, attrs in six.iteritems(hugepages_attributes):
if attrs.get('type') == 'custom_hugepages':
value = attrs['value']
@ -1503,6 +1503,10 @@ class NodeAttributes(object):
hugepages[consts.DEFAULT_HUGEPAGE_SIZE] += (
count_per_numa_node * numa_count)
for size in list(hugepages):
if not hugepages[size]:
hugepages.pop(size)
return hugepages
@classmethod
@ -1522,15 +1526,39 @@ class NodeAttributes(object):
return kernel_opts
@classmethod
def is_nova_hugepages_enabled(cls, node):
hugepages = cls._safe_get_hugepages(node)
def is_hugepages_enabled(cls, node, attributes=None):
return (
cls.is_nova_hugepages_enabled(node, attributes=attributes)
or cls.is_dpdk_hugepages_enabled(node, attributes=attributes)
)
@classmethod
def is_cpu_pinning_enabled(cls, node, attributes=None):
return (
cls.is_nova_cpu_pinning_enabled(node, attributes=attributes)
or cls.is_dpdk_cpu_pinning_enabled(node, attributes=attributes)
)
@classmethod
def is_dpdk_cpu_pinning_enabled(cls, node, attributes=None):
cpu_pinning = cls._safe_get_cpu_pinning(node, attributes=attributes)
return 'dpdk' in cpu_pinning and bool(cpu_pinning['dpdk']['value'])
@classmethod
def is_nova_cpu_pinning_enabled(cls, node, attributes=None):
cpu_pinning = cls._safe_get_cpu_pinning(node, attributes=attributes)
return 'nova' in cpu_pinning and bool(cpu_pinning['nova']['value'])
@classmethod
def is_nova_hugepages_enabled(cls, node, attributes=None):
hugepages = cls._safe_get_hugepages(node, attributes=attributes)
return ('nova' in hugepages and
any(six.itervalues(hugepages['nova']['value'])))
@classmethod
def is_dpdk_hugepages_enabled(cls, node):
return int(Node.get_attributes(
node)['hugepages']['dpdk']['value']) != 0
def is_dpdk_hugepages_enabled(cls, node, attributes=None):
hugepages = cls._safe_get_hugepages(node, attributes=attributes)
return 'dpdk' in hugepages and bool(hugepages['dpdk']['value'])
@classmethod
def dpdk_hugepages_attrs(cls, node):

View File

@ -584,6 +584,9 @@ class DeploymentHASerializer90(DeploymentHASerializer80):
self.generate_node_hugepages(node, serialized_node)
def generate_cpu_pinning(self, node, serialized_node):
if not objects.NodeAttributes.is_cpu_pinning_enabled(node):
return
pinning_info = objects.NodeAttributes.distribute_node_cpus(node)
cpu_pinning = pinning_info['components']
@ -599,6 +602,8 @@ class DeploymentHASerializer90(DeploymentHASerializer80):
serialized_node['cpu_pinning'] = cpu_pinning
def generate_node_hugepages(self, node, serialized_node):
if not objects.NodeAttributes.is_hugepages_enabled(node):
return
self._generate_nova_hugepages(node, serialized_node)
self._generate_dpdk_hugepages(node, serialized_node)
self._generate_hugepages_distribution(node, serialized_node)

View File

@ -373,7 +373,7 @@ class TestDeploymentAttributesSerialization90(
self.assertEqual(serialized_node['dpdk']['ovs_core_mask'], '0x2')
self.assertEqual(serialized_node['dpdk']['ovs_pmd_core_mask'], '0x4')
self.assertNotIn('cpu_pinning', serialized_node['nova'])
self.assertNotIn('cpu_pinning', serialized_node.get('nova', {}))
node_name = objects.Node.get_slave_name(node)
network_data = serialized_for_astute['common']['network_metadata']

View File

@ -364,7 +364,7 @@ class TestTaskDeploy90(BaseIntegrationTest):
'type': 'puppet',
'roles': ['compute'],
'condition': {
'yaql_exp': 'changedAny($.network_scheme, $.dpdk)',
'yaql_exp': 'changedAny($.network_scheme, $.get(dpdk))',
},
'parameters': {},
},
@ -374,7 +374,7 @@ class TestTaskDeploy90(BaseIntegrationTest):
'type': 'puppet',
'roles': ['compute'],
'condition': {
'yaql_exp': 'changedAny($.network_scheme, $.dpdk)',
'yaql_exp': 'changedAny($.network_scheme, $.get(dpdk))',
},
'parameters': {},
}]
@ -453,7 +453,7 @@ class TestTaskDeploy90AfterDeployment(BaseIntegrationTest):
.filter_by(task_name='netconfig')\
.update({
'condition': {
'yaql_exp': 'changedAny($.network_scheme, $.dpdk)',
'yaql_exp': 'changedAny($.network_scheme, $.get(dpdk))',
}
})

View File

@ -166,7 +166,7 @@ class TestNodeAttributes(base.BaseUnitTest):
objects.NodeAttributes.distribute_hugepages(node), expected)
def test_set_default_hugepages(self):
fake_hugepages = ['0', '1', '2', '3']
hugepages = ['2048', '1048576']
node = mock.Mock(
id=1,
attributes={
@ -177,12 +177,8 @@ class TestNodeAttributes(base.BaseUnitTest):
}
}
},
meta={
'numa_topology': {
'supported_hugepages': fake_hugepages,
'numa_nodes': []}}
)
objects.NodeAttributes.set_default_hugepages(node)
hugepages = node.attributes['hugepages']['nova']['value']
for size in fake_hugepages:
self.assertEqual(0, hugepages[size])
nova_hugepages = node.attributes['hugepages']['nova']['value']
for size in hugepages:
self.assertEqual(0, nova_hugepages[size])

View File

@ -146,6 +146,30 @@ class TestNodeAttributesValidatorHugepages(BaseNodeAttributeValidatorTest):
errors.InvalidData, 'could not require more memory than node has',
validator, json.dumps(data), self.node, self.cluster)
@mock_cluster_attributes
def test_limited_supported_hugepages(self, m_dpdk_nics):
data = {
'hugepages': {
'nova': {
'value': {
'2048': 3,
'1048576': 0,
},
},
},
}
self.node.meta['numa_topology']['supported_hugepages'] = ['2048']
self.assertNotRaises(errors.InvalidData, validator,
json.dumps(data), self.node, self.cluster)
data['hugepages']['nova']['value']['1048576'] = 1
self.assertRaisesWithMessageIn(
errors.InvalidData,
"Node 1 doesn't support 1048576 Huge Page(s),"
" supported Huge Page(s): 2048.",
validator, json.dumps(data), self.node, self.cluster)
@mock.patch.object(objects.Node, 'dpdk_nics', return_value=[])
class TestNodeAttributesValidatorCpuPinning(BaseNodeAttributeValidatorTest):