From f8b45aca386ed5852d9568c531ba4595c68cc0e2 Mon Sep 17 00:00:00 2001
From: DanielMartinBuckley <daniel.m.buckley@intel.com>
Date: Tue, 5 Jun 2018 19:06:38 +0100
Subject: Decrease Sampling interval

JIRA: YARDSTICK-1219

Currently NSB for NFVI using PROX returns sampling information every 13
seconds.

This is too slow.

It is required to return sampling information form Generator AND VNF at
least every  1 second.

This change is depandant on JIRA: YARDSTICK-1212 and YARDSTICK-1220

Change-Id: Ica7ab795a2919d191d8cd846d028e15739e33fb7
Signed-off-by: Daniel Martin Buckley <daniel.m.buckley@intel.com>
---
 .../vnf_generic/vnf/prox_helpers.py                | 76 ++++++++++++++++++----
 .../network_services/vnf_generic/vnf/prox_vnf.py   | 28 +++++---
 yardstick/tests/unit/common/test_utils.py          |  1 +
 .../vnf_generic/vnf/test_prox_helpers.py           | 49 ++++++++++----
 .../vnf_generic/vnf/test_prox_vnf.py               |  9 +--
 5 files changed, 124 insertions(+), 39 deletions(-)

diff --git a/yardstick/network_services/vnf_generic/vnf/prox_helpers.py b/yardstick/network_services/vnf_generic/vnf/prox_helpers.py
index 7816c6d91..ad826f905 100644
--- a/yardstick/network_services/vnf_generic/vnf/prox_helpers.py
+++ b/yardstick/network_services/vnf_generic/vnf/prox_helpers.py
@@ -325,7 +325,7 @@ class ProxSocketHelper(object):
 
         return ret_str, False
 
-    def get_data(self, pkt_dump_only=False, timeout=1):
+    def get_data(self, pkt_dump_only=False, timeout=0.01):
         """ read data from the socket """
 
         # This method behaves slightly differently depending on whether it is
@@ -532,6 +532,51 @@ class ProxSocketHelper(object):
             tsc = int(ret[3])
         return rx, tx, drop, tsc
 
+    def multi_port_stats(self, ports):
+        """get counter values from all ports port"""
+
+        ports_str = ""
+        for port in ports:
+            ports_str = ports_str + str(port) + ","
+        ports_str = ports_str[:-1]
+
+        ports_all_data = []
+        tot_result = [0] * len(ports)
+
+        retry_counter = 0
+        port_index = 0
+        while (len(ports) is not len(ports_all_data)) and (retry_counter < 10):
+            self.put_command("multi port stats {}\n".format(ports_str))
+            ports_all_data = self.get_data().split(";")
+
+            if len(ports) is len(ports_all_data):
+                for port_data_str in ports_all_data:
+
+                    try:
+                        tot_result[port_index] = [try_int(s, 0) for s in port_data_str.split(",")]
+                    except (IndexError, TypeError):
+                        LOG.error("Port Index error %d  %s - retrying ", port_index, port_data_str)
+
+                    if (len(tot_result[port_index]) is not 6) or \
+                                    tot_result[port_index][0] is not ports[port_index]:
+                        ports_all_data = []
+                        tot_result = [0] * len(ports)
+                        port_index = 0
+                        time.sleep(0.1)
+                        LOG.error("Corrupted PACKET %s - retrying", port_data_str)
+                        break
+                    else:
+                        port_index = port_index + 1
+            else:
+                LOG.error("Empty / too much data - retry -%s-", ports_all_data)
+                ports_all_data = []
+                tot_result = [0] * len(ports)
+                port_index = 0
+                time.sleep(0.1)
+
+            retry_counter = retry_counter + 1
+        return tot_result
+
     def port_stats(self, ports):
         """get counter values from a specific port"""
         tot_result = [0] * 12
@@ -1012,7 +1057,11 @@ class ProxDataHelper(object):
     @property
     def totals_and_pps(self):
         if self._totals_and_pps is None:
-            rx_total, tx_total = self.sut.port_stats(range(self.port_count))[6:8]
+            rx_total = tx_total = 0
+            all_ports = self.sut.multi_port_stats(range(self.port_count))
+            for port in all_ports:
+                rx_total = rx_total + port[1]
+                tx_total = tx_total + port[2]
             requested_pps = self.value / 100.0 * self.line_rate_to_pps()
             self._totals_and_pps = rx_total, tx_total, requested_pps
         return self._totals_and_pps
@@ -1032,19 +1081,18 @@ class ProxDataHelper(object):
     @property
     def samples(self):
         samples = {}
