From f8c243f448dbb02307ccadc96d9e585091c62060 Mon Sep 17 00:00:00 2001 From: zhang-shaoman Date: Thu, 13 Jul 2017 17:39:24 +0800 Subject: [PATCH] Add memory swap metric Add memory swap metric for VM, including: memory.swap.in memory.swap.out Change-Id: Ia529fe7cb2df41099f62052089332d138cb3dedb Implements: blueprint add-memory-swap-metric --- .../compute/pollsters/instance_stats.py | 12 +++++ ceilometer/compute/virt/inspector.py | 2 + ceilometer/compute/virt/libvirt/inspector.py | 6 +++ .../dispatcher/data/gnocchi_resources.yaml | 2 + .../unit/compute/pollsters/test_memory.py | 46 +++++++++++++++++++ .../compute/virt/libvirt/test_inspector.py | 8 +++- .../tests/unit/dispatcher/test_gnocchi.py | 1 + ...d-memory-swap-metric-f1633962ab2cf0f6.yaml | 5 ++ setup.cfg | 2 + 9 files changed, 83 insertions(+), 1 deletion(-) create mode 100644 releasenotes/notes/add-memory-swap-metric-f1633962ab2cf0f6.yaml diff --git a/ceilometer/compute/pollsters/instance_stats.py b/ceilometer/compute/pollsters/instance_stats.py index a0ad4ebf65..48aee0b717 100644 --- a/ceilometer/compute/pollsters/instance_stats.py +++ b/ceilometer/compute/pollsters/instance_stats.py @@ -51,6 +51,18 @@ class MemoryResidentPollster(InstanceStatsPollster): sample_stats_key = 'memory_resident' +class MemorySwapInPollster(InstanceStatsPollster): + sample_name = 'memory.swap.in' + sample_unit = 'MB' + sample_stats_key = 'memory_swap_in' + + +class MemorySwapOutPollster(InstanceStatsPollster): + sample_name = 'memory.swap.out' + sample_unit = 'MB' + sample_stats_key = 'memory_swap_out' + + class PerfCPUCyclesPollster(InstanceStatsPollster): sample_name = 'perf.cpu.cycles' sample_stats_key = 'cpu_cycles' diff --git a/ceilometer/compute/virt/inspector.py b/ceilometer/compute/virt/inspector.py index a4f62e0ad8..7f6f5174f7 100644 --- a/ceilometer/compute/virt/inspector.py +++ b/ceilometer/compute/virt/inspector.py @@ -45,6 +45,8 @@ class InstanceStats(object): 'cpu_l3_cache_usage', # cachesize: Amount of CPU L3 cache used 'memory_usage', # usage: Amount of memory used 'memory_resident', # + 'memory_swap_in', # memory swap in + 'memory_swap_out', # memory swap out 'memory_bandwidth_total', # total: total system bandwidth from one # level of cache 'memory_bandwidth_local', # local: bandwidth of memory traffic for a diff --git a/ceilometer/compute/virt/libvirt/inspector.py b/ceilometer/compute/virt/libvirt/inspector.py index 3fd1625fe9..a852c815b4 100644 --- a/ceilometer/compute/virt/libvirt/inspector.py +++ b/ceilometer/compute/virt/libvirt/inspector.py @@ -161,6 +161,7 @@ class LibvirtInspector(virt_inspector.Inspector): domain = self._get_domain_not_shut_off_or_raise(instance) memory_used = memory_resident = None + memory_swap_in = memory_swap_out = None memory_stats = domain.memoryStats() # Stat provided from libvirt is in KB, converting it to MB. if 'available' in memory_stats and 'unused' in memory_stats: @@ -168,6 +169,9 @@ class LibvirtInspector(virt_inspector.Inspector): memory_stats['unused']) / units.Ki if 'rss' in memory_stats: memory_resident = memory_stats['rss'] / units.Ki + if 'swap_in' in memory_stats and 'swap_out' in memory_stats: + memory_swap_in = memory_stats['swap_in'] / units.Ki + memory_swap_out = memory_stats['swap_out'] / units.Ki # TODO(sileht): stats also have the disk/vnic info # we could use that instead of the old method for Queen @@ -198,6 +202,8 @@ class LibvirtInspector(virt_inspector.Inspector): cpu_time=cpu_time, memory_usage=memory_used, memory_resident=memory_resident, + memory_swap_in=memory_swap_in, + memory_swap_out=memory_swap_out, cpu_cycles=stats.get("perf.cpu_cycles"), instructions=stats.get("perf.instructions"), cache_references=stats.get("perf.cache_references"), diff --git a/ceilometer/dispatcher/data/gnocchi_resources.yaml b/ceilometer/dispatcher/data/gnocchi_resources.yaml index 288f783fc4..e462551f61 100644 --- a/ceilometer/dispatcher/data/gnocchi_resources.yaml +++ b/ceilometer/dispatcher/data/gnocchi_resources.yaml @@ -37,6 +37,8 @@ resources: - 'memory' - 'memory.usage' - 'memory.resident' + - 'memory.swap.in' + - 'memory.swap.out' - 'memory.bandwidth.total' - 'memory.bandwidth.local' - 'vcpus' diff --git a/ceilometer/tests/unit/compute/pollsters/test_memory.py b/ceilometer/tests/unit/compute/pollsters/test_memory.py index 353a9d179d..6ce8fc4575 100644 --- a/ceilometer/tests/unit/compute/pollsters/test_memory.py +++ b/ceilometer/tests/unit/compute/pollsters/test_memory.py @@ -103,6 +103,52 @@ class TestResidentMemoryPollster(base.TestPollsterBase): _verify_resident_memory_metering(0, 0, 0) +class TestMemorySwapPollster(base.TestPollsterBase): + + @mock.patch('ceilometer.pipeline.setup_pipeline', mock.MagicMock()) + def test_get_samples(self): + self._mock_inspect_instance( + virt_inspector.InstanceStats(memory_swap_in=1.0, + memory_swap_out=2.0), + virt_inspector.InstanceStats(memory_swap_in=3.0, + memory_swap_out=4.0), + ) + + mgr = manager.AgentManager(0, self.CONF) + + def _check_memory_swap_in(expected_swap_in): + pollster = instance_stats.MemorySwapInPollster(self.CONF) + + samples = list(pollster.get_samples(mgr, {}, [self.instance])) + self.assertEqual(1, len(samples)) + self.assertEqual(set(['memory.swap.in']), + set([s.name for s in samples])) + self.assertEqual(expected_swap_in, samples[0].volume) + + def _check_memory_swap_out(expected_swap_out): + pollster = instance_stats.MemorySwapOutPollster(self.CONF) + + samples = list(pollster.get_samples(mgr, {}, [self.instance])) + self.assertEqual(1, len(samples)) + self.assertEqual(set(['memory.swap.out']), + set([s.name for s in samples])) + self.assertEqual(expected_swap_out, samples[0].volume) + + _check_memory_swap_in(1.0) + _check_memory_swap_out(4.0) + + @mock.patch('ceilometer.pipeline.setup_pipeline', mock.MagicMock()) + def test_get_samples_with_empty_stats(self): + self._mock_inspect_instance(virt_inspector.NoDataException()) + mgr = manager.AgentManager(0, self.CONF) + pollster = instance_stats.MemorySwapInPollster(self.CONF) + + def all_samples(): + return list(pollster.get_samples(mgr, {}, [self.instance])) + + self.assertRaises(plugin_base.PollsterPermanentError, all_samples) + + class TestMemoryBandwidthPollster(base.TestPollsterBase): @mock.patch('ceilometer.pipeline.setup_pipeline', mock.MagicMock()) diff --git a/ceilometer/tests/unit/compute/virt/libvirt/test_inspector.py b/ceilometer/tests/unit/compute/virt/libvirt/test_inspector.py index 1b2e32f124..954cd07bc3 100644 --- a/ceilometer/tests/unit/compute/virt/libvirt/test_inspector.py +++ b/ceilometer/tests/unit/compute/virt/libvirt/test_inspector.py @@ -55,7 +55,9 @@ class TestLibvirtInspection(base.BaseTestCase): domain.info.return_value = (0, 0, 0, 2, 999999) domain.memoryStats.return_value = {'available': 51200, 'unused': 25600, - 'rss': 30000} + 'rss': 30000, + 'swap_in': 5120, + 'swap_out': 8192} conn = mock.Mock() conn.lookupByUUIDString.return_value = domain conn.domainListGetStats.return_value = [({}, { @@ -82,6 +84,8 @@ class TestLibvirtInspection(base.BaseTestCase): self.assertEqual(90112, stats.cpu_l3_cache_usage) self.assertEqual(25600 / units.Ki, stats.memory_usage) self.assertEqual(30000 / units.Ki, stats.memory_resident) + self.assertEqual(5120 / units.Ki, stats.memory_swap_in) + self.assertEqual(8192 / units.Ki, stats.memory_swap_out) self.assertEqual(1892352, stats.memory_bandwidth_total) self.assertEqual(1802240, stats.memory_bandwidth_local) self.assertEqual(7259361, stats.cpu_cycles) @@ -406,6 +410,8 @@ class TestLibvirtInspection(base.BaseTestCase): stats = self.inspector.inspect_instance(self.instance, None) self.assertIsNone(stats.memory_usage) self.assertIsNone(stats.memory_resident) + self.assertIsNone(stats.memory_swap_in) + self.assertIsNone(stats.memory_swap_out) def test_inspect_perf_events_libvirt_less_than_2_3_0(self): domain = mock.Mock() diff --git a/ceilometer/tests/unit/dispatcher/test_gnocchi.py b/ceilometer/tests/unit/dispatcher/test_gnocchi.py index 33f5f17052..6e7ec7bddb 100644 --- a/ceilometer/tests/unit/dispatcher/test_gnocchi.py +++ b/ceilometer/tests/unit/dispatcher/test_gnocchi.py @@ -529,6 +529,7 @@ class DispatcherWorkflowTest(base.BaseTestCase, metric_names=[ 'disk.root.size', 'disk.ephemeral.size', 'memory', 'vcpus', 'memory.usage', 'memory.resident', + 'memory.swap.in', 'memory.swap.out', 'memory.bandwidth.total', 'memory.bandwidth.local', 'cpu', 'cpu.delta', 'cpu_util', 'vcpus', 'disk.read.requests', 'cpu_l3_cache', 'perf.cpu.cycles', 'perf.instructions', diff --git a/releasenotes/notes/add-memory-swap-metric-f1633962ab2cf0f6.yaml b/releasenotes/notes/add-memory-swap-metric-f1633962ab2cf0f6.yaml new file mode 100644 index 0000000000..32eca8112a --- /dev/null +++ b/releasenotes/notes/add-memory-swap-metric-f1633962ab2cf0f6.yaml @@ -0,0 +1,5 @@ +--- +features: + - Add memory swap metric for VM, including 'memory.swap.in' and + 'memory.swap.out'. + diff --git a/setup.cfg b/setup.cfg index da188c47a7..e2bc75eb36 100644 --- a/setup.cfg +++ b/setup.cfg @@ -115,6 +115,8 @@ ceilometer.poll.compute = network.outgoing.packets.error = ceilometer.compute.pollsters.net:OutgoingErrorsPollster memory.usage = ceilometer.compute.pollsters.instance_stats:MemoryUsagePollster memory.resident = ceilometer.compute.pollsters.instance_stats:MemoryResidentPollster + memory.swap.in = ceilometer.compute.pollsters.instance_stats:MemorySwapInPollster + memory.swap.out = ceilometer.compute.pollsters.instance_stats:MemorySwapOutPollster memory.bandwidth.total = ceilometer.compute.pollsters.instance_stats:MemoryBandwidthTotalPollster memory.bandwidth.local = ceilometer.compute.pollsters.instance_stats:MemoryBandwidthLocalPollster disk.capacity = ceilometer.compute.pollsters.disk:CapacityPollster