Beispiel #1
0
 def construct_compound_class_description(self, compound_class_list):
     """
     checks if there are duplicated compound component class names
     :param compound_class_list: list of compound classes that need parsing
     :return: None (self.compound_class_description is updated)
     """
     if 'version' not in compound_class_list:
         ERROR_CLEAN_EXIT(
             'please specify the version of parser your input format adheres to using '
             '"version" key at top level')
     for idx in range(len(compound_class_list['classes'])):
         compound_class_name = compound_class_list['classes'][idx]['name']
         if compound_class_name in self.compound_class_description:
             ERROR_CLEAN_EXIT(
                 'duplicate compound class name in component class description,',
                 'error class name', compound_class_name)
         self.compound_class_description[
             compound_class_name] = compound_class_list['classes'][idx]
         try:
             subcomponents = self.compound_class_description[
                 compound_class_name]['subcomponents']
         except KeyError:
             subcomponents = None
             ERROR_CLEAN_EXIT(
                 'compound classes must have "subcomponents" key to specify the lower-level details',
                 'error class name: ', compound_class_name)
     self.compound_class_version = compound_class_list['version']
     self.compound_component_constructor = 'v' + str(self.compound_class_version).replace('.', '') + \
                                       '_compound_component_constructor'
def v02_validate_top_level_architecture_description(architecture_description):
    INFO("architecture description file version: 0.2, checking syntax...")
    if 'subtree' not in architecture_description:
        ERROR_CLEAN_EXIT(
            'v0.2 error: architecture description...',
            'Architecture tree nodes should be the value of top level key "subtree", '
            '"subtree" not found at top-level')
    # top-level subtree should only have one node
    ASSERT_MSG((
        isinstance(architecture_description['subtree'], list)
        and len(architecture_description['subtree']) == 1
    ), 'v0.2 error: top-level subtree must be a single element list that contains the design name'
               )
    if 'local' in architecture_description:
        ERROR_CLEAN_EXIT(
            'v0.2 error: architecture description...',
            'The first level list of your architecture description should only have a subtree, '
            'which is your design\'s root node')

    # design name syntax check
    raw_architecture_description = architecture_description['subtree'][0]
    if 'name' not in raw_architecture_description:
        ERROR_CLEAN_EXIT(
            "v0.2 error: architecture description...\n"
            "please specify the design name as top-level key-value pair =>  name: <design_name>"
        )
    design_name = raw_architecture_description['name']
    if 'local' in raw_architecture_description:
        ASSERT_MSG(
            isinstance(raw_architecture_description['local'], list),
            "v0.2 error: %s.local has to be a list of components" %
            design_name)
    if 'subtree' in raw_architecture_description:
        ASSERT_MSG(isinstance(raw_architecture_description['subtree'], list),
                   "v0.2 error: %s.subtree has to be a list" % design_name)
Beispiel #3
0
    def process_action_count_content(self, action_counts_list):
        if 'version' not in action_counts_list:
            ERROR_CLEAN_EXIT(
                'please specify the version of parser your input format adheres to using '
                '"version" key at top level')
        self.action_counts_version = action_counts_list['version']
        if action_counts_list['version'] == 0.2:
            ASSERT_MSG(
                'subtree' in action_counts_list
                or 'local' in action_counts_list,
                'v0.2 error: action counts... \n'
                'the action counts must contain the "subtree" key or "local" key at the top level'
            )
            # raw_action_counts = action_counts_list['subtree']
            # ASSERT_MSG(len(raw_action_counts) == 1, 'v0.2 error: action counts... \n'
            #                     'the first level list of your action counts should only have one node, '
            #                      'which is your design\'s root node')
            self.v02_flatten_action_count(None, action_counts_list)

        if action_counts_list['version'] == 0.1:
            raw_action_counts = action_counts_list['nodes']
            if 'nodes' not in action_counts_list:
                ERROR_CLEAN_EXIT(
                    'v0.1 error: action counts...\n Tree nodes should be the value of top level key "nodes", '
                    '"nodes" not found at top-level')
            if not len(raw_action_counts) == 1:
                ERROR_CLEAN_EXIT(
                    'the first level list of your action counts should only have one node, '
                    'which is your design\'s root node')
            self.design_name = raw_action_counts[0]['name']
            for node_description in raw_action_counts[0]['nodes']:
                self.v01_flatten_action_count(self.design_name,
                                              node_description)
def parse_expression_for_arithmetic(expression, binding_dictionary):
    """
    Expression contains the operands and the op type,
    binding dictionary contains the numerical values of the operands (if they are strings)
    """
    # parse for the supported arithmetic operations
    if '*' in expression:
        op_type = '*'
    elif '/' in expression:
        op_type = '/'
    elif '//' in expression:
        op_type = '//'
    elif '%' in expression:
        op_type = '%'
    elif '+' in expression:
        op_type = '+'
    elif '-' in expression:
        op_type = '-'
    elif 'log2(' and ')' in expression:
        op_type = 'log2'
    else:
        op_type = None

    # if the expression is an arithmetic operation
    if op_type is not None:

        if not op_type == 'log2':
            op1 = expression[:expression.find(op_type)].strip()
            op2 = expression[expression.find(op_type) + 1:].strip()

        # log2 only needs one operand, and needs to be processed differently
        else:
            op1 = expression[expression.find('(') + 1: expression.find(')')].strip()
            op2 = None

        if op1 in binding_dictionary:
            op1 = binding_dictionary[op1]
        else:
            try:
                op1 = int(op1)
            except ValueError:
                print('arithmetic expression:', expression, '\n',
                      'available operand-value binding:', binding_dictionary)
                ERROR_CLEAN_EXIT('arithmetic operation located, but cannot parse operand value')

        # if the operation needs 2 operands
        if op2 is not None:
            if op2 in binding_dictionary:
                op2 = binding_dictionary[op2]
            else:
                try:
                    op2 = int(op2)
                except ValueError:
                    ERROR_CLEAN_EXIT('arithmetic operation located, but cannot parse operand value')
    # if the expression is not an arithmetic operation
    else:
        op1 = None
        op2 = None
    return op_type, op1, op2
