From d603cd4602dbc5cf882ecd1025fdd0f0c825ca2f Mon Sep 17 00:00:00 2001 From: Mehrdad Hessar Date: Thu, 14 Oct 2021 12:58:24 -0700 Subject: [PATCH 1/8] zephyr lib fixed --- CMakeLists.txt | 2 + cmake/modules/StandaloneCrt.cmake | 15 +----- cmake/modules/Zephyr.cmake | 79 +++++++++++++++++++++++++++++++ cmake/utils/Utils.cmake | 11 +++++ 4 files changed, 94 insertions(+), 13 deletions(-) create mode 100644 cmake/modules/Zephyr.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 24f0653b3a78..d429e9458c78 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -413,6 +413,7 @@ endif(USE_PIPELINE_EXECUTOR) # Module rules include(cmake/modules/VTA.cmake) include(cmake/modules/StandaloneCrt.cmake) +include(cmake/modules/Zephyr.cmake) include(cmake/modules/CUDA.cmake) include(cmake/modules/Hexagon.cmake) include(cmake/modules/OpenCL.cmake) @@ -500,6 +501,7 @@ if(USE_MICRO) # Unix Makefiles generator, need to add these explicit target-level dependency) add_dependencies(tvm host_standalone_crt) add_dependencies(tvm_runtime host_standalone_crt) + add_dependencies(tvm_runtime zephyr) endif() if(USE_CPP_RPC) diff --git a/cmake/modules/StandaloneCrt.cmake b/cmake/modules/StandaloneCrt.cmake index 9f79c7da3cdf..5d822844ae34 100644 --- a/cmake/modules/StandaloneCrt.cmake +++ b/cmake/modules/StandaloneCrt.cmake @@ -16,20 +16,9 @@ # under the License. if(USE_MICRO) - message(STATUS "Build standalone CRT for micro TVM") + message(STATUS "Build standalone CRT for microTVM") file(GLOB crt_srcs src/runtime/crt/**) - function(tvm_crt_add_copy_file var src dest) - get_filename_component(basename "${src}" NAME) - get_filename_component(dest_parent_dir "${dest}" DIRECTORY) - add_custom_command( - OUTPUT "${dest}" - COMMAND "${CMAKE_COMMAND}" -E copy "${src}" "${dest}" - DEPENDS "${src}") - list(APPEND "${var}" "${dest}") - set("${var}" "${${var}}" PARENT_SCOPE) - endfunction(tvm_crt_add_copy_file) - function(tvm_crt_define_targets) # Build an isolated build directory, separate from the TVM tree. list(APPEND CRT_FILE_COPY_JOBS @@ -83,7 +72,7 @@ if(USE_MICRO) endif() foreach(copy_src IN LISTS copy_files) get_filename_component(dest_path "${standalone_crt_base}/${copy_dest}/${copy_src}" ABSOLUTE) - tvm_crt_add_copy_file(host_isolated_build_deps ${job_src_base}/${copy_src} ${dest_path}) + tvm_micro_add_copy_file(host_isolated_build_deps ${job_src_base}/${copy_src} ${dest_path}) endforeach() endforeach() endforeach() diff --git a/cmake/modules/Zephyr.cmake b/cmake/modules/Zephyr.cmake new file mode 100644 index 000000000000..ff8bd4688aef --- /dev/null +++ b/cmake/modules/Zephyr.cmake @@ -0,0 +1,79 @@ +# 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. + +if(USE_MICRO) + message(STATUS "Add Zephyr for microTVM") + + function(microtvm_add_zephyr) + list( + APPEND + ZEPHYR_FILE_COPY_JOBS + "apps/microtvm/zephyr/template_project microtvm_api_server.py -> zephyr" + "apps/microtvm/zephyr/template_project boards.json -> zephyr" + "apps/microtvm/zephyr/template_project CMakeLists.txt.template -> zephyr" + "apps/microtvm/zephyr/template_project/src/aot_demo *.c -> zephyr/src/aot_demo" + "apps/microtvm/zephyr/template_project/src/aot_demo *.h -> zephyr/src/aot_demo" + "apps/microtvm/zephyr/template_project/src/host_driven *.c -> zephyr/src/host_driven" + "apps/microtvm/zephyr/template_project/qemu-hack * -> zephyr/qemu-hack" + "apps/microtvm/zephyr/template_project/crt_config *.h -> zephyr/crt_config" + ) + + set(zephyr_base "${CMAKE_CURRENT_BINARY_DIR}/micro_template_projects") + + foreach(job_spec IN LISTS ZEPHYR_FILE_COPY_JOBS) + string(REPLACE " " ";" job_spec "${job_spec}") + list(LENGTH job_spec job_spec_length) + math(EXPR job_spec_length_mod "${job_spec_length} % 3") + if(NOT "${job_spec_length_mod}" EQUAL 1) + message( + FATAL_ERROR + "Zephyr copy job spec list length is ${job_spec_length}; parsed job spec is ${job_spec}" + ) + endif() + math(EXPR job_spec_stop "${job_spec_length} - 3") + + list(GET job_spec 0 job_src_base) + set(job_src_base "${CMAKE_SOURCE_DIR}/${job_src_base}") + foreach(copy_pattern_index RANGE 1 "${job_spec_stop}" 3) + list(GET job_spec ${copy_pattern_index} copy_pattern) + math(EXPR copy_dest_index "${copy_pattern_index} + 2") + list(GET job_spec ${copy_dest_index} copy_dest) + + file( + GLOB_RECURSE copy_files + RELATIVE "${job_src_base}" + "${job_src_base}/${copy_pattern}") + list(LENGTH copy_files copy_files_length) + if("${copy_files_length}" EQUAL 0) + message( + FATAL_ERROR + "Zephyr copy job matched 0 files: ${job_src_base}/${copy_pattern} -> ${copy_dest}" + ) + endif() + foreach(copy_src IN LISTS copy_files) + get_filename_component( + dest_path "${zephyr_base}/${copy_dest}/${copy_src}" ABSOLUTE) + tvm_micro_add_copy_file(zephyr_template_deps + ${job_src_base}/${copy_src} ${dest_path}) + endforeach() + endforeach() + endforeach() + + add_custom_target(zephyr DEPENDS ${zephyr_template_deps}) + endfunction() + + microtvm_add_zephyr() + +endif(USE_MICRO) diff --git a/cmake/utils/Utils.cmake b/cmake/utils/Utils.cmake index 4e6762b14894..5b504518b1c4 100644 --- a/cmake/utils/Utils.cmake +++ b/cmake/utils/Utils.cmake @@ -75,6 +75,17 @@ function(assign_source_group group) endforeach() endfunction(assign_source_group) +function(tvm_micro_add_copy_file var src dest) + get_filename_component(basename "${src}" NAME) + get_filename_component(dest_parent_dir "${dest}" DIRECTORY) + add_custom_command( + OUTPUT "${dest}" + COMMAND "${CMAKE_COMMAND}" -E copy "${src}" "${dest}" + DEPENDS "${src}") + list(APPEND "${var}" "${dest}") + set("${var}" "${${var}}" PARENT_SCOPE) +endfunction(tvm_micro_add_copy_file) + # From cmake documentation: # True if the constant is 1, ON, YES, TRUE, Y, or a non-zero number. # False if the constant is 0, OFF, NO, FALSE, N, IGNORE, NOTFOUND, the empty string, or ends in the suffix -NOTFOUND. From 92d9416b4f51938f56a607e3211cccde6e2ee8ca Mon Sep 17 00:00:00 2001 From: Mehrdad Hessar Date: Thu, 14 Oct 2021 14:20:24 -0700 Subject: [PATCH 2/8] restructure --- .../standalone_crt/crt_config/crt_config.h | 55 ----------- .../arduino/template_project/boards.json | 59 +++++++++++ .../crt_config/crt_config.h | 0 .../template_project/microtvm_api_server.py | 98 +++++-------------- .../src/example_project}/model.c | 0 .../src/example_project}/model.h | 0 .../src}/example_project/project.ino | 0 .../src/host_driven}/model_support.c | 0 .../src}/host_driven/project.ino | 0 tests/micro/arduino/conftest.py | 20 ++-- 10 files changed, 91 insertions(+), 141 deletions(-) delete mode 100644 apps/microtvm/arduino/host_driven/src/standalone_crt/crt_config/crt_config.h create mode 100644 apps/microtvm/arduino/template_project/boards.json rename apps/microtvm/arduino/{example_project/src/standalone_crt => template_project}/crt_config/crt_config.h (100%) rename apps/microtvm/arduino/{example_project/src => template_project/src/example_project}/model.c (100%) rename apps/microtvm/arduino/{example_project/src => template_project/src/example_project}/model.h (100%) rename apps/microtvm/arduino/{ => template_project/src}/example_project/project.ino (100%) rename apps/microtvm/arduino/{host_driven/src => template_project/src/host_driven}/model_support.c (100%) rename apps/microtvm/arduino/{ => template_project/src}/host_driven/project.ino (100%) diff --git a/apps/microtvm/arduino/host_driven/src/standalone_crt/crt_config/crt_config.h b/apps/microtvm/arduino/host_driven/src/standalone_crt/crt_config/crt_config.h deleted file mode 100644 index cf73103aff8b..000000000000 --- a/apps/microtvm/arduino/host_driven/src/standalone_crt/crt_config/crt_config.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * 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. - */ - -/*! - * \brief CRT configuration for the host-linked CRT. - */ -#ifndef TVM_RUNTIME_MICRO_CRT_CONFIG_H_ -#define TVM_RUNTIME_MICRO_CRT_CONFIG_H_ - -/*! Log level of the CRT runtime */ -#define TVM_CRT_LOG_LEVEL TVM_CRT_LOG_LEVEL_DEBUG - -/*! Support low-level debugging in MISRA-C runtime */ -#define TVM_CRT_DEBUG 0 - -/*! Maximum supported dimension in NDArray */ -#define TVM_CRT_MAX_NDIM 6 -/*! Maximum supported arguments in generated functions */ -#define TVM_CRT_MAX_ARGS 10 -/*! Maximum supported string length in dltype, e.g. "int8", "int16", "float32" */ -#define TVM_CRT_MAX_STRLEN_DLTYPE 10 -/*! Maximum supported string length in function names */ -#define TVM_CRT_MAX_STRLEN_FUNCTION_NAME 80 - -/*! Maximum number of registered modules. */ -#define TVM_CRT_MAX_REGISTERED_MODULES 2 - -/*! Size of the global function registry, in bytes. */ -#define TVM_CRT_GLOBAL_FUNC_REGISTRY_SIZE_BYTES 512 - -/*! Maximum packet size, in bytes, including the length header. */ -#define TVM_CRT_MAX_PACKET_SIZE_BYTES 8 * 1024 - -/*! \brief Maximum length of a PackedFunc function name. */ -#define TVM_CRT_MAX_FUNCTION_NAME_LENGTH_BYTES 30 - -// #define TVM_CRT_FRAMER_ENABLE_LOGS - -#endif // TVM_RUNTIME_MICRO_CRT_CONFIG_H_ diff --git a/apps/microtvm/arduino/template_project/boards.json b/apps/microtvm/arduino/template_project/boards.json new file mode 100644 index 000000000000..595d56b5f615 --- /dev/null +++ b/apps/microtvm/arduino/template_project/boards.json @@ -0,0 +1,59 @@ +{ + "due": { + "package": "arduino", + "architecture": "sam", + "board": "arduino_due_x_dbg", + "model": "sam3x8e" + }, + "feathers2": { + "package": "esp32", + "architecture": "esp32", + "board": "feathers2", + "model": "esp32", + "note": "Due to the way the Feather S2 bootloader works, compilation behaves fine but uploads cannot be done automatically." + }, + "metrom4": { + "package": "adafruit", + "architecture": "samd", + "board": "adafruit_metro_m4", + "model": "atsamd51" + }, + "spresense": { + "package": "SPRESENSE", + "architecture": "spresense", + "board": "spresense", + "model": "cxd5602gg", + "note": "Spresense only works as of its v2.3.0 sdk." + }, + "nano33ble": { + "package": "arduino", + "architecture": "mbed_nano", + "board": "nano33ble", + "model": "nrf52840" + }, + "pybadge": { + "package": "adafruit", + "architecture": "samd", + "board": "adafruit_pybadge_m4", + "model": "atsamd51" + }, + "teensy40": { + "package": "teensy", + "architecture": "avr", + "board": "teensy40", + "model": "imxrt1060", + "note": "The Teensy boards are listed here for completeness, but they won't work until https://github.com/arduino/arduino-cli/issues/700 is finished." + }, + "teensy41": { + "package": "teensy", + "architecture": "avr", + "board": "teensy41", + "model": "imxrt1060" + }, + "wioterminal": { + "package": "Seeeduino", + "architecture": "samd", + "board": "seeed_wio_terminal", + "model": "atsamd51" + } +} diff --git a/apps/microtvm/arduino/example_project/src/standalone_crt/crt_config/crt_config.h b/apps/microtvm/arduino/template_project/crt_config/crt_config.h similarity index 100% rename from apps/microtvm/arduino/example_project/src/standalone_crt/crt_config/crt_config.h rename to apps/microtvm/arduino/template_project/crt_config/crt_config.h diff --git a/apps/microtvm/arduino/template_project/microtvm_api_server.py b/apps/microtvm/arduino/template_project/microtvm_api_server.py index 3d25d0bcad8f..e285ecc6e3b0 100644 --- a/apps/microtvm/arduino/template_project/microtvm_api_server.py +++ b/apps/microtvm/arduino/template_project/microtvm_api_server.py @@ -44,77 +44,21 @@ IS_TEMPLATE = not (API_SERVER_DIR / MODEL_LIBRARY_FORMAT_RELPATH).exists() +BOARDS = API_SERVER_DIR / "boards.json" + +# Data structure to hold the information microtvm_api_server.py needs +# to communicate with each of these boards. +try: + with open(BOARDS) as boards: + BOARD_PROPERTIES = json.load(boards) +except FileNotFoundError: + raise FileNotFoundError(f"Board file {{{BOARDS}}} does not exist.") + + class BoardAutodetectFailed(Exception): """Raised when no attached hardware is found matching the requested board""" -# Data structure to hold the information microtvm_api_server.py needs -# to communicate with each of these boards. Currently just holds the -# components of each board's FQBN, but might be extended in the future -# to include the SRAM, PSRAM, flash, etc. on each board. -BOARD_PROPERTIES = { - "due": { - "package": "arduino", - "architecture": "sam", - "board": "arduino_due_x_dbg", - "model": "sam3x8e", - }, - # Due to the way the Feather S2 bootloader works, compilation - # behaves fine but uploads cannot be done automatically - "feathers2": { - "package": "esp32", - "architecture": "esp32", - "board": "feathers2", - "model": "esp32", - }, - "metrom4": { - "package": "adafruit", - "architecture": "samd", - "board": "adafruit_metro_m4", - "model": "atsamd51", - }, - # Spresense only works as of its v2.3.0 sdk - "spresense": { - "package": "SPRESENSE", - "architecture": "spresense", - "board": "spresense", - "model": "cxd5602gg", - }, - "nano33ble": { - "package": "arduino", - "architecture": "mbed_nano", - "board": "nano33ble", - "model": "nrf52840", - }, - "pybadge": { - "package": "adafruit", - "architecture": "samd", - "board": "adafruit_pybadge_m4", - "model": "atsamd51", - }, - # The Teensy boards are listed here for completeness, but they - # won't work until https://github.com/arduino/arduino-cli/issues/700 - # is finished - "teensy40": { - "package": "teensy", - "architecture": "avr", - "board": "teensy40", - "model": "imxrt1060", - }, - "teensy41": { - "package": "teensy", - "architecture": "avr", - "board": "teensy41", - "model": "imxrt1060", - }, - "wioterminal": { - "package": "Seeeduino", - "architecture": "samd", - "board": "seeed_wio_terminal", - "model": "atsamd51", - }, -} - PROJECT_TYPES = ["example_project", "host_driven"] PROJECT_OPTIONS = [ @@ -123,11 +67,6 @@ class BoardAutodetectFailed(Exception): choices=list(BOARD_PROPERTIES), help="Name of the Arduino board to build for", ), - server.ProjectOption( - "arduino_model", - choices=[board["model"] for _, board in BOARD_PROPERTIES.items()], - help="Name of the model for each Arduino board.", - ), server.ProjectOption("arduino_cli_cmd", help="Path to the arduino-cli tool."), server.ProjectOption("port", help="Port to use for connecting to hardware"), server.ProjectOption( @@ -166,8 +105,9 @@ def _copy_project_files(self, api_server_dir, project_dir, project_type): so this file is copied separately in generate_project. """ - project_types_folder = api_server_dir.parents[0] - for item in (project_types_folder / project_type / "src").iterdir(): + for item in (API_SERVER_DIR / "src" / project_type).iterdir(): + if item.name == "project.ino": + continue dest = project_dir / "src" / item.name if item.is_dir(): shutil.copytree(item, dest) @@ -176,7 +116,7 @@ def _copy_project_files(self, api_server_dir, project_dir, project_type): # Arduino requires the .ino file have the same filename as its containing folder shutil.copy2( - project_types_folder / project_type / "project.ino", + API_SERVER_DIR / "src" / project_type / "project.ino", project_dir / f"{project_dir.stem}.ino", ) @@ -344,12 +284,20 @@ def generate_project(self, model_library_format_path, standalone_crt_dir, projec # Copies files from the template folder to project_dir shutil.copy2(API_SERVER_DIR / "microtvm_api_server.py", project_dir) + shutil.copy2(BOARDS, project_dir / BOARDS.name) self._copy_project_files(API_SERVER_DIR, project_dir, options["project_type"]) # Copy standalone_crt into src folder self._copy_standalone_crt(source_dir, standalone_crt_dir) self._remove_unused_components(source_dir, options["project_type"]) + # Populate crt-config.h + crt_config_dir = project_dir / "src" / "standalone_crt" / "crt_config" + crt_config_dir.mkdir() + shutil.copy2( + API_SERVER_DIR / "crt_config" / "crt_config.h", crt_config_dir / "crt_config.h" + ) + # Unpack the MLF and copy the relevant files metadata = self._disassemble_mlf(model_library_format_path, source_dir) shutil.copy2(model_library_format_path, source_dir / "model") diff --git a/apps/microtvm/arduino/example_project/src/model.c b/apps/microtvm/arduino/template_project/src/example_project/model.c similarity index 100% rename from apps/microtvm/arduino/example_project/src/model.c rename to apps/microtvm/arduino/template_project/src/example_project/model.c diff --git a/apps/microtvm/arduino/example_project/src/model.h b/apps/microtvm/arduino/template_project/src/example_project/model.h similarity index 100% rename from apps/microtvm/arduino/example_project/src/model.h rename to apps/microtvm/arduino/template_project/src/example_project/model.h diff --git a/apps/microtvm/arduino/example_project/project.ino b/apps/microtvm/arduino/template_project/src/example_project/project.ino similarity index 100% rename from apps/microtvm/arduino/example_project/project.ino rename to apps/microtvm/arduino/template_project/src/example_project/project.ino diff --git a/apps/microtvm/arduino/host_driven/src/model_support.c b/apps/microtvm/arduino/template_project/src/host_driven/model_support.c similarity index 100% rename from apps/microtvm/arduino/host_driven/src/model_support.c rename to apps/microtvm/arduino/template_project/src/host_driven/model_support.c diff --git a/apps/microtvm/arduino/host_driven/project.ino b/apps/microtvm/arduino/template_project/src/host_driven/project.ino similarity index 100% rename from apps/microtvm/arduino/host_driven/project.ino rename to apps/microtvm/arduino/template_project/src/host_driven/project.ino diff --git a/tests/micro/arduino/conftest.py b/tests/micro/arduino/conftest.py index bb9c69bf4a0e..73361774821b 100644 --- a/tests/micro/arduino/conftest.py +++ b/tests/micro/arduino/conftest.py @@ -17,8 +17,9 @@ import datetime import pathlib - +import json import pytest + import tvm.target.target from tvm.micro import project from tvm import micro, relay @@ -34,19 +35,16 @@ / "template_project" ).resolve() +BOARDS = TEMPLATE_PROJECT_DIR / "boards.json" + def arduino_boards() -> dict: """Returns a dict mapping board to target model""" - template = project.TemplateProject.from_directory(TEMPLATE_PROJECT_DIR) - project_options = template.info()["project_options"] - for option in project_options: - if option["name"] == "arduino_board": - boards = option["choices"] - if option["name"] == "arduino_model": - models = option["choices"] - - arduino_boards = {boards[i]: models[i] for i in range(len(boards))} - return arduino_boards + with open(BOARDS) as f: + board_properties = json.load(f) + + boards_model = {board: info["model"] for board, info in board_properties.items()} + return boards_model ARDUINO_BOARDS = arduino_boards() From 095da3cd641d34c61f676f8ed76ed2c0209ad404 Mon Sep 17 00:00:00 2001 From: Mehrdad Hessar Date: Thu, 14 Oct 2021 14:31:50 -0700 Subject: [PATCH 3/8] readme --- apps/microtvm/arduino/README.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 apps/microtvm/arduino/README.md diff --git a/apps/microtvm/arduino/README.md b/apps/microtvm/arduino/README.md new file mode 100644 index 000000000000..587d0642b235 --- /dev/null +++ b/apps/microtvm/arduino/README.md @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + +This directory code to interface microTVM with [Arduino](https://www.arduino.cc/). From 81a1e721c911a32910e3d3daca3b1d4c6ba7c137 Mon Sep 17 00:00:00 2001 From: Mehrdad Hessar Date: Thu, 14 Oct 2021 15:06:38 -0700 Subject: [PATCH 4/8] add arduino --- CMakeLists.txt | 2 + cmake/modules/Arduino.cmake | 78 +++++++++++++++++++++++++++++++++++++ cmake/modules/Zephyr.cmake | 9 ++--- cmake/utils/Utils.cmake | 2 + 4 files changed, 86 insertions(+), 5 deletions(-) create mode 100644 cmake/modules/Arduino.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index d429e9458c78..bb5cfdfbd373 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -414,6 +414,7 @@ endif(USE_PIPELINE_EXECUTOR) include(cmake/modules/VTA.cmake) include(cmake/modules/StandaloneCrt.cmake) include(cmake/modules/Zephyr.cmake) +include(cmake/modules/Arduino.cmake) include(cmake/modules/CUDA.cmake) include(cmake/modules/Hexagon.cmake) include(cmake/modules/OpenCL.cmake) @@ -502,6 +503,7 @@ if(USE_MICRO) add_dependencies(tvm host_standalone_crt) add_dependencies(tvm_runtime host_standalone_crt) add_dependencies(tvm_runtime zephyr) + add_dependencies(tvm_runtime arduino) endif() if(USE_CPP_RPC) diff --git a/cmake/modules/Arduino.cmake b/cmake/modules/Arduino.cmake new file mode 100644 index 000000000000..54c144081efa --- /dev/null +++ b/cmake/modules/Arduino.cmake @@ -0,0 +1,78 @@ +# 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. + +if(USE_MICRO) + message(STATUS "Add Arduino for microTVM") + + function(microtvm_add_arduino) + list( + APPEND + ARDUINO_FILE_COPY_JOBS + "apps/microtvm/arduino/template_project microtvm_api_server.py -> arduino" + "apps/microtvm/arduino/template_project boards.json -> arduino" + "apps/microtvm/arduino/template_project/src/example_project *.c -> arduino/src/example_project" + "apps/microtvm/arduino/template_project/src/example_project *.h -> arduino/src/example_project" + "apps/microtvm/arduino/template_project/src/example_project *.ino -> arduino/src/example_project" + "apps/microtvm/arduino/template_project/src/host_driven *.c -> arduino/src/host_driven" + "apps/microtvm/arduino/template_project/src/host_driven *.ino -> arduino/src/host_driven" + "apps/microtvm/arduino/template_project/crt_config *.h -> arduino/crt_config" + ) + + foreach(job_spec IN LISTS ARDUINO_FILE_COPY_JOBS) + string(REPLACE " " ";" job_spec "${job_spec}") + list(LENGTH job_spec job_spec_length) + math(EXPR job_spec_length_mod "${job_spec_length} % 3") + if(NOT "${job_spec_length_mod}" EQUAL 1) + message( + FATAL_ERROR + "Arduino copy job spec list length is ${job_spec_length}; parsed job spec is ${job_spec}" + ) + endif() + math(EXPR job_spec_stop "${job_spec_length} - 3") + + list(GET job_spec 0 job_src_base) + set(job_src_base "${CMAKE_SOURCE_DIR}/${job_src_base}") + foreach(copy_pattern_index RANGE 1 "${job_spec_stop}" 3) + list(GET job_spec ${copy_pattern_index} copy_pattern) + math(EXPR copy_dest_index "${copy_pattern_index} + 2") + list(GET job_spec ${copy_dest_index} copy_dest) + + file( + GLOB_RECURSE copy_files + RELATIVE "${job_src_base}" + "${job_src_base}/${copy_pattern}") + list(LENGTH copy_files copy_files_length) + if("${copy_files_length}" EQUAL 0) + message( + FATAL_ERROR + "Arduino copy job matched 0 files: ${job_src_base}/${copy_pattern} -> ${copy_dest}" + ) + endif() + foreach(copy_src IN LISTS copy_files) + get_filename_component( + dest_path "${MICROTVM_TEMPLATE_PROJECTS}/${copy_dest}/${copy_src}" + ABSOLUTE) + tvm_micro_add_copy_file(arduino_template_deps + ${job_src_base}/${copy_src} ${dest_path}) + endforeach() + endforeach() + endforeach() + + add_custom_target(arduino DEPENDS ${arduino_template_deps}) + endfunction() + + microtvm_add_arduino() + +endif(USE_MICRO) diff --git a/cmake/modules/Zephyr.cmake b/cmake/modules/Zephyr.cmake index ff8bd4688aef..048240375cd6 100644 --- a/cmake/modules/Zephyr.cmake +++ b/cmake/modules/Zephyr.cmake @@ -30,8 +30,6 @@ if(USE_MICRO) "apps/microtvm/zephyr/template_project/crt_config *.h -> zephyr/crt_config" ) - set(zephyr_base "${CMAKE_CURRENT_BINARY_DIR}/micro_template_projects") - foreach(job_spec IN LISTS ZEPHYR_FILE_COPY_JOBS) string(REPLACE " " ";" job_spec "${job_spec}") list(LENGTH job_spec job_spec_length) @@ -64,9 +62,10 @@ if(USE_MICRO) endif() foreach(copy_src IN LISTS copy_files) get_filename_component( - dest_path "${zephyr_base}/${copy_dest}/${copy_src}" ABSOLUTE) - tvm_micro_add_copy_file(zephyr_template_deps - ${job_src_base}/${copy_src} ${dest_path}) + dest_path "${MICROTVM_TEMPLATE_PROJECTS}/${copy_dest}/${copy_src}" + ABSOLUTE) + tvm_micro_add_copy_file(zephyr_template_deps + ${job_src_base}/${copy_src} ${dest_path}) endforeach() endforeach() endforeach() diff --git a/cmake/utils/Utils.cmake b/cmake/utils/Utils.cmake index 5b504518b1c4..44f622126abb 100644 --- a/cmake/utils/Utils.cmake +++ b/cmake/utils/Utils.cmake @@ -86,6 +86,8 @@ function(tvm_micro_add_copy_file var src dest) set("${var}" "${${var}}" PARENT_SCOPE) endfunction(tvm_micro_add_copy_file) +set(MICROTVM_TEMPLATE_PROJECTS "${CMAKE_CURRENT_BINARY_DIR}/microtvm_template_projects") + # From cmake documentation: # True if the constant is 1, ON, YES, TRUE, Y, or a non-zero number. # False if the constant is 0, OFF, NO, FALSE, N, IGNORE, NOTFOUND, the empty string, or ends in the suffix -NOTFOUND. From 986bd5960fb86e34e00354ed74b59abb83f2e7e5 Mon Sep 17 00:00:00 2001 From: Mehrdad Hessar Date: Thu, 14 Oct 2021 17:40:31 -0700 Subject: [PATCH 5/8] add project template to setup.py --- .../work_with_microtvm/micro_autotune.py | 13 +++---- .../how_to/work_with_microtvm/micro_tflite.py | 7 ++-- python/setup.py | 7 ++++ python/tvm/micro/__init__.py | 1 + python/tvm/micro/build.py | 34 +++++++++++++++++++ tests/micro/arduino/conftest.py | 12 ++----- tests/micro/zephyr/test_utils.py | 11 +----- 7 files changed, 52 insertions(+), 33 deletions(-) diff --git a/gallery/how_to/work_with_microtvm/micro_autotune.py b/gallery/how_to/work_with_microtvm/micro_autotune.py index e7a1fa84a110..bdb81fb1e0d3 100644 --- a/gallery/how_to/work_with_microtvm/micro_autotune.py +++ b/gallery/how_to/work_with_microtvm/micro_autotune.py @@ -113,12 +113,9 @@ # choose other options by choosing from `PLATFORM` list. # -repo_root = pathlib.Path( - subprocess.check_output(["git", "rev-parse", "--show-toplevel"], encoding="utf-8").strip() -) module_loader = tvm.micro.AutoTvmModuleLoader( - template_project_dir=repo_root / "src" / "runtime" / "crt" / "host", + template_project_dir=pathlib.Path(tvm.micro.get_microtvm_template_projects("crt")), project_options={"verbose": False}, ) builder = tvm.autotvm.LocalBuilder( @@ -134,7 +131,7 @@ # Compiling for physical hardware # -------------------------------------------------------------------------- # module_loader = tvm.micro.AutoTvmModuleLoader( -# template_project_dir=repo_root / "apps" / "microtvm" / "zephyr" / "template_project", +# template_project_dir=pathlib.Path(tvm.micro.get_microtvm_template_projects("zephyr")), # project_options={ # "zephyr_board": BOARD, # "west_cmd": "west", @@ -183,7 +180,7 @@ temp_dir = tvm.contrib.utils.tempdir() project = tvm.micro.generate_project( - str(repo_root / "src" / "runtime" / "crt" / "host"), + str(tvm.micro.get_microtvm_template_projects("crt")), lowered, temp_dir / "project", {"verbose": False}, @@ -192,7 +189,7 @@ # Compiling for physical hardware # -------------------------------------------------------------------------- # project = tvm.micro.generate_project( -# str(repo_root / "apps" / "microtvm" / "zephyr" / "template_project"), +# str(tvm.micro.get_microtvm_template_projects("zephyr")), # lowered, # temp_dir / "project", # { @@ -235,7 +232,7 @@ # Compiling for physical hardware # -------------------------------------------------------------------------- # project = tvm.micro.generate_project( -# str(repo_root / "apps" / "microtvm" / "zephyr" / "template_project"), +# str(tvm.micro.get_microtvm_template_projects("zephyr")), # lowered_tuned, # temp_dir / "project", # { diff --git a/gallery/how_to/work_with_microtvm/micro_tflite.py b/gallery/how_to/work_with_microtvm/micro_tflite.py index cab105cb450f..35b08d87b9ee 100644 --- a/gallery/how_to/work_with_microtvm/micro_tflite.py +++ b/gallery/how_to/work_with_microtvm/micro_tflite.py @@ -269,10 +269,7 @@ import subprocess import pathlib -repo_root = pathlib.Path( - subprocess.check_output(["git", "rev-parse", "--show-toplevel"], encoding="utf-8").strip() -) -template_project_path = repo_root / "src" / "runtime" / "crt" / "host" +template_project_path = pathlib.Path(tvm.micro.get_microtvm_template_projects("crt")) project_options = {} # You can use options to provide platform-specific options through TVM. # Compiling for physical hardware (or an emulated board, like the mps_an521) @@ -280,7 +277,7 @@ # For physical hardware, you can try out the Zephyr platform by using a different template project # and options: # -# template_project_path = repo_root / "apps" / "microtvm" / "zephyr" / "template_project" +# template_project_path = pathlib.Path(tvm.micro.get_microtvm_template_projects("zephyr")) # project_options = {"project_type": "host_driven", zephyr_board": "nucleo_f746zg"}} # Create a temporary directory diff --git a/python/setup.py b/python/setup.py index 1b2a9d3ee965..5d21af6b5878 100644 --- a/python/setup.py +++ b/python/setup.py @@ -62,6 +62,13 @@ def get_lib_path(): libs.append(candidate_path) break + # Add microTVM template projects + for name in lib_path: + candidate_path = os.path.join(os.path.dirname(name), "microtvm_template_projects") + if os.path.isdir(candidate_path): + libs.append(candidate_path) + break + else: libs = None diff --git a/python/tvm/micro/__init__.py b/python/tvm/micro/__init__.py index 2aea9d3fd61d..ba966d3791bb 100644 --- a/python/tvm/micro/__init__.py +++ b/python/tvm/micro/__init__.py @@ -19,6 +19,7 @@ from .build import autotvm_build_func from .build import AutoTvmModuleLoader from .build import get_standalone_crt_dir +from .build import get_microtvm_template_projects from .model_library_format import export_model_library_format, UnsupportedInModelLibraryFormatError from .project import generate_project, GeneratedProject, TemplateProject from .session import ( diff --git a/python/tvm/micro/build.py b/python/tvm/micro/build.py index 9e278081933c..274250501bf5 100644 --- a/python/tvm/micro/build.py +++ b/python/tvm/micro/build.py @@ -22,6 +22,7 @@ import os import pathlib import contextlib +import enum from typing import Union from .._ffi import libinfo @@ -34,10 +35,24 @@ 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. @@ -64,6 +79,25 @@ def get_standalone_crt_dir() -> str: return STANDALONE_CRT_DIR +def get_microtvm_template_projects(platform: str) -> str: + if platform not in MicroTVMTemplateProject.list(): + raise ValueError(f"platform {platform} is not supported.") + + if platform == MicroTVMTemplateProject.CRT.value: + return os.path.join(get_standalone_crt_dir(), "template", "host") + + 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) + + class AutoTvmModuleLoader: """MicroTVM AutoTVM Module Loader diff --git a/tests/micro/arduino/conftest.py b/tests/micro/arduino/conftest.py index 73361774821b..0bb7fb120844 100644 --- a/tests/micro/arduino/conftest.py +++ b/tests/micro/arduino/conftest.py @@ -24,16 +24,8 @@ from tvm.micro import project from tvm import micro, relay -TEMPLATE_PROJECT_DIR = ( - pathlib.Path(__file__).parent - / ".." - / ".." - / ".." - / "apps" - / "microtvm" - / "arduino" - / "template_project" -).resolve() +TEMPLATE_PROJECT_DIR = pathlib.Path(tvm.micro.get_microtvm_template_projects("arduino")) + BOARDS = TEMPLATE_PROJECT_DIR / "boards.json" diff --git a/tests/micro/zephyr/test_utils.py b/tests/micro/zephyr/test_utils.py index c27c869509d7..c89e6c805498 100644 --- a/tests/micro/zephyr/test_utils.py +++ b/tests/micro/zephyr/test_utils.py @@ -31,16 +31,7 @@ import tvm.micro -TEMPLATE_PROJECT_DIR = ( - pathlib.Path(__file__).parent - / ".." - / ".." - / ".." - / "apps" - / "microtvm" - / "zephyr" - / "template_project" -).resolve() +TEMPLATE_PROJECT_DIR = pathlib.Path(tvm.micro.get_microtvm_template_projects("zephyr")) BOARDS = TEMPLATE_PROJECT_DIR / "boards.json" From d87440796e9b23886c2dd052e38c66b33e4d9eec Mon Sep 17 00:00:00 2001 From: Mehrdad Hessar Date: Mon, 18 Oct 2021 09:20:39 -0700 Subject: [PATCH 6/8] fix lint --- python/tvm/micro/build.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/python/tvm/micro/build.py b/python/tvm/micro/build.py index 274250501bf5..795a61edcbb3 100644 --- a/python/tvm/micro/build.py +++ b/python/tvm/micro/build.py @@ -80,6 +80,18 @@ def get_standalone_crt_dir() -> str: 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.") From b37de64966f926c6f2347faf37e9c28d0d95254a Mon Sep 17 00:00:00 2001 From: Mehrdad Hessar Date: Mon, 18 Oct 2021 14:43:18 -0700 Subject: [PATCH 7/8] fix tutorial --- gallery/how_to/work_with_microtvm/micro_autotune.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gallery/how_to/work_with_microtvm/micro_autotune.py b/gallery/how_to/work_with_microtvm/micro_autotune.py index bdb81fb1e0d3..d3106712aa99 100644 --- a/gallery/how_to/work_with_microtvm/micro_autotune.py +++ b/gallery/how_to/work_with_microtvm/micro_autotune.py @@ -223,7 +223,7 @@ temp_dir = tvm.contrib.utils.tempdir() project = tvm.micro.generate_project( - str(repo_root / "src" / "runtime" / "crt" / "host"), + str(tvm.micro.get_microtvm_template_projects("crt")), lowered_tuned, temp_dir / "project", {"verbose": False}, From 142ae4af7cfc245f0017f0aade71ee37b6d33c46 Mon Sep 17 00:00:00 2001 From: Mehrdad Hessar Date: Mon, 25 Oct 2021 15:31:02 -0700 Subject: [PATCH 8/8] address comments from PR9274 --- .../arduino/template_project/microtvm_api_server.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/apps/microtvm/arduino/template_project/microtvm_api_server.py b/apps/microtvm/arduino/template_project/microtvm_api_server.py index 18c1b659dafd..832f6d2a0435 100644 --- a/apps/microtvm/arduino/template_project/microtvm_api_server.py +++ b/apps/microtvm/arduino/template_project/microtvm_api_server.py @@ -31,6 +31,7 @@ import tempfile import time from string import Template +import re import serial import serial.tools.list_ports @@ -287,11 +288,11 @@ def _find_modified_include_path(self, project_dir, file_path, include_path): return include_path def _get_platform_version(self, arduino_cli_path: str) -> float: + # sample output of this command: + # 'arduino-cli alpha Version: 0.18.3 Commit: d710b642 Date: 2021-05-14T12:36:58Z\n' version_output = subprocess.check_output([arduino_cli_path, "version"], encoding="utf-8") - version_output = ( - version_output.replace("\n", "").replace("\r", "").replace(":", "").lower().split(" ") - ) - full_version = version_output[version_output.index("version") + 1].split(".") + full_version = re.findall("version: ([\.0-9]*)", version_output.lower()) + full_version = full_version[0].split(".") version = float(f"{full_version[0]}.{full_version[1]}") return version