From a4ec0911a3ed4137a1c832fbd7c8fee80c7d4601 Mon Sep 17 00:00:00 2001 From: Gyorgy Szombathelyi Date: Wed, 29 Mar 2017 11:34:52 +0200 Subject: [PATCH] Use vcpu.x.time and vcpu.x.wait values in libvirt inspector If possible, calculate cputime from vcpu time + vcpu wait. Fall back to cpu.time, if any vcpu.x.time or vcpu.x.wait values are missing. derived from I7bce33854dfe9c7b0e03b8c22721d04028183701 Co-Authored-By: Michael Ly Co-Authored-By: Avi Weit Co-Authored-By: Jorge Rodriguez Co-Authored-By: Karolyn Chambers Co-Authored-By: Daniel Berrange Co-Authored-By: gordon chung Change-Id: I20700a32d608b3444b22c5ae460002eeb86d78ae Closes-bug: #1677159 Closes-bug: #1421584 --- ceilometer/compute/virt/libvirt/inspector.py | 22 ++++++++++++++- .../compute/virt/libvirt/test_inspector.py | 28 ++++++++++++++++++- 2 files changed, 48 insertions(+), 2 deletions(-) diff --git a/ceilometer/compute/virt/libvirt/inspector.py b/ceilometer/compute/virt/libvirt/inspector.py index a9c9dae4ec..266d907a07 100644 --- a/ceilometer/compute/virt/libvirt/inspector.py +++ b/ceilometer/compute/virt/libvirt/inspector.py @@ -173,10 +173,30 @@ def inspect_instance(self, instance, duration=None): # TODO(sileht): stats also have the disk/vnic info # we could use that instead of the old method for Queen stats = self.connection.domainListGetStats([domain], 0)[0][1] + cpu_time = 0 + current_cpus = stats.get('vcpu.current') + # Iterate over the maximum number of CPUs here, and count the + # actual number encountered, since the vcpu.x structure can + # have holes according to + # https://libvirt.org/git/?p=libvirt.git;a=blob;f=src/libvirt-domain.c + # virConnectGetAllDomainStats() + for vcpu in six.moves.range(stats.get('vcpu.maximum', 0)): + try: + cpu_time += (stats.get('vcpu.%s.time' % vcpu) + + stats.get('vcpu.%s.wait' % vcpu)) + current_cpus -= 1 + except TypeError: + # pass here, if there are too many holes, the cpu count will + # not match, so don't need special error handling. + pass + + if current_cpus: + # There wasn't enough data, so fall back + cpu_time = stats.get('cpu.time') return virt_inspector.InstanceStats( cpu_number=stats.get('vcpu.current'), - cpu_time=stats.get('cpu.time'), + cpu_time=cpu_time, memory_usage=memory_used, memory_resident=memory_resident, cpu_cycles=stats.get("perf.cpu_cycles"), diff --git a/ceilometer/tests/unit/compute/virt/libvirt/test_inspector.py b/ceilometer/tests/unit/compute/virt/libvirt/test_inspector.py index 0666cacf0c..b12bd2d7eb 100644 --- a/ceilometer/tests/unit/compute/virt/libvirt/test_inspector.py +++ b/ceilometer/tests/unit/compute/virt/libvirt/test_inspector.py @@ -60,7 +60,12 @@ def test_inspect_instance_stats(self): conn.lookupByUUIDString.return_value = domain conn.domainListGetStats.return_value = [({}, { 'cpu.time': 999999, + 'vcpu.maximum': 4, 'vcpu.current': 2, + 'vcpu.0.time': 10000, + 'vcpu.0.wait': 10000, + 'vcpu.2.time': 10000, + 'vcpu.2.wait': 10000, 'perf.cmt': 90112, 'perf.cpu_cycles': 7259361, 'perf.instructions': 8815623, @@ -73,7 +78,7 @@ def test_inspect_instance_stats(self): 'refresh_libvirt_connection', return_value=conn): stats = self.inspector.inspect_instance(self.instance) self.assertEqual(2, stats.cpu_number) - self.assertEqual(999999, stats.cpu_time) + self.assertEqual(40000, stats.cpu_time) self.assertEqual(90112, stats.cpu_l3_cache_usage) self.assertEqual(25600 / units.Ki, stats.memory_usage) self.assertEqual(30000 / units.Ki, stats.memory_resident) @@ -84,6 +89,27 @@ def test_inspect_instance_stats(self): self.assertEqual(74184, stats.cache_references) self.assertEqual(16737, stats.cache_misses) + def test_inspect_instance_stats_fallback_cpu_time(self): + domain = mock.Mock() + domain.info.return_value = (0, 0, 0, 2, 20000) + domain.memoryStats.return_value = {'available': 51200, + 'unused': 25600, + 'rss': 30000} + conn = mock.Mock() + conn.lookupByUUIDString.return_value = domain + conn.domainListGetStats.return_value = [({}, { + 'vcpu.current': 2, + 'vcpu.maximum': 4, + 'vcpu.0.time': 10000, + 'vcpu.1.time': 10000, + 'cpu.time': 999999})] + + with mock.patch('ceilometer.compute.virt.libvirt.utils.' + 'refresh_libvirt_connection', return_value=conn): + stats = self.inspector.inspect_instance(self.instance) + self.assertEqual(2, stats.cpu_number) + self.assertEqual(999999, stats.cpu_time) + def test_inspect_cpus_with_domain_shutoff(self): domain = mock.Mock() domain.info.return_value = (5, 0, 0, 2, 999999)