Beispiel #5
0
    def eval_subcomponent_action_for_ERT(self, subaction, subcomponent_info,
                                         upper_level_arguments,
                                         upper_level_attributes):
        subaction_copy = deepcopy(
            subaction)  # do not want to modify the class definitions
        aggregated_dict = deepcopy(upper_level_attributes)
        if upper_level_arguments is not None:
            aggregated_dict.update(deepcopy(upper_level_arguments))
        if 'arguments' in subaction and subaction_copy[
                'arguments'] is not None:  # if there is arguments, evaluate the arguments in terms of the compound action arguments
            for subarg_name, subarg_info in subaction_copy['arguments'].items(
            ):
                if type(subarg_info) is str:
                    try:
                        subaction_copy['arguments'][
                            subarg_name] = aggregated_dict[subarg_info]
                    except KeyError:
                        op_type, op1, op2 = parse_expression_for_arithmetic(
                            subarg_info, aggregated_dict)
                        if op_type is not None:
                            subaction_copy['arguments'][
                                subarg_name] = process_arithmetic(
                                    op1, op2, op_type)
                        else:
                            print(
                                'available compound arguments and attributes: ',
                                aggregated_dict)
                            print('primitive argument to for binding:',
                                  subarg_info)
                            ERROR_CLEAN_EXIT(
                                'subcomponent argument name cannot be ',
                                'mapped to upper class arguments', subarg_info)

        subcomponent_info['actions'] = [subaction_copy]
        is_subcomponent_primitive_class = self.is_primitive_class(
            subcomponent_info['class'])
        subaction_ERT = self.generate_component_ert(
            subcomponent_info, is_subcomponent_primitive_class)
        # the call is guaranteed to produce an ERT with 'energy' and 'argument' key
        subaction_energy = subaction_ERT[subaction_copy['name']]['energy']
        if type(subaction_energy) is not int and type(
                subaction_energy) is not float:
            ERROR_CLEAN_EXIT('Unusual estimated energy received for:',
                             subcomponent_info,
                             'Energy received: %s' % subaction_energy)
        # parse the repeat information of the subaction (if any)
        #     repeat can be int
        #                   binding to compound component arguments
        #                   binding to compound component attributes
        upper_level_binding = deepcopy(upper_level_attributes)
        if upper_level_arguments is not None:
            upper_level_binding.update(upper_level_arguments)
        parsed_repeat_info = EnergyReferenceTableGenerator.parse_repeat(
            subaction, upper_level_binding)
        subaction_energy *= parsed_repeat_info
        # print(subaction_ERT, parsed_repeat_info, subaction_energy)
        return round(subaction_energy, self.decimal_place)
Beispiel #6
0
def flatten_architecture_description(self,
                                     prefix,
                                     node_description,
                                     shared_attributes_dict=None):
    """ Recursively parse the nodes in the architecture tree"""
    # syntax error checks
    if 'name' not in node_description:
        ERROR_CLEAN_EXIT(
            'component format violation: "name" needs to be specified as a key in node description'
        )
    if 'class' in node_description and 'nodes' in node_description:
        ERROR_CLEAN_EXIT('class and nodes keys cannot exist in the same node')
    # extract basic information
    node_name = node_description['name']

    # construct the shared attributes that can be applied to sub-nodes
    # useful only if current node is internal
    if shared_attributes_dict is None and 'attributes' not in node_description:
        node_attrs = None
    elif shared_attributes_dict is not None and 'attributes' not in node_description:
        node_attrs = deepcopy(shared_attributes_dict)
    elif shared_attributes_dict is None and 'attributes' in node_description:
        node_attrs = node_description['attributes']
    else:  #shared_attributes_dict is not None and attributes in node_description
        node_attrs = deepcopy(shared_attributes_dict)
        node_attrs.update(node_description['attributes'])

    # determine if the component is in list format
    list_length, name_base = is_component_list(node_name,
                                               shared_attributes_dict)

    # if the component is in list format, flatten out and create the instances
    if not list_length == 0:
        for item_idx in range(list_length):
            item_prefix = prefix + '.' + name_base + '[' + str(item_idx) + ']'
            if 'nodes' in node_description:
                for sub_node_description in node_description['nodes']:
                    self.flatten_architecture_description(
                        item_prefix, sub_node_description, node_attrs)
            else:
                self.construct_new_leaf_node_description(
                    item_prefix, node_description, shared_attributes_dict)
    # if the component is a standalone component, parse the component description directly
    else:
        node_prefix = prefix + '.' + node_name
        if 'nodes' in node_description:
            for sub_node_description in node_description['nodes']:
                self.flatten_architecture_description(node_prefix,
                                                      sub_node_description,
                                                      node_attrs)
        else:
            self.construct_new_leaf_node_description(node_prefix,
                                                     node_description,
                                                     shared_attributes_dict)
