CSIT-408 sub-NDR latency measurements
[csit.git] / resources / libraries / python / DropRateSearch.py
index c25f34f..6346125 100644 (file)
@@ -98,6 +98,15 @@ class DropRateSearch(object):
         self._search_result = None
         self._search_result_rate = None
 
+    @abstractmethod
+    def get_latency(self):
+        """Return min/avg/max latency.
+
+        :return: Latency stats.
+        :rtype: list
+        """
+        pass
+
     @abstractmethod
     def measure_loss(self, rate, frame_size, loss_acceptance,
                      loss_acceptance_type, traffic_type):
@@ -135,6 +144,49 @@ class DropRateSearch(object):
             self._rate_max = float(max_rate)
             self._rate_min = float(min_rate)
 
+    def set_loss_acceptance(self, loss_acceptance):
+        """Set loss acceptance treshold for PDR search.
+
+        :param loss_acceptance: Loss acceptance treshold for PDR search.
+        :type loss_acceptance: str
+        :return: nothing
+        """
+        if float(loss_acceptance) < 0:
+            raise ValueError("Loss acceptance must be higher or equal 0")
+        else:
+            self._loss_acceptance = float(loss_acceptance)
+
+    def get_loss_acceptance(self):
+        """Return configured loss acceptance treshold.
+
+        :return: Loss acceptance treshold.
+        :rtype: float
+        """
+        return self._loss_acceptance
+
+    def set_loss_acceptance_type_percentage(self):
+        """Set loss acceptance treshold type to percentage.
+
+        :return: nothing
+        """
+        self._loss_acceptance_type = LossAcceptanceType.PERCENTAGE
+
+    def set_loss_acceptance_type_frames(self):
+        """Set loss acceptance treshold type to frames.
+
+        :return: nothing
+        """
+        self._loss_acceptance_type = LossAcceptanceType.FRAMES
+
+    def loss_acceptance_type_is_percentage(self):
+        """Return true if loss acceptance treshold type is percentage,
+           false otherwise.
+
+        :return: True if loss acceptance treshold type is percentage.
+        :rtype: boolean
+        """
+        return self._loss_acceptance_type == LossAcceptanceType.PERCENTAGE
+
     def set_search_linear_step(self, step_rate):
         """Set step size for linear search.
 
@@ -320,14 +372,13 @@ class DropRateSearch(object):
         else:
             raise ValueError("Unknown search result type")
 
-
     def linear_search(self, start_rate, traffic_type):
         """Linear search of rate with loss below acceptance criteria.
 
         :param start_rate: Initial rate.
         :param traffic_type: Traffic profile.
         :type start_rate: float
-        :param traffic_type: str
+        :type traffic_type: str
         :return: nothing
         """
 
@@ -350,7 +401,7 @@ class DropRateSearch(object):
             res = self._get_res_based_on_search_type(res)
 
             if self._search_linear_direction == SearchDirection.BOTTOM_UP:
-                # loss occured and it was above acceptance criteria
+                # loss occurred and it was above acceptance criteria
                 if not res:
                     # if this is first run then we didn't find drop rate
                     if prev_rate is None:
@@ -381,7 +432,7 @@ class DropRateSearch(object):
                     raise RuntimeError("Unknown search result")
 
             elif self._search_linear_direction == SearchDirection.TOP_DOWN:
-                # loss occured, decrease rate
+                # loss occurred, decrease rate
                 if not res:
                     prev_rate = rate
                     rate -= self._rate_linear_step
@@ -411,24 +462,26 @@ class DropRateSearch(object):
     def verify_search_result(self):
         """Fail if search was not successful.
 
-        :return: Result rate.
-        :rtype: float
+        :return: Result rate and latency stats.
+        :rtype: tuple
         """
         if self._search_result == SearchResults.FAILURE:
             raise Exception('Search FAILED')
         elif self._search_result in [SearchResults.SUCCESS,
                                      SearchResults.SUSPICIOUS]:
-            return self._search_result_rate
+            return self._search_result_rate, self.get_latency()
 
-    def binary_search(self, b_min, b_max, traffic_type):
+    def binary_search(self, b_min, b_max, traffic_type, skip_max_rate=False):
         """Binary search of rate with loss below acceptance criteria.
 
         :param b_min: Min range rate.
         :param b_max: Max range rate.
         :param traffic_type: Traffic profile.
+        :param skip_max_rate: Start with max rate first
         :type b_min: float
         :type b_max: float
         :type traffic_type: str
+        :type skip_max_rate: bool
         :return: nothing
         """
 
@@ -437,11 +490,15 @@ class DropRateSearch(object):
         if not self._rate_min <= float(b_max) <= self._rate_max:
             raise ValueError("Max rate is not in min,max range")
         if float(b_max) < float(b_min):
-            raise ValueError("Min rate is greater then max rate")
+            raise ValueError("Min rate is greater than max rate")
 
         # binary search
-        # rate is half of interval + start of interval
-        rate = ((float(b_max) - float(b_min)) / 2) + float(b_min)
+        if skip_max_rate:
+            # rate is half of interval + start of interval
+            rate = ((float(b_max) - float(b_min)) / 2) + float(b_min)
+        else:
+            # rate is max of interval
+            rate =  float(b_max)
         # rate diff with previous run
         rate_diff = abs(self._last_binary_rate - rate)
 
@@ -464,13 +521,13 @@ class DropRateSearch(object):
 
         res = self._get_res_based_on_search_type(res)
 
-        # loss occured and it was above acceptance criteria
+        # loss occurred and it was above acceptance criteria
         if not res:
-            self.binary_search(b_min, rate, traffic_type)
+            self.binary_search(b_min, rate, traffic_type, True)
         # there was no loss / loss below acceptance criteria
         else:
             self._search_result_rate = rate
-            self.binary_search(rate, b_max, traffic_type)
+            self.binary_search(rate, b_max, traffic_type, True)
 
     def combined_search(self, start_rate, traffic_type):
         """Combined search of rate with loss below acceptance criteria.
@@ -502,7 +559,7 @@ class DropRateSearch(object):
             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_type)
+            self.binary_search(b_min, b_max, traffic_type, True)
 
             # linear and binary search succeed
             if self._search_result == SearchResults.SUCCESS: