ramp generator traffic & prox.log copy 34/71134/1
authorLuc Provoost <luc.provoost@intel.com>
Wed, 16 Sep 2020 07:52:06 +0000 (09:52 +0200)
committerLuc Provoost <luc.provoost@intel.com>
Wed, 16 Sep 2020 07:52:06 +0000 (09:52 +0200)
A new parameter can be put in the *.test files so that the requested
traffic is not generated at once, but slowly increasing up to the
requested traffic. This is important for some SW switched that adapt and
learn from the applied traffic. When suddenly applying a high traffic,
the switch might not have enough time to learn and lose packets. Only
after a period of time (up to 10 seconds?), the switch can cope with the
traffic without packet loss. In order to get reproducible results in
this case with low packet loss, please put the parameter ramp_step in
the test section of the *.test file. The step is expressed in percentage
of a 10Gb/s traffic. If the parameter is not present, the load will be
immediately applied.
When the runrapid.py script is now finished, it also copies the prox.log
files from all the prox instances. In case of issues, please investigate
this log file.
When using background traffic, the tool will also print the average
background traffic for each step in the DEBUG log. In this way, you can
check that the background traffic is actually dealing with the same
amount of traffic as the foreground. The tool is printing the packet
reception rate of the background generators.
A bug was also fixed regarding the latency percentile reporting. When
using tests involving l2gen.cfg, the values of the percentile latency
were wrong.

Change-Id: Id3dd02ed5cab084414c717cf898b30e6980ddf31
Signed-off-by: Luc Provoost <luc.provoost@intel.com>
VNFs/DPPD-PROX/helper-scripts/rapid/basicrapid.test
VNFs/DPPD-PROX/helper-scripts/rapid/l2gen.cfg
VNFs/DPPD-PROX/helper-scripts/rapid/prox_ctrl.py
VNFs/DPPD-PROX/helper-scripts/rapid/rapid_machine.py
VNFs/DPPD-PROX/helper-scripts/rapid/rapid_parser.py
VNFs/DPPD-PROX/helper-scripts/rapid/rapid_test.py

index 80710f3..fbf75a0 100644 (file)
@@ -66,3 +66,4 @@ lat_perc_threshold = 80
 lat_max_threshold = inf
 accuracy = 1
 startspeed = 50
+#ramp_step = 1
index e4c1c37..74ac20e 100644 (file)
@@ -69,3 +69,4 @@ accuracy pos=46
 packet id pos=50
 signature=0x98765432
 signature pos=56
+latency bucket size=${bucket_size_exp}
index 3ee4e83..6f00584 100644 (file)
@@ -193,6 +193,28 @@ class prox_ctrl(object):
             raise RuntimeError('scp returned exit status %d:\n%s'
                     % (ex.returncode, ex.output.strip()))
 
+    def scp_get(self, src, dst):
+        """Copy src file from remote system to dst on local system."""
+        cmd = [ 'scp',
+                '-B',
+                '-oStrictHostKeyChecking=no',
+                '-oUserKnownHostsFile=/dev/null',
+                '-oLogLevel=ERROR' ]
+        if self._key is not None:
+            cmd.extend(['-i', self._key])
+        remote = ''
+        if self._user is not None:
+            remote += self._user + '@'
+        remote += self._ip + ':/home/' + self._user + src
+        cmd.append(remote)
+        cmd.append(dst)
+        try:
+            # Actually ignore output on success, but capture stderr on failure
+            subprocess.check_output(cmd, stderr=subprocess.STDOUT)
+        except subprocess.CalledProcessError as ex:
+            raise RuntimeError('scp returned exit status %d:\n%s'
+                    % (ex.returncode, ex.output.strip()))
+
     def _build_ssh(self, command):
         cmd = [ 'ssh',
                 '-oBatchMode=yes',
index fc3e291..b89c038 100644 (file)
@@ -52,6 +52,9 @@ class RapidMachine(object):
         self.generate_lua(vim)
         self._client.scp_put(self.machine_params['config_file'], '{}/{}'.format(self.rundir, machine_params['config_file']))
 
+    def __del__(self):
+        self._client.scp_get('/prox.log', './{}.prox.log'.format(self.name))
+
     def get_cores(self):
         return (self.machine_params['cores'])
 
index d0a579b..289d836 100644 (file)
@@ -72,7 +72,7 @@ class RapidConfigParser(object):
                 elif option in ['startspeed', 'step', 'drop_rate_threshold',
                         'lat_avg_threshold','lat_perc_threshold',
                         'lat_max_threshold','accuracy','maxr','maxz',
-                        'pass_threshold']:
+                        'pass_threshold','ramp_step']:
                     test[option] = float(testconfig.get(section, option))
                 else:
                     test[option] = testconfig.get(section, option)