Beispiel #7
0
def validate_primitive_classes(primitive_class_description):
    if type(primitive_class_description) is not dict:
        ERROR_CLEAN_EXIT('primitive class description should be a dictionary')

    if 'version' not in primitive_class_description:
        ERROR_CLEAN_EXIT('primitive class description no version found')

    if 'classes' not in primitive_class_description:
        ERROR_CLEAN_EXIT(
            'primitive class description no list of classes found')

    primitive_classes = primitive_class_description['classes']
    if type(primitive_classes) is not list:
        ERROR_CLEAN_EXIT(
            'primitive classes are not described in terms of a list')

    for primitive_class in primitive_classes:
        if type(primitive_class) is not dict:
            ERROR_CLEAN_EXIT(
                'each primitive class should be described as a dictionary')
        if 'name' not in primitive_class:
            ERROR_CLEAN_EXIT('primitive class name not found', primitive_class)
        if 'actions' not in primitive_class:
            ERROR_CLEAN_EXIT('primitive class actions not found',
                             primitive_class)
        if 'attributes' not in primitive_class:
            ERROR_CLEAN_EXIT('primitive class attributes not found',
                             primitive_class)
Beispiel #8
0
def process_arithmetic(op1, op2, op_type):
    """ Turns string expression into arithmetic operation"""
    if op_type == '*':
        result = op1 * op2
    elif op_type == '/':
        result = op1 / op2
    elif op_type == '//':
        result = op1 // op2
    elif op_type == '%':
        result = math.remainder(op1, op2)
    elif op_type == '-':
        result = int(op1 - op2)
    elif op_type == '+':
        result = int(op1 + op2)
    elif op_type == 'log2':
        result = int(math.ceil(math.log2(op1)))
    elif op_type == 'round':
        result = int(round(op1 / op2,
                           0))  # round according to the first decimal
    elif op_type == 'round_up':
        result = int(math.ceil(op1 / op2))
    else:
        result = None
        ERROR_CLEAN_EXIT('wrong op_type')
    return result
def v02_tree_node_classification(self, node_description, prefix, node_attrs):
    if 'subtree' in node_description:
        ASSERT_MSG(isinstance(node_description['subtree'], list),
                   "v0.2 error: %s.subtree has to be a list" % prefix)
        self.flatten_architecture_subtree(prefix, node_description['subtree'],
                                          node_attrs)

    if 'local' in node_description:
        ASSERT_MSG(
            isinstance(node_description['local'], list),
            "v0.2 error: %s.local has to be a list of components" % prefix)
        for c_id in range(len(node_description['local'])):
            local_node_list_length, local_node_name_base = v02_is_component_list(
                node_description['local'][c_id]['name'], node_attrs)
            if not local_node_list_length == 0:
                for local_node_list_item_idx in range(local_node_list_length):
                    local_node_name = prefix + '.' + local_node_name_base + '[' + str(
                        local_node_list_item_idx) + ']'
                    self.construct_new_leaf_node_description(
                        local_node_name, node_description['local'][c_id],
                        node_attrs)
            else:
                local_node_name = prefix + '.' + node_description['local'][
                    c_id]['name']
                self.construct_new_leaf_node_description(
                    local_node_name, node_description['local'][c_id],
                    node_attrs)
    if 'subtree' not in node_description and 'local' not in node_description:
        ERROR_CLEAN_EXIT('v0.2 error: architecture description...',
                         'Unrecognized tree node type', node_description)
Beispiel #10
0
 def eval_primitive_action_energy(self, estimator_plug_in_interface):
     """
     :param estimator_plug_in_interface: dictionary that adheres to
            Accelergy-external estimator interface format
     :return energy estimation of the action
     """
     best_accuracy = 0
     best_estimator = None
     for estimator in self.estimator_plug_ins:
         accuracy = estimator.primitive_action_supported(
             estimator_plug_in_interface)
         ASSERT_MSG(
             type(accuracy) is int or type(accuracy) is float,
             'Wrong plug-in accuracy: %s ...  Returned accuracy must be integers or floats'
             % (estimator))
         if accuracy > best_accuracy:
             best_accuracy = accuracy
             best_estimator = estimator
     if best_estimator is None:
         ERROR_CLEAN_EXIT('cannot find estimator plug-in:',
                          estimator_plug_in_interface,
                          'Available plug-ins:', self.estimator_plug_ins)
     energy = round(
         best_estimator.estimate_energy(estimator_plug_in_interface),
         self.decimal_place)
     if self.verbose:
         INFO('Received energy estimation for primitive class:\n',
              estimator_plug_in_interface, '\n estimated by:',
              best_estimator, ' ---> estimated energy:', str(energy), 'pJ')
     return energy
