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:
parent
c28336d400
commit
a2dbcaf80d
@ -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})
|
||||
|
@ -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.
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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'>
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user