diff --git a/doc/source/admin/cpu-topologies.rst b/doc/source/admin/cpu-topologies.rst index 082c88f655b6..e1e92736deac 100644 --- a/doc/source/admin/cpu-topologies.rst +++ b/doc/source/admin/cpu-topologies.rst @@ -772,6 +772,11 @@ while there could be other tools outside Nova to manage the governor, like tuned. That being said, we also provide a way to automatically change the governors on the fly, as explained below. +.. important:: + Some OS platforms don't support `cpufreq` resources in sysfs, so the + ``governor`` strategy could be not available. Please verify if your OS + supports scaling govenors before modifying the configuration option. + If the strategy is set to ``governor``, a couple of config options are provided to define which exact CPU govenor to use for each of the up and down states : diff --git a/nova/tests/fixtures/filesystem.py b/nova/tests/fixtures/filesystem.py index 932d42fe27ed..0193e6d74520 100644 --- a/nova/tests/fixtures/filesystem.py +++ b/nova/tests/fixtures/filesystem.py @@ -39,10 +39,14 @@ class TempFileSystemFixture(fixtures.Fixture): class SysFileSystemFixture(TempFileSystemFixture): - """Creates a fake /sys filesystem""" + def __init__(self, cpus_supported=None, cpufreq_enabled=True): + """Instantiates a fake sysfs. - def __init__(self, cpus_supported=None): + :param cpus_supported: number of devices/system/cpu (default: 10) + :param cpufreq_enabled: cpufreq subdir created (default: True) + """ self.cpus_supported = cpus_supported or 10 + self.cpufreq_enabled = cpufreq_enabled def _setUp(self): super()._setUp() @@ -73,9 +77,12 @@ class SysFileSystemFixture(TempFileSystemFixture): for cpu_nr in range(self.cpus_supported): cpu_dir = os.path.join(self.cpu_path_mock % {'core': cpu_nr}) - os.makedirs(os.path.join(cpu_dir, 'cpufreq')) - filesystem.write_sys( - os.path.join(cpu_dir, 'cpufreq/scaling_governor'), - data='powersave') + os.makedirs(cpu_dir) + filesystem.write_sys(os.path.join(cpu_dir, 'online'), data='1') + if self.cpufreq_enabled: + os.makedirs(os.path.join(cpu_dir, 'cpufreq')) + filesystem.write_sys( + os.path.join(cpu_dir, 'cpufreq/scaling_governor'), + data='powersave') filesystem.write_sys(core.AVAILABLE_PATH, f'0-{self.cpus_supported - 1}') diff --git a/nova/tests/functional/libvirt/test_power_manage.py b/nova/tests/functional/libvirt/test_power_manage.py index 539b94c68e7c..deef91ede2c1 100644 --- a/nova/tests/functional/libvirt/test_power_manage.py +++ b/nova/tests/functional/libvirt/test_power_manage.py @@ -220,6 +220,39 @@ class PowerManagementTestsGovernor(PowerManagementTestsBase): self.restart_compute_service, hostname='compute1') +class PowerManagementTestsGovernorNotSupported(PowerManagementTestsBase): + """Test suite for OS without governor support usage (same 10-core host)""" + + def setUp(self): + super(PowerManagementTestsGovernorNotSupported, self).setUp() + + self.useFixture(nova_fixtures.SysFileSystemFixture( + cpufreq_enabled=False)) + + # Definining the CPUs to be pinned. + self.flags(cpu_dedicated_set='1-9', cpu_shared_set=None, + group='compute') + self.flags(vcpu_pin_set=None) + self.flags(cpu_power_management=True, group='libvirt') + self.flags(cpu_power_management_strategy='cpu_state', group='libvirt') + + self.flags(allow_resize_to_same_host=True) + self.host_info = fakelibvirt.HostInfo(cpu_nodes=1, cpu_sockets=1, + cpu_cores=5, cpu_threads=2) + + def test_enabling_governor_strategy_fails(self): + self.flags(cpu_power_management_strategy='governor', group='libvirt') + self.assertRaises(exception.FileNotFound, self.start_compute, + host_info=self.host_info, hostname='compute1') + + def test_enabling_cpu_state_strategy_works(self): + self.flags(cpu_power_management_strategy='cpu_state', group='libvirt') + self.compute1 = self.start_compute(host_info=self.host_info, + hostname='compute1') + cpu_dedicated_set = hardware.get_cpu_dedicated_set() + self._assert_cpu_set_state(cpu_dedicated_set, expected='offline') + + class PowerManagementMixedInstances(PowerManagementTestsBase): """Test suite for a single host with 6 dedicated cores, 3 shared and one OS-restricted. diff --git a/nova/tests/unit/virt/libvirt/cpu/test_api.py b/nova/tests/unit/virt/libvirt/cpu/test_api.py index 5e9af44e8ed9..890f4566c472 100644 --- a/nova/tests/unit/virt/libvirt/cpu/test_api.py +++ b/nova/tests/unit/virt/libvirt/cpu/test_api.py @@ -57,6 +57,12 @@ class TestAPI(test.NoDBTestCase): self.assertEqual('fake_governor', self.core_1.governor) mock_get_governor.assert_called_once_with(self.core_1.ident) + @mock.patch.object(core, 'get_governor') + def test_governor_optional(self, mock_get_governor): + mock_get_governor.side_effect = exception.FileNotFound(file_path='foo') + self.assertIsNone(self.core_1.governor) + mock_get_governor.assert_called_once_with(self.core_1.ident) + @mock.patch.object(core, 'set_governor') def test_set_governor_low(self, mock_set_governor): self.flags(cpu_power_governor_low='fake_low_gov', group='libvirt') diff --git a/nova/virt/libvirt/cpu/api.py b/nova/virt/libvirt/cpu/api.py index 060041c0f486..472518843998 100644 --- a/nova/virt/libvirt/cpu/api.py +++ b/nova/virt/libvirt/cpu/api.py @@ -11,6 +11,7 @@ # under the License. from dataclasses import dataclass +import typing as ty from oslo_log import log as logging @@ -59,8 +60,13 @@ class Core: return str(self.ident) @property - def governor(self) -> str: - return core.get_governor(self.ident) + def governor(self) -> ty.Optional[str]: + try: + return core.get_governor(self.ident) + # NOTE(sbauza): cpufreq/scaling_governor is not enabled for some OS + # platforms. + except exception.FileNotFound: + return None def set_high_governor(self) -> None: core.set_governor(self.ident, CONF.libvirt.cpu_power_governor_high) diff --git a/releasenotes/notes/bug-2023018-0f93ca1f679ce259.yaml b/releasenotes/notes/bug-2023018-0f93ca1f679ce259.yaml new file mode 100644 index 000000000000..7d6dfc43db4e --- /dev/null +++ b/releasenotes/notes/bug-2023018-0f93ca1f679ce259.yaml @@ -0,0 +1,9 @@ +--- +fixes: + - | + Some OS platforms don't provide by default cpufreq resources in sysfs, so + they don't have CPU scaling governors. That's why we should let the governor + strategy to be optional for `CPU power management`_. + + .. _CPU power management: https://docs.openstack.org/nova/latest/admin/cpu-topologies.html#configuring-cpu-power-management-for-dedicated-cores +