diff --git a/ibcheck b/ibcheck index fc821f9..882db26 100755 --- a/ibcheck +++ b/ibcheck @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 """Swiss army knife for Infiniband (IB) troubleshooting. ############################################################################ @@ -227,13 +227,13 @@ __author__ = "Yong Qin " __date__ = "September 14, 2012" __version__ = "0.1" -import ConfigParser +import configparser import curses import datetime import getopt import os import pydoc -import Queue +import queue import re import signal import subprocess @@ -247,7 +247,7 @@ try: import pydot WITH_PYDOT = True except ImportError: - print >> sys.stderr, 'Warning: Cannot import \'pydot\'' + print('Warning: Cannot import "pydot"', file=sys.stderr) WITH_PYDOT = False # root @@ -265,41 +265,41 @@ ibnode_nodetype = ['Switch', 'Ca'] ibnode_type = ['Switch', 'Spine', 'Leaf', 'Line', 'Ca'] # different categories that ibnodes will be organized into -collect_list = ['nodedesc', 'desc', 'nodeguid', 'nodelid', 'type', 'portguid', \ +collect_list = ['nodedesc', 'desc', 'nodeguid', 'nodelid', 'type', 'portguid', 'portlid', 'speed', 'width'] # performance counters ibperf_err1 = ['LinkDowned', 'LinkRecovers', 'RcvErrors', 'SymbolErrors'] -ibperf_err2 = ['ExcBufOverrunErrors', 'LinkIntegrityErrors', 'QP1Dropped', \ - 'RcvConstraintErrors', 'RcvRemotePhysErrors', 'RcvSwRelayErrors', \ +ibperf_err2 = ['ExcBufOverrunErrors', 'LinkIntegrityErrors', 'QP1Dropped', + 'RcvConstraintErrors', 'RcvRemotePhysErrors', 'RcvSwRelayErrors', 'VL15Dropped', 'XmtConstraintErrors', 'XmtDiscards', 'XmtWait'] -ibperf_data = ['MulticastRcvPkts', 'MulticastXmitPkts', 'RcvData', 'RcvPkts', \ +ibperf_data = ['MulticastRcvPkts', 'MulticastXmitPkts', 'RcvData', 'RcvPkts', 'UnicastRcvPkts', 'UnicastXmitPkts', 'XmtData', 'XmtPkts'] ibperf_errs = ibperf_err1 + ibperf_err2 ibperf_counters = ibperf_errs + ibperf_data -ibperf_hash = { \ - 'ExcessiveBufferOverrunErrors' : 'ExcBufOverrunErrors', \ - 'LinkDownedCounter' : 'LinkDowned', \ - 'LinkErrorRecoveryCounter' : 'LinkRecovers', \ - 'LocalLinkIntegrityErrors' : 'LinkIntegrityErrors', \ - 'PortMulticastRcvPkts' : 'MulticastRcvPkts', \ - 'PortMulticastXmitPkts' : 'MulticastXmitPkts', \ - 'PortRcvConstraintErrors' : 'RcvConstraintErrors', \ - 'PortRcvData' : 'RcvData', \ - 'PortRcvErrors' : 'RcvErrors', \ - 'PortRcvPkts' : 'RcvPkts', \ - 'PortRcvRemotePhysicalErrors' : 'RcvRemotePhysErrors', \ - 'PortRcvSwitchRelayErrors' : 'RcvSwRelayErrors', \ - 'PortUnicastRcvPkts' : 'UnicastRcvPkts', \ - 'PortUnicastXmitPkts' : 'UnicastXmitPkts', \ - 'PortXmitConstraintErrors' : 'XmtConstraintErrors', \ - 'PortXmitData' : 'XmtData', \ - 'PortXmitDiscards' : 'XmtDiscards', \ - 'PortXmitPkts' : 'XmtPkts', \ - 'PortXmitWait' : 'XmtWait', \ - 'QP1Dropped' : 'QP1Dropped', \ - 'SymbolErrorCounter' : 'SymbolErrors', \ - 'VL15Dropped' : 'VL15Dropped', \ +ibperf_hash = { + 'ExcessiveBufferOverrunErrors': 'ExcBufOverrunErrors', + 'LinkDownedCounter': 'LinkDowned', + 'LinkErrorRecoveryCounter': 'LinkRecovers', + 'LocalLinkIntegrityErrors': 'LinkIntegrityErrors', + 'PortMulticastRcvPkts': 'MulticastRcvPkts', + 'PortMulticastXmitPkts': 'MulticastXmitPkts', + 'PortRcvConstraintErrors': 'RcvConstraintErrors', + 'PortRcvData': 'RcvData', + 'PortRcvErrors': 'RcvErrors', + 'PortRcvPkts': 'RcvPkts', + 'PortRcvRemotePhysicalErrors': 'RcvRemotePhysErrors', + 'PortRcvSwitchRelayErrors': 'RcvSwRelayErrors', + 'PortUnicastRcvPkts': 'UnicastRcvPkts', + 'PortUnicastXmitPkts': 'UnicastXmitPkts', + 'PortXmitConstraintErrors': 'XmtConstraintErrors', + 'PortXmitData': 'XmtData', + 'PortXmitDiscards': 'XmtDiscards', + 'PortXmitPkts': 'XmtPkts', + 'PortXmitWait': 'XmtWait', + 'QP1Dropped': 'QP1Dropped', + 'SymbolErrorCounter': 'SymbolErrors', + 'VL15Dropped': 'VL15Dropped', } # thresholds for performance counters (ibperf_err1 + ibperf_err2) @@ -321,11 +321,11 @@ ibperf_errs_threshold = {'ExcBufOverrunErrors' : 10, # functions -def error(message, errcode = -1): +def error(message, errcode=-1): """ Print the error message and exit with an error code. """ - print >> sys.stderr, 'Error: %s' % (message) + print(f'Error: {message}', file=sys.stderr) sys.exit(errcode) @@ -333,14 +333,14 @@ def warning(message): """ Print the warning message. """ - print >> sys.stderr, 'Warning: %s' % (message) + print(f'Warning: {message}', file=sys.stderr) def info(message): """ Print the info message. """ - print >> sys.stderr, 'Info: %s' % (message) + print(f'Info: {message}', file=sys.stderr) def cpu_number(): @@ -363,13 +363,15 @@ def run_cmd(cmd): """ retvalue = {} try: - p = subprocess.Popen(cmd, shell = True, stdout = subprocess.PIPE, \ - stderr = subprocess.STDOUT) - except OSError, exc: + p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, + stderr=subprocess.STDOUT) + except OSError as exc: exc.args = ['Can not run \"%s\"'] raise - retvalue['retstr'] = p.stdout.read() - retvalue['retval'] = p.wait() + stdout = p.stdout.read().decode('utf-8') + retval = p.wait() + retvalue['retstr'] = stdout + retvalue['retval'] = retval return retvalue @@ -378,7 +380,7 @@ def assert_file(file): Assert if file does not exist. """ if not os.path.isfile(file): - raise RuntimeError, 'Can not find file \"%s\"' % file + raise RuntimeError(f'Can not find file "{file}"') def read_file(file): @@ -392,7 +394,7 @@ def read_file(file): lines = out.read() out.close() except: - raise RuntimeError, 'Failed to read from \"%s\"' % file + raise RuntimeError(f'Failed to read from "{file}"') return lines @@ -403,7 +405,7 @@ def uniq_list(seq): keys = {} for each in seq: keys[each] = 1 - return keys.keys() + return list(keys.keys()) def parse_config(config_file, clusters, verbose=False): @@ -411,22 +413,22 @@ def parse_config(config_file, clusters, verbose=False): Parse fabric config file, obtain guid <-> desc (hostname) mapping. """ if verbose: - info('Reading config file %s ...' % config_file) + info(f'Reading config file {config_file} ...') try: assert_file(config_file) except RuntimeError: - error('Failed to read from %s' % config_file) + error(f'Failed to read from {config_file}') guid_desc_mapping = {} - config = ConfigParser.SafeConfigParser() + config = configparser.SafeConfigParser() config.read(config_file) config_clusters = config.sections() # sanity check if clusters and not set(clusters).issubset(set(config_clusters)): - error('Not all clusters in %s are defined in %s' % (clusters, config_file)) + error(f'Not all clusters in {clusters} are defined in {config_file}') # if no clusters are defined if not clusters: @@ -480,20 +482,20 @@ def parse_topology(topo_string, guid_desc_mapping, hca='', dryrun=False, verbose # sort each sub-category in ibnodes_index['type'] if ibnodes_index: - for type in ibnodes_index['type'].keys(): + for type in list(ibnodes_index['type'].keys()): if type in ['Spine', 'Leaf', 'Line']: try: - ibnodes_index['type'][type].sort( \ - key = lambda guid: int(ibnodes[guid]['typeindex'])) + ibnodes_index['type'][type].sort( + key=lambda guid: int(ibnodes[guid]['typeindex'])) except ValueError: - ibnodes_index['type'][type].sort( \ - key = lambda guid: ibnodes[guid]['typeindex']) + ibnodes_index['type'][type].sort( + key=lambda guid: ibnodes[guid]['typeindex']) else: - ibnodes_index['type'][type].sort( \ - key = lambda guid: ibnodes[guid]['desc']) + ibnodes_index['type'][type].sort( + key=lambda guid: ibnodes[guid]['desc']) # parse all ibnodes to construct link graph - for ibnode in ibnodes.values(): + for ibnode in list(ibnodes.values()): for ibport in ibnode['nodeports']: guid = ibnode['nodeguid'] port = ibport['port'] @@ -535,7 +537,7 @@ def parse_ibnode(block, guid_desc_mapping, hca='', dryrun=False, verbose=False): node_match = node_pattern.match(block) if node_match: - for key in node_pattern.groupindex.keys(): + for key in list(node_pattern.groupindex.keys()): ibnode[key] = node_match.group(key) ibnode['nodedesc'] = ibnode['nodedesc'].strip() @@ -545,21 +547,21 @@ def parse_ibnode(block, guid_desc_mapping, hca='', dryrun=False, verbose=False): # check if this ibnode is online or not if not dryrun: if hca: - cmd = 'ibaddr -C %s -G %s' % (hca, ibnode['nodeguid']) + cmd = f"ibaddr -C {hca} -G {ibnode['nodeguid']}" else: - cmd = 'ibaddr -G %s' % ibnode['nodeguid'] + cmd = f"ibaddr -G {ibnode['nodeguid']}" if not WITH_ROOT: - cmd = 'sudo %s' % cmd + cmd = f'sudo {cmd}' result = run_cmd(cmd) if result['retval']: - warning('%s found on the fabric but not alive' % ibnode['nodeguid']) + warning(f"{ibnode['nodeguid']} found on the fabric but not alive") return None elif ibnode['nodetype'] in ['Ca']: ibnode['nodeguid'] = ibnode['caguid'] else: - warning('Unknown IB node type %s' % ibnode['nodetype']) + warning(f"Unknown IB node type {ibnode['nodetype']}") # generalize model, type, and typeindex if ibnode['nodetype'] in ['Ca']: @@ -592,12 +594,12 @@ def parse_ibnode(block, guid_desc_mapping, hca='', dryrun=False, verbose=False): ibnode['typeindex'] = None # digitize fields - for key in ['vendid', 'devid', 'sysimgguid', 'switchguid', 'caguid', \ + for key in ['vendid', 'devid', 'sysimgguid', 'switchguid', 'caguid', 'nodeguid', 'nodelid', 'nodelmc', 'portcount', 'nodeport']: if ibnode[key]: ibnode[key] = int(ibnode[key], 0) - # if guid_desc_mapping is defined, use it to define ibnode['desc'], \ + # if guid_desc_mapping is defined, use it to define ibnode['desc'], # otherwise use the original ibnode['nodedesc'] if (ibnode['nodeguid'] in guid_desc_mapping): ibnode['desc'] = guid_desc_mapping[ibnode['nodeguid']] @@ -608,7 +610,7 @@ def parse_ibnode(block, guid_desc_mapping, hca='', dryrun=False, verbose=False): ibnode['nodeports'] = parse_ports(ibnode, guid_desc_mapping, verbose) else: if verbose: - warning('Cannot parse the following section:\n%s' % block) + warning(f'Cannot parse the following section:\n{block}') return ibnode @@ -631,7 +633,7 @@ def parse_ports(ibnode, guid_desc_mapping, verbose=False): ibport = {} port_match = port_pattern.match(port) if port_match: - for key in port_pattern.groupindex.keys(): + for key in list(port_pattern.groupindex.keys()): ibport[key] = port_match.group(key) ibport['tonodedesc'] = ibport['tonodedesc'].strip() @@ -645,11 +647,11 @@ def parse_ports(ibnode, guid_desc_mapping, verbose=False): if ibport['tonodeguid'] and not ibport['toportguid']: ibport['toportguid'] = ibport['tonodeguid'] for key in ['guid', 'lid', 'lmc']: - if not ibport['port%s' % key]: - ibport['port%s' % key] = ibnode['node%s' % key] - for key in ['port', 'portguid', 'tonodeguid', 'tonodeport', \ + if not ibport[f'port{key}']: + ibport[f'port{key}'] = ibnode[f'node{key}'] + for key in ['port', 'portguid', 'tonodeguid', 'tonodeport', 'toportguid', 'portlid', 'portlmc', 'toportlid', 'width']: - if key and (type(ibport[key]) is type('')): + if key and (isinstance(ibport[key], type(''))): ibport[key] = int(ibport[key], 0) # ibport['todesc'] is the redefined tonodedesc @@ -661,13 +663,13 @@ def parse_ports(ibnode, guid_desc_mapping, verbose=False): ibports.append(ibport) else: if verbose: - warning('Cannot parse the following section:\n%s' % port) + warning(f'Cannot parse the following section:\n{port}') # complete ports that do not have a link for port in range(1, ibnode['portcount']+1): if port not in [ibport['port'] for ibport in ibports]: ibport = {} - for key in port_pattern.groupindex.keys(): + for key in list(port_pattern.groupindex.keys()): if key in ['port']: ibport[key] = port elif key in ['portguid']: @@ -691,7 +693,7 @@ def parse_ports(ibnode, guid_desc_mapping, verbose=False): # sort all ports based on their port number if ibports: - ibports.sort(key = lambda ibport: ibport['port']) + ibports.sort(key=lambda ibport: ibport['port']) return ibports @@ -702,16 +704,16 @@ def query_ibnode(ibnodes_index, dest_list, cat_list, re_string, verbose=False): categories provided in cat_list, and the regex defined in re_string. """ if verbose: - info('Querying %s ...' % dest_list) + info(f'Querying {dest_list} ...') tgt_guid = [] for dest in dest_list: for cat in cat_list: - for key in [x for x in ibnodes_index[cat].keys() if x is not None]: - if ((cat in ['desc', 'nodedesc', 'speed', 'type']) and \ + for key in [x for x in list(ibnodes_index[cat].keys()) if x is not None]: + if ((cat in ['desc', 'nodedesc', 'speed', 'type']) and (re.search(re_string % dest, key, re.I))) or \ - ((cat in ['nodeguid', 'nodelid', 'portguid', 'portlid', 'width']) \ - and (dest == key)): + ((cat in ['nodeguid', 'nodelid', 'portguid', 'portlid', 'width']) and + (dest == key)): for guid in ibnodes_index[cat][key]: tgt_guid.append(guid) return tgt_guid @@ -724,24 +726,24 @@ def display_ibnode(ibnode, detail, verbose=False): line = '' if detail >= 3: line += ' vendid=0x%x\n devid=0x%x\n sysimgguid=0x%016x\n nodeguid=0x%016x\n' % \ - (ibnode['vendid'], ibnode['devid'], ibnode['sysimgguid'], \ + (ibnode['vendid'], ibnode['devid'], ibnode['sysimgguid'], ibnode['nodeguid']) if detail >= 1: if ibnode['nodetype'] in ['Switch']: line += ' %-6s %2d ports "0x%016x" # "%s" port %s lid %s lmc %s\n' % \ - (ibnode['type'], ibnode['portcount'], ibnode['nodeguid'], \ - ibnode['desc'], ibnode['nodeport'], ibnode['nodelid'], \ + (ibnode['type'], ibnode['portcount'], ibnode['nodeguid'], + ibnode['desc'], ibnode['nodeport'], ibnode['nodelid'], ibnode['nodelmc']) elif ibnode['type'] in ['Ca']: line += ' %-6s %2d ports "0x%016x" # "%s"\n' % \ - (ibnode['type'], ibnode['portcount'], ibnode['nodeguid'], \ + (ibnode['type'], ibnode['portcount'], ibnode['nodeguid'], ibnode['desc']) if detail >= 2: for port in ibnode['nodeports']: if port['tonodeguid']: line += ' [%2d](0x%016x)(lid %4d) <-> [%2d](0x%016x)(lid %4d) lmc %1d %dx%s # "%s"\n' % \ - (port['port'], port['portguid'], port['portlid'], \ - port['tonodeport'], port['tonodeguid'], port['toportlid'], \ + (port['port'], port['portguid'], port['portlid'], + port['tonodeport'], port['tonodeguid'], port['toportlid'], port['portlmc'], port['width'], port['speed'], port['todesc']) else: if detail >= 3: @@ -780,7 +782,7 @@ def compare_components(ibnodes, ibnodes_index1, ibnodes_index2, detail, defined_ line = '' if 'type' in ibnodes_index1: - for type in ibnodes_index1['type'].keys(): + for type in list(ibnodes_index1['type'].keys()): try: delta = set(ibnodes_index1['type'][type]) - \ set(ibnodes_index2['type'][type]) @@ -797,13 +799,13 @@ def compare_components(ibnodes, ibnodes_index1, ibnodes_index2, detail, defined_ if type in ['Spine', 'Leaf', 'Line']: try: - delta = sorted(list(delta), \ - key = lambda guid: int(ibnodes[guid]['typeindex'])) + delta = sorted(list(delta), + key=lambda guid: int(ibnodes[guid]['typeindex'])) except ValueError: - delta = sorted(list(delta), \ - key = lambda guid: ibnodes[guid]['typeindex']) + delta = sorted(list(delta), + key=lambda guid: ibnodes[guid]['typeindex']) else: - delta = sorted(list(delta), key = lambda guid: ibnodes[guid]['desc']) + delta = sorted(list(delta), key=lambda guid: ibnodes[guid]['desc']) for guid in delta: # only output the 1st level of detail @@ -829,23 +831,21 @@ def compare_links(ibnodes, links1, links2, defined_first=True, verbose=False): if delta: if defined_first: - line += '%d link found in the topology file but not on the fabric:\n' \ - % (len(delta)) + line += f'{len(delta)} link found in the topology file but not on the fabric:\n' else: - line += '%d link found on the fabric but not in the topology file:\n' \ - % (len(delta)) + line += f'{len(delta)} link found on the fabric but not in the topology file:\n' for link in delta: try: desc0 = ibnodes[link[0][0]]['desc'] except: - desc0 = '0x%x' % link[0][0] + desc0 = f'0x{link[0][0]:x}' try: desc1 = ibnodes[link[1][0]]['desc'] except: - desc1 = '0x%x' % link[1][0] + desc1 = f'0x{link[1][0]:x}' - line += ' %s [%s] <-> %s [%s]\n' % (desc0, link[0][1], desc1, link[1][1]) + line += f' {desc0} [{link[0][1]}] <-> {desc1} [{link[1][1]}]\n' return line @@ -855,13 +855,13 @@ def plot_topology(ibnodes, tgt_guid, links, graph_file, verbose=False): Plot topology with Graphviz, requires pydot. """ if verbose: - info("Plotting topology %s ..." % graph_file) + info(f"Plotting topology {graph_file} ...") graph = pydot.Dot(graph_type='graph', rankdir='LR') for guid in tgt_guid: if ibnodes[guid]['type'] in ['Switch', 'Spine', 'Leaf', 'Line']: - graph.add_node(pydot.Node(ibnodes[guid]['desc'], shape='box', \ + graph.add_node(pydot.Node(ibnodes[guid]['desc'], shape='box', style='filled', color='green')) for link in links: @@ -873,12 +873,12 @@ def plot_topology(ibnodes, tgt_guid, links, graph_file, verbose=False): # differentiate it if ibnodes[link[0][0]]['desc'] in \ ['Mellanox Technologies Aggregation Node']: - guid = '0x%016x' % ibnodes[link[0][0]]['nodeguid'] + guid = f"0x{ibnodes[link[0][0]]['nodeguid']:016x}" endpoint0 = ibnodes[link[0][0]]['desc'] + '\n' + guid if ibnodes[link[1][0]]['desc'] in \ ['Mellanox Technologies Aggregation Node']: - guid = '0x%016x' % ibnodes[link[0][0]]['nodeguid'] + guid = f"0x{ibnodes[link[0][0]]['nodeguid']:016x}" endpoint1 = ibnodes[link[1][0]]['desc'] + '\n' + guid speed = link[2] @@ -911,7 +911,7 @@ def ibtracert(ibnode1, ibnode2, hca='', verbose=False): text_line = '' # run ibtracert to retrieve routing info if hca: - cmd = 'ibtracert -C %s' % hca + cmd = f'ibtracert -C {hca}' else: cmd = 'ibtracert' @@ -934,11 +934,10 @@ def ibtracert(ibnode1, ibnode2, hca='', verbose=False): result = run_cmd(cmd % (guid1, guid2)) if not result['retval']: for line in result['retstr'].split('\n'): - text_line += ' %s\n' % line + text_line += f' {line}\n' else: - text_line += ' No route from %s to %s\n' % (ibnode1['nodedesc'], \ - ibnode2['nodedesc']) - print text_line[:-1] + text_line += f" No route from {ibnode1['nodedesc']} to {ibnode2['nodedesc']}\n" + print(text_line[:-1]) def sminfo(ibnode, hca='', verbose=False): @@ -950,12 +949,12 @@ def sminfo(ibnode, hca='', verbose=False): sminfo = [] if hca: - cmd = 'sminfo -C %s' % hca + cmd = f'sminfo -C {hca}' else: cmd = 'sminfo' if WITH_ROOT: - cmd = cmd +' -G %s' + cmd = cmd + ' -G %s' else: cmd = 'sudo ' + cmd + ' -G %s' @@ -974,8 +973,8 @@ def sminfo(ibnode, hca='', verbose=False): if verbose: for line in ret_lines.split('\n'): - text_line += ' %s\n' % line - print text_line[:-1] + text_line += f' {line}\n' + print(text_line[:-1]) return sminfo @@ -984,8 +983,8 @@ def sminfo_threading(input_queue, hca, output_queue): """ Collecting SM info in parallel. """ - for ibnode, verbose in iter(input_queue.get, 'STOP'): - output_queue.put(sminfo(ibnode,hca, verbose)) + for ibnode, _, verbose in iter(input_queue.get, 'STOP'): + output_queue.put(sminfo(ibnode, hca, verbose)) def parse_sminfo(lines, desc, verbose=False): @@ -1018,19 +1017,19 @@ def perfquery(ibnode, reset, detail, hca='', verbose=False): if ibport['tonodeguid']: if detail >= 2: - result = perfquery_port(ibport['portguid'], ibport['port'], reset, \ + result = perfquery_port(ibport['portguid'], ibport['port'], reset, hca, verbose) if not result['retval']: ret_lines += result['retstr'] - perf_counters.append(parse_perfquery(result['retstr'], \ + perf_counters.append(parse_perfquery(result['retstr'], ibport['portguid'], ibport['portlid'], ibnode['desc'], verbose)) else: if detail >= 3: - result = perfquery_port(ibport['portguid'], ibport['port'], reset, \ + result = perfquery_port(ibport['portguid'], ibport['port'], reset, hca, verbose) if not result['retval']: ret_lines += result['retstr'] - perf_counters.append(parse_perfquery(result['retstr'], \ + perf_counters.append(parse_perfquery(result['retstr'], ibport['portguid'], ibport['portlid'], ibnode['desc'], verbose)) elif ibnode['nodetype'] in ['Switch']: @@ -1038,31 +1037,31 @@ def perfquery(ibnode, reset, detail, hca='', verbose=False): result = perfquery_port(ibnode['nodeguid'], '255', reset, hca, verbose) if not result['retval']: ret_lines += result['retstr'] - perf_counters.append(parse_perfquery(result['retstr'], \ + perf_counters.append(parse_perfquery(result['retstr'], ibnode['nodeguid'], ibnode['nodelid'], ibnode['desc'], verbose)) for ibport in ibnode['nodeports']: if ibport['tonodeguid']: if detail >= 2: - result = perfquery_port(ibport['portguid'], ibport['port'], reset, \ + result = perfquery_port(ibport['portguid'], ibport['port'], reset, hca, verbose) if not result['retval']: ret_lines += result['retstr'] - perf_counters.append(parse_perfquery(result['retstr'], \ + perf_counters.append(parse_perfquery(result['retstr'], ibport['portguid'], ibport['portlid'], ibnode['desc'], verbose)) else: if detail >= 3: - result = perfquery_port(ibport['portguid'], ibport['port'], reset, \ + result = perfquery_port(ibport['portguid'], ibport['port'], reset, hca, verbose) if not result['retval']: ret_lines += result['retstr'] - perf_counters.append(parse_perfquery(result['retstr'], \ + perf_counters.append(parse_perfquery(result['retstr'], ibport['portguid'], ibport['portlid'], ibnode['desc'], verbose)) if verbose: for line in ret_lines.split('\n'): - text_line += ' %s\n' % line - print text_line[:-1] + text_line += f' {line}\n' + print(text_line[:-1]) return perf_counters @@ -1072,7 +1071,7 @@ def perfquery_port(guid, port, reset, hca='', verbose=False): Run perfquery command for a single port. """ if hca: - cmd = 'perfquery -x -C %s' % hca + cmd = f'perfquery -x -C {hca}' else: cmd = 'perfquery -x' @@ -1137,11 +1136,11 @@ def display_perfquery_help(screen, verbose=False): """ (screen_y, screen_x) = screen.getmaxyx() subwin_y = len(ibperf_counters) + 7 - subwin_x = max(len(line) for line in \ - [' : toggle %s' % key for key in ibperf_counters]) + 5 + subwin_x = max(len(line) for line in + [f' : toggle {key}' for key in ibperf_counters]) + 5 if screen_y >= subwin_y and screen_x >= subwin_x: - subwin = screen.subwin(subwin_y, subwin_x, (screen_y-subwin_y)/2, \ + subwin = screen.subwin(subwin_y, subwin_x, (screen_y-subwin_y)/2, (screen_x-subwin_x)/2) subwin.clear() subwin.border() @@ -1149,18 +1148,18 @@ def display_perfquery_help(screen, verbose=False): subwin.addstr(3, 2, 'Q: quit P: previous .: right') subwin.addstr(4, 2, ' : toggle ibnodes R: reset') for i in range(len(ibperf_counters)): - subwin.addstr(5+i, 2, '%c: toggle %s' % (chr(97+i), ibperf_counters[i])) + subwin.addstr(5+i, 2, f'{chr(97 + i):c}: toggle {ibperf_counters[i]}') else: subwin = screen.subwin(1, screen_x, 0, 0) subwin.clear() - subwin.addstr(0, 0, \ - 'Please increase screen size to display the help window', \ + subwin.addstr(0, 0, + 'Please increase screen size to display the help window', curses.color_pair(2)) subwin.refresh() subwin.getch() -def display_perfquery(screen, perf_counters, ibperf_counter, firstfield, \ +def display_perfquery(screen, perf_counters, ibperf_counter, firstfield, offset_x, offset_y, page, batch=False, verbose=False): """ Format and display perfquery results. @@ -1174,7 +1173,7 @@ def display_perfquery(screen, perf_counters, ibperf_counter, firstfield, \ (screen_y, screen_x) = (1000000, 1000000) # sort results - perf_counters.sort(key = lambda perf: (perf['NodeDesc'], perf['PortSelect'])) + perf_counters.sort(key=lambda perf: (perf['NodeDesc'], perf['PortSelect'])) # define output fields ibperf_counter = ['NodeDesc', 'PortSelect', 'Guid'] + \ @@ -1184,9 +1183,9 @@ def display_perfquery(screen, perf_counters, ibperf_counter, firstfield, \ field_len = {} for key in ibperf_counter: if key in ['Guid']: - items = [('0x%016x' % perf[key]) for perf in perf_counters] + items = [f'0x{perf[key]:016x}' for perf in perf_counters] else: - items = [('%s' % perf[key]) for perf in perf_counters] + items = [f'{perf[key]}' for perf in perf_counters] field_len[key] = max(len(item) for item in items) # replace 'PortSelect' with 'Port' if key in ['PortSelect']: @@ -1196,7 +1195,7 @@ def display_perfquery(screen, perf_counters, ibperf_counter, firstfield, \ # redefine perf_counters only to current screen if not batch: - perf_counters = perf_counters[page * (screen_y - offset_y - 1) : \ + perf_counters = perf_counters[page * (screen_y - offset_y - 1): (page + 1) * (screen_y - offset_y - 1)] count = 0 @@ -1208,28 +1207,28 @@ def display_perfquery(screen, perf_counters, ibperf_counter, firstfield, \ start_x += field_len[ibperf_counter[i]] + 1 if key in ['Guid']: - text_line += ' 0x%016x' % (perf_counter[key]) + text_line += f' 0x{perf_counter[key]:016x}' if start_y < screen_y and (start_x+field_len[key]) < screen_x and \ not batch: - screen.addstr(start_y, start_x, '0x%016x' % (perf_counter[key])) + screen.addstr(start_y, start_x, f'0x{perf_counter[key]:016x}') elif key in ibperf_errs and perf_counter[key] >= \ ibperf_errs_threshold[key]: text_line += ' %*s' % (field_len[key], perf_counter[key]) if start_y < screen_y and (start_x+field_len[key]) < screen_x and \ not batch: - screen.addstr(start_y, start_x, '%*s' % (field_len[key], \ + screen.addstr(start_y, start_x, '%*s' % (field_len[key], perf_counter[key]), curses.color_pair(1)) elif key in ibperf_errs and perf_counter[key] > 0: text_line += ' %*s' % (field_len[key], perf_counter[key]) if start_y < screen_y and (start_x+field_len[key]) < screen_x and \ not batch: - screen.addstr(start_y, start_x, '%*s' % (field_len[key], \ + screen.addstr(start_y, start_x, '%*s' % (field_len[key], perf_counter[key]), curses.color_pair(2)) else: text_line += ' %*s' % (field_len[key], perf_counter[key]) if start_y < screen_y and (start_x+field_len[key]) < screen_x and \ not batch: - screen.addstr(start_y, start_x, '%*s' % (field_len[key], \ + screen.addstr(start_y, start_x, '%*s' % (field_len[key], perf_counter[key])) count += 1 text_line += '\n' @@ -1269,7 +1268,7 @@ def filter_perfquery(perf_counters, showall=False, verbose=False): for perf_counter in perf_counters: beyond_threshold = False for key in ibperf_errs: - beyond_threshold = beyond_threshold or (perf_counter[key] >= \ + beyond_threshold = beyond_threshold or (perf_counter[key] >= ibperf_errs_threshold[key]) if beyond_threshold: filtered.append(perf_counter) @@ -1308,38 +1307,38 @@ def help(myname): """ Help page. """ - print 'Usage: %s [options]' % myname - print ' -a, --showall show all ibnodes when checking errors' - print ' -A, --and use "and" operator instead of "or" (default) on target selection' - print ' -b, --batch batch mode' - print ' -c, --config fabric config file (same as -f)' - print ' -C, --cluster cluster(s) to be queried (comma separated)' - print ' -d, --detail detail level (-d, -dd, -ddd)' - print ' -D, --dryrun dryrun to test topology, use with -t' - print ' -E, --error check errors' - print ' -f, --fabric fabric config file (same as -c)' - print ' -g, --guid query one or more GUIDs (comma separated)' - print ' -G, --graph plot topology with graphviz and output to ' - print ' -h, --help this help page' - print ' -H, --hca HCA to use' - print ' -i, --interval scan interval to check errors (seconds)' - print ' -l, --lid query one or more LIDs (comma separated)' - print ' -L, --leaf query one or more LEAFs (comma separated)' - print ' --line query one or more LINE CARDs (comma separated)' - print ' -M, --sminfo check subnet managers' - print ' -n, --iteration number of iterations' - print ' -N, --nodedesc query one or more NODEDESCs (comma separated)' - print ' -O, --timeout timeout value for scanning fabric (seconds, default is 3 seconds)' - print ' -p, --parallel number of threads for parallel processing' - print ' -P, --port query one or more ports (comma separated)' - print ' -r, --reset reset error counters once' - print ' -R, --route query routing info' - print ' -s, --speed query one or more SPEEDs [SDR|DDR|QDR|FDR|EDR|HDR|NDR|XDR] (comma separated)' - print ' -S, --spine query one or more SPINEs (comma separated)' - print ' -t, --topo topology file' - print ' -T, --type query one or more TYPEs %s (comma separated)' % ibnode_type - print ' -v, --verbose verbose output' - print ' -w, --width query one or more WIDTHes [1|2|4] (comma separated)' + print(f'Usage: {myname} [options]') + print(' -a, --showall show all ibnodes when checking errors') + print(' -A, --and use "and" operator instead of "or" (default) on target selection') + print(' -b, --batch batch mode') + print(' -c, --config fabric config file (same as -f)') + print(' -C, --cluster cluster(s) to be queried (comma separated)') + print(' -d, --detail detail level (-d, -dd, -ddd)') + print(' -D, --dryrun dryrun to test topology, use with -t') + print(' -E, --error check errors') + print(' -f, --fabric fabric config file (same as -c)') + print(' -g, --guid query one or more GUIDs (comma separated)') + print(' -G, --graph plot topology with graphviz and output to ') + print(' -h, --help this help page') + print(' -H, --hca HCA to use') + print(' -i, --interval scan interval to check errors (seconds)') + print(' -l, --lid query one or more LIDs (comma separated)') + print(' -L, --leaf query one or more LEAFs (comma separated)') + print(' --line query one or more LINE CARDs (comma separated)') + print(' -M, --sminfo check subnet managers') + print(' -n, --iteration number of iterations') + print(' -N, --nodedesc query one or more NODEDESCs (comma separated)') + print(' -O, --timeout timeout value for scanning fabric (seconds, default is 3 seconds)') + print(' -p, --parallel number of threads for parallel processing') + print(' -P, --port query one or more ports (comma separated)') + print(' -r, --reset reset error counters once') + print(' -R, --route query routing info') + print(' -s, --speed query one or more SPEEDs [SDR|DDR|QDR|FDR|EDR|HDR|NDR|XDR] (comma separated)') + print(' -S, --spine query one or more SPINEs (comma separated)') + print(' -t, --topo topology file') + print(f' -T, --type query one or more TYPEs {ibnode_type} (comma separated)') + print(' -v, --verbose verbose output') + print(' -w, --width query one or more WIDTHes [1|2|4] (comma separated)') def main(myname, argv): @@ -1386,15 +1385,15 @@ def main(myname, argv): defined_ibnodes_index = {} try: - opts, args = getopt.getopt(argv, 'aAbc:C:dDEf:g:G:hH:i:l:L:Mn:N:O:p:P:rRs:S:t:T:vw:', \ - ['showall', 'and', 'batch', 'config=', 'cluster=', 'detail', \ - 'dryrun', 'error', 'fabric=', 'guid=', 'graph=', 'help', \ - 'interval=', 'lid=', 'leaf=', 'line=', 'sminfo', \ - 'iteration=', 'nodedesc=', 'timeout=', 'parallel=', 'port=', \ - 'reset', 'route', 'speed=', 'spine=', 'topo=', 'type=', \ + opts, args = getopt.getopt(argv, 'aAbc:C:dDEf:g:G:hH:i:l:L:Mn:N:O:p:P:rRs:S:t:T:vw:', + ['showall', 'and', 'batch', 'config=', 'cluster=', 'detail', + 'dryrun', 'error', 'fabric=', 'guid=', 'graph=', 'help', + 'interval=', 'lid=', 'leaf=', 'line=', 'sminfo', + 'iteration=', 'nodedesc=', 'timeout=', 'parallel=', 'port=', + 'reset', 'route', 'speed=', 'spine=', 'topo=', 'type=', 'verbose', 'width=']) except getopt.GetoptError: - warning('Invalid arguments: %s\n' % argv) + warning(f'Invalid arguments: {argv}\n') help(myname) sys.exit(2) @@ -1424,14 +1423,14 @@ def main(myname, argv): if WITH_PYDOT: graph_file = val else: - warning('\'pydot\' is not imported, ignore \'%s %s\'' % (opt, val)) + warning(f'\'pydot\' is not imported, ignore \'{opt} {val}\'') elif opt in ['-H', '--hca']: hca = val elif opt in ['-i', '--interval']: try: interval = int(val) except ValueError: - warning('%s is not a valid interval value' % val) + warning(f'{val} is not a valid interval value') elif opt in ['-l', '--lid']: dest_lid = sorted(int(x) for x in val.split(',')) elif opt in ['-L', '--leaf', '--line']: @@ -1442,19 +1441,19 @@ def main(myname, argv): try: iteration = int(val) except ValueError: - warning('%s is not a valid iteration number' % val) + warning(f'{val} is not a valid iteration number') elif opt in ['-N', '--nodedesc']: dest_nodedesc = sorted(x.strip() for x in val.split(',')) elif opt in ['-O', '--timeout']: try: timeout = int(val) except ValueError: - warning('%s is not a valid timeout value' % val) + warning(f'{val} is not a valid timeout value') elif opt in ['-p', '--parallel']: try: threads = int(val) except ValueError: - warning('%s is not a valid thread number' % val) + warning(f'{val} is not a valid thread number') if threads <= 0: threads = 1 elif opt in ['-P', '--port']: @@ -1478,7 +1477,7 @@ def main(myname, argv): try: dest_width = sorted(int(x) for x in val.split(',')) except ValueError: - warning('%s is not a valid width' % val) + warning(f'{val} is not a valid width') # read fabric config file if config_file: @@ -1490,28 +1489,28 @@ def main(myname, argv): info('Running ibnetdiscover ...') if hca: - cmd = 'ibnetdiscover -C %s' % hca + cmd = f'ibnetdiscover -C {hca}' else: cmd = 'ibnetdiscover' if not WITH_ROOT: - cmd = 'sudo %s' % cmd + cmd = f'sudo {cmd}' - topo_string= run_cmd(cmd)['retstr'] + '\n' + topo_string = run_cmd(cmd)['retstr'] + '\n' - ibnodes, ibnodes_index, links = parse_topology(topo_string, \ + ibnodes, ibnodes_index, links = parse_topology(topo_string, guid_desc_mapping, hca, dryrun, verbose) # read from pre-defined topology file if topo_file: if verbose: - info('Reading topology file %s ...' % topo_file) + info(f'Reading topology file {topo_file} ...') try: assert_file(topo_file) except RuntimeError: - error('Failed to read from %s' % topo_file) - defined_topo_string= read_file(topo_file) + '\n' - defined_ibnodes, defined_ibnodes_index, defined_links = parse_topology( \ + error(f'Failed to read from {topo_file}') + defined_topo_string = read_file(topo_file) + '\n' + defined_ibnodes, defined_ibnodes_index, defined_links = parse_topology( defined_topo_string, guid_desc_mapping, '', True, verbose) if dryrun: ibnodes = defined_ibnodes @@ -1519,52 +1518,56 @@ def main(myname, argv): links = defined_links # output total components found on the fabric - print count_components(ibnodes_index, verbose) + 'found on the fabric' + print(count_components(ibnodes_index, verbose) + 'found on the fabric') # output total components found, and comparison if topo_file: - print count_components(defined_ibnodes_index, verbose) + \ - 'found in the topology file' + print(count_components(defined_ibnodes_index, verbose) + + 'found in the topology file') - print + print() # compare topologies if topo_file: - line = compare_components(defined_ibnodes, defined_ibnodes_index, \ + line = compare_components(defined_ibnodes, defined_ibnodes_index, ibnodes_index, detail, True, verbose) - if line: print line[:-1] - line = compare_components(ibnodes, ibnodes_index, defined_ibnodes_index, \ + if line: + print(line[:-1]) + line = compare_components(ibnodes, ibnodes_index, defined_ibnodes_index, detail, False, verbose) - if line: print line[:-1] + if line: + print(line[:-1]) # compare link graphs line = compare_links(defined_ibnodes, defined_links, links, True, verbose) - if line: print line + if line: + print(line) line = compare_links(ibnodes, links, defined_links, False, verbose) - if line: print line + if line: + print(line) # query fabric if ibnodes_index: if dest_cluster: - tgt_guid.append(query_ibnode(ibnodes_index, guid_desc_mapping, \ + tgt_guid.append(query_ibnode(ibnodes_index, guid_desc_mapping, ['nodeguid', 'portguid'], '^%s$', verbose)) if dest_guid: - tgt_guid.append(query_ibnode(ibnodes_index, dest_guid, \ + tgt_guid.append(query_ibnode(ibnodes_index, dest_guid, ['nodeguid', 'portguid'], '^%s$', verbose)) if dest_lid: - tgt_guid.append(query_ibnode(ibnodes_index, dest_lid, \ + tgt_guid.append(query_ibnode(ibnodes_index, dest_lid, ['nodelid', 'portlid'], '^%s$', verbose)) if dest_nodedesc: - tgt_guid.append(query_ibnode(ibnodes_index, dest_nodedesc, \ + tgt_guid.append(query_ibnode(ibnodes_index, dest_nodedesc, ['nodedesc', 'desc'], '%s', verbose)) if dest_speed: - tgt_guid.append(query_ibnode(ibnodes_index, dest_speed, ['speed'], \ + tgt_guid.append(query_ibnode(ibnodes_index, dest_speed, ['speed'], '^%s$', verbose)) if dest_width: - tgt_guid.append(query_ibnode(ibnodes_index, dest_width, ['width'], \ + tgt_guid.append(query_ibnode(ibnodes_index, dest_width, ['width'], '^%s$', verbose)) if dest_type: - tgt_guid.append(query_ibnode(ibnodes_index, dest_type, ['type'], '^%s$', \ + tgt_guid.append(query_ibnode(ibnodes_index, dest_type, ['type'], '^%s$', verbose)) if dest_spine: tgt_tmp = [] @@ -1587,27 +1590,28 @@ def main(myname, argv): for each in tgt_guid[1:]: tgt_guid[0] = set(tgt_guid[0]) | set(each) - tgt_guid = sorted(uniq_list(tgt_guid[0]), \ - key = lambda guid: ibnodes[guid]['desc']) + tgt_guid = sorted(uniq_list(tgt_guid[0]), + key=lambda guid: ibnodes[guid]['desc']) # if no query, output all components found - if not (dest_cluster or dest_guid or dest_lid or dest_nodedesc or dest_speed \ + if not (dest_cluster or dest_guid or dest_lid or dest_nodedesc or dest_speed or dest_width or dest_type or dest_spine or dest_leaf): - print 'fabric topology:' + print('Fabric topology:') for type in ibnode_type: try: tgt_guid.extend(ibnodes_index['type'][type]) except KeyError: pass else: - print 'Query results:' + print('Query results:') count = len(tgt_guid) for guid in tgt_guid: line = display_ibnode(ibnodes[guid], detail, verbose) - if line: print line - print '%d found\n' % count + if line: + print(line) + print(f'{count} found\n') # plot topology if graph_file: @@ -1623,19 +1627,19 @@ def main(myname, argv): warning('More than 2 end points found, will use the first two to retrive routing info') if count < 2: error('Less than 2 end points found, not able to retrieve routing info') - print 'Routing info:' + print('Routing info:') ibtracert(ibnodes[tgt_guid[0]], ibnodes[tgt_guid[1]], hca, verbose) # check sminfo if check_sm: sminfo = [] - print 'Scanning fabric ...' + print('Scanning fabric ...') # start threading start = time.time() nointerrupt = signal.signal(signal.SIGINT, signal.SIG_IGN) - sminfo_input_queue = Queue.Queue() - sminfo_output_queue = Queue.Queue() + sminfo_input_queue = queue.Queue() + sminfo_output_queue = queue.Queue() # creating input queue for threading for guid in tgt_guid: @@ -1643,7 +1647,7 @@ def main(myname, argv): # start threads, put results in output queue for i in range(len(tgt_guid)): - threading.Thread(target=sminfo_threading, args=(sminfo_input_queue, \ + threading.Thread(target=sminfo_threading, args=(sminfo_input_queue, hca, sminfo_output_queue)).start() # send 'STOP' signal to all threads @@ -1658,18 +1662,17 @@ def main(myname, argv): signal.signal(signal.SIGINT, nointerrupt) end = time.time() - print 'Subnet Manager info:' + print('Subnet Manager info:') line = '' - sminfo.sort(key = lambda sm: (sm['tag'], sm['desc'])) + sminfo.sort(key=lambda sm: (sm['tag'], sm['desc'])) for each in sminfo: if each: line += ' %-14s: guid 0x%016x lid %4d activity %10d priority %2d state %2d [%s]\n' % \ - (each['tag'], each['guid'], each['lid'], each['activity'], \ + (each['tag'], each['guid'], each['lid'], each['activity'], each['priority'], each['state'], each['desc']) - print line[:-1] - print '%d Subnet Managers found' % len(sminfo) - print '%.2f seconds spent on fetching %d ibnodes for Subnet Manager info' % \ - ((end-start), len(tgt_guid)) + print(line[:-1]) + print(f'{len(sminfo)} Subnet Managers found') + print(f'{end - start:.2f} seconds spent on fetching {len(tgt_guid)} ibnodes for Subnet Manager info') # check errors if check_error: @@ -1692,17 +1695,17 @@ def main(myname, argv): screen.move(0, 0) screen.clrtoeol() screen.addstr(0, 0, 'Scanning fabric ...') - screen.addstr(0, screen_x - len('page %d/%d' % (page, maxpage)), \ + screen.addstr(0, screen_x - len('page %d/%d' % (page, maxpage)), 'page %d/%d' % (page, maxpage)) screen.refresh() else: - print 'Scanning fabric ...' + print('Scanning fabric ...') # start threading start = time.time() nointerrupt = signal.signal(signal.SIGINT, signal.SIG_IGN) - perfquery_input_queue = Queue.Queue() - perfquery_output_queue = Queue.Queue() + perfquery_input_queue = queue.Queue() + perfquery_output_queue = queue.Queue() # creating input queue for threading for guid in tgt_guid: @@ -1713,7 +1716,7 @@ def main(myname, argv): # start threads, put results in output queue for i in range(threads): - threading.Thread(target=perfquery_threading, \ + threading.Thread(target=perfquery_threading, args=(perfquery_input_queue, perfquery_output_queue, hca)).start() # send 'STOP' signal to all threads @@ -1724,7 +1727,7 @@ def main(myname, argv): for i in range(len(tgt_guid)): try: perf_counters.extend(perfquery_output_queue.get(timeout=timeout)) - except Queue.Empty: + except queue.Empty: warning('Not all ports returned before timeout') pass @@ -1735,7 +1738,7 @@ def main(myname, argv): # filter results ports_scanned = len(perf_counters) perf_counters = filter_perfquery(perf_counters, showall, verbose) - ports_showed = len(perf_counters) + ports_showed = len(perf_counters) # recalculate max pages if not batch: @@ -1744,7 +1747,7 @@ def main(myname, argv): # capture keyboard inputs if not batch: # define keymap for 'a-z' - keymap = range(97, 97 + len(ibperf_counters)) + keymap = list(range(97, 97 + len(ibperf_counters))) input = screen.getch() while input != -1: if input in [ord('Q'), 27]: @@ -1784,28 +1787,28 @@ def main(myname, argv): if not batch: screen.clear() (screen_y, screen_x) = screen.getmaxyx() - screen.addstr(0, 0, 'Performace counter info:') - screen.addstr(0, screen_x - len('page %d/%d' % (page, maxpage)), \ + screen.addstr(0, 0, 'Performance counter info:') + screen.addstr(0, screen_x - len('page %d/%d' % (page, maxpage)), 'page %d/%d' % (page, maxpage)) - screen.addstr(1, 0, '%.2f seconds spent on scanning %d ibnodes (%s)' % \ + screen.addstr(1, 0, '%.2f seconds spent on scanning %d ibnodes (%s)' % ((end-start), len(tgt_guid), datetime.datetime.now())) else: - print 'Performace counter info:' - print '%.2f seconds spent on scanning %d ibnodes (%s)' % ((end-start), \ - len(tgt_guid), datetime.datetime.now()) + print('Performace counter info:') + print('%.2f seconds spent on scanning %d ibnodes (%s)' % ((end-start), + len(tgt_guid), datetime.datetime.now())) # display performance counters if perf_counters: if batch: screen = None # start to output from screen position (0, 3) - perf_counters_line = display_perfquery(screen, perf_counters, \ + perf_counters_line = display_perfquery(screen, perf_counters, sorted(ibperf_counter), firstfield, 0, 3, page, batch, verbose) if batch: - perf_counters_line = '%d ports scanned, %d showed\n' % \ + perf_counters_line = '%d ports scanned, %d shown\n' % \ (ports_scanned, ports_showed) + perf_counters_line else: - perf_counters_line = '%d ports scanned, %d showed' % \ + perf_counters_line = '%d ports scanned, %d shown' % \ (ports_scanned, ports_showed) else: perf_counters_line = 'Empty performance counters' @@ -1815,7 +1818,7 @@ def main(myname, argv): screen.addstr(2, 0, perf_counters_line) screen.refresh() else: - print perf_counters_line + print(perf_counters_line) # break after a certain iterations if running in batch mode if batch: