Beispiel #1
0
 def construct_primitive_class_description(self):
     """
     construct a dictionary for primitive classes Accelergy
     primitive class file paths are specified in config file
     """
     # load in the stored primitive classes
     primitive_class_paths = self.config['primitive_components']
     for pc_path in primitive_class_paths:
         print(pc_path)
         # primitive component library file is directly specified
         if '.yaml' in pc_path:
             self.expand_primitive_component_lib_info(pc_path)
         else:
             # primitive component dir is specified, need recursive search
             for root, directories, file_names in os.walk(pc_path):
                 for file_name in file_names:
                     if '.lib.yaml' in file_name:
                         pc_path = root + os.sep + file_name
                         primitive_component_list = load(
                             open(pc_path), accelergy_loader)
                         syntax_validators.validate_primitive_classes(
                             primitive_component_list)
                         for idx in range(
                                 len(primitive_component_list['classes'])):
                             pc_name = primitive_component_list['classes'][
                                 idx]['name']
                             if pc_name in self.primitive_class_description:
                                 WARN(pc_name, 'redefined in', pc_path)
                             self.primitive_class_description[
                                 pc_name] = primitive_component_list[
                                     'classes'][idx]
                         INFO('primitive component file parsed: ', pc_path)
Beispiel #2
0
def v02_is_component_list(name, binding_dictionary=None):
    """
    determines if the component is a list according to its name
    if not, return 0; if yes, return list length
    it is possible that the last index of the list involves direct binding or arithmetical operations
    (operands could be strings that are keys in binding dictionary)
    """
    left_bracket_idx = name.find('[')
    range_flag = name.find('..')
    if left_bracket_idx == -1 or range_flag == -1:
        return 0, None
    else:
        if ']' not in name:
            WARN(name, ': located [ and .. but not ], typo?')
        else:
            name_base = name[:left_bracket_idx]
            right_bracket_idx = name.find(']')
            list_start_idx = str_to_int(name[left_bracket_idx + 1:range_flag],
                                        binding_dictionary)
            list_end_idx = str_to_int(name[range_flag + 2:right_bracket_idx],
                                      binding_dictionary)
            list_length = list_end_idx - list_start_idx + 1
            if list_end_idx < list_start_idx:
                list_length = -1
            return list_length, name_base
def v02_is_component_list(name, binding_dictionary=None):
    """
    determines if the component is a list according to its name
    if not, return 0; if yes, return list length
    it is possible that the last index of the list involves direct binding or arithmetical operations
    (operands could be strings that are keys in binding dictionary)
    """
    start_idx = name.find('[')
    if start_idx == -1:
        return 0, None
    else:
        if ']' not in name:
            WARN(name, ': located [ but not ], typo?')
        else:
            name_base = name[:start_idx]
            end_idx = name.find(']')
            n = name[start_idx + 1:end_idx]
            # check if the tail involves arithmetic operations
            optype, op1, op2 = parse_expression_for_arithmetic(
                n, binding_dictionary)
            if optype is None:
                if n in binding_dictionary:
                    # tail is a direct binding, directly retrieve the numerical value
                    n = binding_dictionary[n]
                list_length = int(n)
            else:
                list_length = int(process_arithmetic(op1, op2, optype))
            return list_length, name_base
Beispiel #4
0
    def generate_estimations(self,
                             action_counts_path,
                             ERT_path,
                             output_path,
                             precision,
                             flattened_arch_path=None):
        print('\n=========================================')
        print('Generating energy estimation')
        print('=========================================')
        # load and parse access counts
        self.energy_reference_table = load(open(ERT_path), accelergy_loader)
        self.construct_action_counts(
            load(open(action_counts_path), accelergy_loader))
        self.decimal_points = precision
        INFO('design under evaluation:', self.design_name)
        INFO('processing action counts file:',
             os.path.abspath(action_counts_path))
        if flattened_arch_path is None:
            WARN(
                'flattened architecture is not given, will not perform legal component name check'
            )
        else:
            self.flattened_list = {}
            self.load_flattened_arch(flattened_arch_path)

        for name, action_count_list in self.action_counts.items():
            INFO('processing for component:', name)
            # the components in the list are stored differently in ERT
            processed_name = self.process_name(name)
            component_ERT = self.energy_reference_table[processed_name]
            # generate the total energy for the component
            component_energy = self.process_component_action_counts(
                action_count_list, component_ERT)
            self.energy_estimation_table[name] = round(component_energy,
                                                       self.decimal_points)

        # save results
        file_path = output_path + '/estimation.yaml'
        write_yaml_file(file_path, self.energy_estimation_table)
        print(
            '---> Finished: energy calculation finished, estimation saved to:\n',
            os.path.abspath(output_path))
