diff --git a/README.rst b/README.rst index 6121eba..2dfe0e7 100644 --- a/README.rst +++ b/README.rst @@ -218,7 +218,7 @@ This can be achieved by running OSACA with the command line option ``--import MI ``ARCH`` defines the abbreviation of the target architecture for which the instructions will be added and file must be the path to the generated output file of the benchmark. The format of this file has to match either the basic command line output of ibench, e.g., -.. code-block:: +.. code-block:: bash [INSTRUCTION FORM]-TP: 0.500 (clock cycles) [DEBUG - result: 1.000000] [INSTRUCTION FORM]-LT: 4.000 (clock cycles) [DEBUG - result: 1.000000] @@ -226,7 +226,7 @@ The format of this file has to match either the basic command line output of ibe or the command line output of asmbench including the name of the instruction form in a separate line at the beginning, e.g.: -.. code-block:: +.. code-block:: bash [INSTRUCTION FORM] Latency: 4.00 cycle @@ -276,7 +276,7 @@ Database check Since a manual adjustment of the ISA DB is currently indispensable when adding new instruction forms, OSACA provides a database sanity check using the --db-check flag. It can be executed via: -.. code-block:: +.. code-block:: bash osaca --arch ARCH --db-check [-v] file @@ -304,7 +304,7 @@ The code shows a simple scalar multiplication of a vector ``b`` and a floating-p The result is written in vector ``a``. After including the OSACA byte marker into the assembly, one can start the analysis typing -.. code:: bash +.. code-block:: bash osaca --arch CSX PATH/TO/FILE @@ -312,7 +312,7 @@ in the command line. The output is: -.. code-block:: +.. code-block:: bash Open Source Architecture Code Analyzer (OSACA) - v0.3 Analyzed file: scale.s.csx.O3.s diff --git a/docs/conf.py b/docs/conf.py index b0f0be0..68fde48 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -60,7 +60,7 @@ html_theme = 'sphinx_rtd_theme' # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] +html_static_path = [] htmlhelp_basename = 'osaca_doc' html_sidebars = {'**': ['globaltoc.html', 'relations.html', 'sourcelink.html', 'searchbox.html']} diff --git a/docs/index.rst b/docs/index.rst index b01ac29..bcf8a64 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -1,5 +1,5 @@ OSACA |br| Open Source Architecture Code Analyzer -====================== +================================================= .. toctree:: :maxdepth: 2 diff --git a/docs/sphinx/home.rst b/docs/sphinx/home.rst index 4056aee..8223cfa 100644 --- a/docs/sphinx/home.rst +++ b/docs/sphinx/home.rst @@ -12,12 +12,23 @@ For an innermost loop kernel in assembly, this tool allows automatic instruction .. image:: https://travis-ci.org/RRZE-HPC/OSACA.svg?branch=master :target: https://travis-ci.org/RRZE-HPC/OSACA + :alt: Build Status .. image:: https://codecov.io/github/RRZE-HPC/OSACA/coverage.svg?branch=master :target: https://codecov.io/github/RRZE-HPC/OSACA?branch=master + :alt: Code Coverage + +.. image:: https://readthedocs.org/projects/osaca/badge/?version=latest + :target: https://osaca.readthedocs.io/en/latest/?badge=latest + :alt: Documentation Status + +.. image:: https://img.shields.io/badge/read-the_docs-blue + :target: https://osaca.readthedocs.io/ + :alt: Docs .. image:: https://img.shields.io/badge/code%20style-black-000000.svg :target: https://github.com/ambv/black + :alt: Code Style Getting started =============== @@ -207,7 +218,7 @@ This can be achieved by running OSACA with the command line option ``--import MI ``ARCH`` defines the abbreviation of the target architecture for which the instructions will be added and file must be the path to the generated output file of the benchmark. The format of this file has to match either the basic command line output of ibench, e.g., -.. code-block:: +.. code-block:: bash [INSTRUCTION FORM]-TP: 0.500 (clock cycles) [DEBUG - result: 1.000000] [INSTRUCTION FORM]-LT: 4.000 (clock cycles) [DEBUG - result: 1.000000] @@ -215,7 +226,7 @@ The format of this file has to match either the basic command line output of ibe or the command line output of asmbench including the name of the instruction form in a separate line at the beginning, e.g.: -.. code-block:: +.. code-block:: bash [INSTRUCTION FORM] Latency: 4.00 cycle @@ -265,7 +276,7 @@ Database check Since a manual adjustment of the ISA DB is currently indispensable when adding new instruction forms, OSACA provides a database sanity check using the --db-check flag. It can be executed via: -.. code-block:: +.. code-block:: bash osaca --arch ARCH --db-check [-v] file @@ -293,7 +304,7 @@ The code shows a simple scalar multiplication of a vector ``b`` and a floating-p The result is written in vector ``a``. After including the OSACA byte marker into the assembly, one can start the analysis typing -.. code:: bash +.. code-block:: bash osaca --arch CSX PATH/TO/FILE @@ -301,7 +312,7 @@ in the command line. The output is: -.. code-block:: +.. code-block:: bash Open Source Architecture Code Analyzer (OSACA) - v0.3 Analyzed file: scale.s.csx.O3.s diff --git a/osaca/db_interface.py b/osaca/db_interface.py index 1b30c7d..e9abcb0 100755 --- a/osaca/db_interface.py +++ b/osaca/db_interface.py @@ -19,6 +19,9 @@ def sanity_check(arch: str, verbose=False, output_file=sys.stdout): :type arch: str :param verbose: verbose output flag, defaults to `False` :type verbose: bool, optional + :param output_file: output stream specifying where to write output, defaults to :class:`sys. stdout` + :type output_file: stream, optional + """ # load arch machine model arch_mm = MachineModel(arch=arch) @@ -184,6 +187,10 @@ def _get_ibench_output(input_data, isa): def _validate_measurement(measurement, mode): + """ + Check if latency has a maximum deviation of 0.05% and throughput is a reciprocal of a + an integer number. + """ if mode == 'lt': if ( math.floor(measurement) * 1.05 >= measurement @@ -204,6 +211,7 @@ def _validate_measurement(measurement, mode): def _create_db_operand(operand, isa): + """Get DB operand by input string and ISA.""" if isa == 'aarch64': return _create_db_operand_aarch64(operand) elif isa == 'x86': @@ -211,6 +219,7 @@ def _create_db_operand(operand, isa): def _create_db_operand_aarch64(operand): + """Get DB operand for AArch64 by operand string.""" if operand == 'i': return {'class': 'immediate', 'imd': 'int'} elif operand in 'wxbhsdq': @@ -236,6 +245,7 @@ def _create_db_operand_aarch64(operand): def _create_db_operand_x86(operand): + """Get DB operand for AArch64 by operand string.""" if operand == 'r': return {'class': 'register', 'name': 'gpr'} elif operand in 'xyz': @@ -260,6 +270,7 @@ def _create_db_operand_x86(operand): def _check_sanity_arch_db(arch_mm, isa_mm): + """Do sanity check for ArchDB by given ISA.""" suspicious_prefixes_x86 = ['vfm', 'fm'] suspicious_prefixes_arm = ['fml', 'ldp', 'stp', 'str'] if arch_mm.get_ISA().lower() == 'aarch64': @@ -318,6 +329,7 @@ def _check_sanity_arch_db(arch_mm, isa_mm): def _check_sanity_isa_db(arch_mm, isa_mm): + """Do sanity check for an ISA DB.""" # returned lists duplicate_instr_isa = [] only_in_isa = [] @@ -343,6 +355,7 @@ def _check_sanity_isa_db(arch_mm, isa_mm): def _get_sanity_report( total, m_tp, m_l, m_pp, suspic_instr, dup_arch, dup_isa, only_isa, verbose=False, colors=False ): + """Get sanity summary report.""" s = '' # non-verbose summary s += 'SUMMARY\n----------------------\n' @@ -376,6 +389,7 @@ def _get_sanity_report( def _get_sanity_report_verbose( total, m_tp, m_l, m_pp, suspic_instr, dup_arch, dup_isa, only_isa, colors=False ): + """Get the verbose part of the sanity report with all missing instruction forms.""" BRIGHT_CYAN = '\033[1;36;1m' if colors else '' BRIGHT_BLUE = '\033[1;34;1m' if colors else '' BRIGHT_RED = '\033[1;31;1m' if colors else '' @@ -418,6 +432,7 @@ def _get_sanity_report_verbose( def _get_full_instruction_name(instruction_form): + """Get full instruction form name/identifier string out of given instruction form.""" operands = [] for op in instruction_form['operands']: op_attrs = [ @@ -429,16 +444,19 @@ def _get_full_instruction_name(instruction_form): def __represent_none(self, data): + """Get YAML None representation.""" return self.represent_scalar(u'tag:yaml.org,2002:null', u'~') def _create_yaml_object(): + """Create YAML module with None representation.""" yaml_obj = ruamel.yaml.YAML() yaml_obj.representer.add_representer(type(None), __represent_none) return yaml_obj def __dump_data_to_yaml(filepath, data): + """Dump data to YAML file at given filepath.""" # first add 'normal' meta data in the right order (no ordered dict yet) meta_data = dict(data) del meta_data['instruction_forms'] diff --git a/osaca/osaca.py b/osaca/osaca.py index 5d5dd62..fd93032 100755 --- a/osaca/osaca.py +++ b/osaca/osaca.py @@ -159,7 +159,7 @@ def import_data(benchmark_type, arch, filepath, output_file=sys.stdout): :param filepath: filepath of the output file" :type filepath: str :param output_file: output stream specifying where to write output, defaults to :class:`sys.stdout` - :type output_file: stream + :type output_file: stream, optional """ if benchmark_type.lower() == 'ibench': import_benchmark_output(arch, 'ibench', filepath, output=output_file) @@ -210,6 +210,7 @@ def inspect(args, output_file=sys.stdout): :param args: arguments given from :class:`~argparse.ArgumentParser` after parsing :param output_file: Define the stream for output, defaults to :class:`sys.stdout` + :type output_file: stream, optional """ arch = args.arch isa = MachineModel.get_isa_for_arch(arch) @@ -251,6 +252,7 @@ def run(args, output_file=sys.stdout): :param args: arguments given from :class:`~argparse.ArgumentParser` after parsing :param output_file: Define the stream for output, defaults to :class:`sys.stdout` + :type output_file: stream, optional """ if args.check_db: # Sanity check on DB diff --git a/osaca/parser/attr_dict.py b/osaca/parser/attr_dict.py index 0e04197..6348599 100755 --- a/osaca/parser/attr_dict.py +++ b/osaca/parser/attr_dict.py @@ -1,4 +1,5 @@ #!/usr/bin/env python3 +"""Attribute Dictionary to access dictionary entries as attributes.""" class AttrDict(dict): @@ -8,14 +9,19 @@ class AttrDict(dict): @staticmethod def convert_dict(dictionary): + """ + Convert given dictionary to `AttrDict`. + + :param dictionary: `dict` to be converted + :type dictionary: `dict` + :returns: `AttrDict` representation of ``dictionary`` + """ if isinstance(dictionary, type(list())): return [AttrDict.convert_dict(x) for x in dictionary] if isinstance(dictionary, type(dict())): for key in list(dictionary.keys()): entry = dictionary[key] - if isinstance(entry, type(dict())) or isinstance( - entry, type(AttrDict()) - ): + if isinstance(entry, type(dict())) or isinstance(entry, type(AttrDict())): dictionary[key] = AttrDict.convert_dict(dictionary[key]) if isinstance(entry, type(list())): dictionary[key] = [AttrDict.convert_dict(x) for x in entry] diff --git a/osaca/parser/base_parser.py b/osaca/parser/base_parser.py index 3e67f3b..d08ed97 100755 --- a/osaca/parser/base_parser.py +++ b/osaca/parser/base_parser.py @@ -1,4 +1,5 @@ #!/usr/bin/env python3 +"""Parser superclass of specific parsers.""" class BaseParser(object): @@ -17,14 +18,14 @@ class BaseParser(object): self.construct_parser() def parse_file(self, file_content, start_line=0): - ''' + """ Parse assembly file. This includes *not* extracting of the marked kernel and the parsing of the instruction forms. :param str file_content: assembly code :param int start_line: offset, if first line in file_content is meant to be not 1 :return: list of instruction forms - ''' + """ # Create instruction form list asm_instructions = [] lines = file_content.split('\n') diff --git a/osaca/parser/parser_AArch64v81.py b/osaca/parser/parser_AArch64v81.py index 83db74c..51d2fae 100755 --- a/osaca/parser/parser_AArch64v81.py +++ b/osaca/parser/parser_AArch64v81.py @@ -12,6 +12,7 @@ class ParserAArch64v81(BaseParser): self.isa = 'aarch64' def construct_parser(self): + """Create parser for ARM AArch64 ISA.""" # Comment symbol_comment = '//' self.comment = pp.Literal(symbol_comment) + pp.Group( @@ -181,8 +182,9 @@ class ParserAArch64v81(BaseParser): Parse line and return instruction form. :param str line: line of assembly code - :param int line_id: default None, identifier of instruction form - :return: parsed instruction form + :param line_number: identifier of instruction form, defautls to None + :type line_number: int, optional + :return: `dict` -- parsed asm line (comment, label, directive or instruction form) """ instruction_form = AttrDict( { @@ -263,6 +265,12 @@ class ParserAArch64v81(BaseParser): return instruction_form def parse_instruction(self, instruction): + """ + Parse instruction in asm line. + + :param str instruction: Assembly line string. + :returns: `dict` -- parsed instruction form + """ result = self.instruction_parser.parseString(instruction, parseAll=True).asDict() result = AttrDict.convert_dict(result) operands = [] @@ -292,6 +300,7 @@ class ParserAArch64v81(BaseParser): return return_dict def process_operand(self, operand): + """Post-process operand""" # structure memory addresses if self.MEMORY_ID in operand: return self.process_memory_address(operand[self.MEMORY_ID]) @@ -311,6 +320,7 @@ class ParserAArch64v81(BaseParser): return operand def process_memory_address(self, memory_address): + """Post-process memory address operand""" # Remove unnecessarily created dictionary entries during parsing offset = None if 'offset' not in memory_address else memory_address['offset'] base = None if 'base' not in memory_address else memory_address['base'] @@ -333,11 +343,13 @@ class ParserAArch64v81(BaseParser): return AttrDict({self.MEMORY_ID: new_dict}) def process_sp_register(self, register): + """Post-process stack pointer register""" reg = register reg['prefix'] = 'x' return AttrDict({self.REGISTER_ID: reg}) def process_register_list(self, register_list): + """Post-process register lists (e.g., {r0,r3,r5}) and register ranges (e.g., {r0-r7})""" # Remove unnecessarily created dictionary entries during parsing vlist = [] dict_name = '' @@ -354,6 +366,7 @@ class ParserAArch64v81(BaseParser): return AttrDict({self.REGISTER_ID: new_dict}) def process_immediate(self, immediate): + """Post-process immediate operand""" dict_name = '' if 'identifier' in immediate: # actually an identifier, change declaration @@ -378,11 +391,13 @@ class ParserAArch64v81(BaseParser): ) def process_label(self, label): + """Post-process label asm line""" # remove duplicated 'name' level due to identifier label['name'] = label['name']['name'] return AttrDict({self.LABEL_ID: label}) def get_full_reg_name(self, register): + """Return one register name string including all attributes""" if 'lanes' in register: return ( register['prefix'] @@ -394,19 +409,21 @@ class ParserAArch64v81(BaseParser): return register['prefix'] + str(register['name']) def normalize_imd(self, imd): + """Normalize immediate to decimal based representation""" if 'value' in imd: if imd['value'].lower().startswith('0x'): # hex, return decimal return int(imd['value'], 16) return int(imd['value'], 10) elif 'float' in imd: - return self.ieee_to_int(imd['float']) + return self.ieee_to_float(imd['float']) elif 'double' in imd: - return self.ieee_to_int(imd['double']) + return self.ieee_to_float(imd['double']) # identifier return imd - def ieee_to_int(self, ieee_val): + def ieee_to_float(self, ieee_val): + """Convert IEEE representation to python float""" exponent = int(ieee_val['exponent'], 10) if ieee_val['e_sign'] == '-': exponent *= -1 @@ -416,16 +433,19 @@ class ParserAArch64v81(BaseParser): raise NotImplementedError def is_gpr(self, register): + """Check if register is a general purpose register""" if register['prefix'] in 'wx': return True return False def is_vector_register(self, register): + """Check if register is a vector register""" if register['prefix'] in 'bhsdqv': return True return False def is_flag_dependend_of(self, flag_a, flag_b): + """Check if ``flag_a`` is dependent on ``flag_b``""" # we assume flags are independent of each other, e.g., CF can be read while ZF gets written # TODO validate this assumption if flag_a.name == flag_b.name: @@ -433,6 +453,7 @@ class ParserAArch64v81(BaseParser): return False def is_reg_dependend_of(self, reg_a, reg_b): + """Check if ``reg_a`` is dependent on ``reg_b``""" prefixes_gpr = 'wx' prefixes_vec = 'bhsdqv' if reg_a['name'] == reg_b['name']: @@ -443,4 +464,5 @@ class ParserAArch64v81(BaseParser): return False def get_reg_type(self, register): + """Get register type""" return register['prefix'] diff --git a/osaca/parser/parser_x86att.py b/osaca/parser/parser_x86att.py index 28885e3..7d63312 100755 --- a/osaca/parser/parser_x86att.py +++ b/osaca/parser/parser_x86att.py @@ -13,6 +13,7 @@ class ParserX86ATT(BaseParser): self.isa = 'x86' def construct_parser(self): + """Create parser for ARM AArch64 ISA.""" decimal_number = pp.Combine( pp.Optional(pp.Literal('-')) + pp.Word(pp.nums) ).setResultsName('value') @@ -148,6 +149,7 @@ class ParserX86ATT(BaseParser): ) def parse_register(self, register_string): + """Parse register string""" try: return self.process_operand( self.register.parseString(register_string, parseAll=True).asDict() @@ -160,8 +162,9 @@ class ParserX86ATT(BaseParser): Parse line and return instruction form. :param str line: line of assembly code - :param int line_id: default None, identifier of instruction form - :return: parsed instruction form + :param line_number: default None, identifier of instruction form + :type line_number: int, optional + :return: ``dict`` -- parsed asm line (comment, label, directive or instruction form) """ instruction_form = AttrDict( { @@ -232,6 +235,12 @@ class ParserX86ATT(BaseParser): return instruction_form def parse_instruction(self, instruction): + """ + Parse instruction in asm line. + + :param str instruction: Assembly line string. + :returns: `dict` -- parsed instruction form + """ result = self.instruction_parser.parseString(instruction, parseAll=True).asDict() result = AttrDict.convert_dict(result) operands = [] @@ -260,6 +269,7 @@ class ParserX86ATT(BaseParser): return return_dict def process_operand(self, operand): + """Post-process operand""" # For the moment, only used to structure memory addresses if self.MEMORY_ID in operand: return self.process_memory_address(operand[self.MEMORY_ID]) @@ -270,6 +280,7 @@ class ParserX86ATT(BaseParser): return operand def process_memory_address(self, memory_address): + """Post-process memory address operand""" # Remove unecessarily created dictionary entries during memory address parsing offset = None if 'offset' not in memory_address else memory_address['offset'] base = None if 'base' not in memory_address else memory_address['base'] @@ -284,11 +295,13 @@ class ParserX86ATT(BaseParser): return AttrDict({self.MEMORY_ID: new_dict}) def process_label(self, label): + """Post-process label asm line""" # remove duplicated 'name' level due to identifier label['name'] = label['name']['name'] return AttrDict({self.LABEL_ID: label}) def process_immediate(self, immediate): + """Post-process immediate operand""" if 'identifier' in immediate: # actually an identifier, change declaration return immediate @@ -296,10 +309,12 @@ class ParserX86ATT(BaseParser): return AttrDict({self.IMMEDIATE_ID: immediate}) def get_full_reg_name(self, register): + """Return one register name string including all attributes""" # nothing to do return register['name'] def normalize_imd(self, imd): + """Normalize immediate to decimal based representation""" if 'value' in imd: if imd['value'].lower().startswith('0x'): # hex, return decimal @@ -309,6 +324,7 @@ class ParserX86ATT(BaseParser): return imd def is_flag_dependend_of(self, flag_a, flag_b): + """Check if ``flag_a`` is dependent on ``flag_b``""" # we assume flags are independent of each other, e.g., CF can be read while ZF gets written # TODO validate this assumption if flag_a.name == flag_b.name: @@ -316,6 +332,7 @@ class ParserX86ATT(BaseParser): return False def is_reg_dependend_of(self, reg_a, reg_b): + """Check if ``reg_a`` is dependent on ``reg_b``""" # Check if they are the same registers if reg_a.name == reg_b.name: return True @@ -359,11 +376,13 @@ class ParserX86ATT(BaseParser): return False def is_basic_gpr(self, register): + """Check if register is a basic general purpose register (ebi, rax, ...)""" if any(char.isdigit() for char in register['name']): return False return True def is_gpr(self, register): + """Check if register is a general purpose register""" if register is None: return False gpr_parser = ( @@ -381,6 +400,7 @@ class ParserX86ATT(BaseParser): return False def is_vector_register(self, register): + """Check if register is a vector register""" if register is None: return False if register['name'].rstrip(string.digits).lower() in ['mm', 'xmm', 'ymm', 'zmm']: @@ -388,6 +408,7 @@ class ParserX86ATT(BaseParser): return False def get_reg_type(self, register): + """Ger register type""" if register is None: return False if self.is_gpr(register): diff --git a/osaca/semantics/arch_semantics.py b/osaca/semantics/arch_semantics.py index cd3c841..61aa6ef 100755 --- a/osaca/semantics/arch_semantics.py +++ b/osaca/semantics/arch_semantics.py @@ -1,4 +1,5 @@ #!/usr/bin/env python3 +"""Semantics opbject responsible for architecture specific semantic operations""" import warnings from functools import reduce @@ -19,6 +20,12 @@ class ArchSemantics(ISASemantics): # SUMMARY FUNCTION def add_semantics(self, kernel): + """ + Applies performance data (throughput, latency, port pressure) and source/destination + distribution to each instruction of a given kernel. + + :param list kernel: kernel to apply semantics + """ for instruction_form in kernel: self.assign_src_dst(instruction_form) self.assign_tp_lt(instruction_form) @@ -26,6 +33,11 @@ class ArchSemantics(ISASemantics): self.set_hidden_loads(kernel) def assign_optimal_throughput(self, kernel): + """ + Assign optimal throughput port pressure to a kernel. This is done in steps of ``0.01cy``. + + :param list kernel: kernel to apply optimal port utilization + """ INC = 0.01 kernel.reverse() port_list = self._machine_model.get_ports() @@ -74,6 +86,7 @@ class ArchSemantics(ISASemantics): kernel.reverse() def set_hidden_loads(self, kernel): + """Hide loads behind stores if architecture supports hidden loads (depricated)""" loads = [instr for instr in kernel if INSTR_FLAGS.HAS_LD in instr['flags']] stores = [instr for instr in kernel if INSTR_FLAGS.HAS_ST in instr['flags']] # Filter instructions including load and store @@ -114,6 +127,7 @@ class ArchSemantics(ISASemantics): # get parser result and assign throughput and latency value to instruction form # mark instruction form with semantic flags def assign_tp_lt(self, instruction_form): + """Assign throughput and latency to an instruction form.""" flags = [] port_number = len(self._machine_model['ports']) if instruction_form['instruction'] is None: @@ -298,6 +312,7 @@ class ArchSemantics(ISASemantics): instruction_form['latency_lcd'] = 0 def _handle_instruction_found(self, instruction_data, port_number, instruction_form, flags): + """Apply performance data to instruction if it was found in the archDB""" throughput = instruction_data['throughput'] port_pressure = self._machine_model.average_port_pressure( instruction_data['port_pressure'] @@ -334,14 +349,17 @@ class ArchSemantics(ISASemantics): return throughput, port_pressure, latency, latency_wo_load def substitute_mem_address(self, operands): + """Create memory wildcard for all memory operands""" # reg_ops = [op for op in operands if 'register' in op] # reg_type = self._parser.get_reg_type(reg_ops[0]['register']) return [self._create_reg_wildcard() if 'memory' in op else op for op in operands] def _create_reg_wildcard(self): + """Wildcard constructor""" return {'*': '*'} def convert_op_to_reg(self, reg_type, reg_id='0'): + """Create register operand for a memory addressing operand""" if self._isa == 'x86': if reg_type == 'gpr': register = {'register': {'name': 'r' + str(int(reg_id) + 9)}} @@ -352,6 +370,7 @@ class ArchSemantics(ISASemantics): return register def _nullify_data_ports(self, port_pressure): + """Set all ports to 0.0 for the ports of a machine model""" data_ports = self._machine_model.get_data_ports() for port in data_ports: index = self._machine_model.get_ports().index(port) @@ -381,6 +400,7 @@ class ArchSemantics(ISASemantics): @staticmethod def get_throughput_sum(kernel): + """Get the overall throughput sum separated by port of all instructions of a kernel.""" tp_sum = reduce( (lambda x, y: [sum(z) for z in zip(x, y)]), [instr['port_pressure'] for instr in kernel],