+ :returns: Result rate and latency stats.
+ :rtype: tuple
+ :raises Exception: If search failed.
+ """
+ if self._search_result in \
+ [SearchResults.SUCCESS, SearchResults.SUSPICIOUS]:
+ return self._search_result_rate, self.get_latency()
+ raise Exception(u"Search FAILED")
+
+ def binary_search(
+ self, b_min, b_max, traffic_profile, skip_max_rate=False,
+ skip_warmup=False):
+ """Binary search of rate with loss below acceptance criteria.
+
+ :param b_min: Min range rate.
+ :param b_max: Max range rate.
+ :param traffic_profile: Module name to use for traffic generation.
+ :param skip_max_rate: Start with max rate first
+ :param skip_warmup: Start TRex without warmup traffic if true.
+ :type b_min: float
+ :type b_max: float
+ :type traffic_profile: str
+ :type skip_max_rate: bool
+ :type skip_warmup: bool
+ :returns: nothing
+ :raises ValueError: If input values are not valid.
+ """
+ if not self._rate_min <= float(b_min) <= self._rate_max:
+ raise ValueError(u"Min rate is not in min,max range")
+ if not self._rate_min <= float(b_max) <= self._rate_max:
+ raise ValueError(u"Max rate is not in min,max range")
+ if float(b_max) < float(b_min):
+ raise ValueError(u"Min rate is greater than max rate")
+
+ # rate is half of interval + start of interval if not using max rate
+ rate = ((float(b_max) - float(b_min)) / 2) + float(b_min) \
+ if skip_max_rate else float(b_max)
+
+ # rate diff with previous run
+ rate_diff = abs(self._last_binary_rate - rate)
+
+ # convergence criterium
+ if float(rate_diff) < float(self._binary_convergence_threshold):
+ self._search_result = SearchResults.SUCCESS \
+ if self._search_result_rate else SearchResults.FAILURE
+ return
+
+ self._last_binary_rate = rate
+
+ res = []
+ for dummy in range(self._max_attempts):
+ res.append(self.measure_loss(
+ rate, self._frame_size, self._loss_acceptance,
+ self._loss_acceptance_type, traffic_profile,
+ skip_warmup=skip_warmup
+ ))
+
+ res = self._get_res_based_on_search_type(res)
+
+ # loss occurred and it was above acceptance criteria
+ if not res:
+ self.binary_search(b_min, rate, traffic_profile, True, True)
+ # there was no loss / loss below acceptance criteria
+ else:
+ self._search_result_rate = rate
+ self.binary_search(rate, b_max, traffic_profile, True, True)
+
+ def combined_search(self, start_rate, traffic_profile):
+ """Combined search of rate with loss below acceptance criteria.
+
+ :param start_rate: Initial rate.
+ :param traffic_profile: Module name to use for traffic generation.
+ :type start_rate: float
+ :type traffic_profile: str
+ :returns: nothing
+ :raises RuntimeError: If linear search failed.
+ """
+ self.linear_search(start_rate, traffic_profile)
+
+ if self._search_result in \
+ [SearchResults.SUCCESS, SearchResults.SUSPICIOUS]:
+ b_min = self._search_result_rate
+ b_max = self._search_result_rate + self._rate_linear_step
+
+ # we found max rate by linear search
+ if self.floats_are_close_equal(float(b_min), self._rate_max):
+ return
+
+ # limiting binary range max value into max range
+ if float(b_max) > self._rate_max:
+ b_max = self._rate_max
+
+ # reset result rate
+ temp_rate = self._search_result_rate
+ self._search_result_rate = None
+
+ # we will use binary search to refine search in one linear step
+ self.binary_search(b_min, b_max, traffic_profile, True)
+
+
+ # linear search succeed but binary failed or suspicious
+ if self._search_result != SearchResults.SUCCESS:
+ self._search_result = SearchResults.SUSPICIOUS
+ self._search_result_rate = temp_rate
+ # linear and binary search succeed
+ else:
+ return
+ else:
+ raise RuntimeError(u"Linear search FAILED")
+
+ @staticmethod
+ def floats_are_close_equal(num_a, num_b, rel_tol=1e-9, abs_tol=0.0):
+ """Compares two float numbers for close equality.
+
+ :param num_a: First number to compare.
+ :param num_b: Second number to compare.
+ :param rel_tol: The relative tolerance.
+ :param abs_tol: The minimum absolute tolerance level. (Optional,
+ default value: 0.0)
+ :type num_a: float
+ :type num_b: float
+ :type rel_tol: float
+ :type abs_tol: float
+ :returns: Returns True if num_a is close in value to num_b or equal.
+ False otherwise.
+ :rtype: boolean
+ :raises ValueError: If input values are not valid.