c732e66026e384d14e06bfd0e616fce22601317f
[csit.git] / resources / libraries / python / MLRsearch / ReceiveRateMeasurement.py
1 # Copyright (c) 2020 Cisco and/or its affiliates.
2 # Licensed under the Apache License, Version 2.0 (the "License");
3 # you may not use this file except in compliance with the License.
4 # You may obtain a copy of the License at:
5 #
6 #     http://www.apache.org/licenses/LICENSE-2.0
7 #
8 # Unless required by applicable law or agreed to in writing, software
9 # distributed under the License is distributed on an "AS IS" BASIS,
10 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 # See the License for the specific language governing permissions and
12 # limitations under the License.
13
14 """Module defining ReceiveRateMeasurement class."""
15
16
17 class ReceiveRateMeasurement:
18     """Structure defining the result of single Rr measurement."""
19
20     def __init__(
21             self, duration, target_tr, transmit_count, loss_count,
22             approximated_duration=0.0, partial_transmit_count=0):
23         """Constructor, normalize primary and compute secondary quantities.
24
25         If approximated_duration is nonzero, it is stored.
26         If approximated_duration is zero, duration value is stored.
27         Either way, additional secondary quantities are computed
28         from the store value.
29
30         If there is zero transmit_count, fractions are set to zero.
31
32         In some cases, traffic generator does not attempt all the needed
33         transactions. In that case, nonzero partial_transmit_count
34         holds (an estimate of) count of the actually attempted transactions.
35         This is used to populate some secondary quantities.
36
37         TODO: Use None instead of zero?
38
39         :param duration: Measurement duration [s].
40         :param target_tr: Target transmit rate [pps].
41             If bidirectional traffic is measured, this is bidirectional rate.
42         :param transmit_count: Number of packets transmitted [1].
43         :param loss_count: Number of packets transmitted but not received [1].
44         :param approximated_duration: Estimate of the actual time of the trial.
45         :param partial_transmit_count: Estimate count of actually attempted
46             transactions.
47         :type duration: float
48         :type target_tr: float
49         :type transmit_count: int
50         :type loss_count: int
51         :type approximated_duration: float
52         :type partial_transmit_count: int
53         """
54         self.duration = float(duration)
55         self.target_tr = float(target_tr)
56         self.transmit_count = int(transmit_count)
57         self.loss_count = int(loss_count)
58         self.receive_count = transmit_count - loss_count
59         self.transmit_rate = transmit_count / self.duration
60         self.loss_rate = loss_count / self.duration
61         self.receive_rate = self.receive_count / self.duration
62         self.loss_fraction = (
63             float(self.loss_count) / self.transmit_count
64             if self.transmit_count > 0 else 1.0
65         )
66         self.receive_fraction = (
67             float(self.receive_count) / self.transmit_count
68             if self.transmit_count > 0 else 0.0
69         )
70         self.approximated_duration = (
71             float(approximated_duration) if approximated_duration
72             else self.duration
73         )
74         self.approximated_receive_rate = (
75             self.receive_count / self.approximated_duration
76             if self.approximated_duration > 0.0 else 0.0
77         )
78         # If the traffic generator is unreliable and sends less packets,
79         # the absolute receive rate might be too low for next target.
80         self.partial_transmit_count = (
81             int(partial_transmit_count) if partial_transmit_count
82             else self.transmit_count
83         )
84         self.partial_receive_fraction = (
85             float(self.receive_count) / self.partial_transmit_count
86             if self.partial_transmit_count > 0 else 0.0
87         )
88         self.partial_receive_rate = (
89             self.target_tr * self.partial_receive_fraction
90         )
91         # We use relative packet ratios in order to support cases
92         # where target_tr is in transactions per second,
93         # but there are multiple packets per transaction.
94         self.relative_receive_rate = (
95             self.target_tr * self.receive_count / self.transmit_count
96         )
97
98     def __str__(self):
99         """Return string reporting input and loss fraction."""
100         return f"d={self.duration!s},Tr={self.target_tr!s}," \
101             f"Df={self.loss_fraction!s}"
102
103     def __repr__(self):
104         """Return string evaluable as a constructor call."""
105         return f"ReceiveRateMeasurement(duration={self.duration!r}," \
106             f"target_tr={self.target_tr!r}," \
107             f"transmit_count={self.transmit_count!r}," \
108             f"loss_count={self.loss_count!r}," \
109             f"approximated_duration={self.approximated_duration!r}," \
110             f"partial_transmit_count={self.partial_transmit_count!r})"