From ba7b5dff853a3b11b0cc2e7b29cfc1cd99e606f7 Mon Sep 17 00:00:00 2001 From: imarom Date: Wed, 10 Aug 2016 17:45:36 +0300 Subject: core mask - first phase --- .../stl/trex_stl_lib/trex_stl_client.py | 45 ++++++++++++++++++---- .../stl/trex_stl_lib/trex_stl_port.py | 17 ++++---- .../stl/trex_stl_lib/trex_stl_stats.py | 39 +++++++++++++++---- .../stl/trex_stl_lib/utils/parsing_opts.py | 6 +++ 4 files changed, 84 insertions(+), 23 deletions(-) (limited to 'scripts') diff --git a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_client.py b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_client.py index 611e48f4..f0201d6c 100755 --- a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_client.py +++ b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_client.py @@ -453,6 +453,10 @@ class CCommLink(object): class STLClient(object): """TRex Stateless client object - gives operations per TRex/user""" + # different modes for attaching traffic to ports + CORE_MASK_SPLIT = 1 + CORE_MASK_PIN = 2 + def __init__(self, username = common.get_current_user(), server = "localhost", @@ -675,14 +679,31 @@ class STLClient(object): return self.ports[port_id].get_stream_id_list() - def __start (self, multiplier, duration, port_id_list = None, force = False): + def __start (self, + multiplier, + duration, + port_id_list, + force, + core_mask): port_id_list = self.__ports(port_id_list) rc = RC() + ports_mask = {} + for port_id in port_id_list: + # a pin mode was requested and we have + # the second port from the group in the start list + if (core_mask == self.CORE_MASK_PIN) and ( (port_id ^ 0x1) in port_id_list ): + ports_mask[port_id] = 0x55555555 if( port_id % 2) == 0 else 0xAAAAAAAA + else: + ports_mask[port_id] = None + for port_id in port_id_list: - rc.add(self.ports[port_id].start(multiplier, duration, force)) + rc.add(self.ports[port_id].start(multiplier, + duration, + force, + ports_mask[port_id])) return rc @@ -800,13 +821,14 @@ class STLClient(object): self.server_version = rc.data() self.global_stats.server_version = rc.data() - + # cache system info rc = self._transmit("get_system_info") if not rc: return rc self.system_info = rc.data() + self.global_stats.system_info = rc.data() # cache supported commands rc = self._transmit("get_supported_cmds") @@ -1901,7 +1923,8 @@ class STLClient(object): mult = "1", force = False, duration = -1, - total = False): + total = False, + core_mask = CORE_MASK_SPLIT): """ Start traffic on port(s) @@ -1927,6 +1950,12 @@ class STLClient(object): True: Divide bandwidth among the ports False: Duplicate + core_mask: CORE_MASK_SPLIT, CORE_MASK_PIN + Determine the allocation of cores per port + In CORE_MASK_SPLIT all the traffic will be divided equally between all the cores + associated with each port + In CORE_MASK_PIN, for each dual ports (a group that shares the same cores) + the cores will be divided half pinned for each port :raises: + :exc:`STLError` @@ -1964,7 +1993,7 @@ class STLClient(object): # start traffic self.logger.pre_cmd("Starting traffic on port(s) {0}:".format(ports)) - rc = self.__start(mult_obj, duration, ports, force) + rc = self.__start(mult_obj, duration, ports, force, core_mask) self.logger.post_cmd(rc) if not rc: @@ -2647,7 +2676,8 @@ class STLClient(object): parsing_opts.DURATION, parsing_opts.TUNABLES, parsing_opts.MULTIPLIER_STRICT, - parsing_opts.DRY_RUN) + parsing_opts.DRY_RUN, + parsing_opts.PIN_CORES) opts = parser.parse_args(line.split(), default_ports = self.get_acquired_ports(), verify_acquired = True) if not opts: @@ -2712,7 +2742,8 @@ class STLClient(object): opts.mult, opts.force, opts.duration, - opts.total) + opts.total, + core_mask = self.CORE_MASK_PIN if opts.pin_cores else self.CORE_MASK_SPLIT) return RC_OK() diff --git a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_port.py b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_port.py index d239fc57..556a14d8 100644 --- a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_port.py +++ b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_port.py @@ -100,7 +100,7 @@ class Port(object): # decorator to check server is readable (port not down and etc.) def writeable(func): - def func_wrapper(*args): + def func_wrapper(*args, **kwargs): port = args[0] if not port.is_up(): @@ -112,7 +112,7 @@ class Port(object): if not port.is_writeable(): return port.err("{0} - port is not in a writeable state".format(func.__name__)) - return func(*args) + return func(*args, **kwargs) return func_wrapper @@ -396,16 +396,17 @@ class Port(object): @writeable - def start (self, mul, duration, force): + def start (self, mul, duration, force, mask): if self.state == self.STATE_IDLE: return self.err("unable to start traffic - no streams attached to port") - params = {"handler": self.handler, - "port_id": self.port_id, - "mul": mul, - "duration": duration, - "force": force} + params = {"handler": self.handler, + "port_id": self.port_id, + "mul": mul, + "duration": duration, + "force": force, + "core_mask": mask if mask is not None else ((1 << 64) - 1)} # must set this before to avoid race with the async response last_state = self.state diff --git a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_stats.py b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_stats.py index 1bf0a9a4..b321c00b 100644 --- a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_stats.py +++ b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_stats.py @@ -210,8 +210,11 @@ class CTRexInfoGenerator(object): ("version", "{ver}, UUID: {uuid}".format(ver=global_stats.server_version.get("version", "N/A"), uuid="N/A")), - ("cpu_util.", "{0}% {1}".format( format_threshold(round_float(global_stats.get("m_cpu_util")), [85, 100], [0, 85]), - global_stats.get_trend_gui("m_cpu_util", use_raw = True))), + ("cpu_util.", "{0}% @ {2} cores ({3} per port) {1}".format( format_threshold(round_float(global_stats.get("m_cpu_util")), [85, 100], [0, 85]), + global_stats.get_trend_gui("m_cpu_util", use_raw = True), + global_stats.system_info.get('dp_core_count'), + global_stats.system_info.get('dp_core_count_per_port'), + )), ("rx_cpu_util.", "{0}% {1}".format( format_threshold(round_float(global_stats.get("m_rx_cpu_util")), [85, 100], [0, 85]), global_stats.get_trend_gui("m_rx_cpu_util", use_raw = True))), @@ -234,7 +237,7 @@ class CTRexInfoGenerator(object): ("total_pps", "{0} {1}".format( global_stats.get("m_tx_pps", format=True, suffix="pkt/sec"), global_stats.get_trend_gui("m_tx_pps"))), - (" ", ""), + #(" ", ""), ("drop_rate", "{0}".format( format_num(global_stats.get("m_rx_drop_bps"), suffix = 'b/sec', @@ -422,21 +425,39 @@ class CTRexInfoGenerator(object): def _generate_cpu_util_stats(self): util_stats = self._util_stats_ref.get_stats(use_1sec_cache = True) + stats_table = text_tables.TRexTextTable() if util_stats: if 'cpu' not in util_stats: raise Exception("Excepting 'cpu' section in stats %s" % util_stats) cpu_stats = util_stats['cpu'] - hist_len = len(cpu_stats[0]) + hist_len = len(cpu_stats[0]["history"]) avg_len = min(5, hist_len) show_len = min(15, hist_len) stats_table.header(['Thread', 'Avg', 'Latest'] + list(range(-1, 0 - show_len, -1))) stats_table.set_cols_align(['l'] + ['r'] * (show_len + 1)) - stats_table.set_cols_width([8, 3, 6] + [3] * (show_len - 1)) + stats_table.set_cols_width([10, 3, 6] + [3] * (show_len - 1)) stats_table.set_cols_dtype(['t'] * (show_len + 2)) + for i in range(min(14, len(cpu_stats))): - avg = int(round(sum(cpu_stats[i][:avg_len]) / avg_len)) - stats_table.add_row([i, avg] + cpu_stats[i][:show_len]) + history = cpu_stats[i]["history"] + ports = cpu_stats[i]["ports"] + if not len(ports) == 2: + sys.__stdout__.write(str(util_stats["cpu"])) + exit(-1) + + avg = int(round(sum(history[:avg_len]) / avg_len)) + + # decode active ports for core + if ports == [-1, -1]: + interfaces = "(IDLE)" + elif not -1 in ports: + interfaces = "({:},{:})".format(ports[0], ports[1]) + else: + interfaces = "({:})".format(ports[0] if ports[0] != -1 else ports[1]) + + thread = "{:2} {:^7}".format(i, interfaces) + stats_table.add_row([thread, avg] + history[:show_len]) else: stats_table.add_row(['No Data.']) return {'cpu_util(%)': ExportableStats(None, stats_table)} @@ -542,6 +563,7 @@ class CTRexInfoGenerator(object): per_field_stats = OrderedDict([("owner", []), ("state", []), ("speed", []), + ("CPU util.", []), ("--", []), ("Tx bps L2", []), ("Tx bps L1", []), @@ -1037,7 +1059,8 @@ class CPortStats(CTRexStats): return {"owner": owner, "state": "{0}".format(state), "speed": self._port_obj.get_formatted_speed() if self._port_obj else '', - + "CPU util.": "{0} {1}%".format(self.get_trend_gui("m_cpu_util", use_raw = True), + format_threshold(round_float(self.get("m_cpu_util")), [85, 100], [0, 85])) if self._port_obj else '' , "--": " ", "---": " ", "----": " ", diff --git a/scripts/automation/trex_control_plane/stl/trex_stl_lib/utils/parsing_opts.py b/scripts/automation/trex_control_plane/stl/trex_stl_lib/utils/parsing_opts.py index cfe8a93b..51265252 100755 --- a/scripts/automation/trex_control_plane/stl/trex_stl_lib/utils/parsing_opts.py +++ b/scripts/automation/trex_control_plane/stl/trex_stl_lib/utils/parsing_opts.py @@ -37,6 +37,7 @@ PROMISCUOUS_SWITCH = 21 TUNABLES = 22 REMOTE_FILE = 23 LOCKED = 24 +PIN_CORES = 25 GLOBAL_STATS = 50 PORT_STATS = 51 @@ -323,6 +324,11 @@ OPTIONS_DB = {MULTIPLIER: ArgumentPack(['-m', '--multiplier'], 'default': False, 'help': "Dry run - no traffic will be injected"}), + PIN_CORES: ArgumentPack(['--pin'], + {'action': 'store_true', + 'dest': 'pin_cores', + 'default': False, + 'help': "Pin cores to interfaces - cores will be divided between interfaces (performance boot for symetric profiles)"}), XTERM: ArgumentPack(['-x', '--xterm'], {'action': 'store_true', -- cgit 1.2.3-korg