Beispiel #5
0
    def generate_estimations(self, araw_action_counts, raw_ERT, output_path,
                             precision, raw_flattened_arch):
        print('\n=========================================')
        print('Generating energy estimation')
        print('=========================================')
        # load and parse access counts
        self.extract_ERT(raw_ERT['ERT'])
        self.construct_action_counts(araw_action_counts)
        self.decimal_points = precision
        if raw_flattened_arch is None:
            WARN(
                'flattened architecture is not given or --enable_flattened_arch not set high, will not perform legal component name check'
            )
        else:
            self.flattened_list = {}
            self.load_flattened_arch(
                raw_flattened_arch['flattened_architecture']['components'])

        for name, action_count_list in self.action_counts.items():
            INFO('processing for component:', name)
            # the components in the list are stored differently in ERT
            processed_name = self.process_name(name)
            component_ERT = self.energy_reference_table[processed_name]
            # generate the total energy for the component
            component_energy = self.process_component_action_counts(
                action_count_list, component_ERT)
            self.energy_estimation_table[name] = round(component_energy,
                                                       self.decimal_points)

        # save results
        file_path = output_path + '/estimation.yaml'
        write_yaml_file(
            file_path, {
                'energy_estimation': {
                    'components': self.energy_estimation_table,
                    'version': self.action_counts_version
                }
            })
        print(
            '---> Finished: energy calculation finished, estimation saved to:\n',
            os.path.abspath(output_path))
def v02_check_subcomponent_name_in_action_def(self, action_def,
                                              subcomponent_names,
                                              compound_attributes):
    new_subcomponents = deepcopy(action_def['subcomponents'])
    for sub_component in 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 "', 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' % 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' % action_def['name'],
                    'Cannot find "%s" in compound component definition' %
                    sub_cname)
    action_def['subcomponents'] = new_subcomponents
    return action_def
