add l3 cache usage meter

Some Intel processor families (e.g. the Intel Xeon processor E5 v3
family) introduced CMT (Cache Monitoring Technology) to measure the
usage of l3 cache (last level cache) by applications running on the
platform. This spec introduces one new meter to get l3 cache usage
statistics based on Intel CMT feature.

Implements: blueprint l3-cache-meter
Change-Id: I7f38e80776e1e55533b33e9c72dcab6d3c12abb4
This commit is contained in:
Qiaowei Ren 2016-06-05 16:12:15 +08:00
parent c28336d400
commit a2dbcaf80d
6 changed files with 125 additions and 0 deletions

View File

@ -17,6 +17,7 @@
from oslo_log import log
import ceilometer
from ceilometer.agent import plugin_base
from ceilometer.compute import pollsters
from ceilometer.compute.pollsters import util
from ceilometer.compute.virt import inspector as virt_inspector
@ -91,3 +92,40 @@ class CPUUtilPollster(pollsters.BaseComputePollster):
except Exception as err:
LOG.exception(_('Could not get CPU Util for %(id)s: %(e)s'),
{'id': instance.id, 'e': err})
class CPUL3CachePollster(pollsters.BaseComputePollster):
def get_samples(self, manager, cache, resources):
self._inspection_duration = self._record_poll_time()
for instance in resources:
LOG.debug(_('checking cache usage for instance %s'), instance.id)
try:
cpu_cache = self.inspector.inspect_cpu_l3_cache(
instance, self._inspection_duration)
LOG.debug(_("CPU cache size: %(id)s %(cache_size)d"),
({'id': instance.id,
'l3_cache_usage': cpu_cache.l3_cache_usage}))
yield util.make_sample_from_instance(
instance,
name='cpu_l3_cache',
type=sample.TYPE_GAUGE,
unit='B',
volume=cpu_cache.l3_cache_usage,
)
except virt_inspector.InstanceNotFoundException as err:
# Instance was deleted while getting samples. Ignore it.
LOG.debug('Exception while getting samples %s', err)
except virt_inspector.NoDataException as e:
LOG.warning(('Cannot inspect data of %(pollster)s for '
'%(instance_id)s, non-fatal reason: %(exc)s'),
{'pollster': self.__class__.__name__,
'instance_id': instance.id, 'exc': e})
raise plugin_base.PollsterPermanentError(resources)
except ceilometer.NotImplementedError:
# Selected inspector does not implement this pollster.
LOG.debug('Obtaining cache usage is not implemented for %s',
self.inspector.__class__.__name__)
except Exception as err:
LOG.exception(_('Could not get cache usage for %(id)s: %(e)s'),
{'id': instance.id, 'e': err})

View File

@ -58,6 +58,13 @@ CPUStats = collections.namedtuple('CPUStats', ['number', 'time'])
#
CPUUtilStats = collections.namedtuple('CPUUtilStats', ['util'])
# Named tuple representing CPU L3 cache usage statistics.
#
# cachesize: Amount of CPU L3 cache used
#
CPUL3CacheUsageStats = collections.namedtuple('CPUL3CacheUsageStats',
['l3_cache_usage'])
# Named tuple representing Memory usage statistics.
#
# usage: Amount of memory used
@ -218,6 +225,16 @@ class Inspector(object):
"""
raise ceilometer.NotImplementedError
def inspect_cpu_l3_cache(self, instance, duration=None):
"""Inspect the CPU L3 cache usage for an instance.
:param instance: the target instance
:param duration: the last 'n' seconds, over which the value should be
inspected
:return: the amount of cpu l3 cache used
"""
raise ceilometer.NotImplementedError
def inspect_vnics(self, instance):
"""Inspect the vNIC statistics for an instance.

View File