Beispiel #11
0
    def process_component_action_counts(self, action_count_list,
                                        component_ERT):
        component_total_energy = 0
        for action_count in action_count_list:
            action_name = action_count['name']
            action_args = action_count['arguments'] if 'arguments' in action_count\
                                                    else None
            count = action_count['counts']

            energy = None
            for name, ERT_info in component_ERT.items():
                if action_name == name:
                    if action_args is not None:
                        for arg_combo in ERT_info:
                            args_matched = True
                            for action_arg, action_arg_val in action_args.items(
                            ):
                                if not arg_combo['arguments'][
                                        action_arg] == action_arg_val:
                                    args_matched = False
                            if args_matched:
                                energy = arg_combo['energy']
                    else:
                        energy = ERT_info['energy']
            if energy is None:
                ERROR_CLEAN_EXIT(
                    ['cannot find the action in related ERT', action_count])
            component_total_energy += count * energy
        return component_total_energy
Beispiel #12
0
    def parse_repeat(action, upper_level_binding):
        """
        evaluates the values of repeat of a sub-component action
        - default value of repeat is 1
        - string bindings are allowed, and bindings can be from:
            1. compound attributes
            2. compound action arguments (its own upper-level action)
        - arithemtic operations are allowed in specifying repeat value

        """
        if 'repeat' in action and action['repeat'] is not None:
            if type(action['repeat']) is not int:
                op_type, op1, op2 = parse_expression_for_arithmetic(
                    action['repeat'], upper_level_binding)
                if op_type is not None:
                    parsed_repeat = process_arithmetic(op1, op2, op_type)

                else:
                    if action['repeat'] in upper_level_binding:
                        parsed_repeat = upper_level_binding[action['repeat']]
                    else:
                        parsed_repeat = None
                        ERROR_CLEAN_EXIT(
                            'repeat value for primitive action cannot be parsed, ',
                            'no binding found in compound arguments/ attributes',
                            action)

                return parsed_repeat
            # return the actual value if repeat is an integer
            return action['repeat']
        # default repeat value is 1
        return 1
Beispiel #13
0
 def parse_arg_range(arg_range):
     if type(arg_range) is not str or '..' not in arg_range:
         ERROR_CLEAN_EXIT('cannot parse the argument range specification: ',
                          arg_range)
     split_sub_string = arg_range.split('..')
     start_idx = int(split_sub_string[0])
     end_idx = int(split_sub_string[1])
     return start_idx, end_idx
Beispiel #14
0
    def map_arg_range_bounds(self, arg_range_str, attributes_dict):
        """
        arguments for compound actions might have ranges that are specified in terms of it attributes
        parses the argument ranges in the format int/str..int/str, where str can be arithmetic operation

        :param arg_range_str: string that decribes the range of a compound action
        :param attributes_dict: attribute name-value pairs of the compound component
        :return: parsed argument range, whether there was binding
        """
        split_sub_string = arg_range_str.split('..')
        detect_arg_range_binding = False

        # process the start index
        try:
            start_idx = int(split_sub_string[0])
        except ValueError:
            op_type, op1, op2 = parse_expression_for_arithmetic(
                split_sub_string[0], attributes_dict)
            if op_type is not None:
                start_idx = process_arithmetic(op1, op2, op_type)
            else:
                if split_sub_string[0] not in attributes_dict:
                    ERROR_CLEAN_EXIT('cannot find mapping from', arg_range_str,
                                     'to', attributes_dict)
                start_idx = attributes_dict[split_sub_string[0]]
            detect_arg_range_binding = True

        # process the end index
        try:
            end_idx = int(split_sub_string[1])
        except ValueError:
            op_type, op1, op2 = parse_expression_for_arithmetic(
                split_sub_string[1], attributes_dict)
            if op_type is not None:
                end_idx = process_arithmetic(op1, op2, op_type)
            else:
                if split_sub_string[1] not in attributes_dict:
                    ERROR_CLEAN_EXIT('cannot find mapping from', arg_range_str,
                                     'to', attributes_dict)
                end_idx = attributes_dict[split_sub_string[1]]
            detect_arg_range_binding = True

        new_arg_range_str = str(start_idx) + '..' + str(end_idx)

        return new_arg_range_str, detect_arg_range_binding
def config_file_v02():
    possible_config_dirs = [
        '.' + os.sep,
        os.path.expanduser('~') + '/.config/accelergy/'
    ]
    config_file_name = 'accelergy_config.yaml'
    for possible_dir in possible_config_dirs:
        if os.path.exists(possible_dir + config_file_name):
            original_config_file_path = possible_dir + config_file_name
            original_content = load(open(original_config_file_path),
                                    accelergy_loader)
            INFO('config file located:', original_config_file_path)
            print('config file content: \n', original_content)
            if 'version' not in original_content:
                ERROR_CLEAN_EXIT(
                    'config file has no version number, cannot proceed')
            file_version = original_content['version']
            if file_version == 0.1 or file_version == 1.0:  # probably exist 1.0 in the very initial version
                ERROR_CLEAN_EXIT(
                    'config file version outdated. Latest version is 0.2.'
                    '\nPlease delete the original file, and run accelergy to create a new default config file.'
                    '\nPlease ADD YOUR USER_DEFINED file paths BACK to the updated config file at '
                    '~/.config/accelergy/accelergy_config.yaml')
            else:
                return original_content
    else:
        create_folder(possible_config_dirs[1])
        config_file_path = possible_config_dirs[1] + config_file_name
        curr_file_path = os.path.abspath(__file__)
        accelergy_share_folder_path = os.path.abspath(
            curr_file_path + '../../../../../../share/accelergy/')
        default_estimator_path = os.path.abspath(accelergy_share_folder_path +
                                                 '/estimation_plug_ins/')
        default_pc_lib_path = os.path.abspath(accelergy_share_folder_path +
                                              '/primitive_component_libs/')
        config_file_content = {
            'version': 0.2,
            'estimator_plug_ins': [default_estimator_path],
            'primitive_components': [default_pc_lib_path]
        }
        INFO('Accelergy creating default config at:',
             possible_config_dirs[1] + config_file_name, 'with:\n',
             config_file_content)
        write_yaml_file(config_file_path, config_file_content)
        return config_file_content
