Change in vdsm[master]: sampling: vm: use bulk-stats-style sample format

fromani at redhat.com fromani at redhat.com
Fri Jan 9 12:34:51 UTC 2015


Francesco Romani has uploaded a new change for review.

Change subject: sampling: vm: use bulk-stats-style sample format
......................................................................

sampling: vm: use bulk-stats-style sample format

Use the bulk stats style format for samples.
This makes room for a followup patch
which want to add the statistics gathering
using bulk stats.

Since is data is just translated and not changed,
there is no change in behaviour, but (maybe?)
a small performance penalty.

Change-Id: Ic43b1ecb5e3503f22d3b45576310a169de852b47
Signed-off-by: Francesco Romani <fromani at redhat.com>
---
M vdsm/numaUtils.py
M vdsm/virt/vm.py
2 files changed, 119 insertions(+), 43 deletions(-)


  git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/31/36731/1

diff --git a/vdsm/numaUtils.py b/vdsm/numaUtils.py
index 6207816..1d6d970 100644
--- a/vdsm/numaUtils.py
+++ b/vdsm/numaUtils.py
@@ -92,9 +92,10 @@
 def _getVcpuRuntimePinMap(sample):
     vCpuRuntimePinMap = {}
     if sample:
-        vCpuInfos = sample if sample is not None else []
-        for vCpuInfo in vCpuInfos:
-            vCpuRuntimePinMap[vCpuInfo[0]] = vCpuInfo[3]
+        for idx in xrange(sample['vcpu.maximum']):
+            if 'vcpu.%d.state' % idx in sample:
+                vCpuRuntimePinMap[idx] = sample.get(
+                    'vcpu.%d.physical' % idx, -1)
     return vCpuRuntimePinMap
 
 
diff --git a/vdsm/virt/vm.py b/vdsm/virt/vm.py
index 132f09f..27d6d0f 100644
--- a/vdsm/virt/vm.py
+++ b/vdsm/virt/vm.py
@@ -260,16 +260,16 @@
 
         try:
             stats['cpuSys'] = self._usagePercentage(
-                self._diff(eInfo, sInfo, 'user_time') +
-                self._diff(eInfo, sInfo, 'system_time'),
+                self._diff(eInfo, sInfo, 'cpu.user') +
+                self._diff(eInfo, sInfo, 'cpu.system'),
                 interval)
             stats['cpuUser'] = self._usagePercentage(
-                self._diff(eInfo, sInfo, 'cpu_time')
-                - self._diff(eInfo, sInfo, 'user_time')
-                - self._diff(eInfo, sInfo, 'system_time'),
+                self._diff(eInfo, sInfo, 'cpu.time')
+                - self._diff(eInfo, sInfo, 'cpu.user')
+                - self._diff(eInfo, sInfo, 'cpu.system'),
                 interval)
 
-        except (TypeError, ZeroDivisionError) as e:
+        except (KeyError, TypeError, ZeroDivisionError) as e:
             self._log.exception("CPU stats not available: %s", e)
 
     def _getBalloonStats(self, stats, sample):
@@ -292,7 +292,7 @@
                 'balloon_max': str(max_mem),
                 'balloon_min': str(
                     int(self._vm.conf.get('memGuaranteedSize', '0')) * 1024),
-                'balloon_cur': str(sample),
+                'balloon_cur': str(sample['balloon.current']),
                 'balloon_target': str(balloon_target)
             })
 
@@ -336,7 +336,9 @@
 
     @classmethod
     def _getNicStats(cls, name, model, mac,
-                     start_sample, end_sample, interval):
+                     start_sample, start_index,
+                     end_sample, end_index,
+                     interval):
         ifSpeed = [100, 1000][model in ('e1000', 'virtio')]
 
         ifStats = {'macAddr': mac,
@@ -344,16 +346,22 @@
                    'speed': str(ifSpeed),
                    'state': 'unknown'}
 
-        ifStats['rxErrors'] = str(end_sample[2])
-        ifStats['rxDropped'] = str(end_sample[3])
-        ifStats['txErrors'] = str(end_sample[6])
-        ifStats['txDropped'] = str(end_sample[7])
+        ifStats['rxErrors'] = str(end_sample['net.%d.rx.errs' % end_index])
+        ifStats['rxDropped'] = str(end_sample['net.%d.rx.drop' % end_index])
+        ifStats['txErrors'] = str(end_sample['net.%d.tx.errs' % end_index])
+        ifStats['txDropped'] = str(end_sample['net.%d.tx.drop' % end_index])
 
