From 6c7300036e12f82fa2c51ffb3faa206007f7ac4a Mon Sep 17 00:00:00 2001 From: Mehrdad Hessar Date: Wed, 18 May 2022 09:46:28 -0700 Subject: [PATCH 1/6] Test with CMSIS build added disabled conv2d_nhwc_dsp.arm_cpu for non integers workloads added debugging feature to TempDirectory --- .../template_project/microtvm_api_server.py | 34 ++++++++++++- python/tvm/contrib/utils.py | 14 ++++-- python/tvm/relay/op/strategy/arm_cpu.py | 14 ++++-- tests/micro/zephyr/conftest.py | 6 ++- tests/micro/zephyr/test_zephyr.py | 48 +++++++++++++++++++ 5 files changed, 103 insertions(+), 13 deletions(-) diff --git a/apps/microtvm/zephyr/template_project/microtvm_api_server.py b/apps/microtvm/zephyr/template_project/microtvm_api_server.py index 059e7604896c..a1095a2fd397 100644 --- a/apps/microtvm/zephyr/template_project/microtvm_api_server.py +++ b/apps/microtvm/zephyr/template_project/microtvm_api_server.py @@ -27,7 +27,6 @@ import pathlib import queue import re -import select import shlex import shutil import subprocess @@ -35,7 +34,7 @@ import tarfile import tempfile import threading -import time +from typing import Union import usb import serial @@ -424,6 +423,28 @@ def _get_platform_version(self, zephyr_base: str) -> float: return float(f"{version_major}.{version_minor}") + def _load_cmsis(self, lib_path: Union[str, pathlib.Path]): + """Copy CMSIS header files to generated project.""" + + cmsis_path = pathlib.Path(os.environ["CMSIS_PATH"]) + + lib_path = pathlib.Path(lib_path) + if not lib_path.exists(): + lib_path.mkdir() + + include_directories = ["CMSIS/DSP/Include", "CMSIS/DSP/Include/dsp", "CMSIS/NN/Include"] + for include_path in include_directories: + include_path = pathlib.Path(include_path) + src = cmsis_path / include_path + dest = lib_path + if include_path.name != "Include": + dest = lib_path / include_path.name + dest.mkdir() + + for item in src.iterdir(): + if not item.is_dir(): + shutil.copy(item, dest / item.name) + def generate_project(self, model_library_format_path, standalone_crt_dir, project_dir, options): # Check Zephyr version version = self._get_platform_version(get_zephyr_base(options)) @@ -455,6 +476,15 @@ def generate_project(self, model_library_format_path, standalone_crt_dir, projec os.makedirs(extract_path) tf.extractall(path=extract_path) + # Add CMSIS libraries if required. + if options["project_type"] == "host_driven": + lib2_path = pathlib.Path(extract_path) / "codegen" / "host" / "src" / "default_lib2.c" + if lib2_path.exists(): + with open(lib2_path, "r") as lib1_f: + lib2_content = lib1_f.read() + if "" in lib2_content and "" in lib2_content: + self._load_cmsis(pathlib.Path(project_dir) / "include") + if self._is_qemu(options): shutil.copytree(API_SERVER_DIR / "qemu-hack", project_dir / "qemu-hack") diff --git a/python/tvm/contrib/utils.py b/python/tvm/contrib/utils.py index e2ca182779c6..89688b5bf86f 100644 --- a/python/tvm/contrib/utils.py +++ b/python/tvm/contrib/utils.py @@ -93,11 +93,15 @@ def set_keep_for_debug(cls, set_to=True): finally: cls._KEEP_FOR_DEBUG = old_keep_for_debug - def __init__(self, custom_path=None): + def __init__(self, custom_path=None, keep_for_debug=None): if self.TEMPDIRS is None: raise DirectoryCreatedPastAtExit() - self._created_with_keep_for_debug = self._KEEP_FOR_DEBUG + if keep_for_debug is not None: + self._created_with_keep_for_debug = keep_for_debug + else: + self._created_with_keep_for_debug = self._KEEP_FOR_DEBUG + if custom_path: os.mkdir(custom_path) self.temp_dir = custom_path @@ -169,7 +173,7 @@ def listdir(self): atexit.register(TempDirectory.remove_tempdirs) -def tempdir(custom_path=None): +def tempdir(custom_path=None, keep_for_debug=None): """Create temp dir which deletes the contents when exit. Parameters @@ -177,12 +181,14 @@ def tempdir(custom_path=None): custom_path : str, optional Manually specify the exact temp dir path + keep_for_debug : bool + Keep temp directory for debugging purposes Returns ------- temp : TempDirectory The temp directory object """ - return TempDirectory(custom_path) + return TempDirectory(custom_path=custom_path, keep_for_debug=keep_for_debug) class FileLock(object): diff --git a/python/tvm/relay/op/strategy/arm_cpu.py b/python/tvm/relay/op/strategy/arm_cpu.py index 6ccb449d0e08..a2079f9aa744 100644 --- a/python/tvm/relay/op/strategy/arm_cpu.py +++ b/python/tvm/relay/op/strategy/arm_cpu.py @@ -75,6 +75,7 @@ def conv2d_strategy_arm_cpu(attrs, inputs, out_type, target): """conv2d arm cpu strategy""" strategy = _op.OpStrategy() data, kernel = inputs + out_dtype = attrs.get_str("out_dtype") dilation_h, dilation_w = attrs.get_int_tuple("dilation") stride_h, stride_w = attrs.get_int_tuple("strides") padding = attrs.get_int_tuple("padding") @@ -161,11 +162,14 @@ def conv2d_strategy_arm_cpu(attrs, inputs, out_type, target): ) elif layout == "NHWC": if isa.has_dsp_support and kernel_layout == "HWOI": - strategy.add_implementation( - wrap_compute_conv2d(topi.arm_cpu.conv2d_nhwc_dsp), - wrap_topi_schedule(topi.arm_cpu.schedule_conv2d_nhwc_dsp), - name="conv2d_nhwc_dsp.arm_cpu", - ) + # TODO(mehrdadh): Only integer type due to + # https://github.com/apache/tvm/issues/11351 + if data.dtype in ["int8", "int16"] and out_dtype == "int32": + strategy.add_implementation( + wrap_compute_conv2d(topi.arm_cpu.conv2d_nhwc_dsp), + wrap_topi_schedule(topi.arm_cpu.schedule_conv2d_nhwc_dsp), + name="conv2d_nhwc_dsp.arm_cpu", + ) elif kernel_layout == "HWIO": is_aarch64 = topi.arm_cpu.arm_utils.is_aarch64_arm() has_dot_prod = topi.arm_cpu.arm_utils.is_dotprod_available() diff --git a/tests/micro/zephyr/conftest.py b/tests/micro/zephyr/conftest.py index 177ca8aa269e..0cfeed77abe2 100644 --- a/tests/micro/zephyr/conftest.py +++ b/tests/micro/zephyr/conftest.py @@ -59,7 +59,7 @@ def tvm_debug(request): @pytest.fixture -def temp_dir(board): +def temp_dir(board, tvm_debug): parent_dir = pathlib.Path(os.path.dirname(__file__)) filename = os.path.splitext(os.path.basename(__file__))[0] board_workspace = ( @@ -76,4 +76,6 @@ def temp_dir(board): if not os.path.exists(board_workspace.parent): os.makedirs(board_workspace.parent) - return tempdir(board_workspace) + keep_for_debug = tvm_debug if tvm_debug else None + test_temp_dir = tempdir(custom_path=board_workspace, keep_for_debug=keep_for_debug) + return test_temp_dir diff --git a/tests/micro/zephyr/test_zephyr.py b/tests/micro/zephyr/test_zephyr.py index f89d11cf44dc..bf032c7e8e82 100644 --- a/tests/micro/zephyr/test_zephyr.py +++ b/tests/micro/zephyr/test_zephyr.py @@ -22,6 +22,7 @@ import pytest import numpy as np + import onnx from PIL import Image @@ -504,5 +505,52 @@ def test_autotune_conv2d(temp_dir, board, west_cmd, tvm_debug): tvm.testing.assert_allclose(output, expected_output, rtol=1e-4, atol=1e-5) +@tvm.testing.requires_micro +def test_schedule_build_with_cmsis_dependency(temp_dir, board, west_cmd, tvm_debug): + """Test Relay schedule with CMSIS dependency. This test shows if microTVM Auto tuning + with Zephyr breaks if CMSIS dependency was required for a schedule. + """ + model = test_utils.ZEPHYR_BOARDS[board] + build_config = {"debug": tvm_debug} + + # Create a Relay conv2d + data_shape = (1, 16, 16, 3) + weight_shape = (5, 5, 8, 3) + data = relay.var("data", relay.TensorType(data_shape, "int8")) + weight = relay.var("weight", relay.TensorType(weight_shape, "int8")) + y = relay.nn.conv2d( + data, + weight, + padding=(2, 2), + kernel_size=(5, 5), + data_layout="NHWC", + kernel_layout="HWOI", + out_dtype="int32", + ) + func = relay.Function([data, weight], y) + ir_mod = tvm.IRModule.from_expr(func) + + runtime = Runtime("crt", {"system-lib": True}) + target = tvm.target.target.micro(model, options=["-keys=arm_cpu,cpu"]) + + with tvm.transform.PassContext(opt_level=3, config={"tir.disable_vectorize": True}): + mod = tvm.relay.build(ir_mod, target=target, runtime=runtime) + + project_options = { + "project_type": "host_driven", + "west_cmd": west_cmd, + "verbose": bool(build_config.get("debug")), + "zephyr_board": board, + } + + project = tvm.micro.generate_project( + str(test_utils.TEMPLATE_PROJECT_DIR), + mod, + temp_dir / "project", + project_options, + ) + project.build() + + if __name__ == "__main__": tvm.testing.main() From 83480fd47ed3a3e7023fba0af544cbba2cab6125 Mon Sep 17 00:00:00 2001 From: Mehrdad Hessar Date: Thu, 19 May 2022 12:07:18 -0700 Subject: [PATCH 2/6] revert arm_cpu strategy changes --- python/tvm/relay/op/strategy/arm_cpu.py | 14 +++++--------- tests/micro/zephyr/conftest.py | 15 +++++++++++++++ tests/micro/zephyr/test_zephyr.py | 14 +++++++++++++- tests/micro/zephyr/test_zephyr_aot.py | 2 ++ tests/micro/zephyr/test_zephyr_armv7m.py | 1 + tests/scripts/task_python_microtvm.sh | 1 + 6 files changed, 37 insertions(+), 10 deletions(-) diff --git a/python/tvm/relay/op/strategy/arm_cpu.py b/python/tvm/relay/op/strategy/arm_cpu.py index a2079f9aa744..6ccb449d0e08 100644 --- a/python/tvm/relay/op/strategy/arm_cpu.py +++ b/python/tvm/relay/op/strategy/arm_cpu.py @@ -75,7 +75,6 @@ def conv2d_strategy_arm_cpu(attrs, inputs, out_type, target): """conv2d arm cpu strategy""" strategy = _op.OpStrategy() data, kernel = inputs - out_dtype = attrs.get_str("out_dtype") dilation_h, dilation_w = attrs.get_int_tuple("dilation") stride_h, stride_w = attrs.get_int_tuple("strides") padding = attrs.get_int_tuple("padding") @@ -162,14 +161,11 @@ def conv2d_strategy_arm_cpu(attrs, inputs, out_type, target): ) elif layout == "NHWC": if isa.has_dsp_support and kernel_layout == "HWOI": - # TODO(mehrdadh): Only integer type due to - # https://github.com/apache/tvm/issues/11351 - if data.dtype in ["int8", "int16"] and out_dtype == "int32": - strategy.add_implementation( - wrap_compute_conv2d(topi.arm_cpu.conv2d_nhwc_dsp), - wrap_topi_schedule(topi.arm_cpu.schedule_conv2d_nhwc_dsp), - name="conv2d_nhwc_dsp.arm_cpu", - ) + strategy.add_implementation( + wrap_compute_conv2d(topi.arm_cpu.conv2d_nhwc_dsp), + wrap_topi_schedule(topi.arm_cpu.schedule_conv2d_nhwc_dsp), + name="conv2d_nhwc_dsp.arm_cpu", + ) elif kernel_layout == "HWIO": is_aarch64 = topi.arm_cpu.arm_utils.is_aarch64_arm() has_dot_prod = topi.arm_cpu.arm_utils.is_dotprod_available() diff --git a/tests/micro/zephyr/conftest.py b/tests/micro/zephyr/conftest.py index 0cfeed77abe2..997237d370a5 100644 --- a/tests/micro/zephyr/conftest.py +++ b/tests/micro/zephyr/conftest.py @@ -79,3 +79,18 @@ def temp_dir(board, tvm_debug): keep_for_debug = tvm_debug if tvm_debug else None test_temp_dir = tempdir(custom_path=board_workspace, keep_for_debug=keep_for_debug) return test_temp_dir + + +@pytest.fixture(autouse=True) +def skip_by_board(request, board): + """Skip test if board is in the list.""" + if request.node.get_closest_marker("skip_boards"): + if board in request.node.get_closest_marker("skip_boards").args[0]: + pytest.skip("skipped on this board: {}".format(board)) + + +def pytest_configure(config): + config.addinivalue_line( + "markers", + "skip_by_board(board): skip test for the given board", + ) diff --git a/tests/micro/zephyr/test_zephyr.py b/tests/micro/zephyr/test_zephyr.py index bf032c7e8e82..ac71a497a77a 100644 --- a/tests/micro/zephyr/test_zephyr.py +++ b/tests/micro/zephyr/test_zephyr.py @@ -33,6 +33,7 @@ from tvm.relay.testing import byoc from tvm.contrib import utils from tvm.micro.testing.utils import check_tune_log +from tvm.target import arm_isa import test_utils @@ -88,6 +89,7 @@ def _make_add_sess(temp_dir, model, zephyr_board, west_cmd, build_config, dtype= # The same test code can be executed on both the QEMU simulation and on real hardware. @tvm.testing.requires_micro +@pytest.mark.skip_boards(["mps2_an521"]) def test_add_uint(temp_dir, board, west_cmd, tvm_debug): """Test compiling the on-device runtime.""" @@ -113,6 +115,7 @@ def test_basic_add(sess): # The same test code can be executed on both the QEMU simulation and on real hardware. @tvm.testing.requires_micro +@pytest.mark.skip_boards(["mps2_an521"]) def test_add_float(temp_dir, board, west_cmd, tvm_debug): """Test compiling the on-device runtime.""" model = test_utils.ZEPHYR_BOARDS[board] @@ -139,6 +142,7 @@ def test_basic_add(sess): @tvm.testing.requires_micro +@pytest.mark.skip_boards(["mps2_an521"]) def test_platform_timer(temp_dir, board, west_cmd, tvm_debug): """Test compiling the on-device runtime.""" @@ -168,6 +172,7 @@ def test_basic_add(sess): @tvm.testing.requires_micro +@pytest.mark.skip_boards(["mps2_an521"]) def test_relay(temp_dir, board, west_cmd, tvm_debug): """Testing a simple relay graph""" model = test_utils.ZEPHYR_BOARDS[board] @@ -200,6 +205,7 @@ def test_relay(temp_dir, board, west_cmd, tvm_debug): @tvm.testing.requires_micro +@pytest.mark.skip_boards(["mps2_an521"]) def test_onnx(temp_dir, board, west_cmd, tvm_debug): """Testing a simple ONNX model.""" model = test_utils.ZEPHYR_BOARDS[board] @@ -280,6 +286,7 @@ def check_result( @tvm.testing.requires_micro +@pytest.mark.skip_boards(["mps2_an521"]) def test_byoc_microtvm(temp_dir, board, west_cmd, tvm_debug): """This is a simple test case to check BYOC capabilities of microTVM""" model = test_utils.ZEPHYR_BOARDS[board] @@ -360,6 +367,7 @@ def _make_add_sess_with_shape(temp_dir, model, zephyr_board, west_cmd, shape, bu ], ) @tvm.testing.requires_micro +@pytest.mark.skip_boards(["mps2_an521"]) def test_rpc_large_array(temp_dir, board, west_cmd, tvm_debug, shape): """Test large RPC array transfer.""" model = test_utils.ZEPHYR_BOARDS[board] @@ -512,6 +520,11 @@ def test_schedule_build_with_cmsis_dependency(temp_dir, board, west_cmd, tvm_deb """ model = test_utils.ZEPHYR_BOARDS[board] build_config = {"debug": tvm_debug} + target = tvm.target.target.micro(model, options=["-keys=arm_cpu,cpu"]) + + isa = arm_isa.IsaAnalyzer(target) + if not isa.has_dsp_support: + pytest.skip(f"ISA does not support DSP. target: {target}") # Create a Relay conv2d data_shape = (1, 16, 16, 3) @@ -531,7 +544,6 @@ def test_schedule_build_with_cmsis_dependency(temp_dir, board, west_cmd, tvm_deb ir_mod = tvm.IRModule.from_expr(func) runtime = Runtime("crt", {"system-lib": True}) - target = tvm.target.target.micro(model, options=["-keys=arm_cpu,cpu"]) with tvm.transform.PassContext(opt_level=3, config={"tir.disable_vectorize": True}): mod = tvm.relay.build(ir_mod, target=target, runtime=runtime) diff --git a/tests/micro/zephyr/test_zephyr_aot.py b/tests/micro/zephyr/test_zephyr_aot.py index cfe2ce2ae3c8..3d509f100d6e 100644 --- a/tests/micro/zephyr/test_zephyr_aot.py +++ b/tests/micro/zephyr/test_zephyr_aot.py @@ -38,6 +38,7 @@ @tvm.testing.requires_micro +@pytest.mark.skip_boards(["mps2_an521"]) def test_tflite(temp_dir, board, west_cmd, tvm_debug): """Testing a TFLite model.""" model = test_utils.ZEPHYR_BOARDS[board] @@ -93,6 +94,7 @@ def test_tflite(temp_dir, board, west_cmd, tvm_debug): @tvm.testing.requires_micro +@pytest.mark.skip_boards(["mps2_an521"]) def test_qemu_make_fail(temp_dir, board, west_cmd, tvm_debug): """Testing QEMU make fail.""" if board not in ["qemu_x86", "mps2_an521", "mps3_an547"]: diff --git a/tests/micro/zephyr/test_zephyr_armv7m.py b/tests/micro/zephyr/test_zephyr_armv7m.py index 2631e4379966..c629403ced82 100644 --- a/tests/micro/zephyr/test_zephyr_armv7m.py +++ b/tests/micro/zephyr/test_zephyr_armv7m.py @@ -103,6 +103,7 @@ def _apply_desired_layout_no_simd(relay_mod): @tvm.testing.requires_micro +@pytest.mark.skip_boards(["mps2_an521"]) def test_armv7m_intrinsic(temp_dir, board, west_cmd, tvm_debug): """Testing a ARM v7m SIMD extension.""" diff --git a/tests/scripts/task_python_microtvm.sh b/tests/scripts/task_python_microtvm.sh index 7301c6f833ab..c4b4f59d9423 100755 --- a/tests/scripts/task_python_microtvm.sh +++ b/tests/scripts/task_python_microtvm.sh @@ -28,6 +28,7 @@ make cython3 run_pytest ctypes python-microtvm-zephyr-qemu_x86 tests/micro/zephyr --zephyr-board=qemu_x86 run_pytest ctypes python-microtvm-zephyr-qemu_riscv32 tests/micro/zephyr --zephyr-board=qemu_riscv32 run_pytest ctypes python-microtvm-zephyr-qemu_riscv64 tests/micro/zephyr --zephyr-board=qemu_riscv64 +run_pytest ctypes python-microtvm-zephyr-mps2_an521 tests/micro/zephyr --zephyr-board=mps2_an521 # Arduino run_pytest ctypes python-microtvm-arduino apps/microtvm/arduino/template_project/tests From 724c09a0b7cdaca64905f619c6e18b02980279a9 Mon Sep 17 00:00:00 2001 From: Mehrdad Hessar Date: Mon, 23 May 2022 10:42:28 -0700 Subject: [PATCH 3/6] Address Andrew comments --- .../template_project/microtvm_api_server.py | 33 ++++++++++++++----- tests/micro/zephyr/test_zephyr.py | 11 ++++++- 2 files changed, 34 insertions(+), 10 deletions(-) diff --git a/apps/microtvm/zephyr/template_project/microtvm_api_server.py b/apps/microtvm/zephyr/template_project/microtvm_api_server.py index a1095a2fd397..a267218a4a49 100644 --- a/apps/microtvm/zephyr/template_project/microtvm_api_server.py +++ b/apps/microtvm/zephyr/template_project/microtvm_api_server.py @@ -69,6 +69,8 @@ ZEPHYR_BASE = os.getenv("ZEPHYR_BASE") +CMSIS_PATH = os.getenv("CMSIS_PATH") + # Data structure to hold the information microtvm_api_server.py needs # to communicate with each of these boards. try: @@ -332,6 +334,13 @@ def get_zephyr_base(options: dict): return zephyr_base +def get_cmsis_path(options: dict): + """Returns CMSIS dependency path""" + cmsis_path = options.get("cmsis_path", CMSIS_PATH) + assert cmsis_path, "'cmsis_path' option not passed and not found by default!" + return cmsis_path + + class Handler(server.ProjectAPIHandler): def __init__(self): super(Handler, self).__init__() @@ -423,10 +432,10 @@ def _get_platform_version(self, zephyr_base: str) -> float: return float(f"{version_major}.{version_minor}") - def _load_cmsis(self, lib_path: Union[str, pathlib.Path]): + def _load_cmsis(self, lib_path: Union[str, pathlib.Path], cmsis_path: Union[str, pathlib.Path]): """Copy CMSIS header files to generated project.""" - cmsis_path = pathlib.Path(os.environ["CMSIS_PATH"]) + cmsis_path = pathlib.Path(cmsis_path) lib_path = pathlib.Path(lib_path) if not lib_path.exists(): @@ -445,6 +454,17 @@ def _load_cmsis(self, lib_path: Union[str, pathlib.Path]): if not item.is_dir(): shutil.copy(item, dest / item.name) + def _cmsis_required(self, project_path: Union[str, pathlib.Path]) -> bool: + """Check if CMSIS dependency is required.""" + project_path = pathlib.Path(project_path) + for path in (project_path / "codegen" / "host" / "src").iterdir(): + if path.is_file(): + with open(path, "r") as lib_f: + lib_content = lib_f.read() + if "" in lib_content and "" in lib_content: + return True + return False + def generate_project(self, model_library_format_path, standalone_crt_dir, project_dir, options): # Check Zephyr version version = self._get_platform_version(get_zephyr_base(options)) @@ -477,13 +497,8 @@ def generate_project(self, model_library_format_path, standalone_crt_dir, projec tf.extractall(path=extract_path) # Add CMSIS libraries if required. - if options["project_type"] == "host_driven": - lib2_path = pathlib.Path(extract_path) / "codegen" / "host" / "src" / "default_lib2.c" - if lib2_path.exists(): - with open(lib2_path, "r") as lib1_f: - lib2_content = lib1_f.read() - if "" in lib2_content and "" in lib2_content: - self._load_cmsis(pathlib.Path(project_dir) / "include") + if self._cmsis_required(extract_path): + self._load_cmsis(pathlib.Path(project_dir) / "include", get_cmsis_path(options)) if self._is_qemu(options): shutil.copytree(API_SERVER_DIR / "qemu-hack", project_dir / "qemu-hack") diff --git a/tests/micro/zephyr/test_zephyr.py b/tests/micro/zephyr/test_zephyr.py index ac71a497a77a..cc2f159b5808 100644 --- a/tests/micro/zephyr/test_zephyr.py +++ b/tests/micro/zephyr/test_zephyr.py @@ -555,14 +555,23 @@ def test_schedule_build_with_cmsis_dependency(temp_dir, board, west_cmd, tvm_deb "zephyr_board": board, } + project_dir = temp_dir / "project" project = tvm.micro.generate_project( str(test_utils.TEMPLATE_PROJECT_DIR), mod, - temp_dir / "project", + project_dir, project_options, ) project.build() + generated_project_include_files = [] + for path in (project_dir / "include").iterdir(): + if path.is_file(): + generated_project_include_files.append(path.name) + + assert "arm_math.h" in generated_project_include_files + assert "arm_nnsupportfunctions.h" in generated_project_include_files + if __name__ == "__main__": tvm.testing.main() From b31a618a98e008e822d902505901c38d48d4c9b3 Mon Sep 17 00:00:00 2001 From: Mehrdad Hessar Date: Tue, 24 May 2022 13:29:10 -0700 Subject: [PATCH 4/6] change copy to include --- .../template_project/microtvm_api_server.py | 48 +++++++------------ tests/micro/zephyr/test_zephyr.py | 12 ++--- 2 files changed, 24 insertions(+), 36 deletions(-) diff --git a/apps/microtvm/zephyr/template_project/microtvm_api_server.py b/apps/microtvm/zephyr/template_project/microtvm_api_server.py index a267218a4a49..a9dc1aa8a894 100644 --- a/apps/microtvm/zephyr/template_project/microtvm_api_server.py +++ b/apps/microtvm/zephyr/template_project/microtvm_api_server.py @@ -334,11 +334,11 @@ def get_zephyr_base(options: dict): return zephyr_base -def get_cmsis_path(options: dict): +def get_cmsis_path(options: dict) -> pathlib.Path: """Returns CMSIS dependency path""" cmsis_path = options.get("cmsis_path", CMSIS_PATH) assert cmsis_path, "'cmsis_path' option not passed and not found by default!" - return cmsis_path + return pathlib.Path(cmsis_path) class Handler(server.ProjectAPIHandler): @@ -432,28 +432,6 @@ def _get_platform_version(self, zephyr_base: str) -> float: return float(f"{version_major}.{version_minor}") - def _load_cmsis(self, lib_path: Union[str, pathlib.Path], cmsis_path: Union[str, pathlib.Path]): - """Copy CMSIS header files to generated project.""" - - cmsis_path = pathlib.Path(cmsis_path) - - lib_path = pathlib.Path(lib_path) - if not lib_path.exists(): - lib_path.mkdir() - - include_directories = ["CMSIS/DSP/Include", "CMSIS/DSP/Include/dsp", "CMSIS/NN/Include"] - for include_path in include_directories: - include_path = pathlib.Path(include_path) - src = cmsis_path / include_path - dest = lib_path - if include_path.name != "Include": - dest = lib_path / include_path.name - dest.mkdir() - - for item in src.iterdir(): - if not item.is_dir(): - shutil.copy(item, dest / item.name) - def _cmsis_required(self, project_path: Union[str, pathlib.Path]) -> bool: """Check if CMSIS dependency is required.""" project_path = pathlib.Path(project_path) @@ -496,10 +474,6 @@ def generate_project(self, model_library_format_path, standalone_crt_dir, projec os.makedirs(extract_path) tf.extractall(path=extract_path) - # Add CMSIS libraries if required. - if self._cmsis_required(extract_path): - self._load_cmsis(pathlib.Path(project_dir) / "include", get_cmsis_path(options)) - if self._is_qemu(options): shutil.copytree(API_SERVER_DIR / "qemu-hack", project_dir / "qemu-hack") @@ -515,8 +489,8 @@ def generate_project(self, model_library_format_path, standalone_crt_dir, projec shutil.copy2(src_path, dst_path) # Populate Makefile. - with open(API_SERVER_DIR / "CMakeLists.txt.template", "r") as cmake_template_f: - with open(project_dir / "CMakeLists.txt", "w") as cmake_f: + with open(project_dir / "CMakeLists.txt", "w") as cmake_f: + with open(API_SERVER_DIR / "CMakeLists.txt.template", "r") as cmake_template_f: for line in cmake_template_f: if self.API_SERVER_CRT_LIBS_TOKEN in line: crt_libs = self.CRT_LIBS_BY_PROJECT_TYPE[options["project_type"]] @@ -529,6 +503,20 @@ def generate_project(self, model_library_format_path, standalone_crt_dir, projec for item in flags: cmake_f.write(f"target_compile_definitions(app PUBLIC {item})\n") + # Include CMSIS libraries if required. + if self._cmsis_required(extract_path): + cmsis_path = get_cmsis_path(options) + cmake_f.write("\n") + cmake_f.write( + f'target_include_directories(tvm_model PRIVATE {str(cmsis_path / "CMSIS" / "DSP" / "Include")})\n' + ) + cmake_f.write( + f'target_include_directories(tvm_model PRIVATE {str(cmsis_path / "CMSIS" / "DSP" / "Include" / "dsp")})\n' + ) + cmake_f.write( + f'target_include_directories(tvm_model PRIVATE {str(cmsis_path / "CMSIS" / "NN" / "Include")})\n' + ) + self._create_prj_conf(project_dir, options) # Populate crt-config.h diff --git a/tests/micro/zephyr/test_zephyr.py b/tests/micro/zephyr/test_zephyr.py index cc2f159b5808..fa64a5276338 100644 --- a/tests/micro/zephyr/test_zephyr.py +++ b/tests/micro/zephyr/test_zephyr.py @@ -564,13 +564,13 @@ def test_schedule_build_with_cmsis_dependency(temp_dir, board, west_cmd, tvm_deb ) project.build() - generated_project_include_files = [] - for path in (project_dir / "include").iterdir(): - if path.is_file(): - generated_project_include_files.append(path.name) + with open(project_dir / "CMakeLists.txt", "r") as cmake_f: + cmake_content = cmake_f.read() - assert "arm_math.h" in generated_project_include_files - assert "arm_nnsupportfunctions.h" in generated_project_include_files + assert "CMSIS/DSP/Include" in cmake_content + assert "CMSIS/DSP/Include/dsp" in cmake_content + assert "CMSIS/DSP/Include" in cmake_content + assert "CMSIS/NN/Include" in cmake_content if __name__ == "__main__": From 8e256a4070fc426e7ee2e83fa3473f31fbfced31 Mon Sep 17 00:00:00 2001 From: Mehrdad Hessar Date: Thu, 26 May 2022 13:22:15 -0700 Subject: [PATCH 5/6] add cmsis_path only as project option --- .../zephyr/template_project/microtvm_api_server.py | 12 ++++++++---- tests/micro/zephyr/test_zephyr.py | 1 + 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/apps/microtvm/zephyr/template_project/microtvm_api_server.py b/apps/microtvm/zephyr/template_project/microtvm_api_server.py index a9dc1aa8a894..bcf9f78f4b11 100644 --- a/apps/microtvm/zephyr/template_project/microtvm_api_server.py +++ b/apps/microtvm/zephyr/template_project/microtvm_api_server.py @@ -69,8 +69,6 @@ ZEPHYR_BASE = os.getenv("ZEPHYR_BASE") -CMSIS_PATH = os.getenv("CMSIS_PATH") - # Data structure to hold the information microtvm_api_server.py needs # to communicate with each of these boards. try: @@ -324,6 +322,12 @@ def _get_nrf_device_args(options): type="str", help="Extra definitions added project compile.", ), + server.ProjectOption( + "cmsis_path", + optional=["generate_project"], + type="str", + help="Path to the CMSIS directory.", + ), ] @@ -336,8 +340,8 @@ def get_zephyr_base(options: dict): def get_cmsis_path(options: dict) -> pathlib.Path: """Returns CMSIS dependency path""" - cmsis_path = options.get("cmsis_path", CMSIS_PATH) - assert cmsis_path, "'cmsis_path' option not passed and not found by default!" + cmsis_path = options.get("cmsis_path") + assert cmsis_path, "'cmsis_path' option not passed!" return pathlib.Path(cmsis_path) diff --git a/tests/micro/zephyr/test_zephyr.py b/tests/micro/zephyr/test_zephyr.py index fa64a5276338..2651435434b1 100644 --- a/tests/micro/zephyr/test_zephyr.py +++ b/tests/micro/zephyr/test_zephyr.py @@ -553,6 +553,7 @@ def test_schedule_build_with_cmsis_dependency(temp_dir, board, west_cmd, tvm_deb "west_cmd": west_cmd, "verbose": bool(build_config.get("debug")), "zephyr_board": board, + "cmsis_path": os.getenv("CMSIS_PATH"), } project_dir = temp_dir / "project" From d9770a1dd1fc9636281531184a0d6ed5efd04984 Mon Sep 17 00:00:00 2001 From: Mehrdad Hessar Date: Fri, 27 May 2022 09:27:15 -0700 Subject: [PATCH 6/6] trigger