Performance: TRex approximatedDuration and approximateRate 84/24284/10
authorPeter Mikus <pmikus@cisco.com>
Fri, 10 Jan 2020 12:44:45 +0000 (12:44 +0000)
committerPeter Mikus <pmikus@cisco.com>
Mon, 27 Apr 2020 13:57:08 +0000 (13:57 +0000)
- API to provide duration for send and receive traffic

Signed-off-by: Peter Mikus <pmikus@cisco.com>
Change-Id: Id186a200be66b7703348e6fd3099ffd405e915ae

resources/libraries/python/TrafficGenerator.py
resources/libraries/robot/performance/performance_utils.robot
resources/tools/trex/trex_stateless_profile.py
resources/tools/trex/trex_stateless_stop.py

index 4e3a549..539ced5 100644 (file)
@@ -151,6 +151,8 @@ class TrafficGenerator(AbstractMeasurer):
         self._sent = None
         self._latency = None
         self._received = None
+        self._approximated_rate = None
+        self._approximated_duration = None
         # Measurement input fields, needed for async stop result.
         self._start_time = None
         self._rate = None
@@ -204,6 +206,15 @@ class TrafficGenerator(AbstractMeasurer):
         """
         return self._latency
 
+    def get_approximated_rate(self):
+        """Return approximated rate computed as ratio of transmited packets over
+        duration of trial.
+
+        :returns: Approximated rate.
+        :rtype: str
+        """
+        return self._approximated_rate
+
     # TODO: pylint says disable=too-many-locals.
     # A fix is developed in https://gerrit.fd.io/r/c/csit/+/22221
     def initialize_traffic_generator(
@@ -460,9 +471,12 @@ class TrafficGenerator(AbstractMeasurer):
         self._received = self._result.split(u", ")[1].split(u"=", 1)[1]
         self._sent = self._result.split(u", ")[2].split(u"=", 1)[1]
         self._loss = self._result.split(u", ")[3].split(u"=", 1)[1]
+        self._approximated_duration = \
+            self._result.split(u", ")[5].split(u"=", 1)[1]
+        self._approximated_rate = self._result.split(u", ")[6].split(u"=", 1)[1]
         self._latency = list()
-        self._latency.append(self._result.split(u", ")[4].split(u"=", 1)[1])
-        self._latency.append(self._result.split(u", ")[5].split(u"=", 1)[1])
+        self._latency.append(self._result.split(u", ")[7].split(u"=", 1)[1])
+        self._latency.append(self._result.split(u", ")[8].split(u"=", 1)[1])
 
     def trex_stl_stop_remote_exec(self, node):
         """Execute script on remote node over ssh to stop running traffic.
@@ -748,6 +762,7 @@ class TrafficGenerator(AbstractMeasurer):
             duration, transmit_rate, transmit_count, loss_count
         )
         measurement.latency = self.get_latency_int()
+        measurement.approximated_rate = self.get_approximated_rate()
         return measurement
 
     def measure(self, duration, transmit_rate):
index 52ddc91..ee49b98 100644 (file)
 | | ... | ${fail_no_traffic}=${True} | ${subsamples}=${PERF_TRIAL_MULTIPLICITY}
 | | ... | ${traffic_directions}=${2} | ${tx_port}=${0} | ${rx_port}=${1}
 | |
-| | ${results} = | Send traffic at specified rate | ${trial_duration}
+| | ${results} | ${approximated_results} = | Send traffic at specified rate
+| | ... | ${trial_duration}
 | | ... | ${max_rate}pps | ${frame_size} | ${traffic_profile} | ${subsamples}
 | | ... | ${traffic_directions} | ${tx_port} | ${rx_port}
 | | Set Test Message | ${\n}Maximum Receive Rate trial results
 | | Run Keyword If | ${dut_stats}==${True}
 | | ... | VPP enable elog traces on all DUTs | ${nodes}
 | | ${results} = | Create List
+| | ${approximated_results} = | Create List
 | | FOR | ${i} | IN RANGE | ${subsamples}
 | | | # The following line is skipping some default arguments,
 | | | # that is why subsequent arguments have to be named.
 | | | ... | traffic_directions=${traffic_directions} | tx_port=${tx_port}
 | | | ... | rx_port=${rx_port}
 | | | ${rx} = | Get Received
+| | | ${ar} = | Get Approximated Rate
 | | | ${rr} = | Evaluate | ${rx} / ${trial_duration}
 | | | Append To List | ${results} | ${rr}
+| | | Append To List | ${approximated_results} | ${ar}
 | | END
 | | Run Keyword If | ${dut_stats}==${True} | Show event logger on all DUTs
 | | ... | ${nodes}
 | | ... | ${nodes}
 | | Run Keyword If | ${dut_stats}==${True} and ${pkt_trace}==${True}
 | | ... | Show Packet Trace On All Duts | ${nodes} | maximum=${100}
