"""Performance testing traffic generator library."""
+import math
import time
from robot.api import logger
f"EOF'",
sudo=True, message=u"T-Rex config generation!"
)
+
+ if Constants.TREX_RX_DESCRIPTORS_COUNT != 0:
+ exec_cmd_no_error(
+ self._node,
+ f"sh -c 'cat << EOF >> /etc/trex_cfg.yaml\n"
+ f" rx_desc: {Constants.TREX_RX_DESCRIPTORS_COUNT}\n"
+ f"EOF'",
+ sudo=True, message=u"T-Rex rx_desc modification!"
+ )
+
+ if Constants.TREX_TX_DESCRIPTORS_COUNT != 0:
+ exec_cmd_no_error(
+ self._node,
+ f"sh -c 'cat << EOF >> /etc/trex_cfg.yaml\n"
+ f" tx_desc: {Constants.TREX_TX_DESCRIPTORS_COUNT}\n"
+ f"EOF'",
+ sudo=True, message=u"T-Rex tx_desc modification!"
+ )
else:
raise ValueError(u"Unknown OSI layer!")
# so we can compare with what telemetry suggests
# the real duration was.
logger.debug(f"Expected duration {computed_duration}")
- computed_duration += 0.1115
if not self.duration_limit:
return computed_duration, True
limited_duration = min(computed_duration, self.duration_limit)
command_line.add_if(u"async_start", async_call)
command_line.add_if(u"latency", self.use_latency)
command_line.add_if(u"force", Constants.TREX_SEND_FORCE)
+ command_line.add_with_value(
+ u"delay", Constants.PERF_TRIAL_ASTF_DELAY
+ )
self._start_time = time.monotonic()
self._rate = multiplier
command_line.add_if(u"async_start", async_call)
command_line.add_if(u"latency", self.use_latency)
command_line.add_if(u"force", Constants.TREX_SEND_FORCE)
+ command_line.add_with_value(u"delay", Constants.PERF_TRIAL_STL_DELAY)
# TODO: This is ugly. Handle parsing better.
self._start_time = time.monotonic()
"""
if self._received is None:
raise RuntimeError(u"The traffic generation has not been issued")
- if self._received == u"0":
+ if self._received == 0:
raise RuntimeError(u"No traffic forwarded")
def partial_traffic_loss_accepted(
if not target_duration:
target_duration = approximated_duration
transmit_rate = self._rate
+ unsent = 0
if self.transaction_type == u"packet":
partial_attempt_count = self._sent
- expected_attempt_count = self._sent
- fail_count = self._loss
+ packet_rate = transmit_rate * self.ppta
+ # We have a float. TRex way of rounding it is not obvious.
+ # The biggest source of mismatch is Inter Stream Gap.
+ # So the code tolerates 10 usec of missing packets.
+ expected_attempt_count = (target_duration - 1e-5) * packet_rate
+ expected_attempt_count = math.ceil(expected_attempt_count)
+ # TRex can send more.
+ expected_attempt_count = max(expected_attempt_count, self._sent)
+ unsent = expected_attempt_count - self._sent
+ pass_count = self._received
+ fail_count = expected_attempt_count - pass_count
elif self.transaction_type == u"udp_cps":
if not self.transaction_scale:
raise RuntimeError(u"Add support for no-limit udp_cps.")
partial_attempt_count = self._l7_data[u"client"][u"sent"]
# We do not care whether TG is slow, it should have attempted all.
expected_attempt_count = self.transaction_scale
+ unsent = expected_attempt_count - partial_attempt_count
pass_count = self._l7_data[u"client"][u"received"]
fail_count = expected_attempt_count - pass_count
elif self.transaction_type == u"tcp_cps":
partial_attempt_count = ctca
# We do not care whether TG is slow, it should have attempted all.
expected_attempt_count = self.transaction_scale
+ unsent = expected_attempt_count - partial_attempt_count
# From TCP point of view, server/connects counts full connections,
# but we are testing NAT session so client/connects counts that
# (half connections from TCP point of view).
raise RuntimeError(u"Add support for no-limit udp_pps.")
partial_attempt_count = self._sent
expected_attempt_count = self.transaction_scale * self.ppta
- fail_count = self._loss + (expected_attempt_count - self._sent)
+ unsent = expected_attempt_count - self._sent
+ fail_count = self._loss + unsent
elif self.transaction_type == u"tcp_pps":
if not self.transaction_scale:
raise RuntimeError(u"Add support for no-limit tcp_pps.")
# A simple workaround is to add absolute difference.
# Probability of retransmissions exactly cancelling
# packets unsent due to duration stretching is quite low.
- fail_count = self._loss + abs(expected_attempt_count - self._sent)
+ unsent = abs(expected_attempt_count - self._sent)
+ fail_count = self._loss + unsent
else:
raise RuntimeError(f"Unknown parsing {self.transaction_type!r}")
+ if unsent and isinstance(self._approximated_duration, float):
+ # Do not report unsent for "manual".
+ logger.debug(f"Unsent packets/transactions: {unsent}")
if fail_count < 0 and not self.negative_loss:
fail_count = 0
measurement = ReceiveRateMeasurement(
final_trial_duration=30.0,
initial_trial_duration=1.0,
number_of_intermediate_phases=2,
- timeout=720.0,
- doublings=1,
+ timeout=1200.0,
ppta=1,
resetter=None,
traffic_directions=2,
ramp_up_rate=None,
ramp_up_duration=None,
state_timeout=300.0,
+ expansion_coefficient=4.0,
):
"""Setup initialized TG, perform optimized search, return intervals.
- If transaction_scale is nonzero, all non-init trial durations
- are set to 2.0 (as they do not affect the real trial duration)
+ If transaction_scale is nonzero, all init and non-init trial durations
+ are set to 1.0 (as they do not affect the real trial duration)
and zero intermediate phases are used.
- The initial phase still uses 1.0 seconds, to force remeasurement.
- That makes initial phase act as a warmup.
+ This way no re-measurement happens.
+ Warmup has to be handled via resetter or ramp-up mechanisms.
:param frame_size: Frame size identifier or value [B].
:param traffic_profile: Module name as a traffic profile identifier.
See GPL/traffic_profiles/trex for implemented modules.
:param minimum_transmit_rate: Minimal load in transactions per second.
:param maximum_transmit_rate: Maximal load in transactions per second.
- :param packet_loss_ratio: Fraction of packets lost, for PDR [1].
+ :param packet_loss_ratio: Ratio of packets lost, for PDR [1].
:param final_relative_width: Final lower bound transmit rate
cannot be more distant that this multiple of upper bound [1].
:param final_trial_duration: Trial duration for the final phase [s].
to perform before the final phase [1].
:param timeout: The search will fail itself when not finished
before this overall time [s].
- :param doublings: How many doublings to do in external search step.
- Default 1 is suitable for fairly stable tests,
- less stable tests might get better overal duration with 2 or more.
:param ppta: Packets per transaction, aggregated over directions.
Needed for udp_pps which does not have a good transaction counter,
so we need to compute expected number of packets.
:param ramp_up_rate: Rate to use in ramp-up trials [pps].
:param ramp_up_duration: Duration of ramp-up trials [s].
:param state_timeout: Time of life of DUT state [s].
+ :param expansion_coefficient: In external search multiply width by this.
:type frame_size: str or int
:type traffic_profile: str
:type minimum_transmit_rate: float
:type initial_trial_duration: float
:type number_of_intermediate_phases: int
:type timeout: float
- :type doublings: int
:type ppta: int
:type resetter: Optional[Callable[[], None]]
:type traffic_directions: int
:type ramp_up_rate: float
:type ramp_up_duration: float
:type state_timeout: float
+ :type expansion_coefficient: float
:returns: Structure containing narrowed down NDR and PDR intervals
and their measurements.
- :rtype: NdrPdrResult
+ :rtype: List[Receiverateinterval]
:raises RuntimeError: If total duration is larger than timeout.
"""
# we need instance of TrafficGenerator instantiated by Robot Framework
# even though this is surprising for log readers.
if transaction_scale:
initial_trial_duration = 1.0
- final_trial_duration = 2.0
+ final_trial_duration = 1.0
number_of_intermediate_phases = 0
timeout += transaction_scale * 3e-4
tg_instance.set_rate_provider_defaults(
number_of_intermediate_phases=number_of_intermediate_phases,
initial_trial_duration=initial_trial_duration,
timeout=timeout,
- doublings=doublings,
+ debug=logger.debug,
+ expansion_coefficient=expansion_coefficient,
)
- result = algorithm.narrow_down_ndr_and_pdr(
+ if packet_loss_ratio:
+ packet_loss_ratios = [0.0, packet_loss_ratio]
+ else:
+ # Happens in reconf tests.
+ packet_loss_ratios = [packet_loss_ratio]
+ results = algorithm.narrow_down_intervals(
min_rate=minimum_transmit_rate,
max_rate=maximum_transmit_rate,
- packet_loss_ratio=packet_loss_ratio,
+ packet_loss_ratios=packet_loss_ratios,
)
- return result
+ return results
@staticmethod
def perform_soak_search(
See GPL/traffic_profiles/trex for implemented modules.
:param minimum_transmit_rate: Minimal load in transactions per second.
:param maximum_transmit_rate: Maximal load in transactions per second.
- :param plr_target: Fraction of packets lost to achieve [1].
+ :param plr_target: Ratio of packets lost to achieve [1].
:param tdpt: Trial duration per trial.
The algorithm linearly increases trial duration with trial number,
this is the increment between succesive trials, in seconds.