diff --git a/nova/conf/libvirt.py b/nova/conf/libvirt.py index 0d218807d274..8349455d062e 100644 --- a/nova/conf/libvirt.py +++ b/nova/conf/libvirt.py @@ -696,17 +696,29 @@ Possible cache modes: cfg.ListOpt('enabled_perf_events', default=[], help= """ -This is a performance event list which could be used as monitor. These events -will be passed to libvirt domain xml while creating a new instances. -Then event statistics data can be collected from libvirt. The minimum -libvirt version is 2.0.0. For more information about `Performance monitoring -events`, refer https://libvirt.org/formatdomain.html#elementsPerf . +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. +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_*`` -Possible values: -* A string list. For example: ``enabled_perf_events = cmt, mbml, mbmt`` - The supported events list can be found in - https://libvirt.org/html/libvirt-libvirt-domain.html , - which you may need to search key words ``VIR_PERF_PARAM_*`` +For example, to monitor the count of CPU cycles (total/elapsed) and the +count of cache misses, enable them as follows:: + + [libvirt] + 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. + +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. """), 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 3620f97ef14c..221bd106dedc 100644 --- a/nova/tests/unit/virt/libvirt/test_driver.py +++ b/nova/tests/unit/virt/libvirt/test_driver.py @@ -6567,34 +6567,6 @@ class LibvirtConnTestCase(test.NoDBTestCase, self.assertEqual(events, cfg.perf_events) - @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(host.Host, 'has_min_version', return_value=True) - def test_get_guest_with_perf_supported(self, - mock_min_version): - 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']) - @mock.patch.object(host.Host, 'has_min_version') def test_get_guest_with_perf_libvirt_unsupported(self, mock_min_version): @@ -6627,6 +6599,46 @@ class LibvirtConnTestCase(test.NoDBTestCase, 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) + def test_xml_and_uri_no_ramdisk_no_kernel(self): instance_data = dict(self.test_instance) self._check_xml_and_uri(instance_data, diff --git a/nova/virt/libvirt/driver.py b/nova/virt/libvirt/driver.py index 804e328e0232..2871948a495b 100644 --- a/nova/virt/libvirt/driver.py +++ b/nova/virt/libvirt/driver.py @@ -4740,11 +4740,17 @@ class LibvirtDriver(driver.ComputeDriver): LOG.warning("Libvirt doesn't support event type %s.", event) return False - if (event in PERF_EVENTS_CPU_FLAG_MAPPING - and PERF_EVENTS_CPU_FLAG_MAPPING[event] not in cpu_features): - LOG.warning("Host does not 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, diff --git a/releasenotes/notes/Deprecate-support-for-Intel-CMT-events-017fbb890b631d70.yaml b/releasenotes/notes/Deprecate-support-for-Intel-CMT-events-017fbb890b631d70.yaml new file mode 100644 index 000000000000..a63c14379a5d --- /dev/null +++ b/releasenotes/notes/Deprecate-support-for-Intel-CMT-events-017fbb890b631d70.yaml @@ -0,0 +1,17 @@ +--- +deprecations: + - | + Support to monitor performance events for Intel CMT (Cache + Monitoring Technology, or "CQM" in Linux kernel parlance) -- namely + ``cmt``, ``mbm_local`` and ``mbm_total`` -- via the config attribute + ``[libvirt]/enabled_perf_events`` is now *deprecated* from Nova, and + will be *removed* in the "Stein" release. Otherwise, if you have + enabled those events, and upgraded to Linux kernel 4.14 (or suitable + downstream version), it will result in instances failing to boot. + + That is because the Linux kernel has deleted the `perf` framework + integration with Intel CMT, as the feature was broken by design -- + an incompatibility between Linux's `perf` infrastructure and Intel + CMT. It was removed in upstream Linux version v4.14; but bear in + mind that downstream Linux distributions with lower kernel versions + than 4.14 have backported the said change.