def check_subcomponent_name_in_action_def(action_def, subcomponent_names):
    for sub_component in action_def['subcomponents']:
        sub_cname = sub_component['name']
        if sub_cname not in subcomponent_names:
            ERROR_CLEAN_EXIT(
                'v0.2 error: compound class description...\n',
                'Cannot parse action "%s"\n' % action_def['name'],
                'Cannot find "%s" in compound component definition' %
                sub_cname)
Beispiel #17
0
 def construct_save_architecture_description(self):
     if 'version' not in self.raw_architecture_description:
         ERROR_CLEAN_EXIT(
             'please specify the version of parser your input format adheres to using '
             '"version" key at top level')
     self.arch_version = self.raw_architecture_description['version']
     architecture_description_parser = 'v' + str(self.arch_version).replace('.', '') + \
                              '_parse_architecture_description'
     getattr(self, architecture_description_parser)(
         self.raw_architecture_description)
Beispiel #18
0
    def construct_action_counts(self, action_counts_list):
        if 'version' not in action_counts_list:
            ERROR_CLEAN_EXIT(
                'please specify the version of parser your input format adheres to using '
                '"version" key at top level')
        if 'nodes' not in action_counts_list:
            ERROR_CLEAN_EXIT(
                'action counts tree nodes should be the value of top level key "nodes", '
                '"nodes" not found at top-level')
        raw_action_counts = action_counts_list['nodes']

        if not len(raw_action_counts) == 1:
            ERROR_CLEAN_EXIT(
                'the first level list of your action counts should only have one node, '
                'which is your design\'s root node')

        self.design_name = raw_action_counts[0]['name']
        for node_description in raw_action_counts[0]['nodes']:
            self.flatten_action_count(self.design_name, node_description)
Beispiel #19
0
    def v01_flatten_action_count(self, prefix, node_description):
        # syntax error checks
        if 'name' not in node_description:
            ERROR_CLEAN_EXIT(
                'component format violation: "name" needs to be specified as a key in node description'
            )
        if 'action_counts' in node_description and 'nodes' in node_description:
            ERROR_CLEAN_EXIT(
                'action_counts and nodes keys cannot exist in the same node')
        # extract basic information
        node_name = node_description['name']
        if 'action_counts' in node_description:
            full_name = prefix + '.' + node_name
            self.action_counts[full_name] = node_description['action_counts']

        else:
            prefix = prefix + '.' + node_name
            for sub_node_description in node_description['nodes']:
                self.v01_flatten_action_count(prefix, sub_node_description)
Beispiel #20
0
def v01_validate_top_level_architecture_description(
        architecture_description_list):
    INFO("architecture description file version: 0.1")
    if 'nodes' not in architecture_description_list:
        ERROR_CLEAN_EXIT('v0.1 error: architecture description...',
                         '"nodes" not found at top-level')
    if not len(architecture_description_list['nodes']) == 1:
        ERROR_CLEAN_EXIT(
            'v0.1 error: architecture description...',
            'The first level list of your architecture description should only have one node, '
            'which is your design\'s root node')
    raw_architecture_description = architecture_description_list['nodes'][0]
    if 'nodes' not in raw_architecture_description:
        ERROR_CLEAN_EXIT('v0.1 error: architecture description...',
                         'second-level design tree must contain nodes')
    # design name syntax check
    if 'name' not in raw_architecture_description:
        ERROR_CLEAN_EXIT(
            "v0.1 error: architecture description..."
            "please specify the design name as top-level key-value pair =>  name: <design_name>"
        )
def rename_subcomponent_name_in_action_def(action_def,
                                           subcomponent_list_base_names,
                                           subcomponent_names):
    for sub_component in action_def['subcomponents']:
        sub_cname = sub_component['name']
        if sub_cname not in subcomponent_names:
            if sub_cname in subcomponent_list_base_names:
                sub_component['name'] = sub_cname + '[0]'
            else:
                ERROR_CLEAN_EXIT(
                    'v0.2 error: compound class description...',
                    'Cannot find corresponding sub_component in the action definition',
                    action_def)
Beispiel #22
0
 def belongs_to_list(name):
     if '[' and ']' in name:
         start_idx = name.find('[')
         end_idx = name.find(']')
         index = name[start_idx + 1:end_idx]
         try:
             int(index)
         except TypeError:
             ERROR_CLEAN_EXIT(
                 'list node located, but cannot parse for index')
         name_base = name[:start_idx]
         return name_base
     else:
         return name