Beispiel #7
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
Beispiel #8
0
def interpret_input_path(path_arglist):
    raw_architecture_description = None
    raw_compound_class_description = None
    raw_action_counts = None
    raw_ERT = None
    raw_flattened_arch = None

    available_keys = [
        'architecture', 'compound_components', 'action_counts', 'ERT',
        'flattened_architecture'
    ]

    for file_path in path_arglist:

        file = load(open(file_path), accelergy_loader)
        for key in file:

            if key == 'architecture':
                content = file[key]
                #-------------------------------------------------------------------------
                # check syntax of input file
                #-------------------------------------------------------------------------
                ASSERT_MSG(
                    'version' in content,
                    'File content not legal: %s, %s must contain '
                    '"version" key' % (file_path, key))
                tree_root_name = None
                if content['version'] == 0.1:
                    tree_root_name = 'nodes'
                if content['version'] == 0.2:
                    tree_root_name = 'subtree'
                ASSERT_MSG(
                    tree_root_name is not None, 'File content not legal: %s, '
                    'version %s not supported' %
                    (file_path, content['version']))
                ASSERT_MSG(
                    tree_root_name in content,
                    'File content not legal: %s, architecture description must contain %s key'
                    % (file_path, tree_root_name))
                ASSERT_MSG(
                    type(content[tree_root_name]) is list,
                    'File content not legal: %s, %s key must have value of type list'
                    % (file_path, tree_root_name))
                #-------------------------------------------------------------------------
                # merge input file
                #-------------------------------------------------------------------------
                if raw_architecture_description is None:
                    raw_architecture_description = {'architecture': file[key]}
                else:
                    ERROR_CLEAN_EXIT(
                        'File content not legal: %s. '
                        '\n Second architecture description detected... '
                        'Only one architecture is allowed...' % (file_path))
                    # ASSERT_MSG(raw_architecture_description['architecture']['version'] == content['version'],
                    #            'File content not legal: %s, versions of two %s'
                    #            'related file do not match'%(file_path, key))
                    # raw_architecture_description[key].update(file[key])
            if key == 'compound_components':
                content = file[key]
                file_reload = load(open(file_path), accelergy_loader_ordered)
                #-------------------------------------------------------------------------
                # check syntax of input file
                #-------------------------------------------------------------------------
                ASSERT_MSG(
                    'version' in content and 'classes' in content,
                    'File content not legal: %s, %s must contain '
                    '"version" and "classes" keys' % (file_path, key))
                ASSERT_MSG(
                    type(content['classes']) is list,
                    'File content not legal: %s, "classes" key must have value of type list'
                    % file_path)
                #-------------------------------------------------------------------------
                # merge input file
                #-------------------------------------------------------------------------
                if raw_compound_class_description is None:
                    raw_compound_class_description = {
                        'compound_components': file_reload[key]
                    }
                else:
                    ASSERT_MSG(
                        raw_compound_class_description['compound_components']
                        ['version'] == content['version'],
                        'File content not legal: %s, versions of two %s '
                        'related file do not match' % (file_path, key))

                    raw_compound_class_description[key]['classes'].extend(
                        file_reload[key]['classes'])

            if key == 'action_counts':
                content = file[key]
                #-------------------------------------------------------------------------
                # check syntax of input file
                #-------------------------------------------------------------------------
                ASSERT_MSG(
                    'version' in content,
                    'File content not legal: %s, %s must contain '
                    '"version" key ' % (file_path, key))
                if content['version'] == 0.1:
                    ASSERT_MSG(
                        'nodes' in content,
                        'v0.1 error... File content not legal: %s, %s must contain '
                        '"nodes" key ' % (file_path, key))
                    if raw_action_counts is None:
                        raw_action_counts = {key: content}
                    else:
                        ASSERT_MSG(
                            raw_action_counts[key]['version'] ==
                            content['version'],
                            'File content not legal: %s, versions of two %s'
                            'related files do not match' % (file_path, key))
                        if "nodes" in content:
                            if "nodes" in raw_action_counts[key]:
                                raw_action_counts[key]["nodes"].extend(
                                    content["nodes"])
                            else:
                                raw_action_counts[key]["nodes"] = content[
                                    "nodes"]

                if content['version'] == 0.2:

                    ASSERT_MSG(
                        'local' in content or 'subtree' in content,
                        'File content not legal: %s, %s must contain '
                        '"local"/"subtree" key ' % (file_path, key))

                    if "local" in content:
                        ASSERT_MSG(
                            type(content["local"]) is list,
                            'File content not legal: %s, "local" key must have value of type list'
                            % (file_path))

                    if "subtree" in content:
                        ASSERT_MSG(
                            type(content["subtree"]) is list,
                            'File content not legal: %s, "subtree" key must have value of type list'
                            % (file_path))

                    if raw_action_counts is None:
                        raw_action_counts = {key: content}
                    else:
                        ASSERT_MSG(
                            raw_action_counts[key]['version'] ==
                            content['version'],
                            'File content not legal: %s, versions of two %s'
                            'related files do not match' % (file_path, key))
                        if "local" in content:
                            if "local" in raw_action_counts[key]:
                                raw_action_counts[key]["local"].extend(
                                    content["local"])
                            else:
                                raw_action_counts[key]["local"] = content[
                                    "local"]
                        if "subtree" in content:
                            if "subtree" in raw_action_counts[key]:
                                raw_action_counts[key]["subtree"].extend(
                                    content["subtree"])
                            else:
                                raw_action_counts[key]["subtree"] = content[
                                    "subtree"]

            if key == 'ERT':
                content = file[key]
                ASSERT_MSG(
                    'version' in content and 'tables' in content,
                    'File content not legal: %s, ERT must contain '
                    '"version" and "tables" keys' % file_path)
                ASSERT_MSG(
                    type(content['tables'] is dict),
                    'File content not legal: %s, "tables" key must have value of type dict'
                    % file_path)
                if raw_ERT is None:
                    raw_ERT = {key: file[key]}
                else:
                    ASSERT_MSG(
                        raw_ERT[key]['version'] == content['version'],
                        'File content not legal: %s, versions of two %s '
                        'related files do not match' % (file_path, key))
                    raw_ERT[key]['tables'].update(file[key]['tables'])

            if key == 'flattened_architecture':
                content = file[key]
                ASSERT_MSG(
                    'version' in content and 'components' in content,
                    'File content not legal: %s, flattened_architecture description must contain '
                    '"version" and "tables" keys' % file_path)
                ASSERT_MSG(
                    type(content['components'] is dict),
                    'File content not legal: %s, "components" key must have value of type dict'
                    % file_path)
                if raw_flattened_arch is None:
                    raw_flattened_arch = {key: file[key]}
                else:
                    ASSERT_MSG(
                        raw_ERT['version'] == content['version'],
                        'File content not legal: %s, versions of two %s '
                        'related files do not match' % (file_path, key))
                    raw_flattened_arch[key]['components'].update(
                        file[key]['components'])
            if key not in available_keys:
                WARN('File contains unrecognized information:', file_path, key,
                     '\n Accelergy only recognizes the following keys',
                     available_keys)
            else:
                INFO('%s related info found in %s' % (key, file_path))

    return raw_architecture_description, raw_compound_class_description, raw_action_counts, raw_ERT, raw_flattened_arch