+        ports = []
+        port_names = []
         for port_name, port_num in self.vnfd_helper.ports_iter():
-            try:
-                port_rx_total, port_tx_total = self.sut.port_stats([port_num])[6:8]
-                samples[port_name] = {
-                    "in_packets": port_rx_total,
-                    "out_packets": port_tx_total,
-                }
-            except (KeyError, TypeError, NameError, MemoryError, ValueError,
-                    SystemError, BufferError):
-                samples[port_name] = {
-                    "in_packets": 0,
-                    "out_packets": 0,
-                }
+            ports.append(port_num)
+            port_names.append(port_name)
+
+        results = self.sut.multi_port_stats(ports)
+        for result in results:
+            port_num = result[0]
+            samples[port_names[port_num]] = {
+                    "in_packets": result[1],
+                    "out_packets": result[2]}
         return samples
 
     def __enter__(self):
diff --git a/yardstick/network_services/vnf_generic/vnf/prox_vnf.py b/yardstick/network_services/vnf_generic/vnf/prox_vnf.py
index 36f1a19d0..63295c2e6 100644
--- a/yardstick/network_services/vnf_generic/vnf/prox_vnf.py
+++ b/yardstick/network_services/vnf_generic/vnf/prox_vnf.py
@@ -89,14 +89,15 @@ class ProxApproxVnf(SampleVNF):
             raise RuntimeError("Failed ..Invalid no of ports .. "
                                "1, 2 or 4 ports only supported at this time")
 
-        self.port_stats = self.vnf_execute('port_stats', range(port_count))
+        all_port_stats = self.vnf_execute('multi_port_stats', range(port_count))
+        rx_total = tx_total = 0
         try:
-            rx_total = self.port_stats[6]
-            tx_total = self.port_stats[7]
-            tsc = self.port_stats[10]
-        except IndexError:
-            LOG.debug("port_stats parse fail ")
-            # return empty dict so we don't mess up existing KPIs
+            for single_port_stats in all_port_stats:
+                rx_total = rx_total + single_port_stats[1]
+                tx_total = tx_total + single_port_stats[2]
+                tsc = single_port_stats[5]
+        except (TypeError, IndexError):
+            LOG.error("Invalid data ...")
             return {}
 
         result = {
@@ -107,10 +108,19 @@ class ProxApproxVnf(SampleVNF):
             # collectd KPIs here and not TG KPIs, so use a different method name
             "collect_stats": self.resource_helper.collect_collectd_kpi(),
         }