Beispiel #23
0
def v02_check_subcomponent_name_in_action_def(self, action_def,
                                              subcomponent_names,
                                              compound_attributes):
    returned_action_def = deepcopy(action_def)
    new_subcomponents = deepcopy(action_def['subcomponents'])
    for sub_component in returned_action_def['subcomponents']:
        sub_cname = sub_component['name']
        # check if the subcomponent name is a list
        list_length, name_base = v02_is_component_list(sub_cname,
                                                       compound_attributes)
        if list_length == -1:
            new_subcomponents.remove(sub_component)
            # WARN(sub_cname, ' in "', returned_action_def['name'],
            #      '" interpreted as negative list length --> subcomponent ignored')
        elif name_base is not None:
            new_subcomponents.remove(sub_component)
            for item_idx in range(list_length):
                new_sub_cname = name_base + '[' + str(item_idx) + ']'
                new_sub_comp = deepcopy(sub_component)
                new_sub_comp['name'] = new_sub_cname
                new_subcomponents.append(new_sub_comp)
                if new_sub_cname not in subcomponent_names:
                    ERROR_CLEAN_EXIT(
                        'v0.2 error: compound class description...\n',
                        'Cannot parse action "%s"\n' %
                        returned_action_def['name'],
                        'Cannot find "%s" in compound component definition' %
                        new_sub_cname)
        else:
            if sub_cname not in subcomponent_names:
                ERROR_CLEAN_EXIT(
                    'v0.2 error: compound class description...\n',
                    'Cannot parse action "%s"\n' % returned_action_def['name'],
                    'Cannot find "%s" in compound component definition' %
                    sub_cname)
    returned_action_def['subcomponents'] = new_subcomponents
    return returned_action_def
Beispiel #24
0
def validate_estimator_API(estimatorAPI):

    if not type(estimatorAPI) is dict:
        ERROR_CLEAN_EXIT('estimatorAPI is not a dictionary', estimatorAPI)

    if 'version' not in estimatorAPI:
        ERROR_CLEAN_EXIT('estimatorAPI no version found', estimatorAPI)

    estimator_info = None
    for key, val in estimatorAPI.items():
        if not key == 'version':
            estimator_info = val
    if estimator_info is None:
        ERROR_CLEAN_EXIT('estimatorAPI contains no estimator information',
                         estimatorAPI)

    if 'module' not in estimator_info:
        ERROR_CLEAN_EXIT(
            'no module specified in esitmatorAPI '
            '(module value should be the same as esimtator python wrapper file name)',
            estimatorAPI)

    if 'class' not in estimator_info:
        ERROR_CLEAN_EXIT('no class specified in estimatorAPI', estimatorAPI)
Beispiel #25
0
 def extract_ERT(self, raw_ERT):
     if 'version' not in raw_ERT:
         self.energy_reference_table = raw_ERT
     else:
         ASSERT_MSG(
             'version' in raw_ERT,
             'v>=0.2 error: ERT ... \n ERT must contain "version" key')
         ASSERT_MSG(
             'tables' in raw_ERT,
             'v>=0.2 error: ERT ... \n ERT must contain "tables" key')
         ERT_version = raw_ERT['version']
         if ERT_version <= 0.2:
             self.energy_reference_table = raw_ERT['tables']
         else:
             ERROR_CLEAN_EXIT('ERT version: ', ERT_version,
                              'no parser available...')
Beispiel #26
0
 def v02_flatten_action_count(self, prefix, node_description):
     # syntax error checks
     if 'name' not in node_description:
         ERROR_CLEAN_EXIT(
             'component format violation: "name" needs to be specified as a key in node description'
         )
     # extract basic information
     # node_base_name = EnergyCalculator.belongs_to_list(node_name)
     if 'local' in node_description:
         local_nodes = node_description['local']
         for local_node in local_nodes:
             full_name = prefix + '.' + local_node['name']
             self.action_counts[full_name] = local_node['action_counts']
     if 'subtree' in node_description:
         for subtree_node_description in node_description['subtree']:
             subtree_prefix = prefix + '.' + subtree_node_description['name']
             self.v02_flatten_action_count(subtree_prefix,
                                           subtree_node_description)
def flatten_architecture_subtree(
        self,
        prefix,
        subtree_description,
        shared_attributes_dict=None):  # For version 0.2
    ASSERT_MSG(
        isinstance(subtree_description, list),
        'v0.2 error: architecture description...\n %s.subtree needs to be a list'
        % prefix)
    for subtree_item_description in subtree_description:
        if 'name' not in subtree_item_description:
            ERROR_CLEAN_EXIT(
                'v0.2 error: architecture description...',
                ' "name" needs to be specified as a key in node description',
                subtree_item_description)

        if shared_attributes_dict is None and 'attributes' not in subtree_item_description:
            node_attrs = None
        elif shared_attributes_dict is not None and 'attributes' not in subtree_item_description:
            node_attrs = deepcopy(shared_attributes_dict)
        elif shared_attributes_dict is None and 'attributes' in subtree_item_description:
            node_attrs = subtree_item_description['attributes']
        else:  #shared_attributes_dict is not None and attributes in node_description
            node_attrs = deepcopy(shared_attributes_dict)
            node_attrs.update(subtree_item_description['attributes'])

        node_name = subtree_item_description['name']
        # determine if the component is in list format
        list_length, name_base = v02_is_component_list(node_name,
                                                       shared_attributes_dict)
        # if the component is in list format, flatten out and create the instances
        if not list_length == 0:
            for item_idx in range(list_length):
                item_prefix = prefix + '.' + name_base + '[' + str(
                    item_idx) + ']'
                self.v02_tree_node_classification(subtree_item_description,
                                                  item_prefix, node_attrs)

        # if the component is a standalone component, parse the component description directly
        else:
            item_prefix = prefix + '.' + node_name
            self.v02_tree_node_classification(subtree_item_description,
                                              item_prefix, node_attrs)
