diff options
author | Vratko Polak <vrpolak@cisco.com> | 2019-09-23 15:00:00 +0200 |
---|---|---|
committer | Vratko Polak <vrpolak@cisco.com> | 2019-09-24 07:47:06 +0000 |
commit | bab0b570345ceb6ffeaec9e47a50e62d7303387e (patch) | |
tree | 4ddb29534d9dd1048d1561cc0b93474323c6705b /resources/libraries/python | |
parent | c7c31d5a09cd56ac5faab8d6f690aea00fa9e051 (diff) |
Reconf tests: Fix async measurements
TRex does not zero the server counters.
It copies the values to use as reference,
and subtracts them when asked for results.
But the reference is stored in the client (not the server).
And CSIT uses different scripts to start and stop async traffic,
which means different clients.
This patch introduces a workaround.
Async start will return xstats objects to use as reference,
and async stop will use the objects to compute the correct results.
The xstats objects are stored in TrafficGenerator instance.
Sync measurement does not export the counters, to shorten logs.
Other improvements:
+ Make stop_traffic_on_tg return measurement results directly.
+ Rename --async to --async_start as "async" is reserved in Python 3.7
+ Minor pylint, docstring and typo fixes.
Change-Id: I5fc56a0763afb7d62cfa7c0651f96b6867de3e15
Signed-off-by: Vratko Polak <vrpolak@cisco.com>
Diffstat (limited to 'resources/libraries/python')
-rw-r--r-- | resources/libraries/python/TrafficGenerator.py | 47 |
1 files changed, 38 insertions, 9 deletions
diff --git a/resources/libraries/python/TrafficGenerator.py b/resources/libraries/python/TrafficGenerator.py index 489b44572b..b6d28a4ca6 100644 --- a/resources/libraries/python/TrafficGenerator.py +++ b/resources/libraries/python/TrafficGenerator.py @@ -106,6 +106,7 @@ class TGDropRateSearchImpl(DropRateSearch): logger.trace("comparing: {los} < {acc} {typ}".format( los=loss, acc=loss_acceptance, typ=loss_acceptance_type)) return float(loss) <= float(loss_acceptance) + return False def get_latency(self): """Returns min/avg/max latency. @@ -148,6 +149,9 @@ class TrafficGenerator(AbstractMeasurer): self.traffic_profile = None self.warmup_time = None self.traffic_directions = None + # Transient data needed for async measurements. + self._xstats = (None, None) + # TODO: Rename "xstats" to something opaque, so TRex is not privileged? @property def node(self): @@ -390,7 +394,7 @@ class TrafficGenerator(AbstractMeasurer): sudo=False, message='pkill t-rex failed') def _parse_traffic_results(self, stdout): - """Parse stdout of scripts into fieds of self. + """Parse stdout of scripts into fields of self. Block of code to reuse, by sync start, or stop after async. TODO: Is the output TG subtype dependent? @@ -412,18 +416,23 @@ class TrafficGenerator(AbstractMeasurer): def trex_stl_stop_remote_exec(self, node): """Execute script on remote node over ssh to stop running traffic. - Internal state is updated with results. + Internal state is updated with measurement results. :param node: TRex generator node. :type node: dict - :returns: Nothing :raises RuntimeError: If stop traffic script fails. """ # No need to check subtype, we know it is TREX. + x_args = "" + for index, value in enumerate(self._xstats): + if value is not None: + # Nested quoting is fun. + value = value.replace("'", "\"") + x_args += " --xstat{i}='\"'\"'{v}'\"'\"'".format( + i=index, v=value) stdout, _ = exec_cmd_no_error( - node, - "sh -c '{}/resources/tools/trex/" - "trex_stateless_stop.py'".format(Constants.REMOTE_FW_DIR), + node, "sh -c '{d}/resources/tools/trex/trex_stateless_stop.py{a}'"\ + .format(d=Constants.REMOTE_FW_DIR, a=x_args), message='TRex stateless runtime error') self._parse_traffic_results(stdout) @@ -433,6 +442,9 @@ class TrafficGenerator(AbstractMeasurer): rx_port=1): """Execute script on remote node over ssh to start traffic. + In sync mode, measurement results are stored internally. + In async mode, initial data including xstats are stored internally. + :param duration: Time expresed in seconds for how long to send traffic. :param rate: Traffic rate expressed with units (pps, %) :param frame_size: L2 frame size to send (without padding and IPG). @@ -481,7 +493,7 @@ class TrafficGenerator(AbstractMeasurer): frame_size=frame_size, rate=rate, warmup=warmup_time, p_0=p_0, p_1=p_1, dirs=traffic_directions) if async_call: - command += " --async" + command += " --async_start" if latency: command += " --latency" command += "'" @@ -490,14 +502,24 @@ class TrafficGenerator(AbstractMeasurer): self._node, command, timeout=float(duration) + 60, message='TRex stateless runtime error') + self.traffic_directions = traffic_directions if async_call: #no result self._start_time = time.time() - self._rate = float(rate[:-3]) if "pps" in rate else rate + self._rate = float(rate[:-3]) if "pps" in rate else float(rate) self._received = None self._sent = None self._loss = None self._latency = None + xstats = [None, None] + index = 0 + for line in stdout.splitlines(): + if "Xstats snapshot {i}: ".format(i=index) in line: + xstats[index] = line[19:] + index += 1 + if index == 2: + break + self._xstats = tuple(xstats) else: self._parse_traffic_results(stdout) self._start_time = None @@ -506,12 +528,14 @@ class TrafficGenerator(AbstractMeasurer): def stop_traffic_on_tg(self): """Stop all traffic on TG. - :returns: Nothing + :returns: Structure containing the result of the measurement. + :rtype: ReceiveRateMeasurement :raises RuntimeError: If TG is not set. """ subtype = check_subtype(self._node) if subtype == NodeSubTypeTG.TREX: self.trex_stl_stop_remote_exec(self._node) + return self.get_measurement_result() def send_traffic_on_tg( self, duration, rate, frame_size, traffic_profile, warmup_time=5, @@ -519,6 +543,11 @@ class TrafficGenerator(AbstractMeasurer): rx_port=1): """Send traffic from all configured interfaces on TG. + In async mode, xstats is stored internally, + to enable getting correct result when stopping the traffic. + In both modes, stdout is returned, + but _parse_traffic_results only works in sync output. + Note that bidirectional traffic also contains flows transmitted from rx_port and received in tx_port. But some tests use asymmetric traffic, so those arguments are relevant. |