blob: df7d1fc7196d7965ab597859527f5c7fb3b08592 [file] [log] [blame]
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
"""Defines top-level glue functions for building microTVM artifacts."""
import json
import logging
import os
import contextlib
import enum
from pathlib import Path
import shutil
from typing import Union
from .._ffi import libinfo
from .. import rpc as _rpc
_LOG = logging.getLogger(__name__)
STANDALONE_CRT_DIR = None
class MicroTVMTemplateProject(enum.Enum):
ZEPHYR = "zephyr"
ARDUINO = "arduino"
CRT = "crt"
@classmethod
def list(cls):
return list(map(lambda c: c.value, cls))
class CrtNotFoundError(Exception):
"""Raised when the standalone CRT dirtree cannot be found."""
class MicroTVMTemplateProjectNotFoundError(Exception):
"""Raised when the microTVM template project dirtree cannot be found."""
def get_standalone_crt_dir() -> str:
"""Find the standalone_crt directory.
Though the C runtime source lives in the tvm tree, it is intended to be distributed with any
binary build of TVM. This source tree is intended to be integrated into user projects to run
models targeted with --runtime=c.
Returns
-------
str :
The path to the standalone_crt
"""
global STANDALONE_CRT_DIR
if STANDALONE_CRT_DIR is None:
for path in libinfo.find_lib_path():
crt_path = os.path.join(os.path.dirname(path), "standalone_crt")
if os.path.isdir(crt_path):
STANDALONE_CRT_DIR = crt_path
break
else:
raise CrtNotFoundError()
return STANDALONE_CRT_DIR
def get_microtvm_template_projects(platform: str) -> str:
"""Find microTVM template project directory for specific platform.
Parameters
----------
platform : str
Platform type which should be defined in MicroTVMTemplateProject.
Returns
-------
str :
Path to template project directory for platform.
"""
if platform not in MicroTVMTemplateProject.list():
raise ValueError(f"platform {platform} is not supported.")
microtvm_template_projects = None
for path in libinfo.find_lib_path():
template_path = os.path.join(os.path.dirname(path), "microtvm_template_projects")
if os.path.isdir(template_path):
microtvm_template_projects = template_path
break
else:
raise MicroTVMTemplateProjectNotFoundError()
return os.path.join(microtvm_template_projects, platform)
def copy_crt_config_header(platform: str, output_path: Path):
"""Copy crt_config header file for a platform to destinatin.
Parameters
----------
platform : str
Platform type which should be defined in MicroTVMTemplateProject.
output_path: Path
Output path for crt_config header file.
"""
crt_config_path = Path(get_microtvm_template_projects(platform)) / "crt_config" / "crt_config.h"
shutil.copy(crt_config_path, output_path)
class AutoTvmModuleLoader:
"""MicroTVM AutoTVM Module Loader
Parameters
----------
template_project_dir : Union[os.PathLike, str]
project template path
project_options : dict
project generation option
project_dir: str
if use_existing is False: The path to save the generated microTVM Project.
if use_existing is True: The path to a generated microTVM Project for debugging.
use_existing: bool
skips the project generation and opens transport to the project at the project_dir address.
"""
def __init__(
self,
template_project_dir: Union[os.PathLike, str],
project_options: dict = None,
project_dir: Union[os.PathLike, str] = None,
use_existing: bool = False,
):
self._project_options = project_options
self._use_existing = use_existing
if isinstance(template_project_dir, (os.PathLike, str)):
self._template_project_dir = str(template_project_dir)
elif not isinstance(template_project_dir, str):
raise TypeError(f"Incorrect type {type(template_project_dir)}.")
if isinstance(project_dir, (os.PathLike, str)):
self._project_dir = str(project_dir)
else:
self._project_dir = None
@contextlib.contextmanager
def __call__(self, remote_kw, build_result):
with open(build_result.filename, "rb") as build_file:
build_result_bin = build_file.read()
# In case we are tuning on multiple physical boards (with Meta-schedule), the tracker
# device_key is the serial_number of the board that wil be used in generating micro session.
# For CRT projects, and in cases that the serial number is not provided
# (including tuning with AutoTVM), the serial number field doesn't change.
if "board" in self._project_options and "$local$device" not in remote_kw["device_key"]:
self._project_options["serial_number"] = remote_kw["device_key"]
tracker = _rpc.connect_tracker(remote_kw["host"], remote_kw["port"])
remote = tracker.request(
remote_kw["device_key"],
priority=remote_kw["priority"],
session_timeout=remote_kw["timeout"],
session_constructor_args=[
"tvm.micro.compile_and_create_micro_session",
build_result_bin,
self._template_project_dir,
json.dumps(self._project_options),
self._project_dir,
self._use_existing,
],
)
system_lib = remote.get_function("runtime.SystemLib")()
yield remote, system_lib
def autotvm_build_func():
"""A dummy build function which causes autotvm to use a different export format."""
# A sentinel value for the output format.
autotvm_build_func.output_format = ".model-library-format"