Skip to content

Commit

Permalink
[microTVM][Zephyr] Add 'config_main_stack_size' option to API server (a…
Browse files Browse the repository at this point in the history
  • Loading branch information
mehrdadh authored and ylc committed Jan 13, 2022
1 parent 0743e21 commit 8997c66
Show file tree
Hide file tree
Showing 8 changed files with 201 additions and 196 deletions.
56 changes: 56 additions & 0 deletions apps/microtvm/zephyr/template_project/boards.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
{
"mps2_an521": {
"board": "mps2_an521",
"model": "mps2_an521",
"is_qemu": true,
"fpu": false
},
"nrf5340dk_nrf5340_cpuapp": {
"board": "nrf5340dk_nrf5340_cpuapp",
"model": "nrf5340dk",
"is_qemu": false,
"fpu": true
},
"nucleo_f746zg": {
"board": "nucleo_f746zg",
"model": "stm32f746xx",
"is_qemu": false,
"fpu": true
},
"nucleo_l4r5zi": {
"board": "nucleo_l4r5zi",
"model": "stm32l4r5zi",
"is_qemu": false,
"fpu": true
},
"qemu_cortex_r5": {
"board": "qemu_cortex_r5",
"model": "zynq_mp_r5",
"is_qemu": true,
"fpu": true
},
"qemu_riscv32": {
"board": "qemu_riscv32",
"model": "host",
"is_qemu": true,
"fpu": true
},
"qemu_riscv64": {
"board": "qemu_riscv64",
"model": "host",
"is_qemu": true,
"fpu": true
},
"qemu_x86": {
"board": "qemu_x86",
"model": "host",
"is_qemu": true,
"fpu": true
},
"stm32f746g_disco": {
"board": "stm32f746g_disco",
"model": "stm32f746xx",
"is_qemu": false,
"fpu": true
}
}
77 changes: 18 additions & 59 deletions apps/microtvm/zephyr/template_project/microtvm_api_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
import tempfile
import threading
import time
import json

import serial
import serial.tools.list_ports
Expand All @@ -57,46 +58,16 @@

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.
BOARD_PROPERTIES = {
"qemu_x86": {
"board": "qemu_x86",
"model": "host",
},
"qemu_riscv32": {
"board": "qemu_riscv32",
"model": "host",
},
"qemu_riscv64": {
"board": "qemu_riscv64",
"model": "host",
},
"mps2_an521": {
"board": "mps2_an521",
"model": "mps2_an521",
},
"nrf5340dk_nrf5340_cpuapp": {
"board": "nrf5340dk_nrf5340_cpuapp",
"model": "nrf5340dk",
},
"stm32f746g_disco": {
"board": "stm32f746g_disco",
"model": "stm32f746xx",
},
"nucleo_f746zg": {
"board": "nucleo_f746zg",
"model": "stm32f746xx",
},
"nucleo_l4r5zi": {
"board": "nucleo_l4r5zi",
"model": "stm32l4r5zi",
},
"qemu_cortex_r5": {
"board": "qemu_cortex_r5",
"model": "zynq_mp_r5",
},
}
try:
with open(BOARDS) as boards:
BOARD_PROPERTIES = json.load(boards)
except FileNotFoundError:
raise FileNotFoundError(f"Board file {{{BOARDS}}} does not exist.")


def check_call(cmd_args, *args, **kwargs):
Expand Down Expand Up @@ -290,9 +261,8 @@ def _get_nrf_device_args(options):
help="Name of the Zephyr board to build for.",
),
server.ProjectOption(
"zephyr_model",
choices=[board["model"] for _, board in BOARD_PROPERTIES.items()],
help="Name of the model for each Zephyr board.",
"config_main_stack_size",
help="Sets CONFIG_MAIN_STACK_SIZE for Zephyr board.",
),
]

Expand Down Expand Up @@ -351,13 +321,9 @@ def _create_prj_conf(self, project_dir, options):
if self._has_fpu(options["zephyr_board"]):
f.write("# For models with floating point.\n" "CONFIG_FPU=y\n" "\n")

main_stack_size = None
if self._is_qemu(options) and options["project_type"] == "host_driven":
main_stack_size = 1536

# Set main stack size, if needed.
if main_stack_size is not None:
f.write(f"CONFIG_MAIN_STACK_SIZE={main_stack_size}\n")
if options.get("config_main_stack_size") is not None:
f.write(f"CONFIG_MAIN_STACK_SIZE={options['config_main_stack_size']}\n")

f.write("# For random number generation.\n" "CONFIG_TEST_RANDOM_GENERATOR=y\n")

Expand All @@ -384,6 +350,9 @@ def generate_project(self, model_library_format_path, standalone_crt_dir, projec
# by launching the copy.
shutil.copy2(__file__, project_dir / os.path.basename(__file__))

# Copy boards.json file to generated project.
shutil.copy2(BOARDS, project_dir / BOARDS.name)

# Place Model Library Format tarball in the special location, which this script uses to decide
# whether it's being invoked in a template or generated project.
project_model_library_format_tar_path = project_dir / MODEL_LIBRARY_FORMAT_RELPATH
Expand Down Expand Up @@ -471,20 +440,10 @@ def _is_qemu(cls, options):
or options["zephyr_board"] in cls._KNOWN_QEMU_ZEPHYR_BOARDS
)

