diff --git a/nova/conf/libvirt.py b/nova/conf/libvirt.py index f04ca55ea1e3..4081925c531c 100644 --- a/nova/conf/libvirt.py +++ b/nova/conf/libvirt.py @@ -783,15 +783,13 @@ restricting flavors via host aggregates. cfg.ListOpt('enabled_perf_events', default=[], help= """ +Performance events to monitor and collect statistics for. + This will allow you to specify a list of events to monitor low-level -performance of guests, and collect related statsitics via the libvirt -driver, which in turn uses the Linux kernel's `perf` infrastructure. +performance of guests, and collect related statistics via the libvirt +driver, which in turn uses the Linux kernel's ``perf`` infrastructure. With this config attribute set, Nova will generate libvirt guest XML to -monitor the specified events. For more information, refer to the -"Performance monitoring events" section here: -https://libvirt.org/formatdomain.html#elementsPerf. And here: -https://libvirt.org/html/libvirt-libvirt-domain.html -- look for -``VIR_PERF_PARAM_*`` +monitor the specified events. For example, to monitor the count of CPU cycles (total/elapsed) and the count of cache misses, enable them as follows:: @@ -800,12 +798,11 @@ count of cache misses, enable them as follows:: enabled_perf_events = cpu_clock, cache_misses Possible values: A string list. The list of supported events can be -found here: https://libvirt.org/formatdomain.html#elementsPerf. +found `here`__. Note that Intel CMT events - ``cmt``, ``mbmbt`` and +``mbml`` - are unsupported by recent Linux kernel versions (4.14+) and will be +ignored by nova. -Note that support for Intel CMT events (`cmt`, `mbmbt`, `mbml`) is -deprecated, and will be removed in the "Stein" release. That's because -the upstream Linux kernel (from 4.14 onwards) has deleted support for -Intel CMT, because it is broken by design. +__ https://libvirt.org/formatdomain.html#elementsPerf. """), cfg.IntOpt('num_pcie_ports', default=0, diff --git a/nova/tests/unit/virt/libvirt/test_driver.py b/nova/tests/unit/virt/libvirt/test_driver.py index de41339bcc96..0964ca84dab0 100644 --- a/nova/tests/unit/virt/libvirt/test_driver.py +++ b/nova/tests/unit/virt/libvirt/test_driver.py @@ -8613,97 +8613,19 @@ class LibvirtConnTestCase(test.NoDBTestCase, break self.assertTrue(no_exist) - @mock.patch('nova.virt.libvirt.driver.LOG.warning') - @mock.patch.object(host.Host, 'has_min_version', return_value=True) - @mock.patch.object(host.Host, "get_capabilities") - def test_get_supported_perf_events_foo(self, mock_get_caps, - mock_min_version, - mock_warn): - self.flags(enabled_perf_events=['foo'], group='libvirt') + @mock.patch.object(libvirt_driver, 'LOG') + @mock.patch.object( + fakelibvirt, 'VIR_PERF_PARAM_CPU_CLOCK', 'cpu_clock', create=True) + @mock.patch.object(fakelibvirt, 'VIR_PERF_PARAM_CMT', 'cmt', create=True) + def test_get_supported_perf_events(self, mock_log): + self.flags( + enabled_perf_events=['cpu_clock', 'foo', 'cmt'], group='libvirt') - caps = vconfig.LibvirtConfigCaps() - caps.host = vconfig.LibvirtConfigCapsHost() - caps.host.cpu = vconfig.LibvirtConfigCPU() - caps.host.cpu.arch = fields.Architecture.X86_64 - caps.host.topology = fakelibvirt.NUMATopology() - - mock_get_caps.return_value = caps drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), True) events = drvr._get_supported_perf_events() - self.assertTrue(mock_warn.called) - self.assertEqual([], events) - - @mock.patch.object(host.Host, "get_capabilities") - def _test_get_guest_with_perf(self, caps, events, mock_get_caps): - mock_get_caps.return_value = caps - - drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), True) - drvr.init_host('test_perf') - instance_ref = objects.Instance(**self.test_instance) - image_meta = objects.ImageMeta.from_dict(self.test_image_meta) - - disk_info = blockinfo.get_disk_info(CONF.libvirt.virt_type, - instance_ref, - image_meta) - cfg = drvr._get_guest_config(instance_ref, [], - image_meta, disk_info) - - self.assertEqual(events, cfg.perf_events) - - @mock.patch.object(fakelibvirt, 'VIR_PERF_PARAM_CMT', True, - create=True) - @mock.patch.object(host.Host, 'has_min_version', return_value=True) - def test_get_guest_with_perf_host_unsupported(self, - mock_min_version): - self.flags(enabled_perf_events=['cmt'], group='libvirt') - caps = vconfig.LibvirtConfigCaps() - caps.host = vconfig.LibvirtConfigCapsHost() - caps.host.cpu = vconfig.LibvirtConfigCPU() - caps.host.cpu.arch = fields.Architecture.X86_64 - caps.host.topology = fakelibvirt.NUMATopology() - - self._test_get_guest_with_perf(caps, []) - - @mock.patch.object(fakelibvirt, 'VIR_PERF_PARAM_CMT', True, - create=True) - @mock.patch.object(fakelibvirt, 'VIR_PERF_PARAM_MBMT', True, - create=True) - @mock.patch.object(fakelibvirt, 'VIR_PERF_PARAM_MBML', True, - create=True) - @mock.patch.object(libvirt_driver.LOG, 'warning') - @mock.patch.object(host.Host, 'has_min_version', return_value=True) - def test_intel_cmt_perf_deprecation_warning(self, - mock_min_version, - mock_warn): - perf_events = ['cmt', 'mbml', 'mbmt'] - self.flags(enabled_perf_events=['cmt', 'mbml', 'mbmt'], - group='libvirt') - caps = vconfig.LibvirtConfigCaps() - caps.host = vconfig.LibvirtConfigCapsHost() - caps.host.cpu = vconfig.LibvirtConfigCPU() - caps.host.cpu.arch = fields.Architecture.X86_64 - caps.host.topology = fakelibvirt.NUMATopology() - - features = [] - for f in ('cmt', 'mbm_local', 'mbm_total'): - feature = vconfig.LibvirtConfigGuestCPUFeature() - feature.name = f - feature.policy = fields.CPUFeaturePolicy.REQUIRE - features.append(feature) - - caps.host.cpu.features = set(features) - self._test_get_guest_with_perf(caps, ['cmt', 'mbml', 'mbmt']) - warning_count = 0 - call_args_list = mock_warn.call_args_list - for call in call_args_list: - # Call can be unpackaged as a tuple of args and kwargs - # so we want to check the first arg in the args list - if (len(call) == 2 and len(call[0]) == 2 and - call[0][1] in perf_events and - 'Monitoring Intel CMT' in call[0][0]): - warning_count += 1 - self.assertEqual(3, warning_count) + self.assertEqual(['cpu_clock'], events) + self.assertEqual(2, len(mock_log.warning.mock_calls)) def test_xml_and_uri_no_ramdisk_no_kernel(self): instance_data = dict(self.test_instance) diff --git a/nova/virt/libvirt/driver.py b/nova/virt/libvirt/driver.py index 307b49fa2f1c..532a0aa113e0 100644 --- a/nova/virt/libvirt/driver.py +++ b/nova/virt/libvirt/driver.py @@ -248,11 +248,6 @@ VGPU_RESOURCE_SEMAPHORE = 'vgpu_resources' LIBVIRT_PERF_EVENT_PREFIX = 'VIR_PERF_PARAM_' -PERF_EVENTS_CPU_FLAG_MAPPING = {'cmt': 'cmt', - 'mbml': 'mbm_local', - 'mbmt': 'mbm_total', - } - MIN_LIBVIRT_FILE_BACKED_DISCARD_VERSION = (4, 4, 0) MIN_LIBVIRT_NATIVE_TLS_VERSION = (4, 4, 0) @@ -5688,38 +5683,29 @@ class LibvirtDriver(driver.ComputeDriver): caps.host.cpu.arch == fields.Architecture.AARCH64)) def _get_supported_perf_events(self): - - if (len(CONF.libvirt.enabled_perf_events) == 0): + if not len(CONF.libvirt.enabled_perf_events): return [] supported_events = [] - host_cpu_info = self._get_cpu_info() for event in CONF.libvirt.enabled_perf_events: - if self._supported_perf_event(event, host_cpu_info['features']): - supported_events.append(event) + libvirt_perf_event_name = LIBVIRT_PERF_EVENT_PREFIX + event.upper() + + if not hasattr(libvirt, libvirt_perf_event_name): + LOG.warning("Libvirt does not support event type '%s'.", event) + continue + + if event in ('cmt', 'mbml', 'mbmt'): + LOG.warning( + "Monitoring of Intel CMT `perf` event(s) '%s' is not " + "supported by recent Linux kernels; ignoring.", + event, + ) + continue + + supported_events.append(event) + return supported_events - def _supported_perf_event(self, event, cpu_features): - - libvirt_perf_event_name = LIBVIRT_PERF_EVENT_PREFIX + event.upper() - - if not hasattr(libvirt, libvirt_perf_event_name): - LOG.warning("Libvirt doesn't support event type %s.", event) - return False - - if event in PERF_EVENTS_CPU_FLAG_MAPPING: - LOG.warning('Monitoring Intel CMT `perf` event(s) %s is ' - 'deprecated and will be removed in the "Stein" ' - 'release. It was broken by design in the ' - 'Linux kernel, so support for Intel CMT was ' - 'removed from Linux 4.14 onwards. Therefore ' - 'it is recommended to not enable them.', - event) - if PERF_EVENTS_CPU_FLAG_MAPPING[event] not in cpu_features: - LOG.warning("Host does not support event type %s.", event) - return False - return True - def _configure_guest_by_virt_type(self, guest, virt_type, caps, instance, image_meta, flavor, root_device_name, sev_enabled): diff --git a/releasenotes/notes/remove-intel-cmt-perf-events-69df7324d6fe41a8.yaml b/releasenotes/notes/remove-intel-cmt-perf-events-69df7324d6fe41a8.yaml new file mode 100644 index 000000000000..33108f5cdde6 --- /dev/null +++ b/releasenotes/notes/remove-intel-cmt-perf-events-69df7324d6fe41a8.yaml @@ -0,0 +1,7 @@ +--- +upgrade: + - | + Intel CMT perf events - ``cmt``, ``mbmt``, and ``mbml`` - are no longer + supported by the ``[libvirt] enabled_perf_events`` config option. These + event types were broken by design and are not supported in recent Linux + kernels (4.14+).