Merge "Add new cpu_util meter recording CPU utilization %."

This commit is contained in:
Jenkins 2012-11-02 15:24:18 +00:00 committed by Gerrit Code Review
commit 2206ed8ee7
2 changed files with 62 additions and 11 deletions

View File

@ -17,6 +17,8 @@
# under the License.
import copy
import datetime
import multiprocessing
from lxml import etree
@ -154,13 +156,46 @@ class CPUPollster(LibVirtPollster):
LOG = log.getLogger(__name__ + '.cpu')
utilization_map = {}
def get_cpu_util(self, instance, cpu_info):
prev_times = self.utilization_map.get(instance.uuid)
self.utilization_map[instance.uuid] = (cpu_info['cpu_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.uuid][1] - prev_timestamp
elapsed = (delta.seconds * (10 ** 6) + delta.microseconds) * 1000
cores_fraction = instance.vcpus * 1.0 / multiprocessing.cpu_count()
# account for cpu_time being reset when the instance is restarted
time_used = (cpu_info['cpu_time'] - prev_cpu
if prev_cpu <= cpu_info['cpu_time'] else
cpu_info['cpu_time'])
cpu_util = 100 * cores_fraction * time_used / elapsed
return cpu_util
def get_counters(self, manager, instance):
conn = get_libvirt_connection()
self.LOG.info('checking instance %s', instance.uuid)
try:
cpu_info = conn.get_info(instance)
self.LOG.info("CPUTIME USAGE: %s %d",
instance, cpu_info['cpu_time'])
dict(instance), cpu_info['cpu_time'])
cpu_util = self.get_cpu_util(instance, cpu_info)
self.LOG.info("CPU UTILIZATION %%: %s %0.2f",
dict(instance), cpu_util)
# 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
yield make_counter_from_instance(instance,
name='cpu_util',
type=counter.TYPE_GAUGE,
volume=cpu_util,
)
yield make_counter_from_instance(instance,
name='cpu',
type=counter.TYPE_CUMULATIVE,

View File

@ -27,6 +27,7 @@ else:
libvirt_missing = False
import mock
import time
from nova import flags
@ -39,11 +40,12 @@ import mox
import re
def fake_libvirt_conn(moxobj):
def fake_libvirt_conn(moxobj, count=1):
conn = moxobj.CreateMockAnything()
conn._conn = moxobj.CreateMockAnything()
moxobj.StubOutWithMock(libvirt, 'get_libvirt_connection')
libvirt.get_libvirt_connection().AndReturn(conn)
for _ in xrange(count):
libvirt.get_libvirt_connection().AndReturn(conn)
return conn
@ -210,13 +212,27 @@ class TestCPUPollster(TestLibvirtBase):
self.pollster = libvirt.CPUPollster()
def test_get_counter(self):
expected_cpu_time = 12345
conn = fake_libvirt_conn(self.mox)
self.instance.vcpus = 1
conn = fake_libvirt_conn(self.mox, 3)
self.mox.StubOutWithMock(conn, 'get_info')
conn.get_info(self.instance).AndReturn({'cpu_time': expected_cpu_time})
conn.get_info(self.instance).AndReturn({'cpu_time': 1 * (10 ** 6)})
conn.get_info(self.instance).AndReturn({'cpu_time': 3 * (10 ** 6)})
# cpu_time resets on instance restart
conn.get_info(self.instance).AndReturn({'cpu_time': 2 * (10 ** 6)})
self.mox.ReplayAll()
counters = list(self.pollster.get_counters(self.manager,
self.instance))
self.assertEquals(len(counters), 1)
assert counters[0].volume == expected_cpu_time
def _verify_cpu_metering(zero, expected_time):
counters = list(self.pollster.get_counters(self.manager,
self.instance))
self.assertEquals(len(counters), 2)
assert counters[0].name == 'cpu_util'
assert (counters[0].volume == 0.0 if zero else
counters[0].volume > 0.0)
assert counters[1].name == 'cpu'
assert counters[1].volume == expected_time
# ensure elapsed time between polling cycles is non-zero
time.sleep(0.001)
_verify_cpu_metering(True, 1 * (10 ** 6))
_verify_cpu_metering(False, 3 * (10 ** 6))
_verify_cpu_metering(False, 2 * (10 ** 6))