+ raise Exception(u"The traffic generation has not been issued")
+
+ if loss_acceptance_type == u"percentage":
+ loss = (float(self._loss) / float(self._sent)) * 100
+ elif loss_acceptance_type == u"frames":
+ loss = float(self._loss)
+ else:
+ raise Exception(u"Loss acceptance type not supported")
+
+ if loss > float(loss_acceptance):
+ raise Exception(
+ f"Traffic loss {loss} above loss acceptance: {loss_acceptance}"
+ )
+
+ def set_rate_provider_defaults(
+ self, frame_size, traffic_profile, warmup_time=0.0,
+ traffic_directions=2):
+ """Store values accessed by measure().
+
+ :param frame_size: Frame size identifier or value [B].
+ :param traffic_profile: Module name as a traffic profile identifier.
+ See resources/traffic_profiles/trex for implemented modules.
+ :param warmup_time: Traffic duration before measurement starts [s].
+ :param traffic_directions: Traffic is bi- (2) or uni- (1) directional.
+ Default: 2
+ :type frame_size: str or int
+ :type traffic_profile: str
+ :type warmup_time: float
+ :type traffic_directions: int
+ """
+ self.frame_size = frame_size
+ self.traffic_profile = str(traffic_profile)
+ self.warmup_time = float(warmup_time)
+ self.traffic_directions = traffic_directions
+
+ def get_measurement_result(self, duration=None, transmit_rate=None):
+ """Return the result of last measurement as ReceiveRateMeasurement.
+
+ Separate function, as measurements can end either by time
+ or by explicit call, this is the common block at the end.
+
+ TODO: Fail on running or already reported measurement.
+
+ :param duration: Measurement duration [s] if known beforehand.
+ For explicitly stopped measurement it is estimated.
+ :param transmit_rate: Target aggregate transmit rate [pps].
+ If not given, computed assuming it was bidirectional.
+ :type duration: float or NoneType
+ :type transmit_rate: float or NoneType
+ :returns: Structure containing the result of the measurement.
+ :rtype: ReceiveRateMeasurement
+ """
+ if duration is None:
+ duration = time.time() - self._start_time
+ self._start_time = None
+ if transmit_rate is None:
+ transmit_rate = self._rate * self.traffic_directions
+ transmit_count = int(self.get_sent())
+ loss_count = int(self.get_loss())
+ measurement = ReceiveRateMeasurement(
+ duration, transmit_rate, transmit_count, loss_count
+ )
+ measurement.latency = self.get_latency_int()
+ return measurement
+
+ def measure(self, duration, transmit_rate):
+ """Run trial measurement, parse and return aggregate results.
+
+ Aggregate means sum over traffic directions.
+
+ :param duration: Trial duration [s].
+ :param transmit_rate: Target aggregate transmit rate [pps].
+ :type duration: float
+ :type transmit_rate: float
+ :returns: Structure containing the result of the measurement.
+ :rtype: ReceiveRateMeasurement
+ :raises RuntimeError: If TG is not set, or if node is not TG,
+ or if subtype is not specified.
+ :raises NotImplementedError: If TG is not supported.
+ """
+ duration = float(duration)
+ transmit_rate = float(transmit_rate)
+ # TG needs target Tr per stream, but reports aggregate Tx and Dx.
+ unit_rate_int = transmit_rate / float(self.traffic_directions)
+ unit_rate_str = str(unit_rate_int) + u"pps"
+ self.send_traffic_on_tg(
+ duration, unit_rate_str, self.frame_size, self.traffic_profile,
+ warmup_time=self.warmup_time, latency=True,
+ traffic_directions=self.traffic_directions
+ )
+ return self.get_measurement_result(duration, transmit_rate)
+
+
+class OptimizedSearch:
+ """Class to be imported as Robot Library, containing search keywords.
+
+ Aside of setting up measurer and forwarding arguments,
+ the main business is to translate min/max rate from unidir to aggregate.
+ """
+
+ @staticmethod
+ def perform_optimized_ndrpdr_search(
+ frame_size, traffic_profile, minimum_transmit_rate,
+ maximum_transmit_rate, packet_loss_ratio=0.005,
+ final_relative_width=0.005, final_trial_duration=30.0,
+ initial_trial_duration=1.0, number_of_intermediate_phases=2,
+ timeout=720.0, doublings=1, traffic_directions=2):
+ """Setup initialized TG, perform optimized search, return intervals.
+
+ :param frame_size: Frame size identifier or value [B].
+ :param traffic_profile: Module name as a traffic profile identifier.
+ See resources/traffic_profiles/trex for implemented modules.
+ :param minimum_transmit_rate: Minimal uni-directional
+ target transmit rate [pps].
+ :param maximum_transmit_rate: Maximal uni-directional
+ target transmit rate [pps].
+ :param packet_loss_ratio: Fraction 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].
+ :param initial_trial_duration: Trial duration for the initial phase
+ and also for the first intermediate phase [s].
+ :param number_of_intermediate_phases: Number of intermediate phases
+ 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 traffic_directions: Traffic is bi- (2) or uni- (1) directional.
+ Default: 2
+ :type frame_size: str or int
+ :type traffic_profile: str
+ :type minimum_transmit_rate: float
+ :type maximum_transmit_rate: float
+ :type packet_loss_ratio: float
+ :type final_relative_width: float
+ :type final_trial_duration: float
+ :type initial_trial_duration: float
+ :type number_of_intermediate_phases: int
+ :type timeout: float
+ :type doublings: int
+ :type traffic_directions: int
+ :returns: Structure containing narrowed down NDR and PDR intervals
+ and their measurements.
+ :rtype: NdrPdrResult
+ :raises RuntimeError: If total duration is larger than timeout.
+ """
+ minimum_transmit_rate *= traffic_directions
+ maximum_transmit_rate *= traffic_directions
+ # we need instance of TrafficGenerator instantiated by Robot Framework
+ # to be able to use trex_stl-*()
+ tg_instance = BuiltIn().get_library_instance(
+ u"resources.libraries.python.TrafficGenerator"
+ )
+ tg_instance.set_rate_provider_defaults(
+ frame_size, traffic_profile, traffic_directions=traffic_directions)
+ algorithm = MultipleLossRatioSearch(
+ measurer=tg_instance, final_trial_duration=final_trial_duration,
+ final_relative_width=final_relative_width,
+ number_of_intermediate_phases=number_of_intermediate_phases,
+ initial_trial_duration=initial_trial_duration, timeout=timeout,
+ doublings=doublings
+ )
+ result = algorithm.narrow_down_ndr_and_pdr(
+ minimum_transmit_rate, maximum_transmit_rate, packet_loss_ratio
+ )
+ return result
+
+ @staticmethod
+ def perform_soak_search(
+ frame_size, traffic_profile, minimum_transmit_rate,
+ maximum_transmit_rate, plr_target=1e-7, tdpt=0.1,
+ initial_count=50, timeout=1800.0, trace_enabled=False,
+ traffic_directions=2):
+ """Setup initialized TG, perform soak search, return avg and stdev.
+
+ :param frame_size: Frame size identifier or value [B].
+ :param traffic_profile: Module name as a traffic profile identifier.
+ See resources/traffic_profiles/trex for implemented modules.
+ :param minimum_transmit_rate: Minimal uni-directional
+ target transmit rate [pps].
+ :param maximum_transmit_rate: Maximal uni-directional
+ target transmit rate [pps].
+ :param plr_target: Fraction 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.
+ :param initial_count: Offset to apply before the first trial.
+ For example initial_count=50 makes first trial to be 51*tdpt long.
+ This is needed because initial "search" phase of integrator
+ takes significant time even without any trial results.
+ :param timeout: The search will stop after this overall time [s].
+ :param trace_enabled: True if trace enabled else False.
+ :param traffic_directions: Traffic is bi- (2) or uni- (1) directional.
+ Default: 2
+ :type frame_size: str or int
+ :type traffic_profile: str
+ :type minimum_transmit_rate: float
+ :type maximum_transmit_rate: float
+ :type plr_target: float
+ :type initial_count: int
+ :type timeout: float
+ :type trace_enabled: bool
+ :type traffic_directions: int
+ :returns: Average and stdev of estimated aggregate rate giving PLR.
+ :rtype: 2-tuple of float
+ """
+ minimum_transmit_rate *= traffic_directions
+ maximum_transmit_rate *= traffic_directions
+ tg_instance = BuiltIn().get_library_instance(
+ u"resources.libraries.python.TrafficGenerator"
+ )
+ tg_instance.set_rate_provider_defaults(
+ frame_size, traffic_profile, traffic_directions=traffic_directions)
+ algorithm = PLRsearch(
+ measurer=tg_instance, trial_duration_per_trial=tdpt,
+ packet_loss_ratio_target=plr_target,
+ trial_number_offset=initial_count, timeout=timeout,
+ trace_enabled=trace_enabled
+ )
+ result = algorithm.search(minimum_transmit_rate, maximum_transmit_rate)
+ return result