X-Git-Url: https://gerrit.opnfv.org/gerrit/gitweb?a=blobdiff_plain;f=VNFs%2FDPPD-PROX%2Fhelper-scripts%2Frapid%2Frapid_test.py;h=a54caba5ee58193599b529b017908fd766cdc416;hb=849357bb9ca1d27993c9e96b93156ec69b3ac3a9;hp=2466d89bd0770c61241e8775f3cf66ecfbc73634;hpb=8f21fb5ed8231125bca3cec1329d9fd739f14684;p=samplevnf.git diff --git a/VNFs/DPPD-PROX/helper-scripts/rapid/rapid_test.py b/VNFs/DPPD-PROX/helper-scripts/rapid/rapid_test.py index 2466d89b..a54caba5 100644 --- a/VNFs/DPPD-PROX/helper-scripts/rapid/rapid_test.py +++ b/VNFs/DPPD-PROX/helper-scripts/rapid/rapid_test.py @@ -1,7 +1,7 @@ #!/usr/bin/python ## -## Copyright (c) 2010-2020 Intel Corporation +## Copyright (c) 2020 Intel Corporation ## ## Licensed under the Apache License, Version 2.0 (the "License"); ## you may not use this file except in compliance with the License. @@ -17,34 +17,63 @@ ## limitations under the License. ## +import yaml +import requests import time +import copy from past.utils import old_div from rapid_log import RapidLog from rapid_log import bcolors +inf = float("inf") +from datetime import datetime as dt class RapidTest(object): """ - Class to manage the flowsizetesting + Class to manage the testing """ + def __init__(self, test_param, runtime, testname, environment_file ): + self.test = test_param + self.test['runtime'] = runtime + self.test['testname'] = testname + self.test['environment_file'] = environment_file + if 'maxr' not in self.test.keys(): + self.test['maxr'] = 1 + if 'maxz' not in self.test.keys(): + self.test['maxz'] = inf + with open('format.yaml') as f: + self.data_format = yaml.load(f, Loader=yaml.FullLoader) + @staticmethod def get_percentageof10Gbps(pps_speed,size): # speed is given in pps, returning % of 10Gb/s - return (pps_speed / 1000000.0 * 0.08 * (size+28)) + # 12 bytes is the inter packet gap + # pre-amble is 7 bytes + # SFD (start of frame delimiter) is 1 byte + # Total of 20 bytes overhead per packet + return (pps_speed / 1000000.0 * 0.08 * (size+20)) @staticmethod def get_pps(speed,size): # speed is given in % of 10Gb/s, returning Mpps - return (speed * 100.0 / (8*(size+28))) + # 12 bytes is the inter packet gap + # pre-amble is 7 bytes + # SFD (start of frame delimiter) is 1 byte + # Total of 20 bytes overhead per packet + return (speed * 100.0 / (8*(size+20))) @staticmethod def get_speed(packet_speed,size): # return speed in Gb/s - return (packet_speed / 1000.0 * (8*(size+28))) + # 12 bytes is the inter packet gap + # pre-amble is 7 bytes + # SFD (start of frame delimiter) is 1 byte + # Total of 20 bytes overhead per packet + return (packet_speed / 1000.0 * (8*(size+20))) @staticmethod def set_background_flows(background_machines, number_of_flows): for machine in background_machines: - machine.set_flows(number_of_flows) + _ = machine.set_flows(number_of_flows) @staticmethod def set_background_speed(background_machines, speed): @@ -67,6 +96,34 @@ class RapidTest(object): for machine in background_machines: machine.stop() + @staticmethod + def parse_data_format_dict(data_format, variables): + for k, v in data_format.items(): + if type(v) is dict: + RapidTest.parse_data_format_dict(v, variables) + else: + if v in variables.keys(): + data_format[k] = variables[v] + + def post_data(self, test, variables): + var = copy.deepcopy(self.data_format) + self.parse_data_format_dict(var, variables) + if var.keys() >= {'URL', test, 'Format'}: + URL='' + for value in var['URL'].values(): + URL = URL + value + HEADERS = {'X-Requested-With': 'Python requests', 'Content-type': 'application/rapid'} + if var['Format'] == 'PushGateway': + data = "\n".join("{} {}".format(k, v) for k, v in var[test].items()) + "\n" + response = requests.post(url=URL, data=data,headers=HEADERS) + elif var['Format'] == 'Xtesting': + data = var[test] + response = requests.post(url=URL, json=data) + if (response.status_code >= 300): + RapidLog.info('Cannot send metrics to {}'.format(URL)) + RapidLog.info(data) + return (var[test]) + @staticmethod def report_result(flow_number, size, speed, pps_req_tx, pps_tx, pps_sut_tx, pps_rx, lat_avg, lat_perc, lat_perc_max, lat_max, tx, rx, tot_drop, @@ -91,7 +148,8 @@ class RapidTest(object): if pps_rx is None: pps_rx_str = '{0: >25}'.format('NA |') else: - pps_rx_str = bcolors.OKBLUE + '{:>4.1f} Gb/s |{:7.3f} Mpps {}|'.format(RapidTest.get_speed(pps_rx,size),pps_rx,bcolors.ENDC) + pps_rx_str = bcolors.OKBLUE + '{:>4.1f} Gb/s |{:7.3f} Mpps {}|'.format( + RapidTest.get_speed(pps_rx,size),pps_rx,bcolors.ENDC) if tot_drop is None: tot_drop_str = ' | NA | ' else: @@ -99,14 +157,25 @@ class RapidTest(object): if lat_perc is None: lat_perc_str = ' |{:^10.10}|'.format('NA') elif lat_perc_max == True: - lat_perc_str = '|>{}{:>5.0f} us{} |'.format(lat_perc_prefix,float(lat_perc), bcolors.ENDC) + lat_perc_str = '|>{}{:>5.0f} us{} |'.format(lat_perc_prefix, + float(lat_perc), bcolors.ENDC) else: - lat_perc_str = '| {}{:>5.0f} us{} |'.format(lat_perc_prefix,float(lat_perc), bcolors.ENDC) + lat_perc_str = '| {}{:>5.0f} us{} |'.format(lat_perc_prefix, + float(lat_perc), bcolors.ENDC) if elapsed_time is None: elapsed_time_str = ' NA |' else: elapsed_time_str = '{:>3.0f} |'.format(elapsed_time) - return(flow_number_str + '{:>5.1f}'.format(speed) + '% '+speed_prefix +'{:>6.3f}'.format(RapidTest.get_pps(speed,size)) + ' Mpps|'+ pps_req_tx_str + pps_tx_str + bcolors.ENDC + pps_sut_tx_str + pps_rx_str +lat_avg_prefix+ ' {:>6.0f}'.format(lat_avg)+' us'+lat_perc_str+lat_max_prefix+'{:>6.0f}'.format(lat_max)+' us | ' + '{:>9.0f}'.format(tx) + ' | {:>9.0f}'.format(rx) + ' | '+ abs_drop_rate_prefix+ '{:>9.0f}'.format(tx-rx) + tot_drop_str +drop_rate_prefix+ '{:>5.2f}'.format(old_div(float(tx-rx),tx)) +bcolors.ENDC+' |' + elapsed_time_str) + return(flow_number_str + '{:>5.1f}'.format(speed) + '% ' + speed_prefix + + '{:>6.3f}'.format(RapidTest.get_pps(speed,size)) + ' Mpps|' + + pps_req_tx_str + pps_tx_str + bcolors.ENDC + pps_sut_tx_str + + pps_rx_str + lat_avg_prefix + ' {:>6.0f}'.format(lat_avg) + + ' us' + lat_perc_str +lat_max_prefix+'{:>6.0f}'.format(lat_max) + + ' us | ' + '{:>9.0f}'.format(tx) + ' | {:>9.0f}'.format(rx) + + ' | '+ abs_drop_rate_prefix+ '{:>9.0f}'.format(tx-rx) + + tot_drop_str +drop_rate_prefix + + '{:>5.2f}'.format(100*old_div(float(tx-rx),tx)) + bcolors.ENDC + + ' |' + elapsed_time_str) def run_iteration(self, requested_duration, flow_number, size, speed): BUCKET_SIZE_EXP = self.gen_machine.bucket_size_exp @@ -119,8 +188,34 @@ class RapidTest(object): t1_rx, t1_non_dp_rx, t1_tx, t1_non_dp_tx, t1_drop, t1_tx_fail, t1_tsc, abs_tsc_hz = self.gen_machine.core_stats() t1_dp_rx = t1_rx - t1_non_dp_rx t1_dp_tx = t1_tx - t1_non_dp_tx + self.gen_machine.set_generator_speed(0) self.gen_machine.start_gen_cores() + if self.background_machines: + self.set_background_speed(self.background_machines, 0) + self.start_background_traffic(self.background_machines) + if 'ramp_step' in self.test.keys(): + ramp_speed = self.test['ramp_step'] + else: + ramp_speed = speed + while ramp_speed < speed: + self.gen_machine.set_generator_speed(ramp_speed) + if self.background_machines: + self.set_background_speed(self.background_machines, ramp_speed) + time.sleep(2) + ramp_speed = ramp_speed + self.test['ramp_step'] + self.gen_machine.set_generator_speed(speed) + if self.background_machines: + self.set_background_speed(self.background_machines, speed) time.sleep(2) ## Needs to be 2 seconds since this 1 sec is the time that PROX uses to refresh the stats. Note that this can be changed in PROX!! Don't do it. + start_bg_gen_stats = [] + for bg_gen_machine in self.background_machines: + bg_rx, bg_non_dp_rx, bg_tx, bg_non_dp_tx, _, _, bg_tsc, _ = bg_gen_machine.core_stats() + bg_gen_stat = { + "bg_dp_rx" : bg_rx - bg_non_dp_rx, + "bg_dp_tx" : bg_tx - bg_non_dp_tx, + "bg_tsc" : bg_tsc + } + start_bg_gen_stats.append(dict(bg_gen_stat)) if self.sut_machine!= None: t2_sut_rx, t2_sut_non_dp_rx, t2_sut_tx, t2_sut_non_dp_tx, t2_sut_drop, t2_sut_tx_fail, t2_sut_tsc, sut_tsc_hz = self.sut_machine.core_stats() t2_rx, t2_non_dp_rx, t2_tx, t2_non_dp_tx, t2_drop, t2_tx_fail, t2_tsc, tsc_hz = self.gen_machine.core_stats() @@ -147,8 +242,8 @@ class RapidTest(object): RapidLog.info(self.report_result(flow_number,size,speed,None,None,None,None,lat_avg,sample_percentile,percentile_max,lat_max, dp_tx, dp_rx , None, None)) tot_rx = tot_non_dp_rx = tot_tx = tot_non_dp_tx = tot_drop = 0 lat_avg = used_avg = 0 - buckets_total = [0] * 128 - tot_lat_samples = 0 + buckets_total = buckets + tot_lat_samples = sum(buckets) tot_lat_measurement_duration = float(0) tot_core_measurement_duration = float(0) tot_sut_core_measurement_duration = float(0) @@ -176,8 +271,9 @@ class RapidTest(object): if sample_count > lat_samples * LAT_PERCENTILE: break percentile_max = (sample_percentile == len(buckets)) - sample_percentile = sample_percentile * float(2 ** BUCKET_SIZE_EXP) / (old_div(float(lat_hz),float(10**6))) - buckets_total = [buckets_total[i] + buckets[i] for i in range(len(buckets_total))] + bucket_size = float(2 ** BUCKET_SIZE_EXP) / (old_div(float(lat_hz),float(10**6))) + sample_percentile = sample_percentile * bucket_size + buckets_total = [buckets_total[i] + buckets[i] for i in range(len(buckets_total))] t2_lat_tsc = t3_lat_tsc lat_avail = True t3_rx, t3_non_dp_rx, t3_tx, t3_non_dp_tx, t3_drop, t3_tx_fail, t3_tsc, tsc_hz = self.gen_machine.core_stats() @@ -229,6 +325,45 @@ class RapidTest(object): lat_avg_sample, sample_percentile, percentile_max, lat_max_sample, delta_dp_tx, delta_dp_rx, tot_dp_drop, single_core_measurement_duration)) + variables = { + 'Flows': flow_number, + 'Size': size, + 'RequestedSpeed': self.get_pps(speed,size), + 'CoreGenerated': pps_req_tx, + 'SentByNIC': pps_tx, + 'FwdBySUT': pps_sut_tx, + 'RevByCore': pps_rx, + 'AvgLatency': lat_avg_sample, + 'PCTLatency': sample_percentile, + 'MaxLatency': lat_max_sample, + 'PacketsSent': delta_dp_tx, + 'PacketsReceived': delta_dp_rx, + 'PacketsLost': tot_dp_drop, + 'bucket_size': bucket_size, + 'buckets': buckets} + + self.post_data('rapid_flowsizetest', variables) + end_bg_gen_stats = [] + for bg_gen_machine in self.background_machines: + bg_rx, bg_non_dp_rx, bg_tx, bg_non_dp_tx, _, _, bg_tsc, bg_hz = bg_gen_machine.core_stats() + bg_gen_stat = {"bg_dp_rx" : bg_rx - bg_non_dp_rx, + "bg_dp_tx" : bg_tx - bg_non_dp_tx, + "bg_tsc" : bg_tsc, + "bg_hz" : bg_hz + } + end_bg_gen_stats.append(dict(bg_gen_stat)) + i = 0 + bg_rates =[] + while i < len(end_bg_gen_stats): + bg_rates.append(0.000001*(end_bg_gen_stats[i]['bg_dp_rx'] - + start_bg_gen_stats[i]['bg_dp_rx']) / ((end_bg_gen_stats[i]['bg_tsc'] - + start_bg_gen_stats[i]['bg_tsc']) * 1.0 / end_bg_gen_stats[i]['bg_hz'])) + i += 1 + if len(bg_rates): + avg_bg_rate = sum(bg_rates) / len(bg_rates) + RapidLog.debug('Average Background traffic rate: {:>7.3f} Mpps'.format(avg_bg_rate)) + else: + avg_bg_rate = None #Stop generating self.gen_machine.stop_gen_cores() r += 1 @@ -248,7 +383,7 @@ class RapidTest(object): if sample_count > lat_samples * LAT_PERCENTILE: break percentile_max = (percentile == len(buckets)) - percentile = percentile * float(2 ** BUCKET_SIZE_EXP) / (old_div(float(lat_hz),float(10**6))) + percentile = percentile * bucket_size lat_max = lat_max_sample lat_avg = lat_avg_sample delta_rx = t4_rx - t2_rx @@ -269,12 +404,13 @@ class RapidTest(object): break ## Not really needed since the while loop will stop when evaluating the value of r else: sample_count = 0 + buckets = buckets_total for percentile, bucket in enumerate(buckets_total,start=1): sample_count += bucket if sample_count > tot_lat_samples * LAT_PERCENTILE: break percentile_max = (percentile == len(buckets_total)) - percentile = percentile * float(2 ** BUCKET_SIZE_EXP) / (old_div(float(lat_hz),float(10**6))) + percentile = percentile * bucket_size pps_req_tx = (tot_tx + tot_drop - tot_rx)/tot_core_measurement_duration/1000000.0 # tot_drop is all packets dropped by all tasks. This includes packets dropped at the generator task + packets dropped by the nop task. In steady state, this equals to the number of packets received by this VM pps_tx = tot_tx/tot_core_measurement_duration/1000000.0 # tot_tx is all generated packets actually accepted by the interface pps_rx = tot_rx/tot_core_measurement_duration/1000000.0 # tot_rx is all packets received by the nop task = all packets received in the gen VM @@ -288,4 +424,4 @@ class RapidTest(object): drop_rate = 100.0*tot_dp_drop/dp_tx if ((drop_rate < self.test['drop_rate_threshold']) or (tot_dp_drop == self.test['drop_rate_threshold'] ==0) or (tot_dp_drop > self.test['maxz'])): break - return(pps_req_tx,pps_tx,pps_sut_tx,pps_rx,lat_avg,percentile,percentile_max,lat_max,dp_tx,dp_rx,tot_dp_drop,(t4_tx_fail - t1_tx_fail),drop_rate,lat_min,used_avg,r,tot_core_measurement_duration) + return(pps_req_tx,pps_tx,pps_sut_tx,pps_rx,lat_avg,percentile,percentile_max,lat_max,dp_tx,dp_rx,tot_dp_drop,(t4_tx_fail - t1_tx_fail),drop_rate,lat_min,used_avg,r,tot_core_measurement_duration,avg_bg_rate,bucket_size,buckets)