Source code for microprobe.target.uarch

# Copyright 2011-2021 IBM Corporation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
""":mod:`microprobe.target.uarch` package

"""

# Futures
from __future__ import absolute_import

# Built-in modules
import abc
import os

# Third party modules

# Own modules
import microprobe.target.uarch.element
import microprobe.target.uarch.element_type
from microprobe import MICROPROBE_RC
from microprobe.exceptions import MicroprobeYamlFormatError
from microprobe.property import PropertyHolder, import_properties
from microprobe.target.uarch.cache import cache_hierarchy_from_elements
from microprobe.utils.imp import get_object_from_module, \
    import_cls_definition, import_definition, import_operand_definition
from microprobe.utils.logger import get_logger
from microprobe.utils.misc import findfiles
from microprobe.utils.yaml import read_yaml
import six

# Local modules


# Constants
SCHEMA = os.path.join(
    os.path.dirname(os.path.abspath(__file__)), "schemas",
    "microarchitecture.yaml"
)
DEFAULT_UARCH = os.path.join(
    os.path.dirname(os.path.abspath(__file__)), "default",
    "microarchitecture.yaml"
)
LOG = get_logger(__name__)
__all__ = [
    "import_microarchitecture_definition",
    "find_microarchitecture_definitions", "Microarchitecture",
    "GenericMicroarchitecture", "GenericCPUMicroarchitecture"
]


# Functions
def _read_uarch_extensions(uarchdefs, path):
    """ """

    if "Extends" in uarchdefs[-1]:
        uarchdefval = uarchdefs[-1]["Extends"]
        del uarchdefs[-1]["Extends"]

        if not os.path.isabs(uarchdefval):
            uarchdefval = os.path.join(path, uarchdefval)

        uarchdef = read_yaml(
            os.path.join(
                uarchdefval, "microarchitecture.yaml"
            ), SCHEMA
        )
        uarchdef["Path"] = uarchdefval
        uarchdefs.append(uarchdef)

        _read_uarch_extensions(uarchdefs, uarchdefval)


def _read_yaml_definition(uarchdefs, path):
    """

    :param uarchdefs:
    :param path:

    """

    uarchdef = read_yaml(os.path.join(path, "microarchitecture.yaml"), SCHEMA)
    uarchdef["Path"] = path

    uarchdefs.append(uarchdef)

    _read_uarch_extensions(uarchdefs, path)

    baseuarch = read_yaml(DEFAULT_UARCH, SCHEMA)
    baseuarch["Path"] = DEFAULT_UARCH
    uarchdefs.append(baseuarch)

    complete_uarchdef = {}
    uarchdefs.reverse()

    for uarchdef in uarchdefs:
        for key, val in uarchdef.items():
            if not isinstance(val, dict):
                complete_uarchdef[key] = uarchdef[key]
            else:

                override = val.get("Override", False)

                if key not in complete_uarchdef:
                    complete_uarchdef[key] = {}

                for key2 in val:

                    if key2 in ["YAML", "Modules", "Path"]:
                        if key2 not in complete_uarchdef[key]:
                            complete_uarchdef[key][key2] = []

                        if os.path.isabs(val[key2]):
                            if override:
                                complete_uarchdef[key][key2] = [val[key2]]
                            else:
                                complete_uarchdef[key][key2].append(val[key2])
                        else:
                            if override:
                                complete_uarchdef[key][key2] = [
                                    os.path.join(
                                        uarchdef["Path"], val[key2]
                                    )
                                ]
                            else:
                                complete_uarchdef[key][key2].append(
                                    os.path.join(
                                        uarchdef["Path"], val[key2]
                                    )
                                )
                    elif key2 == "Module":
                        if val[key2].startswith("microprobe"):
                            val[key2] = os.path.join(
                                os.path.dirname(__file__), "..", "..", "..",
                                val[key2]
                            )

                        if os.path.isabs(val[key2]):
                            complete_uarchdef[key][key2] = val[key2]
                        else:
                            complete_uarchdef[key][key2] = os.path.join(
                                uarchdef["Path"], val[key2]
                            )
                    else:
                        complete_uarchdef[key][key2] = val[key2]

    return complete_uarchdef


