From 72ca9e76d4c6a5fe48e8cd7e1e49b9e54e40fca9 Mon Sep 17 00:00:00 2001 From: imarom Date: Wed, 6 Jan 2016 11:14:08 -0500 Subject: more options to the stateless simulation --- .../client/trex_stateless_sim.py | 142 ++++++++++++--------- 1 file changed, 84 insertions(+), 58 deletions(-) (limited to 'scripts/automation/trex_control_plane') diff --git a/scripts/automation/trex_control_plane/client/trex_stateless_sim.py b/scripts/automation/trex_control_plane/client/trex_stateless_sim.py index 5d06c6e5..4382e9fb 100644 --- a/scripts/automation/trex_control_plane/client/trex_stateless_sim.py +++ b/scripts/automation/trex_control_plane/client/trex_stateless_sim.py @@ -26,6 +26,8 @@ except ImportError: from client_utils.jsonrpc_client import JsonRpcClient, BatchMessage from client_utils.packet_builder import CTRexPktBuilder +from client_utils import parsing_opts + import json from common.trex_streams import * @@ -68,29 +70,21 @@ def merge_cap_files (pcap_file_list, out_filename, delete_src = False): class SimRun(object): - def __init__ (self, yaml_file, dp_core_count, core_index, packet_limit, output_filename, is_valgrind, is_gdb, limit): + def __init__ (self, options): - self.yaml_file = yaml_file - self.output_filename = output_filename - self.dp_core_count = dp_core_count - self.core_index = core_index - self.packet_limit = packet_limit - self.is_valgrind = is_valgrind - self.is_gdb = is_gdb - self.limit = limit + self.options = options # dummies self.handler = 0 self.port_id = 0 - self.mul = {"op": "abs", - "type": "raw", - "value": 1} + + self.mul = options.mult self.duration = -1 def load_yaml_file (self): streams_db = CStreamsDB() - stream_list = streams_db.load_yaml_file(self.yaml_file) + stream_list = streams_db.load_yaml_file(self.options.input_file) streams_json = [] for stream in stream_list.compiled: @@ -130,44 +124,65 @@ class SimRun(object): f.close() try: - cmd = ['bp-sim-64-debug', - '--pcap', - '--sl', - '--cores', - str(self.dp_core_count), - '--limit', - str(self.limit), - '-f', - f.name, - '-o', - self.output_filename] - - if self.core_index != None: - cmd += ['--core_index', str(self.core_index)] - - if self.is_valgrind: - cmd = ['valgrind', '--leak-check=full'] + cmd - elif self.is_gdb: - cmd = ['gdb', '--args'] + cmd - - print "executing command: '{0}'".format(" ".join(cmd)) - subprocess.call(cmd) - - # core index - if (self.dp_core_count > 1) and (self.core_index == None): - self.merge_results() - + if self.options.json: + with open(f.name) as file: + data = "\n".join(file.readlines()) + print json.dumps(json.loads(data), indent = 4, separators=(',', ': '), sort_keys = True) + else: + self.execute_bp_sim(f.name) finally: os.unlink(f.name) + def execute_bp_sim (self, json_filename): + exe = 'bp-sim-64' if self.options.release else 'bp-sim-64-debug' + if not os.path.exists(exe): + print "cannot find executable '{0}'".format(exe) + exit(-1) + + cmd = [exe, + '--pcap', + '--sl', + '--cores', + str(self.options.cores), + '--limit', + str(self.options.limit), + '-f', + json_filename, + '-o', + self.options.output_file] + + if self.options.dry: + cmd += ['--dry'] + + if self.options.core_index != None: + cmd += ['--core_index', str(self.options.core_index)] + + if self.options.valgrind: + cmd = ['valgrind', '--leak-check=full'] + cmd + + elif self.options.gdb: + cmd = ['gdb', '--args'] + cmd + + print "executing command: '{0}'".format(" ".join(cmd)) + subprocess.call(cmd) + + self.merge_results() + + def merge_results (self): - if (self.core_index != None) or (self.dp_core_count == 1): - # nothing to do + if self.options.dry: + return + + if self.options.cores == 1: + return + + if self.options.core_index != None: return - inputs = ["{0}-{1}".format(self.output_filename, index) for index in xrange(0, self.dp_core_count)] - merge_cap_files(inputs, self.output_filename, delete_src = True) + + inputs = ["{0}-{1}".format(self.options.output_file, index) for index in xrange(0, self.options.cores)] + merge_cap_files(inputs, self.options.output_file, delete_src = True) @@ -180,8 +195,8 @@ def is_valid_file(filename): def unsigned_int (x): x = int(x) - if x <= 0: - raise argparse.ArgumentTypeError("argument must be >= 1") + if x < 0: + raise argparse.ArgumentTypeError("argument must be >= 0") return x @@ -207,16 +222,26 @@ def setParserOptions(): default = None, type = int) - parser.add_argument("-j", "--join", - help = "run and join output from 0..core_count [default is False]", - default = False, - type = bool) + parser.add_argument("-r", "--release", + help = "runs on release image instead of debug [default is False]", + action = "store_true", + default = False) + + parser.add_argument("-s", "--dry", + help = "dry run only (nothing will be written to the file) [default is False]", + action = "store_true", + default = False) parser.add_argument("-l", "--limit", help = "limit test total packet count [default is 5000]", default = 5000, type = unsigned_int) + parser.add_argument('-m', '--multiplier', + help = parsing_opts.match_multiplier_help, + dest = 'mult', + default = {'type':'raw', 'value':1, 'op': 'abs'}, + type = parsing_opts.match_multiplier_strict) group = parser.add_mutually_exclusive_group() @@ -230,6 +255,11 @@ def setParserOptions(): action = "store_true", default = False) + group.add_argument("--json", + help = "generate JSON output only to stdout [default is False]", + action = "store_true", + default = False) + return parser @@ -239,6 +269,9 @@ def validate_args (parser, options): if not options.core_index in xrange(0, options.cores): parser.error("DP core index valid range is 0 to {0}".format(options.cores - 1)) + # zero is ok - no limit, but other values must be at least as the number of cores + if (options.limit != 0) and options.limit < options.cores: + parser.error("limit cannot be lower than number of DP cores") def main (): @@ -247,14 +280,7 @@ def main (): validate_args(parser, options) - r = SimRun(options.input_file, - options.cores, - options.core_index, - options.limit, - options.output_file, - options.valgrind, - options.gdb, - options.limit) + r = SimRun(options) r.run() -- cgit 1.2.3-korg From 2dff2ccf6fd6e4dae2556c1cf392473989a826b9 Mon Sep 17 00:00:00 2001 From: imarom Date: Thu, 7 Jan 2016 04:38:38 -0500 Subject: yet another stateless simulation phase --- .../client/trex_stateless_sim.py | 8 +- src/bp_sim.cpp | 2 + src/sim/trex_sim.h | 6 +- src/sim/trex_sim_stateless.cpp | 89 +++++++++++++++++----- src/stateless/cp/trex_stateless_port.cpp | 10 +++ src/stateless/cp/trex_stateless_port.h | 11 +++ 6 files changed, 107 insertions(+), 19 deletions(-) (limited to 'scripts/automation/trex_control_plane') diff --git a/scripts/automation/trex_control_plane/client/trex_stateless_sim.py b/scripts/automation/trex_control_plane/client/trex_stateless_sim.py index 4382e9fb..b621be20 100644 --- a/scripts/automation/trex_control_plane/client/trex_stateless_sim.py +++ b/scripts/automation/trex_control_plane/client/trex_stateless_sim.py @@ -165,7 +165,11 @@ class SimRun(object): cmd = ['gdb', '--args'] + cmd print "executing command: '{0}'".format(" ".join(cmd)) - subprocess.call(cmd) + try: + subprocess.call(cmd) + except KeyboardInterrupt as e: + print "\n\n*** Caught Ctrl + C... Exiting...\n\n" + exit(-1) self.merge_results() @@ -181,11 +185,13 @@ class SimRun(object): return + print "Mering cores output to a single pcap file...\n" inputs = ["{0}-{1}".format(self.options.output_file, index) for index in xrange(0, self.options.cores)] merge_cap_files(inputs, self.options.output_file, delete_src = True) + def is_valid_file(filename): if not os.path.isfile(filename): raise argparse.ArgumentTypeError("The file '%s' does not exist" % filename) diff --git a/src/bp_sim.cpp b/src/bp_sim.cpp index 5ee06190..040c0858 100755 --- a/src/bp_sim.cpp +++ b/src/bp_sim.cpp @@ -3180,10 +3180,12 @@ int CNodeGenerator::close_file(CFlowGenListPerThread * thread){ int CNodeGenerator::update_stl_stats(CGenNodeStateless *node_sl){ m_cnt++; + #ifdef _DEBUG if ( m_preview_mode.getVMode() >2 ){ fprintf(stdout," %4lu ,", (ulong)m_cnt); node_sl->Dump(stdout); } + #endif return (0); } diff --git a/src/sim/trex_sim.h b/src/sim/trex_sim.h index a0f44cdb..f11f01c4 100644 --- a/src/sim/trex_sim.h +++ b/src/sim/trex_sim.h @@ -129,7 +129,11 @@ private: void execute_json(const std::string &json_filename); void run_dp(const std::string &out_filename); - uint64_t run_dp_core(int core_index, const std::string &out_filename); + + void run_dp_core(int core_index, + const std::string &out_filename, + uint64_t &simulated_pkts, + uint64_t &written_pkts); void flush_dp_to_cp_messages_core(int core_index); diff --git a/src/sim/trex_sim_stateless.cpp b/src/sim/trex_sim_stateless.cpp index a5d2213e..215315e0 100644 --- a/src/sim/trex_sim_stateless.cpp +++ b/src/sim/trex_sim_stateless.cpp @@ -26,9 +26,34 @@ limitations under the License. #include #include #include +#include using namespace std; +/****** utils ******/ +static string format_num(double num, const string &suffix = "") { + const char x[] = {' ','K','M','G','T','P'}; + + double my_num = num; + + for (int i = 0; i < sizeof(x); i++) { + if (std::abs(my_num) < 1000.0) { + stringstream ss; + + char buf[100]; + snprintf(buf, sizeof(buf), "%.2f", my_num); + + ss << buf << " " << x[i] << suffix; + return ss.str(); + + } else { + my_num /= 1000.0; + } + } + + return "NaN"; +} + TrexStateless * get_stateless_obj() { return SimStateless::get_instance().get_stateless_obj(); } @@ -57,8 +82,12 @@ public: virtual void get_global_stats(TrexPlatformGlobalStats &stats) const { } + virtual void get_interface_info(uint8_t interface_id, std::string &driver_name, driver_speed_e &speed) const { + driver_name = "TEST"; + speed = TrexPlatformApi::SPEED_10G; } + virtual void get_interface_stats(uint8_t interface_id, TrexPlatformInterfaceStats &stats) const { } @@ -284,7 +313,12 @@ static inline bool is_debug() { void SimStateless::show_intro(const std::string &out_filename) { - std::cout << "\nGeneral info:\n\n"; + uint64_t bps = 0; + uint64_t pps = 0; + + std::cout << "\nGeneral info:\n"; + std::cout << "------------\n\n"; + std::cout << "image type: " << (is_debug() ? "debug" : "release") << "\n"; std::cout << "I/O output: " << (m_is_dry_run ? "*DRY*" : out_filename) << "\n"; @@ -300,22 +334,32 @@ SimStateless::show_intro(const std::string &out_filename) { std::cout << "core recording: merge all\n"; } - std::cout << "\nConfiguration info:\n\n"; + std::cout << "\nConfiguration info:\n"; + std::cout << "-------------------\n\n"; std::cout << "ports: " << m_port_count << "\n"; std::cout << "cores: " << m_dp_core_count << "\n"; - std::cout << "\nPort Config:\n\n"; - //TrexStatelessPort *port = get_stateless_obj()->get_port_by_id(0); - //std::cout << "stream count:" << port->get_stream_by_id() + std::cout << "\nPort Config:\n"; + std::cout << "------------\n\n"; - std::cout << "\nStarting simulation...\n"; + TrexStatelessPort *port = get_stateless_obj()->get_port_by_id(0); + + std::cout << "stream count: " << port->get_stream_count() << "\n"; + + port->get_port_effective_rate(bps, pps); + + std::cout << "max BPS: " << format_num(bps, "bps") << "\n"; + std::cout << "max PPS: " << format_num(pps, "pps") << "\n"; + + std::cout << "\n\nStarting simulation...\n"; } void SimStateless::run_dp(const std::string &out_filename) { - uint64_t pkt_cnt = 0; + uint64_t simulated_pkts_cnt = 0; + uint64_t written_pkts_cnt = 0; show_intro(out_filename); @@ -323,17 +367,26 @@ SimStateless::run_dp(const std::string &out_filename) { for (int i = 0; i < m_dp_core_count; i++) { std::stringstream ss; ss << out_filename << "-" << i; - pkt_cnt += run_dp_core(i, ss.str()); + run_dp_core(i, ss.str(), simulated_pkts_cnt, written_pkts_cnt); } } else { for (int i = 0; i < m_dp_core_count; i++) { - pkt_cnt += run_dp_core(i, out_filename); + run_dp_core(i, out_filename, simulated_pkts_cnt, written_pkts_cnt); } } - - std::cout << "\nwritten " << pkt_cnt << " packets " << "to '" << out_filename << "'\n\n"; + std::cout << "\n\nSimulation summary:\n"; + std::cout << "-------------------\n\n"; + std::cout << "simulated " << simulated_pkts_cnt << " packets\n"; + + if (m_is_dry_run) { + std::cout << "*DRY RUN* - no packets were written\n"; + } else { + std::cout << "written " << written_pkts_cnt << " packets " << "to '" << out_filename << "'\n\n"; + } + + std::cout << "\n"; } @@ -351,8 +404,11 @@ SimStateless::get_limit_per_core(int core_index) { } } -uint64_t -SimStateless::run_dp_core(int core_index, const std::string &out_filename) { +void +SimStateless::run_dp_core(int core_index, + const std::string &out_filename, + uint64_t &simulated_pkts, + uint64_t &written_pkts) { CFlowGenListPerThread *lpt = m_fl.m_threads_info[core_index]; @@ -361,12 +417,11 @@ SimStateless::run_dp_core(int core_index, const std::string &out_filename) { flush_dp_to_cp_messages_core(core_index); + simulated_pkts += lpt->m_node_gen.m_cnt; + if (should_capture_core(core_index)) { - return lpt->m_node_gen.m_cnt; - } else { - return (0); + written_pkts += lpt->m_node_gen.m_cnt; } - } diff --git a/src/stateless/cp/trex_stateless_port.cpp b/src/stateless/cp/trex_stateless_port.cpp index aa34e87b..0055b5ef 100644 --- a/src/stateless/cp/trex_stateless_port.cpp +++ b/src/stateless/cp/trex_stateless_port.cpp @@ -589,6 +589,16 @@ TrexStatelessPort::validate(void) { } + +void +TrexStatelessPort::get_port_effective_rate(uint64_t &bps, uint64_t &pps) { + if (!m_graph_obj) { + return; + } + bps = m_graph_obj->get_max_bps() * m_factor; + pps = m_graph_obj->get_max_pps() * m_factor; +} + /************* Trex Port Owner **************/ TrexPortOwner::TrexPortOwner() { diff --git a/src/stateless/cp/trex_stateless_port.h b/src/stateless/cp/trex_stateless_port.h index 784bf4c0..d0e75744 100644 --- a/src/stateless/cp/trex_stateless_port.h +++ b/src/stateless/cp/trex_stateless_port.h @@ -302,6 +302,17 @@ public: return m_owner; } + + /** + * get the port effective rate (on a started / paused port) + * + * @author imarom (07-Jan-16) + * + * @param bps + * @param pps + */ + void get_port_effective_rate(uint64_t &bps, uint64_t &pps); + private: -- cgit 1.2.3-korg From a7223338770034ba6d495cc6368665a332f5b994 Mon Sep 17 00:00:00 2001 From: imarom Date: Thu, 7 Jan 2016 07:35:17 -0500 Subject: first bug caught by the simulator - memory leak --- .../client/trex_stateless_sim.py | 24 +++++++++++++++------- src/stateless/cp/trex_stateless_port.cpp | 5 +++++ src/stateless/cp/trex_stateless_port.h | 2 ++ 3 files changed, 24 insertions(+), 7 deletions(-) (limited to 'scripts/automation/trex_control_plane') diff --git a/scripts/automation/trex_control_plane/client/trex_stateless_sim.py b/scripts/automation/trex_control_plane/client/trex_stateless_sim.py index b621be20..d38411a3 100644 --- a/scripts/automation/trex_control_plane/client/trex_stateless_sim.py +++ b/scripts/automation/trex_control_plane/client/trex_stateless_sim.py @@ -39,6 +39,8 @@ import os from dpkt import pcap from operator import itemgetter +class BpSimException(Exception): + pass def merge_cap_files (pcap_file_list, out_filename, delete_src = False): @@ -134,6 +136,7 @@ class SimRun(object): os.unlink(f.name) + def execute_bp_sim (self, json_filename): exe = 'bp-sim-64' if self.options.release else 'bp-sim-64-debug' if not os.path.exists(exe): @@ -159,17 +162,15 @@ class SimRun(object): cmd += ['--core_index', str(self.options.core_index)] if self.options.valgrind: - cmd = ['valgrind', '--leak-check=full'] + cmd + cmd = ['valgrind', '--leak-check=full', '--error-exitcode=1'] + cmd elif self.options.gdb: cmd = ['gdb', '--args'] + cmd print "executing command: '{0}'".format(" ".join(cmd)) - try: - subprocess.call(cmd) - except KeyboardInterrupt as e: - print "\n\n*** Caught Ctrl + C... Exiting...\n\n" - exit(-1) + rc = subprocess.call(cmd) + if rc != 0: + raise BpSimException() self.merge_results() @@ -288,8 +289,17 @@ def main (): r = SimRun(options) - r.run() + try: + r.run() + except KeyboardInterrupt as e: + print "\n\n*** Caught Ctrl + C... Exiting...\n\n" + exit(1) + + except BpSimException as e: + print "\n\n*** BP sim exit code was non zero\n\n" + exit(1) + exit(0) if __name__ == '__main__': main() diff --git a/src/stateless/cp/trex_stateless_port.cpp b/src/stateless/cp/trex_stateless_port.cpp index 0055b5ef..976d2a09 100644 --- a/src/stateless/cp/trex_stateless_port.cpp +++ b/src/stateless/cp/trex_stateless_port.cpp @@ -76,6 +76,11 @@ TrexStatelessPort::TrexStatelessPort(uint8_t port_id, const TrexPlatformApi *api m_graph_obj = NULL; } +TrexStatelessPort::~TrexStatelessPort() { + if (m_graph_obj) { + delete m_graph_obj; + } +} /** * acquire the port diff --git a/src/stateless/cp/trex_stateless_port.h b/src/stateless/cp/trex_stateless_port.h index d0e75744..c3785b0c 100644 --- a/src/stateless/cp/trex_stateless_port.h +++ b/src/stateless/cp/trex_stateless_port.h @@ -134,6 +134,8 @@ public: TrexStatelessPort(uint8_t port_id, const TrexPlatformApi *api); + ~TrexStatelessPort(); + /** * acquire port * throws TrexException in case of an error -- cgit 1.2.3-korg