diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/aiet/__init__.py | 7 | ||||
-rw-r--r-- | src/aiet/backend/tool.py | 109 | ||||
-rw-r--r-- | src/aiet/cli/__init__.py | 28 | ||||
-rw-r--r-- | src/aiet/cli/application.py | 362 | ||||
-rw-r--r-- | src/aiet/cli/common.py | 173 | ||||
-rw-r--r-- | src/aiet/cli/completion.py | 72 | ||||
-rw-r--r-- | src/aiet/cli/system.py | 122 | ||||
-rw-r--r-- | src/aiet/cli/tool.py | 143 | ||||
-rw-r--r-- | src/aiet/main.py | 13 | ||||
-rw-r--r-- | src/aiet/resources/tools/vela/aiet-config.json | 73 | ||||
-rw-r--r-- | src/aiet/resources/tools/vela/aiet-config.json.license | 3 | ||||
-rw-r--r-- | src/aiet/resources/tools/vela/check_model.py | 75 | ||||
-rw-r--r-- | src/aiet/resources/tools/vela/run_vela.py | 65 | ||||
-rw-r--r-- | src/aiet/resources/tools/vela/vela.ini | 53 | ||||
-rw-r--r-- | src/aiet/utils/__init__.py | 3 | ||||
-rw-r--r-- | src/aiet/utils/helpers.py | 17 | ||||
-rw-r--r-- | src/mlia/backend/__init__.py (renamed from src/aiet/backend/__init__.py) | 0 | ||||
-rw-r--r-- | src/mlia/backend/application.py (renamed from src/aiet/backend/application.py) | 28 | ||||
-rw-r--r-- | src/mlia/backend/common.py (renamed from src/aiet/backend/common.py) | 22 | ||||
-rw-r--r-- | src/mlia/backend/config.py (renamed from src/aiet/backend/config.py) | 18 | ||||
-rw-r--r-- | src/mlia/backend/controller.py (renamed from src/aiet/backend/controller.py) | 16 | ||||
-rw-r--r-- | src/mlia/backend/execution.py (renamed from src/aiet/backend/execution.py) | 148 | ||||
-rw-r--r-- | src/mlia/backend/fs.py (renamed from src/aiet/utils/fs.py) | 19 | ||||
-rw-r--r-- | src/mlia/backend/manager.py (renamed from src/mlia/tools/aiet_wrapper.py) | 108 | ||||
-rw-r--r-- | src/mlia/backend/output_parser.py (renamed from src/aiet/backend/output_parser.py) | 0 | ||||
-rw-r--r-- | src/mlia/backend/proc.py (renamed from src/aiet/utils/proc.py) | 2 | ||||
-rw-r--r-- | src/mlia/backend/protocol.py (renamed from src/aiet/backend/protocol.py) | 8 | ||||
-rw-r--r-- | src/mlia/backend/source.py (renamed from src/aiet/backend/source.py) | 18 | ||||
-rw-r--r-- | src/mlia/backend/system.py (renamed from src/aiet/backend/system.py) | 34 | ||||
-rw-r--r-- | src/mlia/cli/config.py | 6 | ||||
-rw-r--r-- | src/mlia/devices/ethosu/performance.py | 37 | ||||
-rw-r--r-- | src/mlia/resources/aiet/applications/APPLICATIONS.txt | 5 | ||||
-rw-r--r-- | src/mlia/resources/aiet/systems/SYSTEMS.txt | 3 | ||||
-rw-r--r-- | src/mlia/resources/backends/applications/.gitignore (renamed from src/aiet/resources/applications/.gitignore) | 0 | ||||
-rw-r--r-- | src/mlia/resources/backends/systems/.gitignore (renamed from src/aiet/resources/systems/.gitignore) | 0 | ||||
-rw-r--r-- | src/mlia/tools/metadata/corstone.py | 61 | ||||
-rw-r--r-- | src/mlia/utils/proc.py | 20 |
37 files changed, 230 insertions, 1641 deletions
diff --git a/src/aiet/__init__.py b/src/aiet/__init__.py deleted file mode 100644 index 49304b1..0000000 --- a/src/aiet/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -# SPDX-FileCopyrightText: Copyright 2022, Arm Limited and/or its affiliates. -# SPDX-License-Identifier: Apache-2.0 -"""Init of aiet.""" -import pkg_resources - - -__version__ = pkg_resources.get_distribution("mlia").version diff --git a/src/aiet/backend/tool.py b/src/aiet/backend/tool.py deleted file mode 100644 index d643665..0000000 --- a/src/aiet/backend/tool.py +++ /dev/null @@ -1,109 +0,0 @@ -# SPDX-FileCopyrightText: Copyright 2022, Arm Limited and/or its affiliates. -# SPDX-License-Identifier: Apache-2.0 -"""Tool backend module.""" -from typing import Any -from typing import cast -from typing import Dict -from typing import List -from typing import Optional - -from aiet.backend.common import Backend -from aiet.backend.common import ConfigurationException -from aiet.backend.common import get_backend_configs -from aiet.backend.common import get_backend_directories -from aiet.backend.common import load_application_or_tool_configs -from aiet.backend.common import load_config -from aiet.backend.config import ExtendedToolConfig -from aiet.backend.config import ToolConfig - - -def get_available_tool_directory_names() -> List[str]: - """Return a list of directory names for all available tools.""" - return [entry.name for entry in get_backend_directories("tools")] - - -def get_available_tools() -> List["Tool"]: - """Return a list with all available tools.""" - available_tools = [] - for config_json in get_backend_configs("tools"): - config_entries = cast(List[ExtendedToolConfig], load_config(config_json)) - for config_entry in config_entries: - config_entry["config_location"] = config_json.parent.absolute() - tools = load_tools(config_entry) - available_tools += tools - - return sorted(available_tools, key=lambda tool: tool.name) - - -def get_tool(tool_name: str, system_name: Optional[str] = None) -> List["Tool"]: - """Return a tool instance with the same name passed as argument.""" - return [ - tool - for tool in get_available_tools() - if tool.name == tool_name and (not system_name or tool.can_run_on(system_name)) - ] - - -def get_unique_tool_names(system_name: Optional[str] = None) -> List[str]: - """Extract a list of unique tool names of all tools available.""" - return list( - set( - tool.name - for tool in get_available_tools() - if not system_name or tool.can_run_on(system_name) - ) - ) - - -class Tool(Backend): - """Class for representing a single tool component.""" - - def __init__(self, config: ToolConfig) -> None: - """Construct a Tool instance from a dict.""" - super().__init__(config) - - self.supported_systems = config.get("supported_systems", []) - - if "run" not in self.commands: - raise ConfigurationException("A Tool must have a 'run' command.") - - def __eq__(self, other: object) -> bool: - """Overload operator ==.""" - if not isinstance(other, Tool): - return False - - return ( - super().__eq__(other) - and self.name == other.name - and set(self.supported_systems) == set(other.supported_systems) - ) - - def can_run_on(self, system_name: str) -> bool: - """Check if the tool can run on the system passed as argument.""" - return system_name in self.supported_systems - - def get_details(self) -> Dict[str, Any]: - """Return dictionary with all relevant information of the Tool instance.""" - output = { - "type": "tool", - "name": self.name, - "description": self.description, - "supported_systems": self.supported_systems, - "commands": self._get_command_details(), - } - - return output - - -def load_tools(config: ExtendedToolConfig) -> List[Tool]: - """Load tool. - - Tool configuration could contain different parameters/commands for different - supported systems. For each supported system this function will return separate - Tool instance with appropriate configuration. - """ - configs = load_application_or_tool_configs( - config, ToolConfig, is_system_required=False - ) - tools = [Tool(cfg) for cfg in configs] - return tools diff --git a/src/aiet/cli/__init__.py b/src/aiet/cli/__init__.py deleted file mode 100644 index bcd17c3..0000000 --- a/src/aiet/cli/__init__.py +++ /dev/null @@ -1,28 +0,0 @@ -# SPDX-FileCopyrightText: Copyright 2022, Arm Limited and/or its affiliates. -# SPDX-License-Identifier: Apache-2.0 -"""Module to mange the CLI interface.""" -import click - -from aiet import __version__ -from aiet.cli.application import application_cmd -from aiet.cli.completion import completion_cmd -from aiet.cli.system import system_cmd -from aiet.cli.tool import tool_cmd -from aiet.utils.helpers import set_verbosity - - -@click.group() -@click.version_option(__version__) -@click.option( - "-v", "--verbose", default=0, count=True, callback=set_verbosity, expose_value=False -) -@click.pass_context -def cli(ctx: click.Context) -> None: # pylint: disable=unused-argument - """AIET: AI Evaluation Toolkit.""" - # Unused arguments must be present here in definition to pass click context. - - -cli.add_command(application_cmd) -cli.add_command(system_cmd) -cli.add_command(tool_cmd) -cli.add_command(completion_cmd) diff --git a/src/aiet/cli/application.py b/src/aiet/cli/application.py deleted file mode 100644 index 59b652d..0000000 --- a/src/aiet/cli/application.py +++ /dev/null @@ -1,362 +0,0 @@ -# SPDX-FileCopyrightText: Copyright 2022, Arm Limited and/or its affiliates. -# SPDX-FileCopyrightText: Copyright (c) 2021, Gianluca Gippetto. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause -"""Module to manage the CLI interface of applications.""" -import json -import logging -import re -from pathlib import Path -from typing import Any -from typing import IO -from typing import List -from typing import Optional -from typing import Tuple - -import click -import cloup - -from aiet.backend.application import get_application -from aiet.backend.application import get_available_application_directory_names -from aiet.backend.application import get_unique_application_names -from aiet.backend.application import install_application -from aiet.backend.application import remove_application -from aiet.backend.common import DataPaths -from aiet.backend.execution import execute_application_command -from aiet.backend.execution import run_application -from aiet.backend.system import get_available_systems -from aiet.cli.common import get_format -from aiet.cli.common import middleware_exception_handler -from aiet.cli.common import middleware_signal_handler -from aiet.cli.common import print_command_details -from aiet.cli.common import set_format - - -@click.group(name="application") -@click.option( - "-f", - "--format", - "format_", - type=click.Choice(["cli", "json"]), - default="cli", - show_default=True, -) -@click.pass_context -def application_cmd(ctx: click.Context, format_: str) -> None: - """Sub command to manage applications.""" - set_format(ctx, format_) - - -@application_cmd.command(name="list") -@click.pass_context -@click.option( - "-s", - "--system", - "system_name", - type=click.Choice([s.name for s in get_available_systems()]), - required=False, -) -def list_cmd(ctx: click.Context, system_name: str) -> None: - """List all available applications.""" - unique_application_names = get_unique_application_names(system_name) - unique_application_names.sort() - if get_format(ctx) == "json": - data = {"type": "application", "available": unique_application_names} - print(json.dumps(data)) - else: - print("Available applications:\n") - print(*unique_application_names, sep="\n") - - -@application_cmd.command(name="details") -@click.option( - "-n", - "--name", - "application_name", - type=click.Choice(get_unique_application_names()), - required=True, -) -@click.option( - "-s", - "--system", - "system_name", - type=click.Choice([s.name for s in get_available_systems()]), - required=False, -) -@click.pass_context -def details_cmd(ctx: click.Context, application_name: str, system_name: str) -> None: - """Details of a specific application.""" - applications = get_application(application_name, system_name) - if not applications: - raise click.UsageError( - "Application '{}' doesn't support the system '{}'".format( - application_name, system_name - ) - ) - - if get_format(ctx) == "json": - applications_details = [s.get_details() for s in applications] - print(json.dumps(applications_details)) - else: - for application in applications: - application_details = application.get_details() - application_details_template = ( - 'Application "{name}" details\nDescription: {description}' - ) - - print( - application_details_template.format( - name=application_details["name"], - description=application_details["description"], - ) - ) - - print( - "\nSupported systems: {}".format( - ", ".join(application_details["supported_systems"]) - ) - ) - - command_details = application_details["commands"] - - for command, details in command_details.items(): - print("\n{} commands:".format(command)) - print_command_details(details) - - -# pylint: disable=too-many-arguments -@application_cmd.command(name="execute") -@click.option( - "-n", - "--name", - "application_name", - type=click.Choice(get_unique_application_names()), - required=True, -) -@click.option( - "-s", - "--system", - "system_name", - type=click.Choice([s.name for s in get_available_systems()]), - required=True, -) -@click.option( - "-c", - "--command", - "command_name", - type=click.Choice(["build", "run"]), - required=True, -) -@click.option("-p", "--param", "application_params", multiple=True) -@click.option("--system-param", "system_params", multiple=True) -@click.option("-d", "--deploy", "deploy_params", multiple=True) -@middleware_signal_handler -@middleware_exception_handler -def execute_cmd( - application_name: str, - system_name: str, - command_name: str, - application_params: List[str], - system_params: List[str], - deploy_params: List[str], -) -> None: - """Execute application commands. DEPRECATED! Use 'aiet application run' instead.""" - logging.warning( - "Please use 'aiet application run' instead. Use of 'aiet application " - "execute' is deprecated and might be removed in a future release." - ) - - custom_deploy_data = get_custom_deploy_data(command_name, deploy_params) - - execute_application_command( - command_name, - application_name, - application_params, - system_name, - system_params, - custom_deploy_data, - ) - - -@cloup.command(name="run") -@cloup.option( - "-n", - "--name", - "application_name", - type=click.Choice(get_unique_application_names()), -) -@cloup.option( - "-s", - "--system", - "system_name", - type=click.Choice([s.name for s in get_available_systems()]), -) -@cloup.option("-p", "--param", "application_params", multiple=True) -@cloup.option("--system-param", "system_params", multiple=True) -@cloup.option("-d", "--deploy", "deploy_params", multiple=True) -@click.option( - "-r", - "--report", - "report_file", - type=Path, - help="Create a report file in JSON format containing metrics parsed from " - "the simulation output as specified in the aiet-config.json.", -) -@cloup.option( - "--config", - "config_file", - type=click.File("r"), - help="Read options from a config file rather than from the command line. " - "The config file is a json file.", -) -@cloup.constraint( - cloup.constraints.If( - cloup.constraints.conditions.Not( - cloup.constraints.conditions.IsSet("config_file") - ), - then=cloup.constraints.require_all, - ), - ["system_name", "application_name"], -) -@cloup.constraint( - cloup.constraints.If("config_file", then=cloup.constraints.accept_none), - [ - "system_name", - "application_name", - "application_params", - "system_params", - "deploy_params", - ], -) -@middleware_signal_handler -@middleware_exception_handler -def run_cmd( - application_name: str, - system_name: str, - application_params: List[str], - system_params: List[str], - deploy_params: List[str], - report_file: Optional[Path], - config_file: Optional[IO[str]], -) -> None: - """Execute application commands.""" - if config_file: - payload_data = json.load(config_file) - ( - system_name, - application_name, - application_params, - system_params, - deploy_params, - report_file, - ) = parse_payload_run_config(payload_data) - - custom_deploy_data = get_custom_deploy_data("run", deploy_params) - - run_application( - application_name, - application_params, - system_name, - system_params, - custom_deploy_data, - report_file, - ) - - -application_cmd.add_command(run_cmd) - - -def parse_payload_run_config( - payload_data: dict, -) -> Tuple[str, str, List[str], List[str], List[str], Optional[Path]]: - """Parse the payload into a tuple.""" - system_id = payload_data.get("id") - arguments: Optional[Any] = payload_data.get("arguments") - - if not isinstance(system_id, str): - raise click.ClickException("invalid payload json: no system 'id'") - if not isinstance(arguments, dict): - raise click.ClickException("invalid payload json: no arguments object") - - application_name = arguments.pop("application", None) - if not isinstance(application_name, str): - raise click.ClickException("invalid payload json: no application_id") - - report_path = arguments.pop("report_path", None) - - application_params = [] - system_params = [] - deploy_params = [] - - for (param_key, value) in arguments.items(): - (par, _) = re.subn("^application/", "", param_key) - (par, found_sys_param) = re.subn("^system/", "", par) - (par, found_deploy_param) = re.subn("^deploy/", "", par) - - param_expr = par + "=" + value - if found_sys_param: - system_params.append(param_expr) - elif found_deploy_param: - deploy_params.append(par) - else: - application_params.append(param_expr) - - return ( - system_id, - application_name, - application_params, - system_params, - deploy_params, - report_path, - ) - - -def get_custom_deploy_data( - command_name: str, deploy_params: List[str] -) -> List[DataPaths]: - """Get custom deploy data information.""" - custom_deploy_data: List[DataPaths] = [] - if not deploy_params: - return custom_deploy_data - - for param in deploy_params: - parts = param.split(":") - if not len(parts) == 2 or any(not part.strip() for part in parts): - raise click.ClickException( - "Invalid deploy parameter '{}' for command {}".format( - param, command_name - ) - ) - data_path = DataPaths(Path(parts[0]), parts[1]) - if not data_path.src.exists(): - raise click.ClickException("Path {} does not exist".format(data_path.src)) - custom_deploy_data.append(data_path) - - return custom_deploy_data - - -@application_cmd.command(name="install") -@click.option( - "-s", - "--source", - "source", - required=True, - help="Path to the directory or archive with application definition", -) -def install_cmd(source: str) -> None: - """Install new application.""" - source_path = Path(source) - install_application(source_path) - - -@application_cmd.command(name="remove") -@click.option( - "-d", - "--directory_name", - "directory_name", - type=click.Choice(get_available_application_directory_names()), - required=True, - help="Name of the directory with application", -) -def remove_cmd(directory_name: str) -> None: - """Remove application.""" - remove_application(directory_name) diff --git a/src/aiet/cli/common.py b/src/aiet/cli/common.py deleted file mode 100644 index 1d157b6..0000000 --- a/src/aiet/cli/common.py +++ /dev/null @@ -1,173 +0,0 @@ -# SPDX-FileCopyrightText: Copyright 2022, Arm Limited and/or its affiliates. -# SPDX-License-Identifier: Apache-2.0 -"""Common functions for cli module.""" -import enum -import logging -from functools import wraps -from signal import SIG_IGN -from signal import SIGINT -from signal import signal as signal_handler -from signal import SIGTERM -from typing import Any -from typing import Callable -from typing import cast -from typing import Dict - -from click import ClickException -from click import Context -from click import UsageError - -from aiet.backend.common import ConfigurationException -from aiet.backend.execution import AnotherInstanceIsRunningException -from aiet.backend.execution import ConnectionException -from aiet.backend.protocol import SSHConnectionException -from aiet.utils.proc import CommandFailedException - - -class MiddlewareExitCode(enum.IntEnum): - """Middleware exit codes.""" - - SUCCESS = 0 - # exit codes 1 and 2 are used by click - SHUTDOWN_REQUESTED = 3 - BACKEND_ERROR = 4 - CONCURRENT_ERROR = 5 - CONNECTION_ERROR = 6 - CONFIGURATION_ERROR = 7 - MODEL_OPTIMISED_ERROR = 8 - INVALID_TFLITE_FILE_ERROR = 9 - - -class CustomClickException(ClickException): - """Custom click exception.""" - - def show(self, file: Any = None) -> None: - """Override show method.""" - super().show(file) - - logging.debug("Execution failed with following exception: ", exc_info=self) - - -class MiddlewareShutdownException(CustomClickException): - """Exception indicates that user requested middleware shutdown.""" - - exit_code = int(MiddlewareExitCode.SHUTDOWN_REQUESTED) - - -class BackendException(CustomClickException): - """Exception indicates that command failed.""" - - exit_code = int(MiddlewareExitCode.BACKEND_ERROR) - - -class ConcurrentErrorException(CustomClickException): - """Exception indicates concurrent execution error.""" - - exit_code = int(MiddlewareExitCode.CONCURRENT_ERROR) - - -class BackendConnectionException(CustomClickException): - """Exception indicates that connection could not be established.""" - - exit_code = int(MiddlewareExitCode.CONNECTION_ERROR) - - -class BackendConfigurationException(CustomClickException): - """Exception indicates some configuration issue.""" - - exit_code = int(MiddlewareExitCode.CONFIGURATION_ERROR) - - -class ModelOptimisedException(CustomClickException): - """Exception indicates input file has previously been Vela optimised.""" - - exit_code = int(MiddlewareExitCode.MODEL_OPTIMISED_ERROR) - - -class InvalidTFLiteFileError(CustomClickException): - """Exception indicates input TFLite file is misformatted.""" - - exit_code = int(MiddlewareExitCode.INVALID_TFLITE_FILE_ERROR) - - -def print_command_details(command: Dict) -> None: - """Print command details including parameters.""" - command_strings = command["command_strings"] - print("Commands: {}".format(command_strings)) - user_params = command["user_params"] - for i, param in enumerate(user_params, 1): - print("User parameter #{}".format(i)) - print("\tName: {}".format(param.get("name", "-"))) - print("\tDescription: {}".format(param["description"])) - print("\tPossible values: {}".format(param.get("values", "-"))) - print("\tDefault value: {}".format(param.get("default_value", "-"))) - print("\tAlias: {}".format(param.get("alias", "-"))) - - -def raise_exception_at_signal( - signum: int, frame: Any # pylint: disable=unused-argument -) -> None: - """Handle signals.""" - # Disable both SIGINT and SIGTERM signals. Further SIGINT and SIGTERM - # signals will be ignored as we allow a graceful shutdown. - # Unused arguments must be present here in definition as used in signal handler - # callback - - signal_handler(SIGINT, SIG_IGN) - signal_handler(SIGTERM, SIG_IGN) - raise MiddlewareShutdownException("Middleware shutdown requested") - - -def middleware_exception_handler(func: Callable) -> Callable: - """Handle backend exceptions decorator.""" - - @wraps(func) - def wrapper(*args: Any, **kwargs: Any) -> Any: - try: - return func(*args, **kwargs) - except (MiddlewareShutdownException, UsageError, ClickException) as error: - # click should take care of these exceptions - raise error - except ValueError as error: - raise ClickException(str(error)) from error - except AnotherInstanceIsRunningException as error: - raise ConcurrentErrorException( - "Another instance of the system is running" - ) from error - except (SSHConnectionException, ConnectionException) as error: - raise BackendConnectionException(str(error)) from error - except ConfigurationException as error: - raise BackendConfigurationException(str(error)) from error - except (CommandFailedException, Exception) as error: - raise BackendException( - "Execution failed. Please check output for the details." - ) from error - - return wrapper - - -def middleware_signal_handler(func: Callable) -> Callable: - """Handle signals decorator.""" - - @wraps(func) - def wrapper(*args: Any, **kwargs: Any) -> Any: - # Set up signal handlers for SIGINT (ctrl-c) and SIGTERM (kill command) - # The handler ignores further signals and it raises an exception - signal_handler(SIGINT, raise_exception_at_signal) - signal_handler(SIGTERM, raise_exception_at_signal) - - return func(*args, **kwargs) - - return wrapper - - -def set_format(ctx: Context, format_: str) -> None: - """Save format in click context.""" - ctx_obj = ctx.ensure_object(dict) - ctx_obj["format"] = format_ - - -def get_format(ctx: Context) -> str: - """Get format from click context.""" - ctx_obj = cast(Dict[str, str], ctx.ensure_object(dict)) - return ctx_obj["format"] diff --git a/src/aiet/cli/completion.py b/src/aiet/cli/completion.py deleted file mode 100644 index 71f054f..0000000 --- a/src/aiet/cli/completion.py +++ /dev/null @@ -1,72 +0,0 @@ -# SPDX-FileCopyrightText: Copyright 2022, Arm Limited and/or its affiliates. -# SPDX-License-Identifier: Apache-2.0 -""" -Add auto completion to different shells with these helpers. - -See: https://click.palletsprojects.com/en/8.0.x/shell-completion/ -""" -import click - - -def _get_package_name() -> str: - return __name__.split(".", maxsplit=1)[0] - - -# aiet completion bash -@click.group(name="completion") -def completion_cmd() -> None: - """Enable auto completion for your shell.""" - - -@completion_cmd.command(name="bash") -def bash_cmd() -> None: - """ - Enable auto completion for bash. - - Use this command to activate completion in the current bash: - - eval "`aiet completion bash`" - - Use this command to add auto completion to bash globally, if you have aiet - installed globally (requires starting a new shell afterwards): - - aiet completion bash >> ~/.bashrc - """ - package_name = _get_package_name() - print(f'eval "$(_{package_name.upper()}_COMPLETE=bash_source {package_name})"') - - -@completion_cmd.command(name="zsh") -def zsh_cmd() -> None: - """ - Enable auto completion for zsh. - - Use this command to activate completion in the current zsh: - - eval "`aiet completion zsh`" - - Use this command to add auto completion to zsh globally, if you have aiet - installed globally (requires starting a new shell afterwards): - - aiet completion zsh >> ~/.zshrc - """ - package_name = _get_package_name() - print(f'eval "$(_{package_name.upper()}_COMPLETE=zsh_source {package_name})"') - - -@completion_cmd.command(name="fish") -def fish_cmd() -> None: - """ - Enable auto completion for fish. - - Use this command to activate completion in the current fish: - - eval "`aiet completion fish`" - - Use this command to add auto completion to fish globally, if you have aiet - installed globally (requires starting a new shell afterwards): - - aiet completion fish >> ~/.config/fish/completions/aiet.fish - """ - package_name = _get_package_name() - print(f'eval "(env _{package_name.upper()}_COMPLETE=fish_source {package_name})"') diff --git a/src/aiet/cli/system.py b/src/aiet/cli/system.py deleted file mode 100644 index f1f7637..0000000 --- a/src/aiet/cli/system.py +++ /dev/null @@ -1,122 +0,0 @@ -# SPDX-FileCopyrightText: Copyright 2022, Arm Limited and/or its affiliates. -# SPDX-License-Identifier: Apache-2.0 -"""Module to manage the CLI interface of systems.""" -import json -from pathlib import Path -from typing import cast - -import click - -from aiet.backend.application import get_available_applications -from aiet.backend.system import get_available_systems -from aiet.backend.system import get_available_systems_directory_names -from aiet.backend.system import get_system -from aiet.backend.system import install_system -from aiet.backend.system import remove_system -from aiet.backend.system import System -from aiet.cli.common import get_format -from aiet.cli.common import print_command_details -from aiet.cli.common import set_format - - -@click.group(name="system") -@click.option( - "-f", - "--format", - "format_", - type=click.Choice(["cli", "json"]), - default="cli", - show_default=True, -) -@click.pass_context -def system_cmd(ctx: click.Context, format_: str) -> None: - """Sub command to manage systems.""" - set_format(ctx, format_) - - -@system_cmd.command(name="list") -@click.pass_context -def list_cmd(ctx: click.Context) -> None: - """List all available systems.""" - available_systems = get_available_systems() - system_names = [system.name for system in available_systems] - if get_format(ctx) == "json": - data = {"type": "system", "available": system_names} - print(json.dumps(data)) - else: - print("Available systems:\n") - print(*system_names, sep="\n") - - -@system_cmd.command(name="details") -@click.option( - "-n", - "--name", - "system_name", - type=click.Choice([s.name for s in get_available_systems()]), - required=True, -) -@click.pass_context -def details_cmd(ctx: click.Context, system_name: str) -> None: - """Details of a specific system.""" - system = cast(System, get_system(system_name)) - applications = [ - s.name for s in get_available_applications() if s.can_run_on(system.name) - ] - system_details = system.get_details() - if get_format(ctx) == "json": - system_details["available_application"] = applications - print(json.dumps(system_details)) - else: - system_details_template = ( - 'System "{name}" details\n' - "Description: {description}\n" - "Data Transfer Protocol: {protocol}\n" - "Available Applications: {available_application}" - ) - print( - system_details_template.format( - name=system_details["name"], - description=system_details["description"], - protocol=system_details["data_transfer_protocol"], - available_application=", ".join(applications), - ) - ) - - if system_details["annotations"]: - print("Annotations:") - for ann_name, ann_value in system_details["annotations"].items(): - print("\t{}: {}".format(ann_name, ann_value)) - - command_details = system_details["commands"] - for command, details in command_details.items(): - print("\n{} commands:".format(command)) - print_command_details(details) - - -@system_cmd.command(name="install") -@click.option( - "-s", - "--source", - "source", - required=True, - help="Path to the directory or archive with system definition", -) -def install_cmd(source: str) -> None: - """Install new system.""" - source_path = Path(source) - install_system(source_path) - - -@system_cmd.command(name="remove") -@click.option( - "-d", - "--directory_name", - "directory_name", - type=click.Choice(get_available_systems_directory_names()), - required=True, - help="Name of the directory with system", -) -def remove_cmd(directory_name: str) -> None: - """Remove system by given name.""" - remove_system(directory_name) diff --git a/src/aiet/cli/tool.py b/src/aiet/cli/tool.py deleted file mode 100644 index 2c80821..0000000 --- a/src/aiet/cli/tool.py +++ /dev/null @@ -1,143 +0,0 @@ -# SPDX-FileCopyrightText: Copyright 2022, Arm Limited and/or its affiliates. -# SPDX-License-Identifier: Apache-2.0 -"""Module to manage the CLI interface of tools.""" -import json -from typing import Any -from typing import List -from typing import Optional - -import click - -from aiet.backend.execution import execute_tool_command -from aiet.backend.tool import get_tool -from aiet.backend.tool import get_unique_tool_names -from aiet.cli.common import get_format -from aiet.cli.common import middleware_exception_handler -from aiet.cli.common import middleware_signal_handler -from aiet.cli.common import print_command_details -from aiet.cli.common import set_format - - -@click.group(name="tool") -@click.option( - "-f", - "--format", - "format_", - type=click.Choice(["cli", "json"]), - default="cli", - show_default=True, -) -@click.pass_context -def tool_cmd(ctx: click.Context, format_: str) -> None: - """Sub command to manage tools.""" - set_format(ctx, format_) - - -@tool_cmd.command(name="list") -@click.pass_context -def list_cmd(ctx: click.Context) -> None: - """List all available tools.""" - # raise NotImplementedError("TODO") - tool_names = get_unique_tool_names() - tool_names.sort() - if get_format(ctx) == "json": - data = {"type": "tool", "available": tool_names} - print(json.dumps(data)) - else: - print("Available tools:\n") - print(*tool_names, sep="\n") - - -def validate_system( - ctx: click.Context, - _: click.Parameter, # param is not used - value: Any, -) -> Any: - """Validate provided system name depending on the the tool name.""" - tool_name = ctx.params["tool_name"] - tools = get_tool(tool_name, value) - if not tools: - supported_systems = [tool.supported_systems[0] for tool in get_tool(tool_name)] - raise click.BadParameter( - message="'{}' is not one of {}.".format( - value, - ", ".join("'{}'".format(system) for system in supported_systems), - ), - ctx=ctx, - ) - return value - - -@tool_cmd.command(name="details") -@click.option( - "-n", - "--name", - "tool_name", - type=click.Choice(get_unique_tool_names()), - required=True, -) -@click.option( - "-s", - "--system", - "system_name", - callback=validate_system, - required=False, -) -@click.pass_context -@middleware_signal_handler -@middleware_exception_handler -def details_cmd(ctx: click.Context, tool_name: str, system_name: Optional[str]) -> None: - """Details of a specific tool.""" - tools = get_tool(tool_name, system_name) - if get_format(ctx) == "json": - tools_details = [s.get_details() for s in tools] - print(json.dumps(tools_details)) - else: - for tool in tools: - tool_details = tool.get_details() - tool_details_template = 'Tool "{name}" details\nDescription: {description}' - - print( - tool_details_template.format( - name=tool_details["name"], - description=tool_details["description"], - ) - ) - - print( - "\nSupported systems: {}".format( - ", ".join(tool_details["supported_systems"]) - ) - ) - - command_details = tool_details["commands"] - - for command, details in command_details.items(): - print("\n{} commands:".format(command)) - print_command_details(details) - - -# pylint: disable=too-many-arguments -@tool_cmd.command(name="execute") -@click.option( - "-n", - "--name", - "tool_name", - type=click.Choice(get_unique_tool_names()), - required=True, -) -@click.option("-p", "--param", "tool_params", multiple=True) -@click.option( - "-s", - "--system", - "system_name", - callback=validate_system, - required=False, -) -@middleware_signal_handler -@middleware_exception_handler -def execute_cmd( - tool_name: str, tool_params: List[str], system_name: Optional[str] -) -> None: - """Execute tool commands.""" - execute_tool_command(tool_name, tool_params, system_name) diff --git a/src/aiet/main.py b/src/aiet/main.py deleted file mode 100644 index 6898ad9..0000000 --- a/src/aiet/main.py +++ /dev/null @@ -1,13 +0,0 @@ -# SPDX-FileCopyrightText: Copyright 2022, Arm Limited and/or its affiliates. -# SPDX-License-Identifier: Apache-2.0 -"""Entry point module of AIET.""" -from aiet.cli import cli - - -def main() -> None: - """Entry point of aiet application.""" - cli() # pylint: disable=no-value-for-parameter - - -if __name__ == "__main__": - main() diff --git a/src/aiet/resources/tools/vela/aiet-config.json b/src/aiet/resources/tools/vela/aiet-config.json deleted file mode 100644 index c12f291..0000000 --- a/src/aiet/resources/tools/vela/aiet-config.json +++ /dev/null @@ -1,73 +0,0 @@ -[ - { - "name": "vela", - "description": "Neural network model compiler for Arm Ethos-U NPUs", - "supported_systems": [ - { - "name": "Corstone-300: Cortex-M55+Ethos-U55" - }, - { - "name": "Corstone-310: Cortex-M85+Ethos-U55" - }, - { - "name": "Corstone-300: Cortex-M55+Ethos-U65", - "variables": { - "accelerator_config_prefix": "ethos-u65", - "system_config": "Ethos_U65_High_End", - "shared_sram": "U65_Shared_Sram" - }, - "user_params": { - "run": [ - { - "description": "MACs per cycle", - "values": [ - "256", - "512" - ], - "default_value": "512", - "alias": "mac" - } - ] - } - } - ], - "variables": { - "accelerator_config_prefix": "ethos-u55", - "system_config": "Ethos_U55_High_End_Embedded", - "shared_sram": "U55_Shared_Sram" - }, - "commands": { - "run": [ - "run_vela {user_params:input} {user_params:output} --config {tool.config_dir}/vela.ini --accelerator-config {variables:accelerator_config_prefix}-{user_params:mac} --system-config {variables:system_config} --memory-mode {variables:shared_sram} --optimise Performance" - ] - }, - "user_params": { - "run": [ - { - "description": "MACs per cycle", - "values": [ - "32", - "64", - "128", - "256" - ], - "default_value": "128", - "alias": "mac" - }, - { - "name": "--input-model", - "description": "Path to the TFLite model", - "values": [], - "alias": "input" - }, - { - "name": "--output-model", - "description": "Path to the output model file of the vela-optimisation step. The vela output is saved in the parent directory.", - "values": [], - "default_value": "output_model.tflite", - "alias": "output" - } - ] - } - } -] diff --git a/src/aiet/resources/tools/vela/aiet-config.json.license b/src/aiet/resources/tools/vela/aiet-config.json.license deleted file mode 100644 index 9b83bfc..0000000 --- a/src/aiet/resources/tools/vela/aiet-config.json.license +++ /dev/null @@ -1,3 +0,0 @@ -SPDX-FileCopyrightText: Copyright 2022, Arm Limited and/or its affiliates. - -SPDX-License-Identifier: Apache-2.0 diff --git a/src/aiet/resources/tools/vela/check_model.py b/src/aiet/resources/tools/vela/check_model.py deleted file mode 100644 index 7c700b1..0000000 --- a/src/aiet/resources/tools/vela/check_model.py +++ /dev/null @@ -1,75 +0,0 @@ -# SPDX-FileCopyrightText: Copyright 2020, 2022, Arm Limited and/or its affiliates. -# SPDX-License-Identifier: Apache-2.0 -"""Check if a TFLite model file is Vela-optimised.""" -import struct -from pathlib import Path - -from ethosu.vela.tflite.Model import Model - -from aiet.cli.common import InvalidTFLiteFileError -from aiet.cli.common import ModelOptimisedException -from aiet.utils.fs import read_file_as_bytearray - - -def get_model_from_file(input_model_file: Path) -> Model: - """Generate Model instance from TFLite file using flatc generated code.""" - buffer = read_file_as_bytearray(input_model_file) - try: - model = Model.GetRootAsModel(buffer, 0) - except (TypeError, RuntimeError, struct.error) as tflite_error: - raise InvalidTFLiteFileError( - f"Error reading in model from {input_model_file}." - ) from tflite_error - return model - - -def is_vela_optimised(tflite_model: Model) -> bool: - """Return True if 'ethos-u' custom operator found in the Model.""" - operators = get_operators_from_model(tflite_model) - - custom_codes = get_custom_codes_from_operators(operators) - - return check_custom_codes_for_ethosu(custom_codes) - - -def get_operators_from_model(tflite_model: Model) -> list: - """Return list of the unique operator codes used in the Model.""" - return [ - tflite_model.OperatorCodes(index) - for index in range(tflite_model.OperatorCodesLength()) - ] - - -def get_custom_codes_from_operators(operators: list) -> list: - """Return list of each operator's CustomCode() strings, if they exist.""" - return [ - operator.CustomCode() - for operator in operators - if operator.CustomCode() is not None - ] - - -def check_custom_codes_for_ethosu(custom_codes: list) -> bool: - """Check for existence of ethos-u string in the custom codes.""" - return any( - custom_code_name.decode("utf-8") == "ethos-u" - for custom_code_name in custom_codes - ) - - -def check_model(tflite_file_name: str) -> None: - """Raise an exception if model in given file is Vela optimised.""" - tflite_path = Path(tflite_file_name) - - tflite_model = get_model_from_file(tflite_path) - - if is_vela_optimised(tflite_model): - raise ModelOptimisedException( - f"TFLite model in {tflite_file_name} is already " - f"vela optimised ('ethos-u' custom op detected)." - ) - - print( - f"TFLite model in {tflite_file_name} is not vela optimised " - f"('ethos-u' custom op not detected)." - ) diff --git a/src/aiet/resources/tools/vela/run_vela.py b/src/aiet/resources/tools/vela/run_vela.py deleted file mode 100644 index 2c1b0be..0000000 --- a/src/aiet/resources/tools/vela/run_vela.py +++ /dev/null @@ -1,65 +0,0 @@ -# SPDX-FileCopyrightText: Copyright 2022, Arm Limited and/or its affiliates. -# SPDX-License-Identifier: Apache-2.0 -"""Wrapper to only run Vela when the input is not already optimised.""" -import shutil -import subprocess -from pathlib import Path -from typing import Tuple - -import click - -from aiet.cli.common import ModelOptimisedException -from aiet.resources.tools.vela.check_model import check_model - - -def vela_output_model_path(input_model: str, output_dir: str) -> Path: - """Construct the path to the Vela output file.""" - in_path = Path(input_model) - tflite_vela = Path(output_dir) / f"{in_path.stem}_vela{in_path.suffix}" - return tflite_vela - - -def execute_vela(vela_args: Tuple, output_dir: Path, input_model: str) -> None: - """Execute vela as external call.""" - cmd = ["vela"] + list(vela_args) - cmd += ["--output-dir", str(output_dir)] # Re-add parsed out_dir to arguments - cmd += [input_model] - subprocess.run(cmd, check=True) - - -@click.command(context_settings=dict(ignore_unknown_options=True)) -@click.option( - "--input-model", - "-i", - type=click.Path(exists=True, file_okay=True, readable=True), - required=True, -) -@click.option("--output-model", "-o", type=click.Path(), required=True) -# Collect the remaining arguments to be directly forwarded to Vela -@click.argument("vela-args", nargs=-1, type=click.UNPROCESSED) -def run_vela(input_model: str, output_model: str, vela_args: Tuple) -> None: - """Check input, run Vela (if needed) and copy optimised file to destination.""" - output_dir = Path(output_model).parent - try: - check_model(input_model) # raises an exception if already Vela-optimised - execute_vela(vela_args, output_dir, input_model) - print("Vela optimisation complete.") - src_model = vela_output_model_path(input_model, str(output_dir)) - except ModelOptimisedException as ex: - # Input already optimized: copy input file to destination path and return - print(f"Input already vela-optimised.\n{ex}") - src_model = Path(input_model) - except subprocess.CalledProcessError as ex: - print(ex) - raise SystemExit(ex.returncode) from ex - - try: - shutil.copyfile(src_model, output_model) - except (shutil.SameFileError, OSError) as ex: - print(ex) - raise SystemExit(ex.errno) from ex - - -def main() -> None: - """Entry point of check_model application.""" - run_vela() # pylint: disable=no-value-for-parameter diff --git a/src/aiet/resources/tools/vela/vela.ini b/src/aiet/resources/tools/vela/vela.ini deleted file mode 100644 index 5996553..0000000 --- a/src/aiet/resources/tools/vela/vela.ini +++ /dev/null @@ -1,53 +0,0 @@ -; SPDX-FileCopyrightText: Copyright 2021-2022, Arm Limited and/or its affiliates. -; SPDX-License-Identifier: Apache-2.0 - -; ----------------------------------------------------------------------------- -; Vela configuration file - -; ----------------------------------------------------------------------------- -; System Configuration - -; Ethos-U55 High-End Embedded: SRAM (4 GB/s) and Flash (0.5 GB/s) -[System_Config.Ethos_U55_High_End_Embedded] -core_clock=500e6 -axi0_port=Sram -axi1_port=OffChipFlash -Sram_clock_scale=1.0 -Sram_burst_length=32 -Sram_read_latency=32 -Sram_write_latency=32 -OffChipFlash_clock_scale=0.125 -OffChipFlash_burst_length=128 -OffChipFlash_read_latency=64 -OffChipFlash_write_latency=64 - -; Ethos-U65 High-End: SRAM (16 GB/s) and DRAM (3.75 GB/s) -[System_Config.Ethos_U65_High_End] -core_clock=1e9 -axi0_port=Sram -axi1_port=Dram -Sram_clock_scale=1.0 -Sram_burst_length=32 -Sram_read_latency=32 -Sram_write_latency=32 -Dram_clock_scale=0.234375 -Dram_burst_length=128 -Dram_read_latency=500 -Dram_write_latency=250 - -; ----------------------------------------------------------------------------- -; Memory Mode - -; Shared SRAM: the SRAM is shared between the Ethos-U and the Cortex-M software -; The non-SRAM memory is assumed to be read-only -[Memory_Mode.U55_Shared_Sram] -const_mem_area=Axi1 -arena_mem_area=Axi0 -cache_mem_area=Axi0 -arena_cache_size=4194304 - -[Memory_Mode.U65_Shared_Sram] -const_mem_area=Axi1 -arena_mem_area=Axi0 -cache_mem_area=Axi0 -arena_cache_size=2097152 diff --git a/src/aiet/utils/__init__.py b/src/aiet/utils/__init__.py deleted file mode 100644 index fc7ef7c..0000000 --- a/src/aiet/utils/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -# SPDX-FileCopyrightText: Copyright 2022, Arm Limited and/or its affiliates. -# SPDX-License-Identifier: Apache-2.0 -"""This module contains all utils shared across aiet project.""" diff --git a/src/aiet/utils/helpers.py b/src/aiet/utils/helpers.py deleted file mode 100644 index 6d3cd22..0000000 --- a/src/aiet/utils/helpers.py +++ /dev/null @@ -1,17 +0,0 @@ -# SPDX-FileCopyrightText: Copyright 2022, Arm Limited and/or its affiliates. -# SPDX-License-Identifier: Apache-2.0 -"""Helpers functions.""" -import logging -from typing import Any - - -def set_verbosity( - ctx: Any, option: Any, verbosity: Any # pylint: disable=unused-argument -) -> None: - """Set the logging level according to the verbosity.""" - # Unused arguments must be present here in definition as these are required in - # function definition when set as a callback - if verbosity == 1: - logging.getLogger().setLevel(logging.INFO) - elif verbosity > 1: - logging.getLogger().setLevel(logging.DEBUG) diff --git a/src/aiet/backend/__init__.py b/src/mlia/backend/__init__.py index 3d60372..3d60372 100644 --- a/src/aiet/backend/__init__.py +++ b/src/mlia/backend/__init__.py diff --git a/src/aiet/backend/application.py b/src/mlia/backend/application.py index f6ef815..eb85212 100644 --- a/src/aiet/backend/application.py +++ b/src/mlia/backend/application.py @@ -9,19 +9,19 @@ from typing import Dict from typing import List from typing import Optional -from aiet.backend.common import Backend -from aiet.backend.common import ConfigurationException -from aiet.backend.common import DataPaths -from aiet.backend.common import get_backend_configs -from aiet.backend.common import get_backend_directories -from aiet.backend.common import load_application_or_tool_configs -from aiet.backend.common import load_config -from aiet.backend.common import remove_backend -from aiet.backend.config import ApplicationConfig -from aiet.backend.config import ExtendedApplicationConfig -from aiet.backend.source import create_destination_and_install -from aiet.backend.source import get_source -from aiet.utils.fs import get_resources +from mlia.backend.common import Backend +from mlia.backend.common import ConfigurationException +from mlia.backend.common import DataPaths +from mlia.backend.common import get_backend_configs +from mlia.backend.common import get_backend_directories +from mlia.backend.common import load_application_or_tool_configs +from mlia.backend.common import load_config +from mlia.backend.common import remove_backend +from mlia.backend.config import ApplicationConfig +from mlia.backend.config import ExtendedApplicationConfig +from mlia.backend.fs import get_backends_path +from mlia.backend.source import create_destination_and_install +from mlia.backend.source import get_source def get_available_application_directory_names() -> List[str]: @@ -78,7 +78,7 @@ def install_application(source_path: Path) -> None: "Applications [{}] are already installed".format(",".join(names)) ) - create_destination_and_install(source, get_resources("applications")) + create_destination_and_install(source, get_backends_path("applications")) def remove_application(directory_name: str) -> None: diff --git a/src/aiet/backend/common.py b/src/mlia/backend/common.py index b887ee7..2bbb9d3 100644 --- a/src/aiet/backend/common.py +++ b/src/mlia/backend/common.py @@ -23,17 +23,17 @@ from typing import Tuple from typing import Type from typing import Union -from aiet.backend.config import BackendConfig -from aiet.backend.config import BaseBackendConfig -from aiet.backend.config import NamedExecutionConfig -from aiet.backend.config import UserParamConfig -from aiet.backend.config import UserParamsConfig -from aiet.utils.fs import get_resources -from aiet.utils.fs import remove_resource -from aiet.utils.fs import ResourceType +from mlia.backend.config import BackendConfig +from mlia.backend.config import BaseBackendConfig +from mlia.backend.config import NamedExecutionConfig +from mlia.backend.config import UserParamConfig +from mlia.backend.config import UserParamsConfig +from mlia.backend.fs import get_backends_path +from mlia.backend.fs import remove_resource +from mlia.backend.fs import ResourceType -AIET_CONFIG_FILE: Final[str] = "aiet-config.json" +BACKEND_CONFIG_FILE: Final[str] = "aiet-config.json" class ConfigurationException(Exception): @@ -42,7 +42,7 @@ class ConfigurationException(Exception): def get_backend_config(dir_path: Path) -> Path: """Get path to backendir configuration file.""" - return dir_path / AIET_CONFIG_FILE + return dir_path / BACKEND_CONFIG_FILE def get_backend_configs(resource_type: ResourceType) -> Iterable[Path]: @@ -56,7 +56,7 @@ def get_backend_directories(resource_type: ResourceType) -> Iterable[Path]: """Get path to the backend directories for provided resource_type.""" return ( entry - for entry in get_resources(resource_type).iterdir() + for entry in get_backends_path(resource_type).iterdir() if is_backend_directory(entry) ) diff --git a/src/aiet/backend/config.py b/src/mlia/backend/config.py index dd42012..657adef 100644 --- a/src/aiet/backend/config.py +++ b/src/mlia/backend/config.py @@ -89,19 +89,5 @@ class SystemConfig(BaseBackendConfig, total=False): reporting: Dict[str, Dict] -class ToolConfig(BaseBackendConfig, total=False): - """Tool configuration.""" - - supported_systems: List[str] - - -class ExtendedToolConfig(BaseBackendConfig, total=False): - """Extended tool configuration.""" - - supported_systems: List[NamedExecutionConfig] - - -BackendItemConfig = Union[ApplicationConfig, SystemConfig, ToolConfig] -BackendConfig = Union[ - List[ExtendedApplicationConfig], List[SystemConfig], List[ToolConfig] -] +BackendItemConfig = Union[ApplicationConfig, SystemConfig] +BackendConfig = Union[List[ExtendedApplicationConfig], List[SystemConfig]] diff --git a/src/aiet/backend/controller.py b/src/mlia/backend/controller.py index 2650902..f1b68a9 100644 --- a/src/aiet/backend/controller.py +++ b/src/mlia/backend/controller.py @@ -10,14 +10,14 @@ from typing import Tuple import psutil import sh -from aiet.backend.common import ConfigurationException -from aiet.utils.fs import read_file_as_string -from aiet.utils.proc import execute_command -from aiet.utils.proc import get_stdout_stderr_paths -from aiet.utils.proc import read_process_info -from aiet.utils.proc import save_process_info -from aiet.utils.proc import terminate_command -from aiet.utils.proc import terminate_external_process +from mlia.backend.common import ConfigurationException +from mlia.backend.fs import read_file_as_string +from mlia.backend.proc import execute_command +from mlia.backend.proc import get_stdout_stderr_paths +from mlia.backend.proc import read_process_info +from mlia.backend.proc import save_process_info +from mlia.backend.proc import terminate_command +from mlia.backend.proc import terminate_external_process class SystemController: diff --git a/src/aiet/backend/execution.py b/src/mlia/backend/execution.py index 1653ee2..749ccdb 100644 --- a/src/aiet/backend/execution.py +++ b/src/mlia/backend/execution.py @@ -8,7 +8,6 @@ import re import string import sys import time -import warnings from collections import defaultdict from contextlib import contextmanager from contextlib import ExitStack @@ -24,32 +23,29 @@ from typing import Optional from typing import Sequence from typing import Tuple from typing import TypedDict -from typing import Union from filelock import FileLock from filelock import Timeout -from aiet.backend.application import Application -from aiet.backend.application import get_application -from aiet.backend.common import Backend -from aiet.backend.common import ConfigurationException -from aiet.backend.common import DataPaths -from aiet.backend.common import Param -from aiet.backend.common import parse_raw_parameter -from aiet.backend.common import resolve_all_parameters -from aiet.backend.output_parser import Base64OutputParser -from aiet.backend.output_parser import OutputParser -from aiet.backend.output_parser import RegexOutputParser -from aiet.backend.system import ControlledSystem -from aiet.backend.system import get_system -from aiet.backend.system import StandaloneSystem -from aiet.backend.system import System -from aiet.backend.tool import get_tool -from aiet.backend.tool import Tool -from aiet.utils.fs import recreate_directory -from aiet.utils.fs import remove_directory -from aiet.utils.fs import valid_for_filename -from aiet.utils.proc import run_and_wait +from mlia.backend.application import Application +from mlia.backend.application import get_application +from mlia.backend.common import Backend +from mlia.backend.common import ConfigurationException +from mlia.backend.common import DataPaths +from mlia.backend.common import Param +from mlia.backend.common import parse_raw_parameter +from mlia.backend.common import resolve_all_parameters +from mlia.backend.fs import recreate_directory +from mlia.backend.fs import remove_directory +from mlia.backend.fs import valid_for_filename +from mlia.backend.output_parser import Base64OutputParser +from mlia.backend.output_parser import OutputParser +from mlia.backend.output_parser import RegexOutputParser +from mlia.backend.proc import run_and_wait +from mlia.backend.system import ControlledSystem +from mlia.backend.system import get_system +from mlia.backend.system import StandaloneSystem +from mlia.backend.system import System class AnotherInstanceIsRunningException(Exception): @@ -73,7 +69,7 @@ class ExecutionContext: # pylint: disable=too-many-arguments,too-many-instance-attributes def __init__( self, - app: Union[Application, Tool], + app: Application, app_params: List[str], system: Optional[System], system_params: List[str], @@ -106,14 +102,13 @@ class ExecutionContext: self.param_resolver = ParamResolver(self) self._resolved_build_dir: Optional[Path] = None + self.stdout: Optional[bytearray] = None + self.stderr: Optional[bytearray] = None + @property def is_deploy_needed(self) -> bool: """Check if application requires data deployment.""" - if isinstance(self.app, Application): - return ( - len(self.app.get_deploy_data()) > 0 or len(self.custom_deploy_data) > 0 - ) - return False + return len(self.app.get_deploy_data()) > 0 or len(self.custom_deploy_data) > 0 @property def is_locking_required(self) -> bool: @@ -533,45 +528,6 @@ def get_application_and_system( return application, system -def execute_application_command( # pylint: disable=too-many-arguments - command_name: str, - application_name: str, - application_params: List[str], - system_name: str, - system_params: List[str], - custom_deploy_data: List[DataPaths], -) -> None: - """Execute application command. - - .. deprecated:: 21.12 - """ - warnings.warn( - "Use 'run_application()' instead. Use of 'execute_application_command()' is " - "deprecated and might be removed in a future release.", - DeprecationWarning, - ) - - if command_name not in ["build", "run"]: - raise ConfigurationException("Unsupported command {}".format(command_name)) - - application, system = get_application_and_system(application_name, system_name) - validate_parameters(application, [command_name], application_params) - validate_parameters(system, [command_name], system_params) - - ctx = ExecutionContext( - app=application, - app_params=application_params, - system=system, - system_params=system_params, - custom_deploy_data=custom_deploy_data, - ) - - if command_name == "run": - execute_application_command_run(ctx) - else: - execute_application_command_build(ctx) - - # pylint: disable=too-many-arguments def run_application( application_name: str, @@ -580,7 +536,7 @@ def run_application( system_params: List[str], custom_deploy_data: List[DataPaths], report_file: Optional[Path] = None, -) -> None: +) -> ExecutionContext: """Run application on the provided system.""" application, system = get_application_and_system(application_name, system_name) validate_parameters(application, ["build", "run"], application_params) @@ -607,6 +563,8 @@ def run_application( execute_application_command_run(ctx) + return ctx + def execute_application_command_build(ctx: ExecutionContext) -> None: """Execute application command 'build'.""" @@ -655,17 +613,14 @@ def execute_application_command_run(ctx: ExecutionContext) -> None: for command in commands_to_run: print("Running: {}".format(command)) - exit_code, std_output, std_err = ctx.system.run(command) + exit_code, ctx.stdout, ctx.stderr = ctx.system.run(command) if exit_code != 0: print("Application exited with exit code {}".format(exit_code)) if ctx.reporter: - ctx.reporter.parse(std_output) - std_output = ctx.reporter.get_filtered_output(std_output) - - print(std_output.decode("utf8"), end="") - print(std_err.decode("utf8"), end="") + ctx.reporter.parse(ctx.stdout) + ctx.stdout = ctx.reporter.get_filtered_output(ctx.stdout) if ctx.reporter: report = ctx.reporter.report(ctx) @@ -717,12 +672,10 @@ def wait(interval: float) -> None: def deploy_data(ctx: ExecutionContext) -> None: """Deploy data to the system.""" - if isinstance(ctx.app, Application): - # Only application can deploy data (tools can not) - assert ctx.system is not None, "System is required." - for item in itertools.chain(ctx.app.get_deploy_data(), ctx.custom_deploy_data): - print("Deploying {} onto {}".format(item.src, item.dst)) - ctx.system.deploy(item.src, item.dst) + assert ctx.system is not None, "System is required." + for item in itertools.chain(ctx.app.get_deploy_data(), ctx.custom_deploy_data): + print("Deploying {} onto {}".format(item.src, item.dst)) + ctx.system.deploy(item.src, item.dst) def build_run_commands(ctx: ExecutionContext) -> List[str]: @@ -824,36 +777,3 @@ def get_context_managers( managers.append(controlled_system_manager) return managers - - -def get_tool_by_system(tool_name: str, system_name: Optional[str]) -> Tool: - """Return tool (optionally by provided system name.""" - tools = get_tool(tool_name, system_name) - if not tools: - raise ConfigurationException( - "Tool '{}' not found or doesn't support the system '{}'".format( - tool_name, system_name - ) - ) - if len(tools) != 1: - raise ConfigurationException( - "Please specify the system for tool {}.".format(tool_name) - ) - tool = tools[0] - - return tool - - -def execute_tool_command( - tool_name: str, - tool_params: List[str], - system_name: Optional[str] = None, -) -> None: - """Execute the tool command locally calling the 'run' command.""" - tool = get_tool_by_system(tool_name, system_name) - ctx = ExecutionContext( - app=tool, app_params=tool_params, system=None, system_params=[] - ) - commands = tool.build_command("run", tool_params, ctx.param_resolver) - - execute_commands_locally(commands, Path.cwd()) diff --git a/src/aiet/utils/fs.py b/src/mlia/backend/fs.py index ea99a69..9979fcb 100644 --- a/src/aiet/utils/fs.py +++ b/src/mlia/backend/fs.py @@ -1,7 +1,6 @@ # SPDX-FileCopyrightText: Copyright 2022, Arm Limited and/or its affiliates. # SPDX-License-Identifier: Apache-2.0 """Module to host all file system related functions.""" -import importlib.resources as pkg_resources import re import shutil from pathlib import Path @@ -9,17 +8,17 @@ from typing import Any from typing import Literal from typing import Optional -ResourceType = Literal["applications", "systems", "tools"] +from mlia.utils.filesystem import get_mlia_resources +ResourceType = Literal["applications", "systems"] -def get_aiet_resources() -> Path: - """Get resources folder path.""" - with pkg_resources.path("aiet", "__init__.py") as init_path: - project_root = init_path.parent - return project_root / "resources" +def get_backend_resources() -> Path: + """Get backend resources folder path.""" + return get_mlia_resources() / "backends" -def get_resources(name: ResourceType) -> Path: + +def get_backends_path(name: ResourceType) -> Path: """Return the absolute path of the specified resource. It uses importlib to return resources packaged with MANIFEST.in. @@ -27,7 +26,7 @@ def get_resources(name: ResourceType) -> Path: if not name: raise ResourceWarning("Resource name is not provided") - resource_path = get_aiet_resources() / name + resource_path = get_backend_resources() / name if resource_path.is_dir(): return resource_path @@ -48,7 +47,7 @@ def copy_directory_content(source: Path, destination: Path) -> None: def remove_resource(resource_directory: str, resource_type: ResourceType) -> None: """Remove resource data.""" - resources = get_resources(resource_type) + resources = get_backends_path(resource_type) resource_location = resources / resource_directory if not resource_location.exists(): diff --git a/src/mlia/tools/aiet_wrapper.py b/src/mlia/backend/manager.py index 73e82ee..3a1016c 100644 --- a/src/mlia/tools/aiet_wrapper.py +++ b/src/mlia/backend/manager.py @@ -1,6 +1,6 @@ # SPDX-FileCopyrightText: Copyright 2022, Arm Limited and/or its affiliates. # SPDX-License-Identifier: Apache-2.0 -"""Module for AIET integration.""" +"""Module for backend integration.""" import logging import re from abc import ABC @@ -14,11 +14,13 @@ from typing import Literal from typing import Optional from typing import Tuple -from aiet.backend.application import get_available_applications -from aiet.backend.application import install_application -from aiet.backend.system import get_available_systems -from aiet.backend.system import install_system -from mlia.utils.proc import CommandExecutor +from mlia.backend.application import get_available_applications +from mlia.backend.application import install_application +from mlia.backend.common import DataPaths +from mlia.backend.execution import ExecutionContext +from mlia.backend.execution import run_application +from mlia.backend.system import get_available_systems +from mlia.backend.system import install_system from mlia.utils.proc import OutputConsumer from mlia.utils.proc import RunningCommand @@ -54,7 +56,7 @@ _SYSTEM_TO_APP_MAP = { def get_system_name(backend: str, device_type: str) -> str: - """Get the AIET system name for the given backend and device type.""" + """Get the system name for the given backend and device type.""" return _SUPPORTED_SYSTEMS[backend][device_type] @@ -71,7 +73,7 @@ def is_supported(backend: str, device_type: Optional[str] = None) -> bool: def supported_backends() -> List[str]: - """Get a list of all backends supported by the AIET wrapper.""" + """Get a list of all backends supported by the backend manager.""" return list(_SUPPORTED_SYSTEMS.keys()) @@ -129,8 +131,8 @@ class ExecutionParams: deploy_params: List[str] -class AIETLogWriter(OutputConsumer): - """Redirect AIET command output to the logger.""" +class LogWriter(OutputConsumer): + """Redirect output to the logger.""" def feed(self, line: str) -> None: """Process line from the output.""" @@ -211,12 +213,11 @@ class GenericInferenceOutputParser(OutputConsumer): return sorted(self.PATTERNS.keys() - self.result.keys()) -class AIETRunner: - """AIET runner.""" +class BackendRunner: + """Backend runner.""" - def __init__(self, executor: CommandExecutor) -> None: - """Init AIET runner instance.""" - self.executor = executor + def __init__(self) -> None: + """Init BackendRunner instance.""" @staticmethod def get_installed_systems() -> List[str]: @@ -270,39 +271,40 @@ class AIETRunner: """Install application.""" install_application(app_path) - def run_application(self, execution_params: ExecutionParams) -> RunningCommand: + @staticmethod + def run_application(execution_params: ExecutionParams) -> ExecutionContext: """Run requested application.""" - command = [ - "aiet", - "application", - "run", - "-n", + + def to_data_paths(paths: str) -> DataPaths: + """Split input into two and create new DataPaths object.""" + src, dst = paths.split(sep=":", maxsplit=1) + return DataPaths(Path(src), dst) + + deploy_data_paths = [ + to_data_paths(paths) for paths in execution_params.deploy_params + ] + + ctx = run_application( execution_params.application, - "-s", + execution_params.application_params, execution_params.system, - *self._params("-p", execution_params.application_params), - *self._params("--system-param", execution_params.system_params), - *self._params("--deploy", execution_params.deploy_params), - ] + execution_params.system_params, + deploy_data_paths, + ) - return self._submit(command) + return ctx @staticmethod def _params(name: str, params: List[str]) -> List[str]: return [p for item in [(name, param) for param in params] for p in item] - def _submit(self, command: List[str]) -> RunningCommand: - """Submit command for the execution.""" - logger.debug("Submit command %s", " ".join(command)) - return self.executor.submit(command) - class GenericInferenceRunner(ABC): """Abstract class for generic inference runner.""" - def __init__(self, aiet_runner: AIETRunner): + def __init__(self, backend_runner: BackendRunner): """Init generic inference runner instance.""" - self.aiet_runner = aiet_runner + self.backend_runner = backend_runner self.running_inference: Optional[RunningCommand] = None def run( @@ -311,9 +313,9 @@ class GenericInferenceRunner(ABC): """Run generic inference for the provided device/model.""" execution_params = self.get_execution_params(model_info) - self.running_inference = self.aiet_runner.run_application(execution_params) - self.running_inference.output_consumers = output_consumers - self.running_inference.consume_output() + ctx = self.backend_runner.run_application(execution_params) + if ctx.stdout is not None: + self.consume_output(ctx.stdout, output_consumers) def stop(self) -> None: """Stop running inference.""" @@ -336,24 +338,31 @@ class GenericInferenceRunner(ABC): def check_system_and_application(self, system_name: str, app_name: str) -> None: """Check if requested system and application installed.""" - if not self.aiet_runner.is_system_installed(system_name): + if not self.backend_runner.is_system_installed(system_name): raise Exception(f"System {system_name} is not installed") - if not self.aiet_runner.is_application_installed(app_name, system_name): + if not self.backend_runner.is_application_installed(app_name, system_name): raise Exception( f"Application {app_name} for the system {system_name} " "is not installed" ) + @staticmethod + def consume_output(output: bytearray, consumers: List[OutputConsumer]) -> None: + """Pass program's output to the consumers.""" + for line in output.decode("utf8").splitlines(): + for consumer in consumers: + consumer.feed(line) + class GenericInferenceRunnerEthosU(GenericInferenceRunner): """Generic inference runner on U55/65.""" def __init__( - self, aiet_runner: AIETRunner, device_info: DeviceInfo, backend: str + self, backend_runner: BackendRunner, device_info: DeviceInfo, backend: str ) -> None: """Init generic inference runner instance.""" - super().__init__(aiet_runner) + super().__init__(backend_runner) system_name, app_name = self.resolve_system_and_app(device_info, backend) self.system_name = system_name @@ -405,8 +414,8 @@ class GenericInferenceRunnerEthosU(GenericInferenceRunner): def get_generic_runner(device_info: DeviceInfo, backend: str) -> GenericInferenceRunner: """Get generic runner for provided device and backend.""" - aiet_runner = get_aiet_runner() - return GenericInferenceRunnerEthosU(aiet_runner, device_info, backend) + backend_runner = get_backend_runner() + return GenericInferenceRunnerEthosU(backend_runner, device_info, backend) def estimate_performance( @@ -415,7 +424,7 @@ def estimate_performance( """Get performance estimations.""" with get_generic_runner(device_info, backend) as generic_runner: output_parser = GenericInferenceOutputParser() - output_consumers = [output_parser, AIETLogWriter()] + output_consumers = [output_parser, LogWriter()] generic_runner.run(model_info, output_consumers) @@ -429,7 +438,10 @@ def estimate_performance( return PerformanceMetrics(**output_parser.result) -def get_aiet_runner() -> AIETRunner: - """Return AIET runner.""" - executor = CommandExecutor() - return AIETRunner(executor) +def get_backend_runner() -> BackendRunner: + """ + Return BackendRunner instance. + + Note: This is needed for the unit tests. + """ + return BackendRunner() diff --git a/src/aiet/backend/output_parser.py b/src/mlia/backend/output_parser.py index 111772a..111772a 100644 --- a/src/aiet/backend/output_parser.py +++ b/src/mlia/backend/output_parser.py diff --git a/src/aiet/utils/proc.py b/src/mlia/backend/proc.py index b6f4357..90ff414 100644 --- a/src/aiet/utils/proc.py +++ b/src/mlia/backend/proc.py @@ -24,7 +24,7 @@ from sh import CommandNotFound from sh import ErrorReturnCode from sh import RunningCommand -from aiet.utils.fs import valid_for_filename +from mlia.backend.fs import valid_for_filename class CommandFailedException(Exception): diff --git a/src/aiet/backend/protocol.py b/src/mlia/backend/protocol.py index c621436..ebfe69a 100644 --- a/src/aiet/backend/protocol.py +++ b/src/mlia/backend/protocol.py @@ -14,10 +14,10 @@ from typing import Union import paramiko -from aiet.backend.common import ConfigurationException -from aiet.backend.config import LocalProtocolConfig -from aiet.backend.config import SSHConfig -from aiet.utils.proc import run_and_wait +from mlia.backend.common import ConfigurationException +from mlia.backend.config import LocalProtocolConfig +from mlia.backend.config import SSHConfig +from mlia.backend.proc import run_and_wait # Redirect all paramiko thread exceptions to a file otherwise these will be diff --git a/src/aiet/backend/source.py b/src/mlia/backend/source.py index dec175a..dcf6835 100644 --- a/src/aiet/backend/source.py +++ b/src/mlia/backend/source.py @@ -11,13 +11,13 @@ from tarfile import TarFile from typing import Optional from typing import Union -from aiet.backend.common import AIET_CONFIG_FILE -from aiet.backend.common import ConfigurationException -from aiet.backend.common import get_backend_config -from aiet.backend.common import is_backend_directory -from aiet.backend.common import load_config -from aiet.backend.config import BackendConfig -from aiet.utils.fs import copy_directory_content +from mlia.backend.common import BACKEND_CONFIG_FILE +from mlia.backend.common import ConfigurationException +from mlia.backend.common import get_backend_config +from mlia.backend.common import is_backend_directory +from mlia.backend.common import load_config +from mlia.backend.config import BackendConfig +from mlia.backend.fs import copy_directory_content class Source(ABC): @@ -99,7 +99,7 @@ class TarArchiveSource(Source): with self._open(self.archive_path) as archive: try: - config_entry = archive.getmember(AIET_CONFIG_FILE) + config_entry = archive.getmember(BACKEND_CONFIG_FILE) self._has_top_level_folder = False except KeyError as error_no_config: try: @@ -112,7 +112,7 @@ class TarArchiveSource(Source): "Archive has no top level directory" ) from error_no_config - config_path = "{}/{}".format(top_level_dir, AIET_CONFIG_FILE) + config_path = "{}/{}".format(top_level_dir, BACKEND_CONFIG_FILE) config_entry = archive.getmember(config_path) self._has_top_level_folder = True diff --git a/src/aiet/backend/system.py b/src/mlia/backend/system.py index 48f1bb1..469083e 100644 --- a/src/aiet/backend/system.py +++ b/src/mlia/backend/system.py @@ -10,22 +10,22 @@ from typing import Optional from typing import Tuple from typing import Union -from aiet.backend.common import Backend -from aiet.backend.common import ConfigurationException -from aiet.backend.common import get_backend_configs -from aiet.backend.common import get_backend_directories -from aiet.backend.common import load_config -from aiet.backend.common import remove_backend -from aiet.backend.config import SystemConfig -from aiet.backend.controller import SystemController -from aiet.backend.controller import SystemControllerSingleInstance -from aiet.backend.protocol import ProtocolFactory -from aiet.backend.protocol import SupportsClose -from aiet.backend.protocol import SupportsConnection -from aiet.backend.protocol import SupportsDeploy -from aiet.backend.source import create_destination_and_install -from aiet.backend.source import get_source -from aiet.utils.fs import get_resources +from mlia.backend.common import Backend +from mlia.backend.common import ConfigurationException +from mlia.backend.common import get_backend_configs +from mlia.backend.common import get_backend_directories +from mlia.backend.common import load_config +from mlia.backend.common import remove_backend +from mlia.backend.config import SystemConfig +from mlia.backend.controller import SystemController +from mlia.backend.controller import SystemControllerSingleInstance +from mlia.backend.fs import get_backends_path +from mlia.backend.protocol import ProtocolFactory +from mlia.backend.protocol import SupportsClose +from mlia.backend.protocol import SupportsConnection +from mlia.backend.protocol import SupportsDeploy +from mlia.backend.source import create_destination_and_install +from mlia.backend.source import get_source def get_available_systems_directory_names() -> List[str]: @@ -75,7 +75,7 @@ def install_system(source_path: Path) -> None: "Systems [{}] are already installed".format(",".join(names)) ) - create_destination_and_install(source, get_resources("systems")) + create_destination_and_install(source, get_backends_path("systems")) def remove_system(directory_name: str) -> None: diff --git a/src/mlia/cli/config.py b/src/mlia/cli/config.py index 838b051..a673230 100644 --- a/src/mlia/cli/config.py +++ b/src/mlia/cli/config.py @@ -5,7 +5,7 @@ import logging from functools import lru_cache from typing import List -import mlia.tools.aiet_wrapper as aiet +import mlia.backend.manager as backend_manager from mlia.tools.metadata.common import DefaultInstallationManager from mlia.tools.metadata.common import InstallationManager from mlia.tools.metadata.corstone import get_corstone_installations @@ -25,12 +25,12 @@ def get_available_backends() -> List[str]: """Return list of the available backends.""" available_backends = ["Vela"] - # Add backends using AIET + # Add backends using backend manager manager = get_installation_manager() available_backends.extend( ( backend - for backend in aiet.supported_backends() + for backend in backend_manager.supported_backends() if manager.backend_installed(backend) ) ) diff --git a/src/mlia/devices/ethosu/performance.py b/src/mlia/devices/ethosu/performance.py index b0718a5..a73045a 100644 --- a/src/mlia/devices/ethosu/performance.py +++ b/src/mlia/devices/ethosu/performance.py @@ -10,7 +10,7 @@ from typing import Optional from typing import Tuple from typing import Union -import mlia.tools.aiet_wrapper as aiet +import mlia.backend.manager as backend_manager import mlia.tools.vela_wrapper as vela from mlia.core.context import Context from mlia.core.performance import PerformanceEstimator @@ -147,15 +147,15 @@ class VelaPerformanceEstimator( return memory_usage -class AIETPerformanceEstimator( +class CorstonePerformanceEstimator( PerformanceEstimator[Union[Path, ModelConfiguration], NPUCycles] ): - """AIET based performance estimator.""" + """Corstone-based performance estimator.""" def __init__( self, context: Context, device: EthosUConfiguration, backend: str ) -> None: - """Init AIET based performance estimator.""" + """Init Corstone-based performance estimator.""" self.context = context self.device = device self.backend = backend @@ -179,24 +179,24 @@ class AIETPerformanceEstimator( model_path, self.device.compiler_options, optimized_model_path ) - model_info = aiet.ModelInfo(model_path=optimized_model_path) - device_info = aiet.DeviceInfo( + model_info = backend_manager.ModelInfo(model_path=optimized_model_path) + device_info = backend_manager.DeviceInfo( device_type=self.device.target, # type: ignore mac=self.device.mac, memory_mode=self.device.compiler_options.memory_mode, # type: ignore ) - aiet_perf_metrics = aiet.estimate_performance( + corstone_perf_metrics = backend_manager.estimate_performance( model_info, device_info, self.backend ) npu_cycles = NPUCycles( - aiet_perf_metrics.npu_active_cycles, - aiet_perf_metrics.npu_idle_cycles, - aiet_perf_metrics.npu_total_cycles, - aiet_perf_metrics.npu_axi0_rd_data_beat_received, - aiet_perf_metrics.npu_axi0_wr_data_beat_written, - aiet_perf_metrics.npu_axi1_rd_data_beat_received, + corstone_perf_metrics.npu_active_cycles, + corstone_perf_metrics.npu_idle_cycles, + corstone_perf_metrics.npu_total_cycles, + corstone_perf_metrics.npu_axi0_rd_data_beat_received, + corstone_perf_metrics.npu_axi0_wr_data_beat_written, + corstone_perf_metrics.npu_axi1_rd_data_beat_received, ) logger.info("Done\n") @@ -220,10 +220,11 @@ class EthosUPerformanceEstimator( if backends is None: backends = ["Vela"] # Only Vela is always available as default for backend in backends: - if backend != "Vela" and not aiet.is_supported(backend): + if backend != "Vela" and not backend_manager.is_supported(backend): raise ValueError( f"Unsupported backend '{backend}'. " - f"Only 'Vela' and {aiet.supported_backends()} are supported." + f"Only 'Vela' and {backend_manager.supported_backends()} " + "are supported." ) self.backends = set(backends) @@ -242,11 +243,11 @@ class EthosUPerformanceEstimator( if backend == "Vela": vela_estimator = VelaPerformanceEstimator(self.context, self.device) memory_usage = vela_estimator.estimate(tflite_model) - elif backend in aiet.supported_backends(): - aiet_estimator = AIETPerformanceEstimator( + elif backend in backend_manager.supported_backends(): + corstone_estimator = CorstonePerformanceEstimator( self.context, self.device, backend ) - npu_cycles = aiet_estimator.estimate(tflite_model) + npu_cycles = corstone_estimator.estimate(tflite_model) else: logger.warning( "Backend '%s' is not supported for Ethos-U performance " diff --git a/src/mlia/resources/aiet/applications/APPLICATIONS.txt b/src/mlia/resources/aiet/applications/APPLICATIONS.txt index 09127f8..a702e19 100644 --- a/src/mlia/resources/aiet/applications/APPLICATIONS.txt +++ b/src/mlia/resources/aiet/applications/APPLICATIONS.txt @@ -1,6 +1,7 @@ SPDX-FileCopyrightText: Copyright 2022, Arm Limited and/or its affiliates. SPDX-License-Identifier: Apache-2.0 -This directory contains the Generic Inference Runner application packages for AIET +This directory contains the application packages for the Generic Inference +Runner. -Each package should contain its own aiet-config.json file +Each package should contain its own aiet-config.json file. diff --git a/src/mlia/resources/aiet/systems/SYSTEMS.txt b/src/mlia/resources/aiet/systems/SYSTEMS.txt index bc27e73..3861769 100644 --- a/src/mlia/resources/aiet/systems/SYSTEMS.txt +++ b/src/mlia/resources/aiet/systems/SYSTEMS.txt @@ -1,8 +1,7 @@ SPDX-FileCopyrightText: Copyright 2022, Arm Limited and/or its affiliates. SPDX-License-Identifier: Apache-2.0 -This directory contains the configuration files of the systems for the AIET -middleware. +This directory contains the configuration files of the system backends. Supported systems: diff --git a/src/aiet/resources/applications/.gitignore b/src/mlia/resources/backends/applications/.gitignore index 0226166..0226166 100644 --- a/src/aiet/resources/applications/.gitignore +++ b/src/mlia/resources/backends/applications/.gitignore diff --git a/src/aiet/resources/systems/.gitignore b/src/mlia/resources/backends/systems/.gitignore index 0226166..0226166 100644 --- a/src/aiet/resources/systems/.gitignore +++ b/src/mlia/resources/backends/systems/.gitignore diff --git a/src/mlia/tools/metadata/corstone.py b/src/mlia/tools/metadata/corstone.py index 7a9d113..a92f81c 100644 --- a/src/mlia/tools/metadata/corstone.py +++ b/src/mlia/tools/metadata/corstone.py @@ -12,7 +12,8 @@ from typing import Iterable from typing import List from typing import Optional -import mlia.tools.aiet_wrapper as aiet +import mlia.backend.manager as backend_manager +from mlia.backend.fs import get_backend_resources from mlia.tools.metadata.common import DownloadAndInstall from mlia.tools.metadata.common import Installation from mlia.tools.metadata.common import InstallationType @@ -41,8 +42,8 @@ PathChecker = Callable[[Path], Optional[BackendInfo]] BackendInstaller = Callable[[bool, Path], Path] -class AIETMetadata: - """AIET installation metadata.""" +class BackendMetadata: + """Backend installation metadata.""" def __init__( self, @@ -55,7 +56,7 @@ class AIETMetadata: supported_platforms: Optional[List[str]] = None, ) -> None: """ - Initialize AIETMetaData. + Initialize BackendMetadata. Members expected_systems and expected_apps are filled automatically. """ @@ -67,15 +68,15 @@ class AIETMetadata: self.download_artifact = download_artifact self.supported_platforms = supported_platforms - self.expected_systems = aiet.get_all_system_names(name) - self.expected_apps = aiet.get_all_application_names(name) + self.expected_systems = backend_manager.get_all_system_names(name) + self.expected_apps = backend_manager.get_all_application_names(name) @property def expected_resources(self) -> Iterable[Path]: """Return list of expected resources.""" resources = [self.system_config, *self.apps_resources] - return (get_mlia_resources() / resource for resource in resources) + return (get_backend_resources() / resource for resource in resources) @property def supported_platform(self) -> bool: @@ -86,49 +87,49 @@ class AIETMetadata: return platform.system() in self.supported_platforms -class AIETBasedInstallation(Installation): - """Backend installation based on AIET functionality.""" +class BackendInstallation(Installation): + """Backend installation.""" def __init__( self, - aiet_runner: aiet.AIETRunner, - metadata: AIETMetadata, + backend_runner: backend_manager.BackendRunner, + metadata: BackendMetadata, path_checker: PathChecker, backend_installer: Optional[BackendInstaller], ) -> None: - """Init the tool installation.""" - self.aiet_runner = aiet_runner + """Init the backend installation.""" + self.backend_runner = backend_runner self.metadata = metadata self.path_checker = path_checker self.backend_installer = backend_installer @property def name(self) -> str: - """Return name of the tool.""" + """Return name of the backend.""" return self.metadata.name @property def description(self) -> str: - """Return description of the tool.""" + """Return description of the backend.""" return self.metadata.description @property def already_installed(self) -> bool: - """Return true if tool already installed.""" - return self.aiet_runner.all_installed( + """Return true if backend already installed.""" + return self.backend_runner.all_installed( self.metadata.expected_systems, self.metadata.expected_apps ) @property def could_be_installed(self) -> bool: - """Return true if tool could be installed.""" + """Return true if backend could be installed.""" if not self.metadata.supported_platform: return False return all_paths_valid(self.metadata.expected_resources) def supports(self, install_type: InstallationType) -> bool: - """Return true if tools supported type of the installation.""" + """Return true if backends supported type of the installation.""" if isinstance(install_type, DownloadAndInstall): return self.metadata.download_artifact is not None @@ -138,7 +139,7 @@ class AIETBasedInstallation(Installation): return False # type: ignore def install(self, install_type: InstallationType) -> None: - """Install the tool.""" + """Install the backend.""" if isinstance(install_type, DownloadAndInstall): download_artifact = self.metadata.download_artifact assert download_artifact is not None, "No artifact provided" @@ -153,7 +154,7 @@ class AIETBasedInstallation(Installation): raise Exception(f"Unable to install {install_type}") def install_from(self, backend_info: BackendInfo) -> None: - """Install tool from the directory.""" + """Install backend from the directory.""" mlia_resources = get_mlia_resources() with temp_directory() as tmpdir: @@ -169,15 +170,15 @@ class AIETBasedInstallation(Installation): copy_all(*resources_to_copy, dest=fvp_dist_dir) - self.aiet_runner.install_system(fvp_dist_dir) + self.backend_runner.install_system(fvp_dist_dir) for app in self.metadata.apps_resources: - self.aiet_runner.install_application(mlia_resources / app) + self.backend_runner.install_application(mlia_resources / app) def download_and_install( self, download_artifact: DownloadArtifact, eula_agrement: bool ) -> None: - """Download and install the tool.""" + """Download and install the backend.""" with temp_directory() as tmpdir: try: downloaded_to = download_artifact.download_to(tmpdir) @@ -307,10 +308,10 @@ class Corstone300Installer: def get_corstone_300_installation() -> Installation: """Get Corstone-300 installation.""" - corstone_300 = AIETBasedInstallation( - aiet_runner=aiet.get_aiet_runner(), + corstone_300 = BackendInstallation( + backend_runner=backend_manager.BackendRunner(), # pylint: disable=line-too-long - metadata=AIETMetadata( + metadata=BackendMetadata( name="Corstone-300", description="Corstone-300 FVP", system_config="aiet/systems/corstone-300/aiet-config.json", @@ -356,10 +357,10 @@ def get_corstone_300_installation() -> Installation: def get_corstone_310_installation() -> Installation: """Get Corstone-310 installation.""" - corstone_310 = AIETBasedInstallation( - aiet_runner=aiet.get_aiet_runner(), + corstone_310 = BackendInstallation( + backend_runner=backend_manager.BackendRunner(), # pylint: disable=line-too-long - metadata=AIETMetadata( + metadata=BackendMetadata( name="Corstone-310", description="Corstone-310 FVP", system_config="aiet/systems/corstone-310/aiet-config.json", diff --git a/src/mlia/utils/proc.py b/src/mlia/utils/proc.py index 39aca43..18a4305 100644 --- a/src/mlia/utils/proc.py +++ b/src/mlia/utils/proc.py @@ -8,7 +8,6 @@ import time from abc import ABC from abc import abstractmethod from contextlib import contextmanager -from contextlib import suppress from pathlib import Path from typing import Any from typing import Generator @@ -23,7 +22,7 @@ class OutputConsumer(ABC): @abstractmethod def feed(self, line: str) -> None: - """Feed new line to the consumerr.""" + """Feed new line to the consumer.""" class RunningCommand: @@ -32,7 +31,7 @@ class RunningCommand: def __init__(self, process: subprocess.Popen) -> None: """Init running command instance.""" self.process = process - self._output_consumers: Optional[List[OutputConsumer]] = None + self.output_consumers: List[OutputConsumer] = [] def is_alive(self) -> bool: """Return true if process is still alive.""" @@ -57,25 +56,14 @@ class RunningCommand: """Send signal to the process.""" self.process.send_signal(signal_num) - @property - def output_consumers(self) -> Optional[List[OutputConsumer]]: - """Property output_consumers.""" - return self._output_consumers - - @output_consumers.setter - def output_consumers(self, output_consumers: List[OutputConsumer]) -> None: - """Set output consumers.""" - self._output_consumers = output_consumers - def consume_output(self) -> None: """Pass program's output to the consumers.""" - if self.process is None or self.output_consumers is None: + if self.process is None or not self.output_consumers: return for line in self.stdout(): for consumer in self.output_consumers: - with suppress(): - consumer.feed(line) + consumer.feed(line) def stop( self, wait: bool = True, num_of_attempts: int = 5, interval: float = 0.5 |