+        rxDelta = (
+            end_sample['net.%d.rx.bytes' % end_index] -
+            start_sample['net.%d.rx.bytes' % start_index])
         ifRxBytes = (100.0 *
-                     ((end_sample[0] - start_sample[0]) % 2 ** 32) /
+                     (rxDelta % 2 ** 32) /
                      interval / ifSpeed / cls.MBPS_TO_BPS)
+        txDelta = (
+            end_sample['net.%d.tx.bytes' % end_index] -
+            start_sample['net.%d.tx.bytes' % start_index])
         ifTxBytes = (100.0 *
-                     ((end_sample[4] - start_sample[4]) % 2 ** 32) /
+                     (txDelta % 2 ** 32) /
                      interval / ifSpeed / cls.MBPS_TO_BPS)
 
         ifStats['rxRate'] = '%.1f' % ifRxBytes
@@ -371,13 +379,14 @@
             if nic.name.startswith('hostdev'):
                 continue
 
+            sIdx = _findBulkStatIndex('net', nic.name, sInfo)
+            eIdx = _findBulkStatIndex('net', nic.name, eInfo)
             # may happen if nic is a new hot-plugged one
-            if nic.name not in sInfo or nic.name not in eInfo:
+            if sIdx is None or eIdx is None:
                 continue
-
             stats['network'][nic.name] = self._getNicStats(
                 nic.name, nic.nicModel, nic.macAddr,
-                sInfo[nic.name], eInfo[nic.name], interval)
+                sInfo, sIdx, eInfo, eIdx, sampleInterval)
 
     def _getDiskStats(self, stats, sInfo, eInfo, interval):
         for vmDrive in self._vm.getDiskDevices():
@@ -392,12 +401,14 @@
                     dStats['imageID'] = vmDrive.imageID
                 elif "GUID" in vmDrive:
                     dStats['lunGUID'] = vmDrive.GUID
-                if (sInfo and vmDrive.name in sInfo and
-                        eInfo and vmDrive.name in eInfo):
+                sIdx = _findBulkStatIndex('block', vmDrive.name, sInfo)
+                eIdx = _findBulkStatIndex('block', vmDrive.name, eInfo)
+                if sIdx is not None and eIdx is not None:
                     # will be None if sampled during recovery