Beispiel #28
0
    def eval_subcomponent_action_for_ERT(self, subaction, subcomponent_info,
                                         upper_level_arguments,
                                         upper_level_attributes):
        subaction_copy = deepcopy(
            subaction)  # do not want to modify the class definitions
        if 'arguments' in subaction and subaction_copy[
                'arguments'] is not None:  # if there is arguments, evaluate the arguments in terms of the compound action arguments
            for subarg_name, subarg_info in subaction_copy['arguments'].items(
            ):
                if type(subarg_info) is str:
                    try:
                        subaction_copy['arguments'][
                            subarg_name] = upper_level_arguments[subarg_info]
                    except KeyError:
                        print('available compound arguments: ',
                              upper_level_arguments)
                        print('primitive argument to for binding:',
                              subarg_info)
                        ERROR_CLEAN_EXIT(
                            'subcomponent argument name cannot be ',
                            'mapped to upper class arguments', subarg_info)

        subcomponent_info['actions'] = [subaction_copy]
        is_subcomponent_primitive_class = self.is_primitive_class(
            subcomponent_info['class'])
        subaction_ERT = self.generate_component_ert(
            subcomponent_info, is_subcomponent_primitive_class)
        # the call is guaranteed to produce an ERT with 'energy' and 'argument' key
        subaction_energy = subaction_ERT[subaction_copy['name']]['energy']
        # parse the repeat information of the subaction (if any)
        #     repeat can be int
        #                   binding to compound component arguments
        #                   binding to compound component attributes
        upper_level_binding = deepcopy(upper_level_attributes)
        if upper_level_arguments is not None:
            upper_level_binding.update(upper_level_arguments)

        parsed_repeat_info = EnergyReferenceTableGenerator.parse_repeat(
            subaction, upper_level_binding)
        subaction_energy *= parsed_repeat_info
        # print(subaction_ERT, parsed_repeat_info, subaction_energy)
        return subaction_energy
Beispiel #29
0
 def eval_primitive_action_energy(self, estimator_plug_in_interface):
     """
     :param estimator_plug_in_interface: dictionary that adheres to
            Accelergy-external estimator interface format
     :return energy estimation of the action
     """
     best_accuracy = 0
     best_estimator = None
     for estimator in self.estimator_plug_ins:
         accuracy = estimator.primitive_action_supported(
             estimator_plug_in_interface)
         if accuracy > best_accuracy:
             best_accuracy = accuracy
             best_estimator = estimator
     if best_estimator is None:
         ERROR_CLEAN_EXIT('cannot find estimator plug-in:',
                          estimator_plug_in_interface,
                          self.estimator_plug_ins)
     energy = best_estimator.estimate_energy(estimator_plug_in_interface)
     return energy