@ -117,6 +117,29 @@ class LibvirtInspector(virt_inspector.Inspector):
dom_info = domain.info()
return virt_inspector.CPUStats(number=dom_info[3], time=dom_info[4])
def inspect_cpu_l3_cache(self, instance):
domain = self._lookup_by_uuid(instance)
try:
stats = self.connection.domainListGetStats(
[domain], libvirt.VIR_DOMAIN_STATS_PERF)
perf = stats[0][1]
usage = perf["perf.cmt"]
return virt_inspector.CPUL3CacheUsageStats(l3_cache_usage=usage)
except AttributeError as e:
msg = _('Perf is not supported by current version of libvirt, and '
'failed to inspect l3 cache usage of %(instance_uuid)s, '
'can not get info from libvirt: %(error)s') % {
'instance_uuid': instance.id, 'error': e}
raise virt_inspector.NoDataException(msg)
# domainListGetStats might launch an exception if the method or
# cmt perf event is not supported by the underlying hypervisor
# being used by libvirt.
except libvirt.libvirtError as e:
msg = _('Failed to inspect l3 cache usage of %(instance_uuid)s, '
'can not get info from libvirt: %(error)s') % {
'instance_uuid': instance.id, 'error': e}
raise virt_inspector.NoDataException(msg)
def _get_domain_not_shut_off_or_raise(self, instance):
instance_name = util.instance_name(instance)
domain = self._lookup_by_uuid(instance)

View File

@ -106,3 +106,36 @@ class TestCPUUtilPollster(base.TestPollsterBase):
_verify_cpu_util_metering(40)
_verify_cpu_util_metering(60)
class TestCPUL3CachePollster(base.TestPollsterBase):
def setUp(self):
super(TestCPUL3CachePollster, self).setUp()
@mock.patch('ceilometer.pipeline.setup_pipeline', mock.MagicMock())
def test_get_samples(self):
next_value = iter((
virt_inspector.CPUL3CacheUsageStats(l3_cache_usage=90112),
virt_inspector.CPUL3CacheUsageStats(l3_cache_usage=180224),
))
def inspect_cpu_l3_cache(name, duration):
return next(next_value)
self.inspector.inspect_cpu_l3_cache = (mock.Mock(
side_effect=inspect_cpu_l3_cache))
mgr = manager.AgentManager()
pollster = cpu.CPUL3CachePollster()
def _verify_cpu_l3_cache_metering(expected_usage):
cache = {}
samples = list(pollster.get_samples(mgr, cache, [self.instance]))
self.assertEqual(1, len(samples))
self.assertEqual(set(['cpu_l3_cache']),
set([s.name for s in samples]))
self.assertEqual(expected_usage, samples[0].volume)
_verify_cpu_l3_cache_metering(90112)
_verify_cpu_l3_cache_metering(180224)

View File

@ -71,6 +71,19 @@ class TestLibvirtInspection(base.BaseTestCase):
self.inspector.inspect_cpus,
self.instance)
def test_inspect_cpu_l3_cache(self):
fake_stats = [({}, {'perf.cmt': 90112})]
connection = self.inspector.connection
with contextlib.ExitStack() as stack:
stack.enter_context(mock.patch.object(connection,
'lookupByUUIDString',
return_value=self.domain))
stack.enter_context(mock.patch.object(connection,
'domainListGetStats',
return_value=fake_stats))
cpu_info = self.inspector.inspect_cpu_l3_cache(self.instance)
self.assertEqual(90112, cpu_info.l3_cache_usage)
def test_inspect_vnics(self):
dom_xml = """
<domain type='kvm'>

View File

@ -95,6 +95,7 @@ ceilometer.poll.compute =
disk.device.iops = ceilometer.compute.pollsters.disk:PerDeviceDiskIOPSPollster
cpu = ceilometer.compute.pollsters.cpu:CPUPollster
cpu_util = ceilometer.compute.pollsters.cpu:CPUUtilPollster
cpu_l3_cache = ceilometer.compute.pollsters.cpu:CPUL3CachePollster
network.incoming.bytes = ceilometer.compute.pollsters.net:IncomingBytesPollster
network.incoming.packets = ceilometer.compute.pollsters.net:IncomingPacketsPollster
network.outgoing.bytes = ceilometer.compute.pollsters.net:OutgoingBytesPollster