Merge "Add new cpu_util meter recording CPU utilization %."
This commit is contained in:
commit
2206ed8ee7
@ -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,
|
||||
|
@ -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))
|
||||
|
Loading…
Reference in New Issue
Block a user