index 9cbc4de..6654d36 100644 (file)
@@ -202,8 +202,34 @@ class RapidTest(object):
             t1_rx, t1_non_dp_rx, t1_tx, t1_non_dp_tx, t1_drop, t1_tx_fail, t1_tsc, abs_tsc_hz = self.gen_machine.core_stats()
             t1_dp_rx = t1_rx - t1_non_dp_rx
             t1_dp_tx = t1_tx - t1_non_dp_tx
+            self.gen_machine.set_generator_speed(0)
             self.gen_machine.start_gen_cores()
+            if self.background_machines:
+                self.set_background_speed(self.background_machines, 0)
+                self.start_background_traffic(self.background_machines)
+            if 'ramp_step' in self.test.keys():
+                ramp_speed = self.test['ramp_step']
+            else:
+                ramp_speed = speed
+            while ramp_speed < speed:
+                self.gen_machine.set_generator_speed(ramp_speed)
+                if self.background_machines:
+                    self.set_background_speed(self.background_machines, ramp_speed)
+                time.sleep(2)
+                ramp_speed = ramp_speed + self.test['ramp_step']
+            self.gen_machine.set_generator_speed(speed)
+            if self.background_machines:
+                self.set_background_speed(self.background_machines, speed)
             time.sleep(2) ## Needs to be 2 seconds since this 1 sec is the time that PROX uses to refresh the stats. Note that this can be changed in PROX!! Don't do it.
+            start_bg_gen_stats = []
+            for bg_gen_machine in self.background_machines:
+                bg_rx, bg_non_dp_rx, bg_tx, bg_non_dp_tx, _, _, bg_tsc, _ = bg_gen_machine.core_stats()
+                bg_gen_stat = {
+                        "bg_dp_rx" : bg_rx - bg_non_dp_rx,
+                        "bg_dp_tx" : bg_tx - bg_non_dp_tx,
+                        "bg_tsc"   : bg_tsc
+                        }
+                start_bg_gen_stats.append(dict(bg_gen_stat))
             if self.sut_machine!= None:
                 t2_sut_rx, t2_sut_non_dp_rx, t2_sut_tx, t2_sut_non_dp_tx, t2_sut_drop, t2_sut_tx_fail, t2_sut_tsc, sut_tsc_hz = self.sut_machine.core_stats()
             t2_rx, t2_non_dp_rx, t2_tx, t2_non_dp_tx, t2_drop, t2_tx_fail, t2_tsc, tsc_hz = self.gen_machine.core_stats()
@@ -327,6 +353,27 @@ class RapidTest(object):
                                 'PacketsReceived': delta_dp_rx,
                                 'PacketsLost': tot_dp_drop}
                         self.post_data('rapid_flowsizetest', variables)
+            end_bg_gen_stats = []
+            for bg_gen_machine in self.background_machines:
+                bg_rx, bg_non_dp_rx, bg_tx, bg_non_dp_tx, _, _, bg_tsc, bg_hz = bg_gen_machine.core_stats()
+                bg_gen_stat = {"bg_dp_rx" : bg_rx - bg_non_dp_rx,
+                        "bg_dp_tx" : bg_tx - bg_non_dp_tx,
+                        "bg_tsc"   : bg_tsc,
+                        "bg_hz"    : bg_hz
+                        }
+                end_bg_gen_stats.append(dict(bg_gen_stat))
+            i = 0
+            bg_rates =[]
+            while i < len(end_bg_gen_stats):
+                bg_rates.append(0.000001*(end_bg_gen_stats[i]['bg_dp_rx'] -
+                    start_bg_gen_stats[i]['bg_dp_rx']) / ((end_bg_gen_stats[i]['bg_tsc'] -
+                    start_bg_gen_stats[i]['bg_tsc']) * 1.0 / end_bg_gen_stats[i]['bg_hz']))
+                i += 1
+            if len(bg_rates):
+                avg_bg_rate = sum(bg_rates) / len(bg_rates)
+                RapidLog.debug('Average Background traffic rate: {:>7.3f} Mpps'.format(avg_bg_rate))
+            else:
+                avg_bg_rate = None
             #Stop generating
             self.gen_machine.stop_gen_cores()
             r += 1