Support reporting multi CPU model traits

Change existing method: '_get_cpu_traits'. Make it support report multi
CPU model's traits.

Change-Id: I448f9fe02acda111aa90b3ea17e53bc0c27cd09d
Implements: blueprint cpu-model-selection
This commit is contained in:
ya.wang 2019-07-11 19:36:40 +08:00
parent ac7a0e8409
commit 3d31d97eca
2 changed files with 153 additions and 15 deletions

View File

@ -22242,6 +22242,138 @@ class LibvirtDriverTestCase(test.NoDBTestCase, TraitsComparisonMixin):
</cpu>
'''], 1)
@mock.patch('nova.virt.libvirt.host.libvirt.Connection.getCapabilities')
@mock.patch('nova.virt.libvirt.host.libvirt.Connection.baselineCPU')
def test_cpu_traits_with_mode_custom_multi_models(self, mocked_baseline,
mocked_cap):
"""Test getting CPU traits when cpu_mode is 'custom' and cpu_model is
['qemu64', 'SandyBridge'], and guest CPU model is Broadwell-noTSX,
traits are calculated from _fake_qemu64_cpu_feature and
_fake_sandy_bridge_cpu_feature.
"""
self.flags(cpu_mode='custom',
cpu_models=['QEMU64', 'sandybridge'],
group='libvirt')
mocked_cap.return_value = '''
<capabilities>
<host>
<uuid>cef19ce0-0ca2-11df-855d-b19fbce37686</uuid>
<cpu>
<arch>x86_64</arch>
<model>Broadwell-noTSX</model>
<topology sockets='1' cores='2' threads='2'/>
<feature policy='require' name='erms'/>
<pages unit='KiB' size='4' />
<pages unit='KiB' size='1024' />
</cpu>
</host>
</capabilities>
'''
mocked_baseline.side_effect = (_fake_broadwell_cpu_feature,
_fake_qemu64_cpu_feature,
_fake_sandy_bridge_cpu_feature)
self.assertTraitsEqual(
[
'HW_CPU_X86_AVX',
'HW_CPU_X86_AESNI',
'HW_CPU_X86_SSE42',
'HW_CPU_X86_SSE41',
'HW_CPU_X86_CLMUL',
'HW_CPU_X86_SSSE3',
'HW_CPU_X86_SSE2',
'HW_CPU_X86_SSE',
'HW_CPU_X86_MMX',
'HW_CPU_X86_SVM'
], self.drvr._get_cpu_feature_traits()
)
calls = [mock.call([u'''<cpu>
<arch>x86_64</arch>
<model>Broadwell-noTSX</model>
<topology sockets="1" cores="2" threads="2"/>
<feature name="erms"/>
</cpu>
'''], 1), mock.call([u'''<cpu>
<arch>x86_64</arch>
<model>qemu64</model>
<topology sockets="1" cores="2" threads="2"/>
</cpu>
'''], 1), mock.call([u'''<cpu>
<arch>x86_64</arch>
<model>SandyBridge</model>
<topology sockets="1" cores="2" threads="2"/>
</cpu>
'''], 1)]
mocked_baseline.assert_has_calls(calls)
@mock.patch('nova.virt.libvirt.host.libvirt.Connection.getCapabilities')
@mock.patch('nova.virt.libvirt.host.libvirt.Connection.baselineCPU')
def test_cpu_traits_with_mode_custom_multi_models_and_extra_flags(self,
mocked_baseline, mocked_cap):
"""Test getting CPU traits when cpu_mode is 'custom' and cpu_model is
['qemu64', 'SandyBridge'], cpu_model_extra_specs is ['pcid', 'avx2']
and guest CPU model is Broadwell-noTSX, traits are calculated from
_fake_qemu64_cpu_feature and _fake_sandy_bridge_cpu_feature.
"""
self.flags(cpu_mode='custom',
cpu_models=['QEMU64', 'sandybridge'],
cpu_model_extra_flags=['pcid', 'avx2'],
group='libvirt')
mocked_cap.return_value = '''
<capabilities>
<host>
<uuid>cef19ce0-0ca2-11df-855d-b19fbce37686</uuid>
<cpu>
<arch>x86_64</arch>
<model>Broadwell-noTSX</model>
<topology sockets='1' cores='2' threads='2'/>
<feature policy='require' name='erms'/>
<pages unit='KiB' size='4' />
<pages unit='KiB' size='1024' />
</cpu>
</host>
</capabilities>
'''
mocked_baseline.side_effect = (_fake_broadwell_cpu_feature,
_fake_qemu64_cpu_feature,
_fake_sandy_bridge_cpu_feature)
self.assertTraitsEqual(
[
'HW_CPU_X86_AVX',
'HW_CPU_X86_AVX2',
'HW_CPU_X86_AESNI',
'HW_CPU_X86_SSE42',
'HW_CPU_X86_SSE41',
'HW_CPU_X86_CLMUL',
'HW_CPU_X86_SSSE3',
'HW_CPU_X86_SSE2',
'HW_CPU_X86_SSE',
'HW_CPU_X86_MMX',
'HW_CPU_X86_SVM'
], self.drvr._get_cpu_feature_traits()
)
calls = [mock.call([u'''<cpu>
<arch>x86_64</arch>
<model>Broadwell-noTSX</model>
<topology sockets="1" cores="2" threads="2"/>
<feature name="erms"/>
</cpu>
'''], 1), mock.call([u'''<cpu>
<arch>x86_64</arch>
<model>qemu64</model>
<topology sockets="1" cores="2" threads="2"/>
</cpu>
'''], 1), mock.call([u'''<cpu>
<arch>x86_64</arch>
<model>SandyBridge</model>
<topology sockets="1" cores="2" threads="2"/>
</cpu>
'''], 1)]
mocked_baseline.assert_has_calls(calls)
@mock.patch('nova.virt.libvirt.host.libvirt.Connection.baselineCPU')
def test_cpu_traits_with_no_baseline_support(self, mock_baseline):
"""Test getting CPU traits when baseline call is not supported."""
@ -22339,7 +22471,6 @@ class LibvirtDriverTestCase(test.NoDBTestCase, TraitsComparisonMixin):
<model fallback='forbid'>IvyBridge</model>
<vendor>Intel</vendor>
<feature policy='require' name='erms'/>
<feature policy='require' name='pcid'/>
</cpu>
"""
self.drvr._get_cpu_feature_traits()
@ -22348,7 +22479,6 @@ class LibvirtDriverTestCase(test.NoDBTestCase, TraitsComparisonMixin):
<model>IvyBridge</model>
<vendor>Intel</vendor>
<topology sockets="1" cores="2" threads="1"/>
<feature name="pcid"/>
</cpu>
'''], 1)
self.assertItemsEqual(['pcid', 'erms'], mock_to_traits.call_args[0][0])

