WARNING - OLD ARCHIVES

This is an archived copy of the Xen.org mailing list, which we have preserved to ensure that existing links to archives are not broken. The live archive, which contains the latest emails, can be found at http://lists.xen.org/
   
 
 
Xen 
 
Home Products Support Community News
 
   
 

xen-changelog

[Xen-changelog] [xen-unstable] [XEND] Add missing XendMonitor.py

To: xen-changelog@xxxxxxxxxxxxxxxxxxx
Subject: [Xen-changelog] [xen-unstable] [XEND] Add missing XendMonitor.py
From: Xen patchbot-unstable <patchbot-unstable@xxxxxxxxxxxxxxxxxxx>
Date: Thu, 25 Jan 2007 08:55:15 -0800
Delivery-date: Thu, 25 Jan 2007 08:56:53 -0800
Envelope-to: www-data@xxxxxxxxxxxxxxxxxx
List-help: <mailto:xen-changelog-request@lists.xensource.com?subject=help>
List-id: BK change log <xen-changelog.lists.xensource.com>
List-post: <mailto:xen-changelog@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-changelog>, <mailto:xen-changelog-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-changelog>, <mailto:xen-changelog-request@lists.xensource.com?subject=unsubscribe>
Reply-to: xen-devel@xxxxxxxxxxxxxxxxxxx
Sender: xen-changelog-bounces@xxxxxxxxxxxxxxxxxxx
# HG changeset patch
# User Alastair Tse <atse@xxxxxxxxxxxxx>
# Date 1169641579 0
# Node ID 6c087036b3ed02b1853f4dd92480c0eb75e36685
# Parent  f7a52957b427f7bd107be57f06d311e126e9eff1
[XEND] Add missing XendMonitor.py

Signed-off-by: Alastair Tse <atse@xxxxxxxxxxxxx>
---
 tools/python/xen/xend/XendMonitor.py |  318 +++++++++++++++++++++++++++++++++++
 1 files changed, 318 insertions(+)

