Hello Adam Litke,
I'd like you to do a code review. Please visit
http://gerrit.ovirt.org/28815
to review the following change.
Change subject: Adding support in CPU monitoring
......................................................................
Adding support in CPU monitoring
Adding two new collectors and a controller to enable
monitoring the CPU tuning parameters: vcpu_quota, vcpu_period.
This patch is part of the CPU SLA feature:
http://www.ovirt.org/Features/CPU_SLA.
Changes in collectors:
Added a new utility method to Collector.py, "count_int",
count the number of matches in a string according to a regular expression.
Added HostCpu to expose the number of cpu on the host.
Added GuestCpuTune to expose the current tuning parameters and the latest user
selection
Changes in controller:
Added CpuTune to apply changes to the vcpu tuning.
This patch is used in the cputune.policy, some code snip:
(defvar anchor 100000)
(def check_and_set_quota (guest)
{
(defvar calcQuota (/ (* anchor (/ guest.user_vcpu_limit 100)))
guest.vcpu_count)
(if (!= guest.vcpu_quota calcQuota)
(guest.Control "vcpu_quota" calcQuota) 0)
})
Change-Id: I66aa9723d3cfc6fc1c1d36a3bf42086abd010f26
Reviewed-on: http://gerrit.ovirt.org/27240
Tested-by: Kobi Ianko <[email protected]>
Reviewed-by: Adam Litke <[email protected]>
Signed-off-by: Kobi Ianko <[email protected]>
---
M mom/Collectors/Collector.py
A mom/Collectors/GuestCpuTune.py
A mom/Collectors/HostCpu.py
A mom/Controllers/CpuTune.py
M mom/HypervisorInterfaces/libvirtInterface.py
M mom/HypervisorInterfaces/vdsmInterface.py
6 files changed, 227 insertions(+), 0 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/mom refs/changes/15/28815/1
diff --git a/mom/Collectors/Collector.py b/mom/Collectors/Collector.py
index 46b3a5e..3a135b2 100644
--- a/mom/Collectors/Collector.py
+++ b/mom/Collectors/Collector.py
@@ -138,3 +138,14 @@
return int(m.group(1))
else:
return None
+
+def count_occurrences(regex, src):
+ """
+ Parse a body of text according to the provided regular expression and
return
+ the count of matches as an integer.
+ """
+ m = re.findall(regex, src, re.M)
+ if m:
+ return len(m)
+ else:
+ return None
diff --git a/mom/Collectors/GuestCpuTune.py b/mom/Collectors/GuestCpuTune.py
new file mode 100644
index 0000000..4c704b9
--- /dev/null
+++ b/mom/Collectors/GuestCpuTune.py
@@ -0,0 +1,45 @@
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public
+# License along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+from mom.Collectors.Collector import *
+class GuestCpuTune(Collector):
+ """
+ This Collector uses hypervisor interface to collect guest cpu info
+ """
+ def getFields(self=None):
+ return set(['vcpu_quota', 'vcpu_period', 'vcpu_user_limit',
'vcpu_count'])
+
+ def __init__(self, properties):
+ self.hypervisor_iface = properties['hypervisor_iface']
+ self.uuid = properties['uuid']
+ self.logger = logging.getLogger('mom.Collectors.CpuTuneInfo')
+ self.cpu_tune_info_available = True
+
+ def stats_error(self, msg):
+ """
+ Only print stats interface errors one time when we first discover a
+ problem. Otherwise the log will be overrun with noise.
+ """
+ if self.cpu_tune_info_available:
+ self.logger.debug(msg)
+ self.cpu_tune_info_available = False
+
+ def collect(self):
+ stat = self.hypervisor_iface.getVmCpuTuneInfo(self.uuid)
+
+ if stat == None:
+ self.stats_error('getVmCpuTuneInfo() is not ready')
+ else:
+ self.cpu_tune_info_available = True
+
+ return stat
diff --git a/mom/Collectors/HostCpu.py b/mom/Collectors/HostCpu.py
new file mode 100644
index 0000000..3107f34
--- /dev/null
+++ b/mom/Collectors/HostCpu.py
@@ -0,0 +1,39 @@
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public
+# License along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+from mom.Collectors.Collector import *
+
+class HostCpu(Collector):
+ """
+ This Collector uses the /proc/cpuinfo file to retrieve CPU info for the
host.
+ Currently it only retrieve the number of CPUs in the host into 'cpu_count'
+ """
+
+ def __init__(self, properties):
+ self.cpuinfo = open_datafile("/proc/cpuinfo")
+
+ def __del__(self):
+ if self.cpuinfo is not None:
+ self.cpuinfo.close()
+
+ def collect(self):
+ self.cpuinfo.seek(0)
+
+ contents = self.cpuinfo.read()
+ cpu_count = count_occurrences("^processor.*:.*", contents)
+
+ data = { 'cpu_count': cpu_count }
+ return data
+
+ def getFields(self=None):
+ return set(['cpu_count'])
diff --git a/mom/Controllers/CpuTune.py b/mom/Controllers/CpuTune.py
new file mode 100644
index 0000000..687f7bc
--- /dev/null
+++ b/mom/Controllers/CpuTune.py
@@ -0,0 +1,45 @@
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public
+# License along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import logging
+
+class CpuTune:
+ """
+ Controller that uses the hypervisor interface to manipulate
+ the cpu tuning parameters.
+ The current parameters that can be set are:
+ vcpu_quota: The optional quota element specifies the maximum allowed
bandwidth(unit: microseconds).
+ vcpu_period: The optional period element specifies the enforcement
interval(unit: microseconds).
+ For more: http://libvirt.org/formatdomain.html#elementsCPUTuning
+ """
+ def __init__(self, properties):
+ self.hypervisor_iface = properties['hypervisor_iface']
+ self.logger = logging.getLogger('mom.Controllers.Cputune')
+
+ def process_guest(self, guest):
+ quota = guest.GetControl('vcpu_quota')
+ period = guest.GetControl('vcpu_period')
+ if quota is not None and period is not None:
+ quota = int(quota)
+ period = int(period)
+ uuid = guest.Prop('uuid')
+ name = guest.Prop('name')
+ prev_quota = guest.vcpu_quota
+ prev_period = guest.vcpu_period
+ self.logger.info("CpuTune guest:%s from quota:%s period:%s to
quota:%s period:%s", \
+ name, prev_quota, prev_period, quota, period)
+ self.hypervisor_iface.setVmCpuTune(uuid, quota, period)
+
+ def process(self, host, guests):
+ for guest in guests:
+ self.process_guest(guest)
diff --git a/mom/HypervisorInterfaces/libvirtInterface.py
b/mom/HypervisorInterfaces/libvirtInterface.py
index 916ca12..e29333d 100644
--- a/mom/HypervisorInterfaces/libvirtInterface.py
+++ b/mom/HypervisorInterfaces/libvirtInterface.py
@@ -244,6 +244,37 @@
'balloon_min': self._getGuaranteedMemory(domain) }
return ret
+ def getVmCpuTuneInfo(self, uuid):
+ ret = {}
+ domain = self._getDomainFromUUID(uuid)
+
+ # Get the user selection for vcpuLimit from the metadata
+ metadataCpuLimit =
domain.getMetadata(2,'http://ovirt.org/param/vcpu_limit',0)
+
+ if metadataCpuLimit:
+ ret['vcpu_user_limit'] = metadataCpuLimit
+ else:
+ ret['vcpu_user_limit'] = 100
+
+ # Retrieve the current cpu tuning params
+ ret.update(domain.getSchedulerParameters({ 'vcpu_quota',
'vcpu_period'}))
+
+ if ret['vcpu_quota'] == None:
+ ret['vcpu_quota'] = -1
+
+ if ret['vcpu_period'] == None:
+ ret['vcpu_period'] = 1000
+
+ # Get the number of vcpus
+ vcpuCount = domain.getVcpusFlags(libvirt.VIR_DOMAIN_MEM_CURRENT)
+ if vcpuCount != -1:
+ ret['vcpu_count'] = vcpuCount
+ else:
+ self.logger.error('Failed to get VM cpu count')
+ return None
+
+ return ret
+
def setVmBalloonTarget(self, uuid, target):
dom = self._getDomainFromUUID(uuid)
if dom is not None:
@@ -251,6 +282,14 @@
name = self._domainGetName(dom)
self.logger.warn("Error while ballooning guest:%i", name)
+ def setVmCpuTune(self, uuid, quota, period):
+ dom = self._getDomainFromUUID(uuid)
+ try:
+ dom.setSchedulerParameters({ 'vcpu_quota': quota, 'vcpu_period':
period})
+ except libvirt.libvirtError, e:
+ self.logger.error("libvirtInterface: Exception while " \
+ "setSchedulerParameters: %s", e.message);
+
def ksmTune(self, tuningParams):
def write_value(fname, value):
try:
diff --git a/mom/HypervisorInterfaces/vdsmInterface.py
b/mom/HypervisorInterfaces/vdsmInterface.py
index ddf8981..cde4744 100644
--- a/mom/HypervisorInterfaces/vdsmInterface.py
+++ b/mom/HypervisorInterfaces/vdsmInterface.py
@@ -163,6 +163,54 @@
except vdsmException, e:
e.handle_exception()
+ def getVmCpuTuneInfo(self, uuid):
+ try:
+ ret = {}
+ vm = API.VM(uuid)
+ response = vm.getStats()
+ self._check_status(response)
+
+ # Get user selection for vCPU limit
+ vcpuUserLimit = response['statsList'][0].get('vcpuUserLimit', 100)
+ ret['vcpu_user_limit'] = vcpuUserLimit
+
+ # Get current vcpu tuning info
+ vcpuQuota = response['statsList'][0].get('vcpuQuota', 0)
+ ret['vcpu_quota'] = vcpuQuota
+ vcpuPeriod = response['statsList'][0].get('vcpuPeriod', 0)
+ ret['vcpu_period'] = vcpuPeriod
+
+ #Get num of vCPUs
+ vcpuCount = response['statsList'][0]['vcpuCount']
+ if vcpuCount == None:
+ return None
+ else:
+ ret['vcpu_count'] = vcpuCount
+
+ # Make sure the values are numbers, VDSM is using str
+ # to avoid xml-rpc issues
+ # We are modifying the dict keys inside the loop so
+ # iterate over copy of the list with keys, also use
+ # list() to make this compatible with Python 3
+ for key in list(ret.keys()):
+ ret[key] = int(ret[key])
+ return ret
+ except vdsmException, e:
+ e.handle_exception()
+
+ def setVmCpuTune(self, uuid, quota, period):
+ vm = API.VM(uuid)
+ try:
+ response = vm.setCpuTuneQuota(quota)
+ self._check_status(response)
+ except vdsmException, e:
+ e.handle_exception()
+ try:
+ response = vm.setCpuTunePeriod(period)
+ self._check_status(response)
+ except vdsmException, e:
+ e.handle_exception()
+
def ksmTune(self, tuningParams):
# When MOM is lauched by vdsm, it's running without root privileges.
# So we need resort to supervdsm to set the KSM parameters.
--
To view, visit http://gerrit.ovirt.org/28815
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I66aa9723d3cfc6fc1c1d36a3bf42086abd010f26
Gerrit-PatchSet: 1
Gerrit-Project: mom
Gerrit-Branch: master
Gerrit-Owner: Kobi Ianko <[email protected]>
Gerrit-Reviewer: Adam Litke <[email protected]>
_______________________________________________
Engine-patches mailing list
[email protected]
http://lists.ovirt.org/mailman/listinfo/engine-patches