_KNOWN_FPU_ZEPHYR_BOARDS = (
"nucleo_f746zg",
"nucleo_l4r5zi",
"nrf5340dk_nrf5340_cpuapp",
"qemu_cortex_r5",
"qemu_riscv32",
"qemu_riscv64",
"qemu_x86",
"stm32f746g_disco",
)

@classmethod
def _has_fpu(cls, zephyr_board):
return zephyr_board in cls._KNOWN_FPU_ZEPHYR_BOARDS
fpu_boards = [name for name, board in BOARD_PROPERTIES.items() if board["fpu"]]
return zephyr_board in fpu_boards

def flash(self, options):
if self._is_qemu(options):
Expand Down
18 changes: 14 additions & 4 deletions python/tvm/micro/project.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
"""Defines glue wrappers around the Project API which mate to TVM interfaces."""

import pathlib
import typing
from typing import Union

from .. import __version__
from ..contrib import utils
Expand Down Expand Up @@ -64,7 +64,7 @@ class GeneratedProject:
"""Defines a glue interface to interact with a generated project through the API server."""

@classmethod
def from_directory(cls, project_dir: typing.Union[pathlib.Path, str], options: dict):
def from_directory(cls, project_dir: Union[pathlib.Path, str], options: dict):
return cls(client.instantiate_from_dir(project_dir), options)

def __init__(self, api_client, options):
Expand Down Expand Up @@ -101,7 +101,17 @@ def __init__(self, api_client):
if not self._info["is_template"]:
raise NotATemplateProjectError()

def _check_project_options(self, options: dict):
"""Check if options are valid ProjectOptions"""
available_options = [option["name"] for option in self.info()["project_options"]]
if options and not set(options.keys()).issubset(available_options):
raise ValueError(
f"""options:{list(options)} include non valid ProjectOptions.
Here is a list of available options:{list(available_options)}."""
)

def generate_project_from_mlf(self, model_library_format_path, project_dir, options):
self._check_project_options(options)
self._api_client.generate_project(
model_library_format_path=str(model_library_format_path),
standalone_crt_dir=get_standalone_crt_dir(),
Expand All @@ -124,9 +134,9 @@ def generate_project(self, graph_executor_factory, project_dir, options):


def generate_project(
template_project_dir: typing.Union[pathlib.Path, str],
template_project_dir: Union[pathlib.Path, str],
module: ExportableModule,
generated_project_dir: typing.Union[pathlib.Path, str],
generated_project_dir: Union[pathlib.Path, str],
options: dict = None,
):
"""Generate a project for an embedded platform that contains the given model.
Expand Down
1 change: 0 additions & 1 deletion python/tvm/micro/project_api/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,6 @@ def instantiate_from_dir(project_dir: typing.Union[pathlib.Path, str], debug: bo
"""Launch server located in project_dir, and instantiate a Project API Client
connected to it."""
args = None

project_dir = pathlib.Path(project_dir)

python_script = project_dir / SERVER_PYTHON_FILENAME
Expand Down
36 changes: 4 additions & 32 deletions tests/micro/zephyr/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,44 +20,16 @@

import pytest

from tvm.micro import project
import tvm.contrib.utils
import tvm.target.target
import test_utils

TEMPLATE_PROJECT_DIR = (
pathlib.Path(__file__).parent
/ ".."
/ ".."
/ ".."
/ "apps"
/ "microtvm"
/ "zephyr"
/ "template_project"
).resolve()


def zephyr_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"] == "zephyr_board":
boards = option["choices"]
if option["name"] == "zephyr_model":
models = option["choices"]

arduino_boards = {boards[i]: models[i] for i in range(len(boards))}
return arduino_boards


ZEPHYR_BOARDS = zephyr_boards()
from tvm.contrib.utils import tempdir


def pytest_addoption(parser):
parser.addoption(
"--zephyr-board",
required=True,
choices=ZEPHYR_BOARDS.keys(),
choices=test_utils.ZEPHYR_BOARDS.keys(),
help=("Zephyr board for test."),
)
parser.addoption(
Expand Down Expand Up @@ -104,4 +76,4 @@ def temp_dir(board):
if not os.path.exists(board_workspace.parent):
os.makedirs(board_workspace.parent)

return tvm.contrib.utils.tempdir(board_workspace)
return tempdir(board_workspace)
62 changes: 62 additions & 0 deletions tests/micro/zephyr/test_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# 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.
import json
import pathlib


TEMPLATE_PROJECT_DIR = (
pathlib.Path(__file__).parent
/ ".."
/ ".."
/ ".."
/ "apps"
/ "microtvm"
/ "zephyr"
/ "template_project"
).resolve()

BOARDS = TEMPLATE_PROJECT_DIR / "boards.json"


def zephyr_boards() -> dict:
"""Returns a dict mapping board to target model"""
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


ZEPHYR_BOARDS = zephyr_boards()


def qemu_boards(board: str):
"""Returns True if board is QEMU."""
with open(BOARDS) as f:
board_properties = json.load(f)

qemu_boards = [name for name, board in board_properties.items() if board["is_qemu"]]
return board in qemu_boards


def has_fpu(board: str):
"""Returns True if board has FPU."""
with open(BOARDS) as f:
board_properties = json.load(f)

fpu_boards = [name for name, board in board_properties.items() if board["fpu"]]
return board in fpu_boards
Loading

0 comments on commit 8997c66

Please sign in to comment.