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, annotations

# Built-in modules
import abc
import os
from typing import TYPE_CHECKING, List

# 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_definition
from microprobe.utils.logger import get_logger
from microprobe.utils.misc import findfiles
from microprobe.utils.typeguard_decorator import typeguard_testsuite
from microprobe.utils.yaml import read_yaml

# Local modules

# Type hinting
if TYPE_CHECKING:
    from microprobe.target import Target, Definition

# 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
@typeguard_testsuite
def _read_uarch_extensions(uarchdefs, path: str):
    """ """

    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)


@typeguard_testsuite
def _read_yaml_definition(uarchdefs, path: str):
    """

    :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] @typeguard_testsuite def import_microarchitecture_definition(path: str): """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] @typeguard_testsuite def find_microarchitecture_definitions(paths: List[str] | None = None): if paths is None: paths = [] paths = paths + MICROPROBE_RC["microarchitecture_paths"] \ + MICROPROBE_RC["default_paths"] results: List[Definition] = [] 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] @typeguard_testsuite class Microarchitecture(PropertyHolder, metaclass=abc.ABCMeta): """ """
[docs] @abc.abstractmethod def __init__(self): pass
@property @abc.abstractmethod def name(self) -> str: raise NotImplementedError @property @abc.abstractmethod def description(self) -> str: raise NotImplementedError @property @abc.abstractmethod 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) -> str: raise NotImplementedError
[docs] @abc.abstractmethod def set_target(self, target: Target): """ :param target: """ raise NotImplementedError
@property @abc.abstractmethod def target(self): raise NotImplementedError
[docs] @typeguard_testsuite class GenericMicroarchitecture(Microarchitecture): """ """
[docs] def __init__(self, name: str, descr: str, 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: Target | None = 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: 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] @typeguard_testsuite class GenericCPUMicroarchitecture(GenericMicroarchitecture): """Generic CPU Microarchitecture Generic CPU microarchitecture. Assumes a cache hierarchy """
[docs] def __init__(self, name: str, descr: str, 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