View File

@ -9781,27 +9781,35 @@ class LibvirtDriver(driver.ComputeDriver):
caps.host.cpu.features | cpu.features]
return libvirt_utils.cpu_features_to_traits(host_features)
def _resolve_features(cpu):
xml_str = cpu.to_xml()
features_xml = self._get_guest_baseline_cpu_features(xml_str)
feature_names = []
if features_xml:
cpu = vconfig.LibvirtConfigCPU()
cpu.parse_str(features_xml)
feature_names = [f.name for f in cpu.features]
return feature_names
features = set()
# Choose a default CPU model when cpu_mode is not specified
if cpu.mode is None:
caps.host.cpu.model = libvirt_utils.get_cpu_model_from_arch(
caps.host.cpu.arch)
caps.host.cpu.features = set()
features = features.union(_resolve_features(caps.host.cpu))
else:
# For custom mode, set model to guest CPU model
caps.host.cpu.model = cpu.model
caps.host.cpu.features = set()
models = [self._get_cpu_model_mapping(model)
for model in CONF.libvirt.cpu_models]
# For custom mode, iterate through cpu models
for model in models:
caps.host.cpu.model = model
caps.host.cpu.features = set()
features = features.union(_resolve_features(caps.host.cpu))
# Account for features in cpu_model_extra_flags conf
for f in cpu.features:
caps.host.cpu.add_feature(
vconfig.LibvirtConfigCPUFeature(name=f.name))
features = features.union([f.name for f in cpu.features])
xml_str = caps.host.cpu.to_xml()
features_xml = self._get_guest_baseline_cpu_features(xml_str)
feature_names = []
if features_xml:
cpu.parse_str(features_xml)
feature_names = [f.name for f in cpu.features]
return libvirt_utils.cpu_features_to_traits(feature_names)
return libvirt_utils.cpu_features_to_traits(features)
def _get_guest_baseline_cpu_features(self, xml_str):
"""Calls libvirt's baselineCPU API to compute the biggest set of