diff options
Diffstat (limited to 'src/mlia/backend')
-rw-r--r-- | src/mlia/backend/corstone/install.py | 9 | ||||
-rw-r--r-- | src/mlia/backend/corstone/performance.py | 8 | ||||
-rw-r--r-- | src/mlia/backend/install.py | 40 | ||||
-rw-r--r-- | src/mlia/backend/manager.py | 56 |
4 files changed, 84 insertions, 29 deletions
diff --git a/src/mlia/backend/corstone/install.py b/src/mlia/backend/corstone/install.py index 5f11d5b..5c18334 100644 --- a/src/mlia/backend/corstone/install.py +++ b/src/mlia/backend/corstone/install.py @@ -19,7 +19,7 @@ from mlia.backend.install import CompoundPathChecker from mlia.backend.install import Installation from mlia.backend.install import PackagePathChecker from mlia.backend.install import StaticPathChecker -from mlia.utils.download import DownloadArtifact +from mlia.utils.download import DownloadConfig from mlia.utils.filesystem import working_directory @@ -159,8 +159,6 @@ def get_corstone_installation(corstone_name: str) -> Installation: archive = corstone_fvp.archive sha256_hash = corstone_fvp.sha256_hash url = ARM_ECOSYSTEM_FVP_URL + archive - filename = archive.split("/")[-1] - version = corstone_fvp.get_fvp_version() expected_files_fvp = corstone_fvp.fvp_expected_files expected_files_vht = corstone_fvp.get_vht_expected_files() backend_subfolder = expected_files_fvp[0].split("FVP")[0] @@ -169,11 +167,8 @@ def get_corstone_installation(corstone_name: str) -> Installation: name=corstone_name, description=corstone_name.capitalize() + " FVP", fvp_dir_name=corstone_name.replace("-", "_"), - download_artifact=DownloadArtifact( - name=corstone_name.capitalize() + " FVP", + download_config=DownloadConfig( url=url, - filename=filename, - version=version, sha256_hash=sha256_hash, ), supported_platforms=["Linux"], diff --git a/src/mlia/backend/corstone/performance.py b/src/mlia/backend/corstone/performance.py index fc50109..fe4e271 100644 --- a/src/mlia/backend/corstone/performance.py +++ b/src/mlia/backend/corstone/performance.py @@ -15,6 +15,7 @@ from mlia.backend.errors import BackendExecutionFailed from mlia.backend.repo import get_backend_repository from mlia.utils.filesystem import get_mlia_resources from mlia.utils.proc import Command +from mlia.utils.proc import OutputLogger from mlia.utils.proc import process_command_output @@ -187,15 +188,12 @@ def get_metrics( ) from err output_parser = GenericInferenceOutputParser() - - def redirect_to_log(line: str) -> None: - """Redirect FVP output to the logger.""" - logger.debug(line.strip()) + output_logger = OutputLogger(logger) try: process_command_output( command, - [output_parser, redirect_to_log], + [output_parser, output_logger], ) except subprocess.CalledProcessError as err: raise BackendExecutionFailed("Backend execution failed.") from err diff --git a/src/mlia/backend/install.py b/src/mlia/backend/install.py index 0ced9f6..1a7d58b 100644 --- a/src/mlia/backend/install.py +++ b/src/mlia/backend/install.py @@ -16,7 +16,8 @@ from typing import Optional from typing import Union from mlia.backend.repo import get_backend_repository -from mlia.utils.download import DownloadArtifact +from mlia.utils.download import download +from mlia.utils.download import DownloadConfig from mlia.utils.filesystem import all_files_exist from mlia.utils.filesystem import temp_directory from mlia.utils.filesystem import working_directory @@ -45,10 +46,18 @@ InstallationType = Union[InstallFromPath, DownloadAndInstall] class Installation(ABC): """Base class for the installation process of the backends.""" - def __init__(self, name: str, description: str) -> None: + def __init__( + self, name: str, description: str, dependencies: list[str] | None = None + ) -> None: """Init the installation.""" + assert not dependencies or name not in dependencies, ( + f"Invalid backend configuration: Backend '{name}' has itself as a " + "dependency! The backend source code needs to be fixed." + ) + self.name = name self.description = description + self.dependencies = dependencies if dependencies else [] @property @abstractmethod @@ -89,21 +98,22 @@ BackendInstaller = Callable[[bool, Path], Path] class BackendInstallation(Installation): """Backend installation.""" - def __init__( + def __init__( # pylint: disable=too-many-arguments self, name: str, description: str, fvp_dir_name: str, - download_artifact: DownloadArtifact | None, + download_config: DownloadConfig | None, supported_platforms: list[str] | None, path_checker: PathChecker, backend_installer: BackendInstaller | None, + dependencies: list[str] | None = None, ) -> None: """Init the backend installation.""" - super().__init__(name, description) + super().__init__(name, description, dependencies) self.fvp_dir_name = fvp_dir_name - self.download_artifact = download_artifact + self.download_config = download_config self.supported_platforms = supported_platforms self.path_checker = path_checker self.backend_installer = backend_installer @@ -125,7 +135,7 @@ class BackendInstallation(Installation): def supports(self, install_type: InstallationType) -> bool: """Return true if backends supported type of the installation.""" if isinstance(install_type, DownloadAndInstall): - return self.download_artifact is not None + return self.download_config is not None if isinstance(install_type, InstallFromPath): return self.path_checker(install_type.backend_path) is not None @@ -135,10 +145,10 @@ class BackendInstallation(Installation): def install(self, install_type: InstallationType) -> None: """Install the backend.""" if isinstance(install_type, DownloadAndInstall): - assert self.download_artifact is not None, "No artifact provided" + assert self.download_config is not None, "No artifact provided" self._download_and_install( - self.download_artifact, install_type.eula_agreement + self.download_config, install_type.eula_agreement ) elif isinstance(install_type, InstallFromPath): backend_info = self.path_checker(install_type.backend_path) @@ -207,13 +217,17 @@ class BackendInstallation(Installation): ex, ) - def _download_and_install( - self, download_artifact: DownloadArtifact, eula_agrement: bool - ) -> None: + def _download_and_install(self, cfg: DownloadConfig, eula_agrement: bool) -> None: """Download and install the backend.""" with temp_directory() as tmpdir: try: - dest = download_artifact.download_to(tmpdir) + dest = tmpdir / cfg.filename + download( + dest=dest, + cfg=cfg, + show_progress=True, + ) + except Exception as err: raise RuntimeError("Unable to download backend artifact.") from err diff --git a/src/mlia/backend/manager.py b/src/mlia/backend/manager.py index a4bc8c0..a752791 100644 --- a/src/mlia/backend/manager.py +++ b/src/mlia/backend/manager.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: Copyright 2022-2023, Arm Limited and/or its affiliates. +# SPDX-FileCopyrightText: Copyright 2022-2024, Arm Limited and/or its affiliates. # SPDX-License-Identifier: Apache-2.0 """Module for installation process.""" from __future__ import annotations @@ -188,6 +188,33 @@ class DefaultInstallationManager(InstallationManager, InstallationFiltersMixin): logger.info("%s installation canceled.", installation.name) return + for dependency in installation.dependencies: + deps = self.find_by_name(dependency) + if not deps: + raise ValueError( + f"Backend {installation.name} depends on " + f"unknown backend '{dependency}'." + ) + missing_deps = [dep for dep in deps if not dep.already_installed] + if missing_deps: + proceed = self.noninteractive or yes( + "The following dependencies are not installed: " + f"{[dep.name for dep in missing_deps]}. " + "Continue installation anyway?" + ) + logger.warning( + "Installing backend %s with the following dependencies " + "missing: %s", + installation.name, + missing_deps, + ) + if not proceed: + logger.info( + "%s installation canceled due to missing dependencies.", + installation.name, + ) + return + if installation.already_installed and force: logger.info( "Force installing %s, so delete the existing " @@ -254,16 +281,37 @@ class DefaultInstallationManager(InstallationManager, InstallationFiltersMixin): installations = self.already_installed(backend_name) if not installations: - raise ConfigurationError(f"Backend '{backend_name}' is not installed") + raise ConfigurationError(f"Backend '{backend_name}' is not installed.") if len(installations) != 1: raise InternalError( - f"More than one installed backend with name {backend_name} found" + f"More than one installed backend with name {backend_name} found." ) installation = installations[0] - installation.uninstall() + dependent_backends = [ + dep.name + for dep in self.installations + if dep.name in installation.dependencies + ] + if dependent_backends: + msg = ( + f"The following backends depend on '{installation.name}' which " + f"you are about to uninstall: {dependent_backends}", + ) + proceed = self.noninteractive or yes( + f"{msg}. Continue uninstalling anyway?" + ) + logger.warning(msg) + if not proceed: + logger.info( + "Uninstalling %s canceled due to dependencies.", + installation.name, + ) + return + + installation.uninstall() logger.info("%s successfully uninstalled.", installation.name) def backend_installed(self, backend_name: str) -> bool: |