Beispiel #30
0
def v02_compound_component_constructor(self, compound_component_info):
    """
    given the physical information of a compound component, the compound component object is constructed according
    to its compound classes, all compound properties are fully resolved and subcomponent definitions are included
    1. compound attributes are all assigned with values
    2. compound action argument ranges are all assigned values/ compound action arguments are static values
    3. subcomponent attributes values are assigned, as they only depend on compound attributes
        - subcomponent attributes can be:
            1. numbers
            2. string bindings to compound component attributes
            3. arithmetic operations that contain string bindings and numbers
    3. subcomponent definition of the compound actions are included

    :param compound_component_info: physical specification of a compound component
    :return: fully defined compound component
    """
    compound_component_name = compound_component_info['name']
    compound_class_info = self.compound_class_description[
        compound_component_info['class']]
    compound_component_definition = deepcopy(
        compound_class_info)  # a copy of default class definition
    compound_component_definition['class'] = compound_component_info['class']
    compound_component_definition['attributes'] = deepcopy(
        compound_component_info['attributes'])

    # fully defined attribute values
    compound_attributes = compound_component_definition['attributes']

    # process subcomponent name format
    #     if subcomponent is a list, expand the list of subcomponents (list tail index can be arithmetic operantions)
    #     else keep the subcomponent name

    subcomponents = deepcopy(compound_component_definition['subcomponents'])
    # check if any sub-compound-component attribute is not specified in the top-level, apply defualt value specified
    # in the class definition

    list_of_new_components = []
    list_of_to_remove_components = []

    for subcomponent_idx in range(len(subcomponents)):
        subcomponent = subcomponents[subcomponent_idx]
        list_length, subcomponent_name_base = v02_is_component_list(
            subcomponent['name'], compound_attributes)
        if subcomponent_name_base is not None:
            list_of_to_remove_components.append(subcomponent)
            # INFO('list component name: ', subcomponent['name'], 'detected in compound class: ', compound_component_info['class'])
            for i in range(list_length):
                new_component = deepcopy(subcomponent)
                new_component['name'] = subcomponent_name_base + '[' + str(
                    i) + ']'
                list_of_new_components.append(new_component)
    for comp in list_of_to_remove_components:
        subcomponents.remove(comp)
    for comp in list_of_new_components:
        subcomponents.append(comp)

    # process the subcomponent attribute values
    # subcomponent attributes can be:
    #     1. numbers
    #     2. string bindings to compound component attributes
    #     3. arithmetic operations that contain string bindings and numbers
    compound_component_definition['subcomponents'] = {}
    for subcomponent in subcomponents:
        subcomponent_name = subcomponent['name']
        sub_component_attributes = subcomponent['attributes']
        for sub_attr_name, sub_attr_val in sub_component_attributes.items():
            if type(sub_attr_val) is str:
                # subcomponent attributes can be computed in terms of upper-level compound attributes
                op_type, op1, op2 = parse_expression_for_arithmetic(
                    sub_attr_val, compound_attributes)
                if op_type is not None:
                    sub_component_attributes[
                        sub_attr_name] = process_arithmetic(op1, op2, op_type)
                    # INFO(compound_component_name, 'sub-attribute', sub_attr_name, 'processed as arithmetic operation')
                else:
                    try:
                        sub_component_attributes[
                            sub_attr_name] = compound_attributes[sub_attr_val]
                        # INFO(compound_component_name, 'sub-attribute', sub_attr_name,'processed as binding')
                    except KeyError:
                        ERROR_CLEAN_EXIT(
                            'cannot find bindings from upper-level attribute names',
                            '{', sub_attr_name, ':', sub_attr_val, '}')
        # process default sub-component-component attribute values that are not specified in the top-level
        # default values can be :
        #   (1) numerical values
        #   (2) arithmetic operations of other sub-compound-component attribute values
        sub_class = subcomponent['class']
        if sub_class in self.compound_class_description:
            sub_class_description = deepcopy(
                self.compound_class_description[sub_class])
            for attr_name, default_attr_val in sub_class_description[
                    'attributes'].items():
                if attr_name not in subcomponent['attributes']:
                    if type(default_attr_val) is str:
                        op_type, op1, op2 = parse_expression_for_arithmetic(
                            default_attr_val, subcomponent['attributes'])
                        if op_type is not None:
                            default_attr_val = process_arithmetic(
                                op1, op2, op_type)
                            # INFO(compound_component_name, 'sub-attribute', sub_attr_name, 'processed as arithmetic operation')
                        else:
                            try:
                                default_attr_val = subcomponent['attributes'][
                                    default_attr_val]
                                # INFO(compound_component_name, 'sub-attribute', sub_attr_name,'processed as binding')
                            except KeyError:
                                WARN(
                                    'did not find bindings of the specified default attribute value for class: ',
                                    sub_class, '---> {', attr_name, ':',
                                    default_attr_val, '}, '
                                    '   Keep the original specifications')
                    subcomponent['attributes'][attr_name] = default_attr_val
        compound_component_definition['subcomponents'][
            subcomponent_name] = subcomponent
        # check if the subcomponent name is a list
        # list_length, name_base = v02_is_component_list(subcomponent_name, compound_attributes)
        # if subcomponent_name == 'Y_memory_controller[0..total_PEs-1]':
        #     print('----------------------', list_length, name_base)
        # if name_base is None:
        #     compound_component_definition['subcomponents'][subcomponent_name] = subcomponent
        # else:
        #     for item_idx in range(list_length):
        #         new_subcomponent_name = name_base + '[' + str(item_idx) + ']'
        #         compound_component_definition['subcomponents'][new_subcomponent_name] = deepcopy(subcomponent)

    # top-level compound component will not have 'actions' specified in the component info
    #      because accelergy needs to generate the energy values for all possible actions (and arguments)
    # the actions in the component class description is therefore processed
    #     action arguments can be:
    #             1. numbers
    #             2. string bindings to compound attributes (its own attributes)
    #     action arguments cannot be arithmetic operations
    if 'actions' not in compound_component_info:
        # if there is no actions specified in the compound component info
        compound_actions = compound_component_definition['actions']
        for c_action in compound_actions:
            c_action_name = c_action['name']
            if 'arguments' in c_action:
                c_action_args = c_action['arguments']
                for c_action_arg_name, c_action_arg_range in c_action_args.items(
                ):
                    c_action_args[c_action_arg_name], detect_arg_range_binding = \
                        self.map_arg_range_bounds(c_action_arg_range, compound_attributes)
                    if detect_arg_range_binding:
                        INFO(compound_component_name, 'action:', c_action_name,
                             'arg:', c_action_arg_name,
                             'range interpreted as:',
                             c_action_args[c_action_arg_name])
    # low-level compound components will have 'actions' assigned, since top-level action will be interpreted as
    # one or more defined low-level compound action
    #     no change should be added as the action arguments should be defined already, so the required action list
    #     from component info is copied, with the definition of the action retrieved from class description
    else:
        compound_component_definition['actions'] = deepcopy(
            compound_component_info['actions'])
        for action in compound_component_definition['actions']:
            action_name = action['name']
            for class_action_def in compound_class_info['actions']:
                if class_action_def['name'] == action_name:
                    action['subcomponents'] = deepcopy(
                        class_action_def['subcomponents'])
    return compound_component_definition