From fc4794acc6b13afade1bb72a1ae9f574707d2f0d Mon Sep 17 00:00:00 2001 From: Kashyap Chamarthy Date: Tue, 8 May 2018 10:52:17 +0200 Subject: [PATCH] libvirt: Deprecate support for monitoring Intel CMT `perf` events Upstream Linux kernel has deleted[*] the `perf` framework integration with Intel CMT (Cache Monitoring Technology; or "CQM" in Linux kernel parlance), because the feature was broken by design -- an incompatibility between Linux's `perf` infrastructure and Intel CMT hardware support. It was removed in upstream kernel version v4.14; but bear in mind that downstream Linux distributions with lower kernel versions than 4.14 have backported the said change. Nova supports monitoring of the above mentioned Intel CMT events (namely: 'cmt', 'mbm_local', and 'mbm_total') via the configuration attribute `[libvirt]/enabled_perf_events`. Given that the underlying Linux kernel infrastructure for Intel CMT is removed, we should remove support for it in Nova too. Otherwise enabling them in Nova, and updating to a Linux kernel 4.14 (or above) will result in instances failing to boot. To that end, deprecate support for the three Intel CMT events in "Rocky" release, with the intention to remove support for it in the upcoming "Stein" release. Note that we cannot deprecate / remove `enabled_perf_events` config attribute altogether -- since there are other[+] `perf` events besides Intel CMT. Whether anyone is using those other events with Nova is a good question to which we don't have an equally good answer for, if at all. [*] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=c39a0e2 [+] https://libvirt.org/formatdomain.html#elementsPerf Closes-Bug: #1751073 Change-Id: I7e77f87650d966d605807c7be184e670259a81c1 Signed-off-by: Kashyap Chamarthy --- nova/conf/libvirt.py | 32 ++++++--- nova/tests/unit/virt/libvirt/test_driver.py | 68 +++++++++++-------- nova/virt/libvirt/driver.py | 16 +++-- ...for-Intel-CMT-events-017fbb890b631d70.yaml | 17 +++++ 4 files changed, 90 insertions(+), 43 deletions(-) create mode 100644 releasenotes/notes/Deprecate-support-for-Intel-CMT-events-017fbb890b631d70.yaml 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 c29d3ba3502c..9ad847797f07 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.