-                    dStats.update(_calcDiskRate(vmDrive, sInfo, eInfo,
-                                                interval))
-                    dStats.update(_calcDiskLatency(vmDrive, sInfo, eInfo))
+                    dStats.update(_calcDiskRate(sInfo, sIdx,
+                                                eInfo, eIdx,
+                                                sampleInterval))
+                    dStats.update(_calcDiskLatency(sInfo, sIdx, eInfo, eIdx))
 
             except (AttributeError, TypeError, ZeroDivisionError):
                 self._log.exception("Disk %s stats not available",
@@ -712,22 +723,33 @@
         return infos
 
     def _getSampleCpu(self):
-        return self.sampleCpu.getStats()
+        stats = self.sampleCpu.getStats()
+        return {
+            'cpu.user': stats['user_time'],
+            'cpu.system': stats['system_time'],
+            'cpu.time': stats['cpu_time']}
 
     def _getSampleNet(self):
-        return self.sampleNet.getStats()
+        sInfo, eInfo, interval = self.sampleNet.getStats()
+        return (_translateNetSample(sInfo),
+                _translateNetSample(eInfo),
+                interval)
 
     def _getSampleDisk(self):
-        return self.sampleDisk.getStats()
+        sInfo, eInfo, interval = self.sampleDisk.getStats()
+        return (_translateDiskSample(sInfo),
+                _translateDiskSample(eInfo),
+                interval)
 
     def _getSampleBalloon(self):
-        return self.sampleBalloon.getLastSample()
+        return {
+            'balloon.current': self.sampleBalloon.getLastSample()}
 
     def _getSampleVmJobs(self):
         return self.sampleVmJobs.getLastSample()
 
     def _getSampleVcpu(self):
-        return self.sampleVcpuPinning.getLastSample()
+        return _translateVcpuSample(self.sampleVcpuPinning.getLastSample())
 
     def _getSampleCpuTune(self):
         return self.sampleCpuTune.getLastSample()
@@ -744,33 +766,86 @@
         return True
 
 
-def _calcDiskRate(vmDrive, sInfo, eInfo, sampleInterval):
+def _findBulkStatIndex(group, value, stats, attr='name'):
+    if stats:
+        for idx in xrange(stats['%s.count' % group]):
+            if stats['%s.%d.%s' % (group, idx, attr)] == value:
+                return idx
+    return None
+
+
+def _translateNetSample(oldInfo):
+    newInfo = {'net.count': len(oldInfo)}
+    for idx, (name, values) in enumerate(oldInfo.iteritems()):
+        newInfo['net.%d.name' % idx] = name
+        newInfo['net.%d.rx.bytes' % (idx)] = values[0]
+        newInfo['net.%d.rx.pkts' % (idx)] = values[1]
+        newInfo['net.%d.rx.errs' % (idx)] = values[2]
+        newInfo['net.%d.rx.drop' % (idx)] = values[3]
+        newInfo['net.%d.tx.bytes' % (idx)] = values[4]
+        newInfo['net.%d.tx.pkts' % (idx)] = values[5]
+        newInfo['net.%d.tx.errs' % (idx)] = values[6]
+        newInfo['net.%d.tx.drop' % (idx)] = values[7]
+    return newInfo
+
+
+def _translateDiskSample(oldInfo):
+    newInfo = {'block.count': len(oldInfo)}
+    for idx, (name values) in enumerate(oldInfo.iteritems()):
+        newInfo['block.%d.name' % idx] = name
+        newInfo['block.%d.rd.times' % idx] = values['rd_total_times']
+        newInfo['block.%d.wr.times' % idx] = values['wr_total_times']
+        newInfo['block.%d.fl.times' % idx] = values['flush_total_times']
+        newInfo['block.%d.rd.reqs' % idx] = values['rd_operations']
+        newInfo['block.%d.wr.reqs' % idx] = values['wr_operations']
+        newInfo['block.%d.fl.reqs' % idx] = values['flush_operations']
+        newInfo['block.%d.rd.bytes' % idx] = values['rd_bytes']
+        newInfo['block.%d.wr.bytes' % idx] = values['wr_bytes']
+    return newInfo
+
+
+def _translateVcpuSample(oldInfo):
+    newInfo = {'vcpu.current': len(oldInfo)}
+    vcpuMax = 0
+    for (vcpuNum, vcpuState, vcpuTime, pcpuNum) in oldInfo:
+        vcpuMax = max(vcpuMax, vcpuNum)
+        newInfo['vcpu.%d.state' % vcpuNum] = vcpuState
+        newInfo['vcpu.%d.time' % vcpuNum] = vcpuTime
+        newInfo['vcpu.%d.physical' % vcpuNum] = pcpuNum
+    # yep, just guesswork
+    newInfo['vcpu.maximum'] = vcpuMax
+    return newInfo
+
+
+def _calcDiskRate(sInfo, sIdx, eInfo, eIdx, sampleInterval):
     return {
         'readRate': (
-            (eInfo[vmDrive.name]['rd_bytes'] -
-             sInfo[vmDrive.name]['rd_bytes'])
+            (eInfo['block.%d.rd.bytes' % eIdx] -
+             sInfo['block.%d.rd.bytes' % sIdx])
             / sampleInterval),
         'writeRate': (
-            (eInfo[vmDrive.name]['wr_bytes'] -
-             sInfo[vmDrive.name]['wr_bytes'])
+            (eInfo['block.%d.wr.bytes' % eIdx] -
+             sInfo['block.%d.wr.bytes' % sIdx])
             / sampleInterval)}
 
 
-def _calcDiskLatency(vmDrive, sInfo, eInfo):
-    dname = vmDrive.name
-
+def _calcDiskLatency(sInfo, sIdx, eInfo, eIdx):
     def compute_latency(ltype):
-        ops = ltype + '_operations'
-        operations = eInfo[dname][ops] - sInfo[dname][ops]
+        ops = ltype + '.reqs'
+        operations = (
+            eInfo['block.%d.%s' % (eIdx, ops)] -
+            sInfo['block.%d.%s' % (sIdx, ops)])
         if not operations:
             return 0
-        times = ltype + '_total_times'
-        elapsed_time = eInfo[dname][times] - sInfo[dname][times]
+        times = ltype + '.times'
+        elapsed_time = (
+            eInfo['block.%d.%s' % (eIdx, times)] -
+            sInfo['block.%d.%s' % (sIdx, times)])
         return elapsed_time / operations
 
     return {'readLatency': str(compute_latency('rd')),
             'writeLatency': str(compute_latency('wr')),
-            'flushLatency': str(compute_latency('flush'))}
+            'flushLatency': str(compute_latency('fl'))}
 
 
 class TimeoutError(libvirt.libvirtError):


-- 
To view, visit http://gerrit.ovirt.org/36731
To unsubscribe, visit http://gerrit.ovirt.org/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: Ic43b1ecb5e3503f22d3b45576310a169de852b47
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Francesco Romani <fromani at redhat.com>


More information about the vdsm-patches mailing list