-        curr_packets_in = int(((rx_total - self.prev_packets_in) * self.tsc_hz)
+        try:
+            curr_packets_in = int(((rx_total - self.prev_packets_in) * self.tsc_hz)
                                 / (tsc - self.prev_tsc) * port_count)
-        curr_packets_fwd = int(((tx_total - self.prev_packets_sent) * self.tsc_hz)
+        except ZeroDivisionError:
+            LOG.error("Error.... Divide by Zero")
+            curr_packets_in = 0
+
+        try:
+            curr_packets_fwd = int(((tx_total - self.prev_packets_sent) * self.tsc_hz)
                                 / (tsc - self.prev_tsc) * port_count)
+        except ZeroDivisionError:
+            LOG.error("Error.... Divide by Zero")
+            curr_packets_fwd = 0
 
         result["curr_packets_in"] = curr_packets_in
         result["curr_packets_fwd"] = curr_packets_fwd
diff --git a/yardstick/tests/unit/common/test_utils.py b/yardstick/tests/unit/common/test_utils.py
index 6e7a0bfc4..6247afd18 100644
--- a/yardstick/tests/unit/common/test_utils.py
+++ b/yardstick/tests/unit/common/test_utils.py
@@ -19,6 +19,7 @@ from six.moves import configparser
 import time
 import unittest
 
+import yardstick
 from yardstick import ssh
 from yardstick.common import constants
 from yardstick.common import utils
diff --git a/yardstick/tests/unit/network_services/vnf_generic/vnf/test_prox_helpers.py b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_prox_helpers.py
index cc695a5bf..1c3acb6e5 100644
--- a/yardstick/tests/unit/network_services/vnf_generic/vnf/test_prox_helpers.py
+++ b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_prox_helpers.py
@@ -560,6 +560,31 @@ class TestProxSocketHelper(unittest.TestCase):
         result = prox.core_stats([3, 4, 5], 16)
         self.assertEqual(result, expected)
 
+    def test_multi_port_stats(self):
+
+        mock_socket = mock.MagicMock()
+        prox = ProxSocketHelper(mock_socket)
+        prox.get_data = mock.MagicMock(return_value='0,1,2,3,4,5;1,1,2,3,4,5')
+        expected = [[0, 1, 2, 3, 4, 5], [1, 1, 2, 3, 4, 5]]
+        result = prox.multi_port_stats([0, 1])
+        self.assertEqual(result, expected)
+
+        prox.get_data = mock.MagicMock(return_value='0,1,2,3,4,5;1,1,2,3,4,5')
+        result = prox.multi_port_stats([0])
+        expected = [0]
+        self.assertEqual(result, expected)
+
+        prox.get_data = mock.MagicMock(return_value='0,1,2,3;1,1,2,3,4,5')
+        result = prox.multi_port_stats([0, 1])
+        expected = [0] * 2
+        self.assertEqual(result, expected)
+
+        prox.get_data = mock.MagicMock(return_value='99,1,2,3,4,5;1,1,2,3,4,5')
+        expected = [0] * 2
+        result = prox.multi_port_stats([0, 1])
+        self.assertEqual(result, expected)
+
+
     def test_port_stats(self):
         port_stats = [
             ','.join(str(n) for n in range(3, 15)),
@@ -1546,34 +1571,34 @@ class TestProxDataHelper(unittest.TestCase):
         vnfd_helper.port_pairs.all_ports = list(range(4))
 
         sut = mock.MagicMock()
-        sut.port_stats.return_value = list(range(10))
+        sut.multi_port_stats.return_value = [[0, 1, 2, 3, 4, 5], [1, 1, 2, 3, 4, 5],
+                                             [2, 1, 2, 3, 4, 5], [3, 1, 2, 3, 4, 5]]
 
         data_helper = ProxDataHelper(
             vnfd_helper, sut, pkt_size, 25, None,
             constants.NIC_GBPS_DEFAULT * constants.ONE_GIGABIT_IN_BITS)
 
-        self.assertEqual(data_helper.rx_total, 6)
-        self.assertEqual(data_helper.tx_total, 7)
+        self.assertEqual(data_helper.rx_total, 4)
+        self.assertEqual(data_helper.tx_total, 8)
         self.assertEqual(data_helper.requested_pps, 6.25e6)
 
     def test_samples(self):
         vnfd_helper = mock.MagicMock()
-        vnfd_helper.port_pairs.all_ports = list(range(4))
-        vnfd_helper.ports_iter.return_value = [('xe1', 3), ('xe2', 7)]
+        vnfd_helper.ports_iter.return_value = [('xe0', 0), ('xe1', 1)]
 
         sut = mock.MagicMock()
-        sut.port_stats.return_value = list(range(10))
+        sut.multi_port_stats.return_value = [[0, 1, 2, 3, 4, 5], [1, 11, 12, 3, 4, 5]]
 
         data_helper = ProxDataHelper(vnfd_helper, sut, None, None, None, None)
 
         expected = {
-            'xe1': {
-                'in_packets': 6,
-                'out_packets': 7,
+            'xe0': {
+                'in_packets': 1,
+                'out_packets': 2,
             },
-            'xe2': {
-                'in_packets': 6,
-                'out_packets': 7,
+            'xe1': {
+                'in_packets': 11,
+                'out_packets': 12,
             },
         }
         result = data_helper.samples
diff --git a/yardstick/tests/unit/network_services/vnf_generic/vnf/test_prox_vnf.py b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_prox_vnf.py
index f5f4b3907..b23854e9f 100644
--- a/yardstick/tests/unit/network_services/vnf_generic/vnf/test_prox_vnf.py
+++ b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_prox_vnf.py
@@ -339,16 +339,17 @@ class TestProxApproxVnf(unittest.TestCase):
         mock_ssh(ssh)
 
         resource_helper = mock.MagicMock()
-        resource_helper.execute.return_value = list(range(12))
+        resource_helper.execute.return_value = [[0, 1, 2, 3, 4, 5], [1, 1, 2, 3, 4, 5],
+                                                [2, 1, 2, 3, 4, 5], [3, 1, 2, 3, 4, 5]]
         resource_helper.collect_collectd_kpi.return_value = {'core': {'result': 234}}
 
         prox_approx_vnf = ProxApproxVnf(NAME, self.VNFD0)
         prox_approx_vnf.resource_helper = resource_helper
 
         expected = {
-            'packets_in': 6,
-            'packets_dropped': 1,
-            'packets_fwd': 7,
+            'packets_in': 4,
+            'packets_dropped': 4,
+            'packets_fwd': 8,
             'collect_stats': {'core': {'result': 234}},
         }
         result = prox_approx_vnf.collect_kpi()
-- 
cgit