-| | Return From Keyword | ${results}
+| | Return From Keyword | ${results} | ${approximated_results}
 
 | Measure and show latency at specified rate
 | | [Documentation]
index a41e4e8..a0de5c0 100755 (executable)
@@ -1,6 +1,6 @@
 #!/usr/bin/python3
 
-# Copyright (c) 2019 Cisco and/or its affiliates.
+# Copyright (c) 2020 Cisco and/or its affiliates.
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
 # You may obtain a copy of the License at:
@@ -105,6 +105,8 @@ def simple_burst(
     client = None
     total_rcvd = 0
     total_sent = 0
+    approximated_duration = 0
+    approximated_rate = 0
     lost_a = 0
     lost_b = 0
     lat_a = u"-1/-1/-1/"
@@ -161,14 +163,14 @@ def simple_burst(
             client.clear_stats()
 
             # Choose rate and start traffic:
-            time_start = time.time()
             client.start(ports=ports, mult=rate, duration=warmup_time,
                          force=force)
 
             # Block until done:
+            time_start = time.monotonic()
             client.wait_on_traffic(ports=ports, timeout=warmup_time+30)
-            time_stop = time.time()
-            print(f"Warmup traffic took {time_stop - time_start} seconds.")
+            time_stop = time.monotonic()
+            approximated_duration = time_stop - time_start
 
             if client.get_warnings():
                 for warning in client.get_warnings():
@@ -194,8 +196,7 @@ def simple_burst(
         lost_b = 0
 
         # Choose rate and start traffic:
-        client.start(ports=ports, mult=rate, duration=duration, force=force)
-        time_start = time.time()
+        client.start(ports=ports, mult=rate, duration=duration)
 
         if async_start:
             # For async stop, we need to export the current snapshot.
@@ -206,9 +207,10 @@ def simple_burst(
                 print(f"Xstats snapshot 1: {xsnap1!r}")
         else:
             # Block until done:
+            time_start = time.monotonic()
             client.wait_on_traffic(ports=ports, timeout=duration+30)
-            time_stop = time.time()
-            print(f"Main traffic took {time_stop - time_start} seconds.")
+            time_stop = time.monotonic()
+            approximated_duration = time_stop - time_start
 
             if client.get_warnings():
                 for warning in client.get_warnings():
@@ -225,7 +227,6 @@ def simple_burst(
                 lost_b = stats[port_1][u"opackets"] - stats[port_0][u"ipackets"]
 
             # Stats index is not a port number, but "pgid".
-            # TODO: Find out what "pgid" means.
             if latency:
                 lat_obj = stats[u"latency"][0][u"latency"]
                 lat_a = fmt_latency(
@@ -243,6 +244,10 @@ def simple_burst(
             else:
                 total_sent = stats[port_0][u"opackets"]
                 total_rcvd = stats[port_1][u"ipackets"]
+            try:
+                approximated_rate = total_sent / approximated_duration
+            except ZeroDivisionError:
+                pass
 
             print(f"\npackets lost from {port_0} --> {port_1}: {lost_a} pkts")
             if traffic_directions > 1:
@@ -262,8 +267,10 @@ def simple_burst(
             print(
                 f"rate={rate!r}, totalReceived={total_rcvd}, "
                 f"totalSent={total_sent}, frameLoss={lost_a + lost_b}, "
+                f"targetDuration={duration!r}, "
+                f"approximatedDuration={approximated_duration!r}, "
+                f"approximatedRate={approximated_rate}, "
                 f"latencyStream0(usec)={lat_a}, latencyStream1(usec)={lat_b}, "
-                f"targetDuration={duration!r}"
             )
 
 
index d4461ff..5e8721d 100755 (executable)
@@ -1,6 +1,6 @@
 #!/usr/bin/python3
 
-# Copyright (c) 2019 Cisco and/or its affiliates.
+# Copyright (c) 2020 Cisco and/or its affiliates.
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
 # You may obtain a copy of the License at:
@@ -94,8 +94,9 @@ def main():
     # TODO: Add latency.
     print(
         f"rate='unknown', totalReceived={total_rcvd}, totalSent={total_sent}, "
-        f"frameLoss={total_lost}, latencyStream0(usec)=-1/-1/-1, "
-        f"latencyStream1(usec)=-1/-1/-1, targetDuration='manual'"
+        f"frameLoss={total_lost}, targetDuration='manual', "
+        f"approximatedDuration='manual', approximatedRate='unknown', "
+        f"latencyStream0(usec)=-1/-1/-1, latencyStream1(usec)=-1/-1/-1"
     )