4 ## Copyright (c) 2020 Intel Corporation
6 ## Licensed under the Apache License, Version 2.0 (the "License");
7 ## you may not use this file except in compliance with the License.
8 ## You may obtain a copy of the License at
11 ## http://www.apache.org/licenses/LICENSE-2.0
13 ## Unless required by applicable law or agreed to in writing, software
14 ## distributed under the License is distributed on an "AS IS" BASIS,
15 ## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 ## See the License for the specific language governing permissions and
17 ## limitations under the License.
23 from statistics import mean
24 from past.utils import old_div
25 from rapid_log import RapidLog
26 from rapid_log import bcolors
27 from rapid_test import RapidTest
30 class FlowSizeTest(RapidTest):
32 Class to manage the flowsizetesting
34 def __init__(self, test_param, lat_percentile, runtime, testname,
35 environment_file, gen_machine, sut_machine, background_machines):
36 super().__init__(test_param, runtime, testname, environment_file)
37 self.gen_machine = gen_machine
38 self.sut_machine = sut_machine
39 self.background_machines = background_machines
40 self.test['lat_percentile'] = lat_percentile
41 if self.test['test'] == 'TST009test':
42 # This test implements some of the testing as defined in
43 # https://docbox.etsi.org/ISG/NFV/open/Publications_pdf/Specs-Reports/NFV-TST%20009v3.2.1%20-%20GS%20-%20NFVI_Benchmarks.pdf
44 self.test['TST009_n'] = int(ceil(old_div(
45 self.test['maxframespersecondallingress'],
46 self.test['stepsize'])))
47 self.test['TST009'] = True
48 self.test['TST009_L'] = 0
49 self.test['TST009_R'] = self.test['TST009_n'] - 1
50 self.test['TST009_S']= []
51 for m in range(0, self.test['TST009_n']):
52 self.test['TST009_S'].append((m+1) * self.test['stepsize'])
53 elif self.test['test'] == 'fixed_rate':
54 for key in['drop_rate_threshold','lat_avg_threshold',
55 'lat_perc_threshold','lat_max_threshold']:
58 def new_speed(self, speed,size,success):
59 if self.test['test'] == 'fixed_rate':
60 return (self.test['startspeed'])
61 elif self.test['test'] == 'increment_till_fail':
62 return (speed + self.test['step'])
63 elif 'TST009' in self.test.keys():
65 self.test['TST009_L'] = self.test['TST009_m'] + 1
67 self.test['TST009_R'] = max(self.test['TST009_m'] - 1,
68 self.test['TST009_L'])
69 self.test['TST009_m'] = int (old_div((self.test['TST009_L'] +
70 self.test['TST009_R']),2))
71 return (self.get_percentageof10Gbps(self.test['TST009_S'][self.test['TST009_m']],size))
74 self.test['minspeed'] = speed
76 self.test['maxspeed'] = speed
77 return (old_div((self.test['minspeed'] + self.test['maxspeed']),2.0))
79 def get_start_speed_and_init(self, size):
80 if self.test['test'] == 'fixed_rate':
81 return (self.test['startspeed'])
82 elif self.test['test'] == 'increment_till_fail':
83 return (self.test['startspeed'])
84 elif 'TST009' in self.test.keys():
85 self.test['TST009_L'] = 0
86 self.test['TST009_R'] = self.test['TST009_n'] - 1
87 self.test['TST009_m'] = int(old_div((self.test['TST009_L'] +
88 self.test['TST009_R']), 2))
89 return (self.get_percentageof10Gbps(self.test['TST009_S'][self.test['TST009_m']],size))
91 self.test['minspeed'] = 0
92 self.test['maxspeed'] = self.test['startspeed']
93 return (self.test['startspeed'])
95 def resolution_achieved(self):
96 if self.test['test'] == 'fixed_rate':
98 elif 'TST009' in self.test.keys():
99 return (self.test['TST009_L'] == self.test['TST009_R'])
101 return ((self.test['maxspeed'] - self.test['minspeed']) <= self.test['accuracy'])
104 # Running at low speed to make sure the ARP messages can get through.
105 # If not doing this, the ARP message could be dropped by a switch in overload and then the test will not give proper results
106 # Note however that if we would run the test steps during a very long time, the ARP would expire in the switch.
107 # PROX will send a new ARP request every seconds so chances are very low that they will all fail to get through
108 imix = self.test['warmupimix']
109 FLOWSIZE = self.test['warmupflowsize']
110 WARMUPSPEED = self.test['warmupspeed']
111 WARMUPTIME = self.test['warmuptime']
112 RapidLog.info(("Warming up during {} seconds..., packet size = {},"
113 " flows = {}, speed = {}").format(WARMUPTIME, imix, FLOWSIZE,
115 self.gen_machine.set_generator_speed(WARMUPSPEED)
116 self.set_background_speed(self.background_machines, WARMUPSPEED)
117 self.gen_machine.set_udp_packet_size(imix)
118 self.set_background_size(self.background_machines, imix)
119 _ = self.gen_machine.set_flows(FLOWSIZE)
120 self.set_background_flows(self.background_machines, FLOWSIZE)
121 self.gen_machine.start()
122 self.start_background_traffic(self.background_machines)
123 time.sleep(WARMUPTIME)
124 self.stop_background_traffic(self.background_machines)
125 self.gen_machine.stop()
128 result_details = {'Details': 'Nothing'}
131 iteration_prefix = {}
133 for imix in self.test['imixs']:
135 self.gen_machine.set_udp_packet_size(imix)
136 if self.background_machines:
137 backgroundinfo = ('{}Running {} x background traffic not '
138 'represented in the table{}').format(bcolors.FLASH,
139 len(self.background_machines),bcolors.ENDC)
141 backgroundinfo = '{}{}'.format(bcolors.FLASH,bcolors.ENDC)
142 self.set_background_size(self.background_machines, imix)
143 RapidLog.info('+' + '-' * 188 + '+')
144 RapidLog.info(("| UDP, {:>5} bytes, different number of flows by "
145 "randomizing SRC & DST UDP port. {:116.116}|").
146 format(round(size), backgroundinfo))
147 RapidLog.info('+' + '-' * 8 + '+' + '-' * 18 + '+' + '-' * 13 +
148 '+' + '-' * 13 + '+' + '-' * 13 + '+' + '-' * 24 + '+' +
149 '-' * 10 + '+' + '-' * 10 + '+' + '-' * 10 + '+' + '-' * 11
150 + '+' + '-' * 11 + '+' + '-' * 11 + '+' + '-' * 11 + '+'
151 + '-' * 7 + '+' + '-' * 4 + '+')
152 RapidLog.info(('| Flows | Speed requested | Gen by core | Sent by'
153 ' NIC | Fwrd by SUT | Rec. by core | Avg. Lat.|{:.0f}'
154 ' Pcentil| Max. Lat.| Sent | Received | Lost | Total'
155 ' Lost|L.Ratio|Time|').format(self.test['lat_percentile']*100))
156 RapidLog.info('+' + '-' * 8 + '+' + '-' * 18 + '+' + '-' * 13 +
157 '+' + '-' * 13 + '+' + '-' * 13 + '+' + '-' * 24 + '+' +
158 '-' * 10 + '+' + '-' * 10 + '+' + '-' * 10 + '+' + '-' * 11
159 + '+' + '-' * 11 + '+' + '-' * 11 + '+' + '-' * 11 + '+'
160 + '-' * 7 + '+' + '-' * 4 + '+')
161 for flow_number in self.test['flows']:
163 self.gen_machine.reset_stats()
165 self.sut_machine.reset_stats()
166 flow_number = self.gen_machine.set_flows(flow_number)
167 self.set_background_flows(self.background_machines, flow_number)
168 end_data['speed'] = None
169 speed = self.get_start_speed_and_init(size)
173 print('{} flows: Measurement ongoing at speed: {}%'.format(
174 str(flow_number), str(round(speed, 2))), end=' \r')
176 iteration_data = self.run_iteration(
177 float(self.test['runtime']),flow_number,size,speed)
178 if iteration_data['r'] > 1:
179 retry_warning = '{} {:1} retries needed{}'.format(
180 bcolors.WARNING, iteration_data['r'],
184 # Drop rate is expressed in percentage. lat_used is a ratio
185 # (0 to 1). The sum of these 2 should be 100%.
186 # If the sum is lower than 95, it means that more than 5%
187 # of the latency measurements where dropped for accuracy
189 if (iteration_data['drop_rate'] +
190 iteration_data['lat_used'] * 100) < 95:
191 lat_warning = ('{} Latency accuracy issue?: {:>3.0f}%'
192 '{}').format(bcolors.WARNING,
193 iteration_data['lat_used'] * 100,
197 iteration_prefix = {'speed' : bcolors.ENDC,
198 'lat_avg' : bcolors.ENDC,
199 'lat_perc' : bcolors.ENDC,
200 'lat_max' : bcolors.ENDC,
201 'abs_drop_rate' : bcolors.ENDC,
202 'drop_rate' : bcolors.ENDC}
203 if self.test['test'] == 'fixed_rate':
204 end_data = copy.deepcopy(iteration_data)
205 end_prefix = copy.deepcopy(iteration_prefix)
206 if lat_warning or retry_warning:
207 endwarning = '| | {:177.177} |'.format(
208 retry_warning + lat_warning)
210 # TestResult = TestResult + iteration_data['pps_rx']
211 # fixed rate testing result is strange: we just report
213 # The following if statement is testing if we pass the
214 # success criteria of a certain drop rate, average latency
215 # and maximum latency below the threshold.
216 # The drop rate success can be achieved in 2 ways: either
217 # the drop rate is below a treshold, either we want that no
218 # packet has been lost during the test.
219 # This can be specified by putting 0 in the .test file
220 elif ((iteration_data['drop_rate'] < self.test['drop_rate_threshold']) or (iteration_data['abs_dropped']==self.test['drop_rate_threshold']==0)) and (iteration_data['lat_avg']< self.test['lat_avg_threshold']) and (iteration_data['lat_perc']< self.test['lat_perc_threshold']) and (iteration_data['lat_max'] < self.test['lat_max_threshold']):
221 if (old_div((self.get_pps(speed,size) - iteration_data['pps_tx']),self.get_pps(speed,size)))>0.01:
222 iteration_prefix['speed'] = bcolors.WARNING
223 if iteration_data['abs_tx_fail'] > 0:
224 gen_warning = bcolors.WARNING + ' Network limit?: requesting {:<.3f} Mpps and getting {:<.3f} Mpps - {} failed to be transmitted'.format(self.get_pps(speed,size), iteration_data['pps_tx'], iteration_data['abs_tx_fail']) + bcolors.ENDC
226 gen_warning = bcolors.WARNING + ' Generator limit?: requesting {:<.3f} Mpps and getting {:<.3f} Mpps'.format(self.get_pps(speed,size), iteration_data['pps_tx']) + bcolors.ENDC
228 iteration_prefix['speed'] = bcolors.ENDC
230 end_data = copy.deepcopy(iteration_data)
231 end_prefix = copy.deepcopy(iteration_prefix)
232 if lat_warning or gen_warning or retry_warning:
233 endwarning = '| | {:186.186} |'.format(retry_warning + lat_warning + gen_warning)
235 success_message=' SUCCESS'
236 RapidLog.debug(self.report_result(-attempts, size,
237 iteration_data, iteration_prefix) + success_message +
238 retry_warning + lat_warning + gen_warning)
240 success_message=' FAILED'
241 if ((iteration_data['abs_dropped']>0) and (self.test['drop_rate_threshold'] ==0)):
242 iteration_prefix['abs_drop_rate'] = bcolors.FAIL
243 if (iteration_data['drop_rate'] < self.test['drop_rate_threshold']):
244 iteration_prefix['drop_rate'] = bcolors.ENDC
246 iteration_prefix['drop_rate'] = bcolors.FAIL
247 if (iteration_data['lat_avg']< self.test['lat_avg_threshold']):
248 iteration_prefix['lat_avg'] = bcolors.ENDC
250 iteration_prefix['lat_avg'] = bcolors.FAIL
251 if (iteration_data['lat_perc']< self.test['lat_perc_threshold']):
252 iteration_prefix['lat_perc'] = bcolors.ENDC
254 iteration_prefix['lat_perc'] = bcolors.FAIL
255 if (iteration_data['lat_max']< self.test['lat_max_threshold']):
256 iteration_prefix['lat_max'] = bcolors.ENDC
258 iteration_prefix['lat_max'] = bcolors.FAIL
259 if ((old_div((self.get_pps(speed,size) - iteration_data['pps_tx']),self.get_pps(speed,size)))<0.001):
260 iteration_prefix['speed'] = bcolors.ENDC
262 iteration_prefix['speed'] = bcolors.FAIL
264 RapidLog.debug(self.report_result(-attempts, size,
265 iteration_data, iteration_prefix) +
266 success_message + retry_warning + lat_warning)
267 speed = self.new_speed(speed, size, success)
268 if self.test['test'] == 'increment_till_fail':
271 elif self.resolution_achieved():
273 if end_data['speed'] is None:
274 end_data = iteration_data
275 end_prefix = iteration_prefix
276 RapidLog.info('|{:>7} | {:<177} |'.format("FAILED","Speed 0 or close to 0, data for last failed step below:"))
277 RapidLog.info(self.report_result(flow_number, size,
278 end_data, end_prefix))
279 if end_data['avg_bg_rate']:
280 tot_avg_rx_rate = end_data['pps_rx'] + (end_data['avg_bg_rate'] * len(self.background_machines))
281 endtotaltrafficrate = '| | Total amount of traffic received by all generators during this test: {:>4.3f} Gb/s {:7.3f} Mpps {} |'.format(RapidTest.get_speed(tot_avg_rx_rate,size) , tot_avg_rx_rate, ' '*84)
282 RapidLog.info (endtotaltrafficrate)
284 RapidLog.info (endwarning)
285 if self.test['test'] != 'fixed_rate':
286 TestResult = TestResult + end_data['pps_rx']
287 end_data['test'] = self.test['testname']
288 end_data['environment_file'] = self.test['environment_file']
289 end_data['Flows'] = flow_number
290 end_data['Size'] = size
291 end_data['RequestedSpeed'] = RapidTest.get_pps(end_data['speed'] ,size)
292 result_details = self.post_data(end_data)
293 RapidLog.debug(result_details)
294 RapidLog.info('+' + '-' * 8 + '+' + '-' * 18 + '+' + '-' * 13 +
295 '+' + '-' * 13 + '+' + '-' * 13 + '+' + '-' * 24 + '+' +
296 '-' * 10 + '+' + '-' * 10 + '+' + '-' * 10 + '+' + '-' * 11
297 + '+' + '-' * 11 + '+' + '-' * 11 + '+' + '-' * 11 + '+'
298 + '-' * 7 + '+' + '-' * 4 + '+')
299 return (TestResult, result_details)