[docs]def import_microarchitecture_definition(path): """Imports a Microarchitecture definition given a path :param path: """ LOG.info("Start microarchitecture import") LOG.debug("Importing definition from '%s'", path) if not os.path.isabs(path): path = os.path.abspath(path) uarchdef = _read_yaml_definition([], path) element_types, force = import_definition( uarchdef, os.path.join( path, "microarchitecture.yaml" ), "Element_type", getattr(microprobe.target.uarch, 'element_type'), None ) element, force = import_definition( uarchdef, os.path.join( path, "microarchitecture.yaml" ), "Element", getattr( microprobe.target.uarch, 'element' ), element_types, force=force ) uarch_cls = get_object_from_module( uarchdef["Microarchitecture"]["Class"], uarchdef["Microarchitecture"]["Module"] ) uarch = uarch_cls( uarchdef["Name"], uarchdef["Description"], element, uarchdef["Instruction_properties"]["Path"] ) import_properties( os.path.join(path, "microarchitecture.yaml"), {uarchdef["Name"]: uarch} ) LOG.info("Microarchitecture '%s' imported", uarch) return uarch
[docs]def find_microarchitecture_definitions(paths=None): if paths is None: paths = [] paths = paths + MICROPROBE_RC["microarchitecture_paths"] \ + MICROPROBE_RC["default_paths"] results = [] uarchfiles = findfiles(paths, "^microarchitecture.yaml$") if len(uarchfiles) > 0: from microprobe.target import Definition for uarchfile in uarchfiles: try: isadef = read_yaml(uarchfile, SCHEMA) except MicroprobeYamlFormatError as exc: LOG.info("Exception: %s", exc) LOG.info("Skipping '%s'", uarchfile) continue try: definition = Definition( uarchfile, isadef["Name"], isadef["Description"] ) if ( definition not in results and not definition.name.endswith("common") ): results.append(definition) except TypeError as exc: # Skip bad definitions LOG.info("Exception: %s", exc) LOG.info("Skipping '%s'", uarchfile) continue return results
# Classes
[docs]class Microarchitecture(six.with_metaclass(abc.ABCMeta, PropertyHolder)): """ """
[docs] @abc.abstractmethod def __init__(self): """ """ pass
@abc.abstractproperty def name(self): """ """ raise NotImplementedError @abc.abstractproperty def description(self): """ """ raise NotImplementedError @abc.abstractproperty def elements(self): """ """ raise NotImplementedError
[docs] @abc.abstractmethod def add_properties_to_isa(self, instructions): """ :param instructions: """ raise NotImplementedError
[docs] @abc.abstractmethod def full_report(self): """ """ raise NotImplementedError
@abc.abstractmethod def __str__(self): """ """ raise NotImplementedError
[docs] @abc.abstractmethod def set_target(self, target): """ :param target: """ raise NotImplementedError
@abc.abstractproperty def target(self): """ """ raise NotImplementedError
[docs]class GenericMicroarchitecture(Microarchitecture): """ """
[docs] def __init__(self, name, descr, elements, instruction_properties_defs): """ :param name: :param descr: :param elements: :param instruction_properties_defs: """ super(GenericMicroarchitecture, self).__init__() self._name = name self._descr = descr self._elements = elements self._target = None self._instruction_property_defs = instruction_properties_defs
@property def name(self): """ """ return self._name @property def description(self): """ """ return self._descr @property def elements(self): """ """ return self._elements @property def target(self): """ """ return self._target
[docs] def set_target(self, target): """ :param target: """ self._target = target
[docs] def add_properties_to_isa(self, instructions): """ :param instructions: """ for cfile in self._instruction_property_defs: import_properties(cfile, instructions)
[docs] def full_report(self): """ """ rstr = "-" * 80 + "\n" rstr += "Microarchitecture Name: %s\n" % self.name rstr += "Microarchitecture Description: %s\n" % self.name rstr += "-" * 80 + "\n" rstr += "Element Types:\n" for elem in sorted( set( [ elem.type for elem in self.elements.values() ] ) ): rstr += str(elem) + "\n" rstr += "-" * 80 + "\n" rstr += "Elements:\n" for elem in sorted(self.elements.values()): rstr += str(elem) + "\n" rstr += "-" * 80 + "\n" return rstr
def __str__(self): """ """ return "%s('%s', '%s')" % ( self.__class__.__name__, self.name, self.description )
[docs]class GenericCPUMicroarchitecture(GenericMicroarchitecture): """Generic CPU Microarchitecture Generic CPU microarchitecture. Assumes a cache hierarchy """
[docs] def __init__(self, name, descr, elements, instruction_properties_defs): """ :param name: :param descr: :param elements: :param instruction_properties_defs: """ super( GenericCPUMicroarchitecture, self ).__init__( name, descr, elements, instruction_properties_defs ) self._cache_hierarchy = cache_hierarchy_from_elements(elements)
@property def cache_hierarchy(self): """ """ return self._cache_hierarchy