4 ## Copyright (c) 2010-2017 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
10 ## http://www.apache.org/licenses/LICENSE-2.0
12 ## Unless required by applicable law or agreed to in writing, software
13 ## distributed under the License is distributed on an "AS IS" BASIS,
14 ## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 ## See the License for the specific language governing permissions and
16 ## limitations under the License.
23 from datetime import datetime
24 from optparse import OptionParser
26 from remote_system import *
30 accuracy = 0.1 # in percent of line rate
31 max_dropped = 0.1 # in percent
32 all_pkt_size = [64,128,256,512,1024,1280,1494]
33 all_ip_src = [0,6,12,18]
34 all_ip_dst = [0,6,12,18]
37 step_time = 0.001 # in seconds
38 step_delta = 10 # in percent of line rate
40 ##### Use case 1: packet loss and latency #####
41 low_steps_delta_for_loss = 0.01 # Use increment of 0.01% from 0 to low_steps
42 medium_steps_delta_for_loss = 0.1 # Use increment of 0.1% from low_steps to medium_steps
43 normal_steps_delta_for_loss = 1.0 # Use increment of 1% from medium_steps till 100%
58 all_rx_cores = [20,22,24,26,28,30,32,34]
59 rx_lat_cores = [20,22,24,26,28,30,32,34]
62 # Some variables, do not change
65 parser = OptionParser()
66 parser.add_option("-d", "--duration", dest="test_duration", help="Duration of each steps", metavar="integer", default=10)
67 parser.add_option("-s", "--speed", dest="init_speed", help="Initial speed", metavar="integer", default=100)
68 parser.add_option("-r", "--run", dest="run", help="Run test", metavar="integer", default=0)
69 parser.add_option("-c", "--configure", dest="configure", help="Configure Test", metavar="integer", default=0)
70 (options, args) = parser.parse_args()
72 init_speed = int(options.init_speed)
73 test_duration = int(options.test_duration)
74 configure = int(options.configure)
75 run = int(options.run)
77 nb_cores_per_interface = len(tx_port0)
78 max_speed = (100.0/nb_cores_per_interface)
79 init_speed = (init_speed * 1.0/nb_cores_per_interface)
80 accuracy = (accuracy * 1.0/nb_cores_per_interface)
81 normal_steps_delta_for_loss = (normal_steps_delta_for_loss /nb_cores_per_interface)
82 medium_steps_delta_for_loss = (medium_steps_delta_for_loss /nb_cores_per_interface)
83 low_steps_delta_for_loss = (low_steps_delta_for_loss /nb_cores_per_interface)
84 medium_steps = (medium_steps /nb_cores_per_interface)
85 low_steps = (low_steps /nb_cores_per_interface)
87 max_dropped = max_dropped / 100
100 tx_cores_cpe = tx_port0 + tx_port1 + tx_port2 + tx_port3
101 tx_cores_inet = tx_port4 + tx_port5 + tx_port6 + tx_port7
102 tx_cores = tx_cores_cpe + tx_cores_inet
104 def send_all_pkt_size(cores, pkt_size):
106 sock.sendall("pkt_size " + str(c) + " 0 " + str(pkt_size) + "\n");
108 def send_all_value(cores, offset, value, len):
110 sock.sendall("set value " + str(c) + " 0 " + str(offset) + " " + str(value) + " " + str(len)+ "\n");
112 def send_all_random(cores, offset, rand_str, len):
114 sock.sendall("set random " + str(c) + " 0 " + str(offset) + " " + str(rand_str) + " " + str(len)+ "\n");
115 #print("set random " + str(c) + " 0 " + str(offset) + " " + str(rand_str) + " " + str(len)+ "\n");
117 def send_all_speed(cores, speed_perc):
119 sock.sendall("speed " + str(c) + " 0 " + str(speed_perc) + "\n");
121 def send_reset_random():
122 sock.sendall("reset randoms all" + "\n");
124 def send_reset_value():
125 sock.sendall("reset values all" + "\n");
127 def rx_stats(tx_cores, tx_task, rx_cores, rx_task):
128 rx = tx = drop = tsc = tsc_hs = ierrors = 0
130 sock.sendall("core stats " + str(e) + " " + str(tx_task) + "\n")
132 rx += int(recv.split(",")[0])
133 tx += int(recv.split(",")[1])
134 drop += int(recv.split(",")[2])
135 tsc = int(recv.split(",")[3])
136 tsc_hz = int(recv.split(",")[4])
138 sock.sendall("core stats " + str(e) + " " + str(rx_task) + "\n")
140 rx += int(recv.split(",")[0])
141 tx += int(recv.split(",")[1])
142 drop += int(recv.split(",")[2])
143 tsc = int(recv.split(",")[3])
144 tsc_hz = int(recv.split(",")[4])
145 # Also get the ierrors as generators might be the bottleneck...
146 sock.sendall("tot ierrors tot\n")
148 ierrors += int(recv.split(",")[0])
150 return rx,tx,drop,tsc,tsc_hz
152 def lat_stats(cores,task):
153 lat_min = [0 for e in range(127)]
154 lat_max = [0 for e in range(127)]
155 lat_avg = [0 for e in range(127)]
157 sock.sendall("lat stats " + str(e) + " " + str(task) + " " + "\n")
159 lat_min[e] = int(recv.split(",")[0])
160 lat_max[e] = int(recv.split(",")[1])
161 lat_avg[e] = int(recv.split(",")[2])
162 return lat_min, lat_max, lat_avg
168 dat = sock.recv(256);
178 def set_pkt_sizes(tx_cores, p):
179 send_all_pkt_size(tx_cores, p-4)
180 # For all cores, need to adapt IP Length (byte 16) and UDP Length (byte 38) to pkt size
181 send_all_value(tx_cores, 16, p - 18, 2) # 14 for MAC (12) EthType (2)
182 send_all_value(tx_cores, 38, p - 38, 2) # 34 for MAC (12) EthType (2) IP (20)
184 def set_pkt_sizes_cpe(tx_cores, p):
185 send_all_pkt_size(tx_cores, p-4)
186 # For all cores, need to adapt IP Length (byte 16) and UDP Length (byte 38) to pkt size
187 send_all_value(tx_cores, 24, p - 26, 2) # 22 for QinQ (8) MAC (12) EthType (2)
188 send_all_value(tx_cores, 46, p - 46, 2) # 42 for QinQ (8) MAC (12) EthType (2) IP (20)
190 def set_pkt_sizes_inet(tx_cores, p):
191 send_all_pkt_size(tx_cores, p+24-4)
192 # For all cores, need to adapt IP Length (byte 16) and UDP Length (byte 38) to pkt size
193 send_all_value(tx_cores, 20, p + 2, 2) # 14 for MAC (12) EthType (2)
194 send_all_value(tx_cores, 48, p - 26, 2) # 14 for MAC (12) EthType (2)
195 send_all_value(tx_cores, 70, p - 46, 2) # 34 for MAC (12) EthType (2) IP (20)
197 def run_measure_throughput(speed, speed_cpe):
199 # Intialize tests by stopping cores and resetting stats
202 sock.sendall("start " + to_str(all_rx_cores) + "\n")
204 sock.sendall("stop " + to_str(all_rx_cores) + "\n")
205 sock.sendall("reset stats\n")
206 print "Speed = " + str(speed * nb_cores_per_interface)
209 send_all_speed(tx_cores, step);
211 # Now starting the steps. First go to the common speed, then increase steps for the faster one.
212 sock.sendall("start " + to_str(tx_cores) + "," + to_str(rx_lat_cores) + "\n")
213 while (steps_done == 0):
215 if (step + step_delta <= speed):
219 send_all_speed(tx_cores, step)
221 # Steps are now OK. Set speed
222 send_all_speed(tx_cores_inet, speed);
223 send_all_speed(tx_cores_cpe, speed_cpe);
226 # Getting statistics to calculate PPS at right speed....
227 rx_pps_beg,tx_pps_beg,drop_pps_beg,tsc_pps_beg,tsc_hz = rx_stats(tx_cores, tx_task, all_rx_cores, rx_task);
228 sleep(test_duration);
230 # Collect statistics before test stops...and stop the test. Important to get stats before stopping as stops take some time...
231 rx_pps_end,tx_pps_end,drop_pps_end,tsc_pps_end,tsc_hz = rx_stats(tx_cores, tx_task, all_rx_cores, rx_task);
232 lat_min,lat_max,lat_avg = lat_stats(rx_lat_cores, rx_task)
233 sock.sendall("stop " + to_str(tx_cores) + "\n")
234 sock.sendall("start " + to_str(all_rx_cores) + "\n")
236 sock.sendall("stop " + to_str(all_rx_cores) + "\n")
238 rx_end, tx_end,drop_end,tsc_end,tsc_hz = rx_stats(tx_cores, tx_task, all_rx_cores, rx_task);
239 rx = rx_pps_end - rx_pps_beg
240 tsc = tsc_pps_end - tsc_pps_beg
241 mpps = rx / (tsc/float(tsc_hz)) / 1000000
242 tx = tx_pps_end - tx_pps_beg
243 tx_mpps = tx / (tsc/float(tsc_hz)) / 1000000
245 #print "Runtime = " + str((tsc)/float(tsc_hz));
247 dropped_tot = tx_end - rx_end
250 dropped_tot = tx_end - rx_end
251 dropped_pct = ((dropped_tot) * 1.0) / tx_end
253 if (dropped_tot > 0):
254 if (dropped_pct >= max_dropped):
255 print "** FAILED **: lost " + str(100*dropped_pct) + "% packets RX = " + str(rx_end) + " TX = " + str(tx_end) + " DROPPED = " + str(tx_end - rx_end)
257 print "OK but lost " + str(100*dropped_pct) + "% packets RX = " + str(rx_end) + " TX = " + str(tx_end) + " DROPPED = " + str(tx_end - rx_end)
259 if (dropped_tot < 0):
260 print "Something wrong happened - received more packets than transmitted"
262 print "** OK **: RX = " + str(rx_end) + " TX = " + str(tx_end) + " DROPPED = " + str(tx_end - rx_end)
263 print "MPPS = " + str(mpps)
264 print "===================================================="
265 return dropped_pct, mpps, tx_mpps, dropped_tot,lat_min,lat_max,lat_avg
267 def write_results(f, pkt_size, tx_mpps, mpps, dropped_pct, dropped_tot, speed, nb_cores_per_interface, number_flows, lat_min, lat_max, lat_avg):
268 f.write(str(pkt_size) + "; " + str(tx_mpps) + "; " + str(mpps) + "; " + str(100 * dropped_pct) + "; " + str(dropped_tot) + "; " + str(speed * nb_cores_per_interface) + "; " + str(number_flows) + "; " )
269 for e in rx_lat_cores:
270 f.write(str(lat_min[e]) + "; " + str(lat_max[e]) + "; " + str(lat_avg[e]) + "; ")
274 def run_dicho_search(number_flows, pkt_size):
275 previous_success_speed = 0.0
276 previous_error_speed = max_speed
277 speed = init_speed * 1.0
284 good_lat_min = [0 for e in range(127)]
285 good_lat_max = [0 for e in range(127)]
286 good_lat_avg = [0 for e in range(127)]
289 speed_cpe = (speed * (pkt_size + 20)) / (pkt_size + 24 + 20)
290 dropped_pct, mpps, tx_mpps, dropped_tot,lat_min,lat_max,lat_avg = run_measure_throughput(speed, speed_cpe)
291 if ((dropped_tot >= 0) and (dropped_pct <= max_dropped)):
292 good_tx_mpps = tx_mpps
294 good_dropped_pct = dropped_pct
295 good_dropped_tot = dropped_tot
297 good_lat_min = lat_min
298 good_lat_max = lat_max
299 good_lat_avg = lat_avg
300 write_results(f, pkt_size, tx_mpps, mpps, dropped_pct, dropped_tot, speed, nb_cores_per_interface, number_flows, lat_min, lat_max, lat_avg);
301 write_results(f_all, pkt_size, tx_mpps, mpps, dropped_pct, dropped_tot, speed, nb_cores_per_interface, number_flows, lat_min, lat_max, lat_avg);
303 write_results(f_all, pkt_size, tx_mpps, mpps, dropped_pct, dropped_tot, speed, nb_cores_per_interface, number_flows, lat_min, lat_max, lat_avg);
305 if ((speed == max_speed) and (dropped_pct <= max_dropped)):
306 write_results(f_minimal, pkt_size, tx_mpps, mpps, dropped_pct, dropped_tot, speed, nb_cores_per_interface, number_flows, lat_min, lat_max, lat_avg);
308 if (dropped_pct <= max_dropped):
309 previous_success_speed = speed
310 if (speed > max_speed - accuracy):
313 if (previous_error_speed - speed < accuracy):
314 write_results(f_minimal, pkt_size, good_tx_mpps, good_mpps, good_dropped_pct, good_dropped_tot, good_speed, nb_cores_per_interface, number_flows, good_lat_min, good_lat_max, good_lat_avg);
317 speed = speed + (previous_error_speed - speed)/2;
319 previous_error_speed = speed
320 if (speed - previous_success_speed < accuracy):
321 write_results(f_minimal, pkt_size, good_tx_mpps, good_mpps, good_dropped_pct, good_dropped_tot, good_speed, nb_cores_per_interface, number_flows, good_lat_min, good_lat_max, good_lat_avg);
324 speed = speed - (speed - previous_success_speed) / 2;
327 def set_source_destination_ip(nb_sources, nb_destinations):
328 # Destination addressese: "00XXXXXX" "XXXXXXXX" "XXXXXXXX" "XXXXXX10"
329 # Starting with 00 to be in class A and skipping 0.x.y.z and 127.x.y.z
330 # Ending with 10 to avoid x.y.z.0 and x.y.z.255
333 for i in range (nb_destinations):
334 dst_mask = "X" + str(dst_mask)
335 for i in range (32 - nb_destinations - 2):
336 dst_mask = "0" + str(dst_mask)
339 for i in range (nb_sources):
340 src_mask = "X" + str(src_mask)
341 for i in range (32 - nb_sources - 2):
342 src_mask = "0" + str(src_mask)
345 send_all_random([c], 26, src_mask, 4)
346 send_all_random([c], 30, dst_mask, 4)
348 send_all_random([c], 26, src_mask, 4)
349 send_all_random([c], 30, dst_mask, 4)
351 send_all_random([c], 26, src_mask, 4)
352 send_all_random([c], 30, dst_mask, 4)
354 send_all_random([c], 26, src_mask, 4)
355 send_all_random([c], 30, dst_mask, 4)
357 send_all_random([c], 26, src_mask, 4)
358 send_all_random([c], 30, dst_mask, 4)
360 send_all_random([c], 26, src_mask, 4)
361 send_all_random([c], 30, dst_mask, 4)
363 send_all_random([c], 26, src_mask, 4)
364 send_all_random([c], 30, dst_mask, 4)
366 send_all_random([c], 26, src_mask, 4)
367 send_all_random([c], 30, dst_mask, 4)
369 #========================================================================
370 class TestDefinition():
371 "Stores test parameters"
372 def __init__(self, number_ip_src, number_ip_dst, pkt_size):
373 self.number_ip_src = number_ip_src
374 self.number_ip_dst = number_ip_dst
375 self.pkt_size = pkt_size
377 #========================================================================
378 def run_use_case(number_ip_src, number_ip_dst, pkt_size):
379 number_flows = (2 ** number_ip_src) * (2 ** number_ip_dst)
380 # send_reset_random()
382 # set_source_destination_ip(number_ip_src, number_ip_dst)
383 set_pkt_sizes_inet(tx_cores_inet, pkt_size)
384 set_pkt_sizes_cpe(tx_cores_cpe, pkt_size)
385 print "Running test with pkt size= " + str(pkt_size) + " number_ip_src = " + str(number_ip_src) + " number_ip_dst = " + str(number_ip_dst) + " Number flows = " + str(number_flows) + "; \n"
386 run_dicho_search(number_flows, pkt_size)
389 #========================================================================
390 def run_all_use_cases():
393 file_path = '/tmp/prox.sock'
394 sock.connect(file_path)
396 f.write("pkt_size; tx_mpps; rx_mpps; dropped_pct; dropped_tot; percent_line_rate; latency per core\n")
397 f_all.write("pkt_size; tx_mpps; rx_mpps; dropped_pct; dropped_tot; percent_line_rate; latency per core\n")
398 f_minimal.write("pkt_size; tx_mpps; rx_mpps; dropped_pct; dropped_tot; percent_line_rate; latency per core\n")
404 print "Stopping all cores and resetting all values and randoms before starting\n"
405 sock.sendall("stop " + to_str(all_rx_cores) + "\n")
406 sock.sendall("stop " + to_str(tx_cores) + "\n")
407 #sock.sendall("stop all")
408 sock.sendall("reset stats\n")
410 for line in file_tests:
411 info = line.split(';')
412 if (info[0][0] == '#'):
414 if (info[0][0] == ''):
416 number_ip_src = int(info[0])
417 number_ip_dst = int(info[1])
418 pkt_size = int(info[2])
419 run_use_case(number_ip_src, number_ip_dst, pkt_size)
421 #========================================================================
422 def configure_use_case():
426 for pkt_size in all_pkt_size:
427 Tests.append(TestDefinition(number_ip_src, number_ip_dst, pkt_size))
430 while (pkt_size < 1494):
431 Tests.append(TestDefinition(number_ip_src, number_ip_dst, pkt_size))
432 pkt_size = (pkt_size *11) / 10
434 file_tests = open('test_description.txt', 'w')
435 file_tests.write("# Number_ip_src; number_ip_dst; pkt_size; \n")
437 file_tests.write(str(test.number_ip_src) + "; " + str(test.number_ip_dst) + "; " + str(test.pkt_size) + "; " + ";\n")
440 #========================================================================
441 if ((configure == 0) and (run == 0)):
442 print "Nothing to do - please use -r 1 or -c 1"
446 print "****************************************************************************************************************"
447 print "** Running Characterization with " + str(test_duration) + " seconds steps and starting at " + str(init_speed) + " percent of line rate **"
448 print "****************************************************************************************************************"
449 sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
450 f_all = open('all_results.txt', 'w')
451 f = open('detailed_results.txt', 'w')
452 f_minimal = open('minimal_results.txt', 'w')
453 file_tests = open('test_description.txt', 'r')