diff -r f7a52957b427 -r 6c087036b3ed tools/python/xen/xend/XendMonitor.py
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/python/xen/xend/XendMonitor.py      Wed Jan 24 12:26:19 2007 +0000
@@ -0,0 +1,318 @@
+#============================================================================
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of version 2.1 of the GNU Lesser General Public
+# License as published by the Free Software Foundation.
+#
+# This library 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
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#============================================================================
+# Copyright (C) 2007 XenSource Ltd.
+#============================================================================
+
+from xen.lowlevel.xc import xc
+import time
+import threading
+import os
+import re
+
+"""Monitoring thread to keep track of Xend statistics. """
+
+VBD_SYSFS_PATH = '/sys/devices/xen-backend/'
+VBD_WR_PATH = VBD_SYSFS_PATH + '%s/statistics/wr_req'
+VBD_RD_PATH = VBD_SYSFS_PATH + '%s/statistics/rd_req'
+VBD_DOMAIN_RE = r'vbd-(?P<domid>\d+)-(?P<devid>\d+)$'
+
+NET_PROCFS_PATH = '/proc/net/dev'
+PROC_NET_DEV_RE = r'(?P<rx_bytes>\d+)\s+' \
+                  r'(?P<rx_packets>\d+)\s+' \
+                  r'(?P<rx_errs>\d+)\s+' \
+                  r'(?P<rx_drop>\d+)\s+' \
+                  r'(?P<rx_fifo>\d+)\s+' \
+                  r'(?P<rx_frame>\d+)\s+' \
+                  r'(?P<rx_compressed>\d+)\s+' \
+                  r'(?P<rx_multicast>\d+)\s+' \
+                  r'(?P<tx_bytes>\d+)\s+' \
+                  r'(?P<tx_packets>\d+)\s+' \
+                  r'(?P<tx_errs>\d+)\s+' \
+                  r'(?P<tx_drop>\d+)\s+' \
+                  r'(?P<tx_fifo>\d+)\s+' \
+                  r'(?P<tx_collisions>\d+)\s+' \
+                  r'(?P<tx_carrier>\d+)\s+' \
+                  r'(?P<tx_compressed>\d+)\s*$'
+
+
+VIF_DOMAIN_RE = re.compile(r'vif(?P<domid>\d+)\.(?P<iface>\d+):\s*' +
+                           PROC_NET_DEV_RE)
+PIF_RE = re.compile(r'peth(?P<iface>\d+):\s*' + PROC_NET_DEV_RE)
+
+# The VBD transfer figures are in "requests" where we don't
+# really know how many bytes per requests. For now we make
+# up a number roughly could be.
+VBD_ROUGH_BYTES_PER_REQUEST = 1024 * 8 * 4
+
+# Interval to poll xc, sysfs and proc
+POLL_INTERVAL = 2.0
+
+class XendMonitor(threading.Thread):
+    """Monitors VCPU, VBD, VIF and PIF statistics for Xen API.
+
+    Polls sysfs and procfs for statistics on VBDs and VIFs respectively.
+    
+    @ivar domain_vcpus_util: Utilisation for VCPUs indexed by domain
+    @type domain_vcpus_util: {domid: {vcpuid: float, vcpuid: float}}
+    @ivar domain_vifs_util: Bytes per second for VIFs indexed by domain
+    @type domain_vifs_util: {domid: {vifid: (rx_bps, tx_bps)}}
+    @ivar domain_vbds_util: Blocks per second for VBDs index by domain.
+    @type domain_vbds_util: {domid: {vbdid: (rd_reqps, wr_reqps)}}    
+    
+    """
+    def __init__(self):
+        threading.Thread.__init__(self)
+        self.setDaemon(True)
+        self.xc = xc()
+
+        self.lock = threading.Lock()
+        
+        # tracks the last polled statistics
+        self._domain_vcpus = {}
+        self._domain_vifs = {}
+        self._domain_vbds = {}
+        self.pifs = {}
+
+        # instantaneous statistics
+        self._domain_vcpus_util = {}
+        self._domain_vifs_util = {}
+        self._domain_vbds_util = {}
+        self.pifs_util = {}
+
+    def get_domain_vcpus_util(self):
+        self.lock.acquire()
+        try:
+            return self._domain_vcpus_util
+        finally:
+            self.lock.release()
+
+    def get_domain_vbds_util(self):
+        self.lock.acquire()
+        try:
+            return self._domain_vbds_util
+        finally:
+            self.lock.release()                        
+
+    def get_domain_vifs_util(self):
+        self.lock.acquire()
+        try:
+            return self._domain_vifs_util
+        finally:
+            self.lock.release()
+
+    def get_pifs_util(self):
+        self.lock.acquire()
+        try:
+            return self.pifs_util
+        finally:
+            self.lock.release()        
+
+    def _get_vif_stats(self):
+        stats = {}
+
+        if not os.path.exists(NET_PROCFS_PATH):
+            return stats
+
+        usage_at = time.time()        
+        for line in open(NET_PROCFS_PATH):
+            is_vif = re.search(VIF_DOMAIN_RE, line.strip())
+            if not is_vif:
+                continue
+            
+            domid = int(is_vif.group('domid'))
+            vifid = int(is_vif.group('iface'))
+            rx_bytes = int(is_vif.group('rx_bytes'))
+            tx_bytes = int(is_vif.group('tx_bytes'))
+            if not domid in stats:
+                stats[domid] = {}
+                
+            stats[domid][vifid] = (usage_at, rx_bytes, tx_bytes)
+
+        return stats
+
+    def _get_pif_stats(self):
+        stats = {}
+
+        if not os.path.exists(NET_PROCFS_PATH):
+            return stats
+        
+        usage_at = time.time()        
+        for line in open(NET_PROCFS_PATH):
+            is_pif = re.search(PIF_RE, line.strip())
+            if not is_pif:
+                continue
+            
+            pifid = int(is_pif.group('iface'))
+            rx_bytes = int(is_pif.group('rx_bytes'))
+            tx_bytes = int(is_pif.group('tx_bytes'))
+            stats[pifid] = (usage_at, rx_bytes, tx_bytes)
+
+        return stats    
+
+    def _get_vbd_stats(self):
+        stats = {}
+
+        if not os.path.exists(VBD_SYSFS_PATH):
+            return stats
+        
+        for vbd_path in os.listdir(VBD_SYSFS_PATH):
+            is_vbd = re.search(VBD_DOMAIN_RE, vbd_path)
+            if not is_vbd:
+                continue
+
+            domid = int(is_vbd.group('domid'))
+            vbdid = int(is_vbd.group('devid'))
+            rd_stat_path = VBD_RD_PATH % vbd_path
+            wr_stat_path = VBD_WR_PATH % vbd_path
+            
+            if not os.path.exists(rd_stat_path) or \
+                   not os.path.exists(wr_stat_path):
+                continue
+
+            
+            try:
+                usage_at = time.time()
+                rd_stat = int(open(rd_stat_path).readline().strip())
+                wr_stat = int(open(wr_stat_path).readline().strip())
+                rd_stat *= VBD_ROUGH_BYTES_PER_REQUEST
+                wr_stat *= VBD_ROUGH_BYTES_PER_REQUEST
+                
+                if domid not in stats:
+                    stats[domid] = {}
+
+                stats[domid][vbdid] = (usage_at, rd_stat, wr_stat)
+                
+            except (IOError, ValueError):
+                continue
+
+        return stats
+
+    def _get_cpu_stats(self):
+        stats = {}
+        for domain in self.xc.domain_getinfo():
+            domid = domain['domid']
+            vcpu_count = domain['online_vcpus']
+            stats[domid] = {}
+            for i in range(vcpu_count):
+                vcpu_info = self.xc.vcpu_getinfo(domid, i)
+                usage = vcpu_info['cpu_time']
+                usage_at = time.time()
+                stats[domid][i] = (usage_at, usage)
+
+        return stats
+            
+
+    def run(self):
+
+        # loop every second for stats
+        while True:
+            self.lock.acquire()
+            try:
+            
+                # Calculate utilisation for VCPUs
+                
+                for domid, cputimes in self._get_cpu_stats().items():
+                    if domid not in self._domain_vcpus:
+                        # if not initialised, save current stats
+                        # and skip utilisation calculation
+                        self._domain_vcpus[domid] = cputimes
+                        self._domain_vcpus_util[domid] = {}
+                        continue
+
+                    for vcpu, (usage_at, usage) in cputimes.items():
+                        if vcpu not in self._domain_vcpus[domid]:
+                            continue
+                    
+                        prv_usage_at, prv_usage = \
+                                   self._domain_vcpus[domid][vcpu]
+                        interval_s = (usage_at - prv_usage_at) * 1000000000
+                        if interval_s > 0:
+                            util = (usage - prv_usage) / interval_s
+                            self._domain_vcpus_util[domid][vcpu] = util
+
+                    self._domain_vcpus[domid] = cputimes
+
+                # Calculate utilisation for VBDs
+                
+                for domid, vbds in self._get_vbd_stats().items():
+                    if domid not in self._domain_vbds:
+                        self._domain_vbds[domid] = vbds
+                        self._domain_vbds_util[domid] = {}
+                        continue
+                
+                    for devid, (usage_at, rd, wr) in vbds.items():
+                        if devid not in self._domain_vbds[domid]:
+                            continue
+                    
+                        prv_at, prv_rd, prv_wr  = \
+                                self._domain_vbds[domid][devid]
+                        interval = usage_at - prv_at
+                        rd_util = (rd - prv_rd)/interval
+                        wr_util = (wr - prv_wr)/interval
+                        self._domain_vbds_util[domid][devid] = \
+                                 (rd_util, wr_util)
+                        
+                    self._domain_vbds[domid] = vbds
+                
+
+                # Calculate utilisation for VIFs
+
+                for domid, vifs in self._get_vif_stats().items():
+                
+                    if domid not in self._domain_vifs:
+                        self._domain_vifs[domid] = vifs
+                        self._domain_vifs_util[domid] = {}
+                        continue
+                
+                    for devid, (usage_at, rx, tx) in vifs.items():
+                        if devid not in self._domain_vifs[domid]:
+                            continue
+                    
+                        prv_at, prv_rx, prv_tx  = \
+                                self._domain_vifs[domid][devid]
+                        interval = usage_at - prv_at
+                        rx_util = (rx - prv_rx)/interval
+                        tx_util = (tx - prv_tx)/interval
+
+                        # note these are flipped around because
+                        # we are measuring the host interface,
+                        # not the guest interface
+                        self._domain_vifs_util[domid][devid] = \
+                             (tx_util, rx_util)
+                        
+                    self._domain_vifs[domid] = vifs
+
+                # Calculate utilisation for PIFs
+
+                for pifid, stats in self._get_pif_stats().items():
+                    if pifid not in self.pifs:
+                        self.pifs[pifid] = stats
+                        continue
+
+                    usage_at, rx, tx = stats
+                    prv_at, prv_rx, prv_tx  = self.pifs[pifid]
+                    interval = usage_at - prv_at
+                    rx_util = (rx - prv_rx)/interval
+                    tx_util = (tx - prv_tx)/interval
+
+                    self.pifs_util[pifid] = (rx_util, tx_util)
+                    self.pifs[pifid] = stats
+
+            finally:
+                self.lock.release()
+
+            # Sleep a while before next poll
+            time.sleep(POLL_INTERVAL)
+

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog

<Prev in Thread] Current Thread [Next in Thread>
  • [Xen-changelog] [xen-unstable] [XEND] Add missing XendMonitor.py, Xen patchbot-unstable <=