#!/bin/env python ## ## Copyright (c) 2010-2017 Intel Corporation ## ## Licensed under the Apache License, Version 2.0 (the "License"); ## you may not use this file except in compliance with the License. ## You may obtain a copy of the License at ## ## http://www.apache.org/licenses/LICENSE-2.0 ## ## Unless required by applicable law or agreed to in writing, software ## distributed under the License is distributed on an "AS IS" BASIS, ## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ## See the License for the specific language governing permissions and ## limitations under the License. ## import socket import sys import os from time import * from datetime import datetime from optparse import OptionParser import time from remote_system import * from math import log # General parameters accuracy = 0.1 # in percent of line rate max_dropped = 0.1 # in percent all_pkt_size = [64,128,256,512,1024,1280,1494] all_ip_src = [0,6,12,18] all_ip_dst = [0,6,12,18] # Stear parameters step_time = 0.001 # in seconds step_delta = 10 # in percent of line rate ##### Use case 1: packet loss and latency ##### low_steps_delta_for_loss = 0.01 # Use increment of 0.01% from 0 to low_steps medium_steps_delta_for_loss = 0.1 # Use increment of 0.1% from low_steps to medium_steps normal_steps_delta_for_loss = 1.0 # Use increment of 1% from medium_steps till 100% low_steps = 0.1 medium_steps = 1.0 # Prox parameters tx_port0 = [4] tx_port1 = [6] tx_port2 = [8] tx_port3 = [10] tx_port4 = [12] tx_port5 = [14] tx_port6 = [16] tx_port7 = [18] tx_task = 0 all_rx_cores = [20,22,24,26,28,30,32,34] rx_lat_cores = [20,22,24,26,28,30,32,34] rx_task = 0 # Some variables, do not change # Program arguments parser = OptionParser() parser.add_option("-d", "--duration", dest="test_duration", help="Duration of each steps", metavar="integer", default=10) parser.add_option("-s", "--speed", dest="init_speed", help="Initial speed", metavar="integer", default=100) parser.add_option("-r", "--run", dest="run", help="Run test", metavar="integer", default=0) parser.add_option("-c", "--configure", dest="configure", help="Configure Test", metavar="integer", default=0) (options, args) = parser.parse_args() init_speed = int(options.init_speed) test_duration = int(options.test_duration) configure = int(options.configure) run = int(options.run) nb_cores_per_interface = len(tx_port0) max_speed = (100.0/nb_cores_per_interface) init_speed = (init_speed * 1.0/nb_cores_per_interface) accuracy = (accuracy * 1.0/nb_cores_per_interface) normal_steps_delta_for_loss = (normal_steps_delta_for_loss /nb_cores_per_interface) medium_steps_delta_for_loss = (medium_steps_delta_for_loss /nb_cores_per_interface) low_steps_delta_for_loss = (low_steps_delta_for_loss /nb_cores_per_interface) medium_steps = (medium_steps /nb_cores_per_interface) low_steps = (low_steps /nb_cores_per_interface) max_dropped = max_dropped / 100 def to_str(arr): ret = "" first = 1; for a in arr: if (first == 0): ret += "," ret += str(a) first = 0; return ret; tx_cores_cpe = tx_port0 + tx_port1 + tx_port2 + tx_port3 tx_cores_inet = tx_port4 + tx_port5 + tx_port6 + tx_port7 tx_cores = tx_cores_cpe + tx_cores_inet def send_all_pkt_size(cores, pkt_size): for c in cores: sock.sendall("pkt_size " + str(c) + " 0 " + str(pkt_size) + "\n"); def send_all_value(cores, offset, value, len): for c in cores: sock.sendall("set value " + str(c) + " 0 " + str(offset) + " " + str(value) + " " + str(len)+ "\n"); def send_all_random(cores, offset, rand_str, len): for c in cores: sock.sendall("set random " + str(c) + " 0 " + str(offset) + " " + str(rand_str) + " " + str(len)+ "\n"); #print("set random " + str(c) + " 0 " + str(offset) + " " + str(rand_str) + " " + str(len)+ "\n"); def send_all_speed(cores, speed_perc): for c in cores: sock.sendall("speed " + str(c) + " 0 " + str(speed_perc) + "\n"); def send_reset_random(): sock.sendall("reset randoms all" + "\n"); def send_reset_value(): sock.sendall("reset values all" + "\n"); def rx_stats(tx_cores, tx_task, rx_cores, rx_task): rx = tx = drop = tsc = tsc_hs = ierrors = 0 for e in tx_cores: sock.sendall("core stats " + str(e) + " " + str(tx_task) + "\n") recv = recv_once() rx += int(recv.split(",")[0]) tx += int(recv.split(",")[1]) drop += int(recv.split(",")[2]) tsc = int(recv.split(",")[3]) tsc_hz = int(recv.split(",")[4]) for e in rx_cores: sock.sendall("core stats " + str(e) + " " + str(rx_task) + "\n") recv = recv_once() rx += int(recv.split(",")[0]) tx += int(recv.split(",")[1]) drop += int(recv.split(",")[2]) tsc = int(recv.split(",")[3]) tsc_hz = int(recv.split(",")[4]) # Also get the ierrors as generators might be the bottleneck... sock.sendall("tot ierrors tot\n") recv = recv_once() ierrors += int(recv.split(",")[0]) rx+=ierrors return rx,tx,drop,tsc,tsc_hz def lat_stats(cores,task): lat_min = [0 for e in range(127)] lat_max = [0 for e in range(127)] lat_avg = [0 for e in range(127)] for e in cores: sock.sendall("lat stats " + str(e) + " " + str(task) + " " + "\n") recv = recv_once() lat_min[e] = int(recv.split(",")[0]) lat_max[e] = int(recv.split(",")[1]) lat_avg[e] = int(recv.split(",")[2]) return lat_min, lat_max, lat_avg def recv_once(): ret_str = ""; done = 0; while done == 0: dat = sock.recv(256); i = 0; while(i < len(dat)): if (dat[i] == '\n'): done = 1 else: ret_str += dat[i]; i = i + 1; return ret_str def set_pkt_sizes(tx_cores, p): send_all_pkt_size(tx_cores, p-4) # For all cores, need to adapt IP Length (byte 16) and UDP Length (byte 38) to pkt size send_all_value(tx_cores, 16, p - 18, 2) # 14 for MAC (12) EthType (2) send_all_value(tx_cores, 38, p - 38, 2) # 34 for MAC (12) EthType (2) IP (20) def set_pkt_sizes_cpe(tx_cores, p): send_all_pkt_size(tx_cores, p-4) # For all cores, need to adapt IP Length (byte 16) and UDP Length (byte 38) to pkt size send_all_value(tx_cores, 24, p - 26, 2) # 22 for QinQ (8) MAC (12) EthType (2) send_all_value(tx_cores, 46, p - 46, 2) # 42 for QinQ (8) MAC (12) EthType (2) IP (20) def set_pkt_sizes_inet(tx_cores, p): send_all_pkt_size(tx_cores, p+24-4) # For all cores, need to adapt IP Length (byte 16) and UDP Length (byte 38) to pkt size send_all_value(tx_cores, 20, p + 2, 2) # 14 for MAC (12) EthType (2) send_all_value(tx_cores, 48, p - 26, 2) # 14 for MAC (12) EthType (2) send_all_value(tx_cores, 70, p - 46, 2) # 34 for MAC (12) EthType (2) IP (20) def run_measure_throughput(speed, speed_cpe): done = 0 # Intialize tests by stopping cores and resetting stats step=0 steps_done = 0 sock.sendall("start " + to_str(all_rx_cores) + "\n") sleep(2) sock.sendall("stop " + to_str(all_rx_cores) + "\n") sock.sendall("reset stats\n") print "Speed = " + str(speed * nb_cores_per_interface) sleep(1); send_all_speed(tx_cores, step); # Now starting the steps. First go to the common speed, then increase steps for the faster one. sock.sendall("start " + to_str(tx_cores) + "," + to_str(rx_lat_cores) + "\n") while (steps_done == 0): sleep(step_time) if (step + step_delta <= speed): step+=step_delta else: steps_done = 1; send_all_speed(tx_cores, step) # Steps are now OK. Set speed send_all_speed(tx_cores_inet, speed); send_all_speed(tx_cores_cpe, speed_cpe); sleep(2); # Getting statistics to calculate PPS at right speed.... 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); sleep(test_duration); # Collect statistics before test stops...and stop the test. Important to get stats before stopping as stops take some time... 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); lat_min,lat_max,lat_avg = lat_stats(rx_lat_cores, rx_task) sock.sendall("stop " + to_str(tx_cores) + "\n") sock.sendall("start " + to_str(all_rx_cores) + "\n") sleep(3); sock.sendall("stop " + to_str(all_rx_cores) + "\n") rx_end, tx_end,drop_end,tsc_end,tsc_hz = rx_stats(tx_cores, tx_task, all_rx_cores, rx_task); rx = rx_pps_end - rx_pps_beg tsc = tsc_pps_end - tsc_pps_beg mpps = rx / (tsc/float(tsc_hz)) / 1000000 tx = tx_pps_end - tx_pps_beg tx_mpps = tx / (tsc/float(tsc_hz)) / 1000000 #print "Runtime = " + str((tsc)/float(tsc_hz)); if (tx_end == 0): dropped_tot = tx_end - rx_end dropped_pct = 0 else: dropped_tot = tx_end - rx_end dropped_pct = ((dropped_tot) * 1.0) / tx_end if (dropped_tot > 0): if (dropped_pct >= max_dropped): print "** FAILED **: lost " + str(100*dropped_pct) + "% packets RX = " + str(rx_end) + " TX = " + str(tx_end) + " DROPPED = " + str(tx_end - rx_end) else: print "OK but lost " + str(100*dropped_pct) + "% packets RX = " + str(rx_end) + " TX = " + str(tx_end) + " DROPPED = " + str(tx_end - rx_end) else: if (dropped_tot < 0): print "Something wrong happened - received more packets than transmitted" else: print "** OK **: RX = " + str(rx_end) + " TX = " + str(tx_end) + " DROPPED = " + str(tx_end - rx_end) print "MPPS = " + str(mpps) print "====================================================" return dropped_pct, mpps, tx_mpps, dropped_tot,lat_min,lat_max,lat_avg 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): 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) + "; " ) for e in rx_lat_cores: f.write(str(lat_min[e]) + "; " + str(lat_max[e]) + "; " + str(lat_avg[e]) + "; ") f.write("\n"); f.flush() def run_dicho_search(number_flows, pkt_size): previous_success_speed = 0.0 previous_error_speed = max_speed speed = init_speed * 1.0 done = 0; good_tx_mpps = 0 good_mpps = 0 good_dropped_pct = 0 good_dropped_tot = 0 good_speed = 0 good_lat_min = [0 for e in range(127)] good_lat_max = [0 for e in range(127)] good_lat_avg = [0 for e in range(127)] while done == 0: speed_cpe = (speed * (pkt_size + 20)) / (pkt_size + 24 + 20) dropped_pct, mpps, tx_mpps, dropped_tot,lat_min,lat_max,lat_avg = run_measure_throughput(speed, speed_cpe) if ((dropped_tot >= 0) and (dropped_pct <= max_dropped)): good_tx_mpps = tx_mpps good_mpps = mpps good_dropped_pct = dropped_pct good_dropped_tot = dropped_tot good_speed = speed good_lat_min = lat_min good_lat_max = lat_max good_lat_avg = lat_avg 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); 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); else: 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); if ((speed == max_speed) and (dropped_pct <= max_dropped)): 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); done = 1 if (dropped_pct <= max_dropped): previous_success_speed = speed if (speed > max_speed - accuracy): speed = max_speed else: if (previous_error_speed - speed < accuracy): 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); done = 1 else: speed = speed + (previous_error_speed - speed)/2; else: previous_error_speed = speed if (speed - previous_success_speed < accuracy): 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); done = 1 else: speed = speed - (speed - previous_success_speed) / 2; def set_source_destination_ip(nb_sources, nb_destinations): # Destination addressese: "00XXXXXX" "XXXXXXXX" "XXXXXXXX" "XXXXXX10" # Starting with 00 to be in class A and skipping 0.x.y.z and 127.x.y.z # Ending with 10 to avoid x.y.z.0 and x.y.z.255 dst_mask = "10" for i in range (nb_destinations): dst_mask = "X" + str(dst_mask) for i in range (32 - nb_destinations - 2): dst_mask = "0" + str(dst_mask) src_mask = "10" for i in range (nb_sources): src_mask = "X" + str(src_mask) for i in range (32 - nb_sources - 2): src_mask = "0" + str(src_mask) for c in tx_port0: send_all_random([c], 26, src_mask, 4) send_all_random([c], 30, dst_mask, 4) for c in tx_port1: send_all_random([c], 26, src_mask, 4) send_all_random([c], 30, dst_mask, 4) for c in tx_port2: send_all_random([c], 26, src_mask, 4) send_all_random([c], 30, dst_mask, 4) for c in tx_port3: send_all_random([c], 26, src_mask, 4) send_all_random([c], 30, dst_mask, 4) for c in tx_port4: send_all_random([c], 26, src_mask, 4) send_all_random([c], 30, dst_mask, 4) for c in tx_port5: send_all_random([c], 26, src_mask, 4) send_all_random([c], 30, dst_mask, 4) for c in tx_port6: send_all_random([c], 26, src_mask, 4) send_all_random([c], 30, dst_mask, 4) for c in tx_port7: send_all_random([c], 26, src_mask, 4) send_all_random([c], 30, dst_mask, 4) #======================================================================== class TestDefinition(): "Stores test parameters" def __init__(self, number_ip_src, number_ip_dst, pkt_size): self.number_ip_src = number_ip_src self.number_ip_dst = number_ip_dst self.pkt_size = pkt_size #======================================================================== def run_use_case(number_ip_src, number_ip_dst, pkt_size): number_flows = (2 ** number_ip_src) * (2 ** number_ip_dst) # send_reset_random() # send_reset_value() # set_source_destination_ip(number_ip_src, number_ip_dst) set_pkt_sizes_inet(tx_cores_inet, pkt_size) set_pkt_sizes_cpe(tx_cores_cpe, pkt_size) 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" run_dicho_search(number_flows, pkt_size) sleep(3) #======================================================================== def run_all_use_cases(): use_case_nb = 1 # Connect to dppd file_path = '/tmp/prox.sock' sock.connect(file_path) f.write("pkt_size; tx_mpps; rx_mpps; dropped_pct; dropped_tot; percent_line_rate; latency per core\n") f_all.write("pkt_size; tx_mpps; rx_mpps; dropped_pct; dropped_tot; percent_line_rate; latency per core\n") f_minimal.write("pkt_size; tx_mpps; rx_mpps; dropped_pct; dropped_tot; percent_line_rate; latency per core\n") f.flush(); f_all.flush(); f_minimal.flush(); # Starting tests print "Stopping all cores and resetting all values and randoms before starting\n" sock.sendall("stop " + to_str(all_rx_cores) + "\n") sock.sendall("stop " + to_str(tx_cores) + "\n") #sock.sendall("stop all") sock.sendall("reset stats\n") sleep(3); for line in file_tests: info = line.split(';') if (info[0][0] == '#'): continue if (info[0][0] == ''): break number_ip_src = int(info[0]) number_ip_dst = int(info[1]) pkt_size = int(info[2]) run_use_case(number_ip_src, number_ip_dst, pkt_size) #======================================================================== def configure_use_case(): Tests = [] number_ip_dst = 0 number_ip_src = 0 for pkt_size in all_pkt_size: Tests.append(TestDefinition(number_ip_src, number_ip_dst, pkt_size)) pkt_size = 64 while (pkt_size < 1494): Tests.append(TestDefinition(number_ip_src, number_ip_dst, pkt_size)) pkt_size = (pkt_size *11) / 10 file_tests = open('test_description.txt', 'w') file_tests.write("# Number_ip_src; number_ip_dst; pkt_size; \n") for test in Tests: file_tests.write(str(test.number_ip_src) + "; " + str(test.number_ip_dst) + "; " + str(test.pkt_size) + "; " + ";\n") file_tests.close() #======================================================================== if ((configure == 0) and (run == 0)): print "Nothing to do - please use -r 1 or -c 1" if (configure == 1): configure_use_case() if (run == 1): print "****************************************************************************************************************" print "** Running Characterization with " + str(test_duration) + " seconds steps and starting at " + str(init_speed) + " percent of line rate **" print "****************************************************************************************************************" sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) f_all = open('all_results.txt', 'w') f = open('detailed_results.txt', 'w') f_minimal = open('minimal_results.txt', 'w') file_tests = open('test_description.txt', 'r') run_all_use_cases() f.close(); sock.close();