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

Reply via email to