diff --git a/ceilometer/compute/pollsters/cpu.py b/ceilometer/compute/pollsters/cpu.py index eecdfbf38..2e980c4a9 100644 --- a/ceilometer/compute/pollsters/cpu.py +++ b/ceilometer/compute/pollsters/cpu.py @@ -18,9 +18,6 @@ # License for the specific language governing permissions and limitations # under the License. -import abc -import datetime - from ceilometer import counter from ceilometer.compute import plugin from ceilometer.compute.pollsters import util @@ -29,91 +26,25 @@ from ceilometer.openstack.common import log LOG = log.getLogger(__name__) -class _Base(plugin.ComputePollster): - - CACHE_KEY_CPU = 'cpu' - - def _get_cpu_info(self, inspector, instance_name, cache): - i_cache = cache.setdefault(self.CACHE_KEY_CPU, {}) - if instance_name not in i_cache: - i_cache[instance_name] = inspector.inspect_cpus(instance_name) - return i_cache[instance_name] - - @abc.abstractmethod - def _get_counter(instance, instance_name, cpu_info): - """Return one Counter.""" +class CPUPollster(plugin.ComputePollster): def get_counters(self, manager, cache, instance): LOG.info('checking instance %s', instance.id) instance_name = util.instance_name(instance) try: - cpu_info = self._get_cpu_info( - manager.inspector, - instance_name, - cache, - ) - yield self._get_counter( + cpu_info = manager.inspector.inspect_cpus(instance_name) + LOG.info("CPUTIME USAGE: %s %d", + instance.__dict__, cpu_info.time) + cpu_num = {'cpu_number': cpu_info.number} + yield util.make_counter_from_instance( instance, - instance_name, - cpu_info, + name='cpu', + type=counter.TYPE_CUMULATIVE, + unit='ns', + volume=cpu_info.time, + additional_metadata=cpu_num, ) except Exception as err: LOG.error('could not get CPU time for %s: %s', instance.id, err) LOG.exception(err) - - -class CPUPollster(_Base): - - @staticmethod - def _get_counter(instance, instance_name, cpu_info): - LOG.info("CPUTIME USAGE: %s %d", - instance.__dict__, cpu_info.time) - cpu_num = {'cpu_number': cpu_info.number} - return util.make_counter_from_instance( - instance, - name='cpu', - type=counter.TYPE_CUMULATIVE, - unit='ns', - volume=cpu_info.time, - additional_metadata=cpu_num, - ) - - -class CPUUtilPollster(_Base): - # FIXME(eglynn): once we have a way of configuring which measures - # are published to each sink, we should by default - # disable publishing this derived measure to the - # metering store, only publishing to those sinks - # that specifically need it - - utilization_map = {} - - def _get_cpu_util(self, instance, cpu_info): - prev_times = self.utilization_map.get(instance.id) - self.utilization_map[instance.id] = (cpu_info.time, - datetime.datetime.now()) - cpu_util = 0.0 - if prev_times: - prev_cpu = prev_times[0] - prev_timestamp = prev_times[1] - delta = self.utilization_map[instance.id][1] - prev_timestamp - elapsed = (delta.seconds * (10 ** 6) + delta.microseconds) * 1000 - cores_fraction = 1.0 / cpu_info.number - # account for cpu_time being reset when the instance is restarted - time_used = (cpu_info.time - prev_cpu - if prev_cpu <= cpu_info.time else cpu_info.time) - cpu_util = 100 * cores_fraction * time_used / elapsed - return cpu_util - - def _get_counter(self, instance, instance_name, cpu_info): - cpu_util = self._get_cpu_util(instance, cpu_info) - LOG.info("CPU UTILIZATION %%: %s %0.2f", - instance.__dict__, cpu_util) - return util.make_counter_from_instance( - instance, - name='cpu_util', - type=counter.TYPE_GAUGE, - unit='%', - volume=cpu_util, - ) diff --git a/etc/ceilometer/pipeline.yaml b/etc/ceilometer/pipeline.yaml index 8aa4d2bd8..3c3bc25e5 100644 --- a/etc/ceilometer/pipeline.yaml +++ b/etc/ceilometer/pipeline.yaml @@ -7,3 +7,19 @@ transformers: publishers: - rpc:// +- + name: cpu_pipeline + interval: 600 + counters: + - "cpu" + transformers: + - name: "rate_of_change" + parameters: + target: + name: "cpu_util" + unit: "%" + type: "gauge" + scale: "100.0 / (10**9 * (resource_metadata.cpu_number or 1))" + replace: False + publishers: + - rpc:// diff --git a/setup.cfg b/setup.cfg index e2a1724f7..c0e5d3b90 100644 --- a/setup.cfg +++ b/setup.cfg @@ -56,7 +56,6 @@ ceilometer.poll.compute = disk.read.bytes = ceilometer.compute.pollsters.disk:ReadBytesPollster disk.write.bytes = ceilometer.compute.pollsters.disk:WriteBytesPollster cpu = ceilometer.compute.pollsters.cpu:CPUPollster - cpu_util = ceilometer.compute.pollsters.cpu:CPUUtilPollster network.incoming.bytes = ceilometer.compute.pollsters.net:IncomingBytesPollster network.incoming.packets = ceilometer.compute.pollsters.net:IncomingPacketsPollster network.outgoing.bytes = ceilometer.compute.pollsters.net:OutgoingBytesPollster diff --git a/tests/compute/pollsters/test_cpu.py b/tests/compute/pollsters/test_cpu.py index 9184281a7..8998f906d 100644 --- a/tests/compute/pollsters/test_cpu.py +++ b/tests/compute/pollsters/test_cpu.py @@ -55,8 +55,6 @@ class TestCPUPollster(base.TestPollsterBase): self.assertEqual(set([c.name for c in counters]), set(['cpu'])) assert counters[0].volume == expected_time - assert pollster.CACHE_KEY_CPU in cache - assert self.instance.name in cache[pollster.CACHE_KEY_CPU] self.assertEquals(counters[0].resource_metadata.get('cpu_number'), 2) # ensure elapsed time between polling cycles is non-zero @@ -67,78 +65,16 @@ class TestCPUPollster(base.TestPollsterBase): _verify_cpu_metering(2 * (10 ** 6)) @mock.patch('ceilometer.pipeline.setup_pipeline', mock.MagicMock()) - def test_get_counters_cache(self): + def test_get_counters_no_caching(self): + self.inspector.inspect_cpus(self.instance.name).AndReturn( + virt_inspector.CPUStats(time=1 * (10 ** 6), number=2)) self.mox.ReplayAll() mgr = manager.AgentManager() pollster = cpu.CPUPollster() - cache = { - pollster.CACHE_KEY_CPU: { - self.instance.name: virt_inspector.CPUStats( - time=10 ** 6, - number=2, - ), - }, - } + cache = {} counters = list(pollster.get_counters(mgr, cache, self.instance)) self.assertEquals(len(counters), 1) self.assertEquals(counters[0].volume, 10 ** 6) - - -class TestCPUUtilPollster(base.TestPollsterBase): - - def setUp(self): - super(TestCPUUtilPollster, self).setUp() - - @mock.patch('ceilometer.pipeline.setup_pipeline', mock.MagicMock()) - def test_get_counters(self): - self.inspector.inspect_cpus(self.instance.name).AndReturn( - virt_inspector.CPUStats(time=1 * (10 ** 6), number=2)) - self.inspector.inspect_cpus(self.instance.name).AndReturn( - virt_inspector.CPUStats(time=3 * (10 ** 6), number=2)) - # cpu_time resets on instance restart - self.inspector.inspect_cpus(self.instance.name).AndReturn( - virt_inspector.CPUStats(time=2 * (10 ** 6), number=2)) - self.mox.ReplayAll() - - mgr = manager.AgentManager() - pollster = cpu.CPUUtilPollster() - pollster.utilization_map = {} # clear the internal cache - - def _verify_cpu_metering(zero): - cache = {} - counters = list(pollster.get_counters(mgr, cache, self.instance)) - self.assertEquals(len(counters), 1) - self.assertEqual(set([c.name for c in counters]), - set(['cpu_util'])) - assert (counters[0].volume == 0.0 if zero else - counters[0].volume > 0.0) - assert pollster.CACHE_KEY_CPU in cache - assert self.instance.name in cache[pollster.CACHE_KEY_CPU] - # ensure elapsed time between polling cycles is non-zero - time.sleep(0.001) - - _verify_cpu_metering(True) - _verify_cpu_metering(False) - _verify_cpu_metering(False) - - @mock.patch('ceilometer.pipeline.setup_pipeline', mock.MagicMock()) - def test_get_counters_cache(self): - self.mox.ReplayAll() - - mgr = manager.AgentManager() - pollster = cpu.CPUUtilPollster() - pollster.utilization_map = {} # clear the internal cache - - cache = { - pollster.CACHE_KEY_CPU: { - self.instance.name: virt_inspector.CPUStats( - time=10 ** 6, - number=2, - ), - }, - } - counters = list(pollster.get_counters(mgr, cache, self.instance)) - self.assertEquals(len(counters), 1) - self.assertEquals(counters[0].volume, 0) + self.assertEquals(len(cache), 0)