Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[µTVM] Enable AutoTVM for ARM STM32F746XX Boards #4274

Merged
merged 70 commits into from
Dec 2, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
70 commits
Select commit Hold shift + click to select a range
dbbffbd
TEMP
weberlo Oct 1, 2019
5b356a7
TEMP 2
weberlo Oct 4, 2019
93e7068
GDB-driven execution works
weberlo Oct 6, 2019
cbce8e0
fadd works!
weberlo Oct 6, 2019
c6f6f2b
RAM-only fadd works
weberlo Oct 7, 2019
a9f1736
Remove unnecessary include
weberlo Oct 8, 2019
bc87f18
TEMP
weberlo Oct 12, 2019
bbffe95
compiling as obj instead of shared
weberlo Oct 15, 2019
043297d
no longer relying on external makefile
weberlo Oct 15, 2019
5e48b68
working with dynamically loaded kernels
weberlo Oct 15, 2019
c476648
Make conv2d werk
weberlo Oct 18, 2019
70e9b75
added timing funcs
weberlo Oct 21, 2019
6197423
bring FPU back online and print execution times
weberlo Oct 23, 2019
88e34dd
Add alternative timing impl
weberlo Oct 24, 2019
6f63005
prepping to try host micro rpc
weberlo Oct 24, 2019
7d0c079
Add microRPC support
weberlo Oct 25, 2019
61c6fe8
I think AutoTVM just fucking worked
weberlo Oct 28, 2019
1b66dcb
Add evaluation to tuning script
weberlo Oct 28, 2019
dc0a345
maybe using cycle counts now?
weberlo Oct 29, 2019
6908f70
Fix cycle count struct unpacking bug
weberlo Oct 29, 2019
75acf00
simplify if
weberlo Oct 29, 2019
438e534
remove old demo
weberlo Oct 29, 2019
b3f3c38
shit don't work and idk why
weberlo Nov 1, 2019
1043b9d
still no fokn clue
weberlo Nov 1, 2019
415df9b
i'm a moron
weberlo Nov 2, 2019
edeafb3
Cleanup
weberlo Nov 2, 2019
68b5113
Still works
weberlo Nov 2, 2019
0f7577e
Refactor part 1
weberlo Nov 5, 2019
37c9ee3
Host works again
weberlo Nov 5, 2019
4df83c8
ARM and host work simultaneously
weberlo Nov 5, 2019
bf10c43
refactor yo life
weberlo Nov 5, 2019
face9ce
More cleanup
weberlo Nov 5, 2019
277cbe8
big refactor but now host no work
weberlo Nov 5, 2019
2669d1c
Host works again
weberlo Nov 6, 2019
cf84064
more cleanup
weberlo Nov 6, 2019
838054a
More cleanup
weberlo Nov 6, 2019
6843fb8
garbage collect
weberlo Nov 6, 2019
feeb3b8
cleanup
weberlo Nov 7, 2019
097528b
clean
weberlo Nov 7, 2019
b609e76
refactor and docs
weberlo Nov 7, 2019
bcede67
More cleanup
weberlo Nov 7, 2019
9a76461
Cleanup
weberlo Nov 7, 2019
b09a176
Last round of cleanup before we remove debug code
weberlo Nov 7, 2019
05c53ee
Remove debug code
weberlo Nov 7, 2019
625c16a
remove demo files (temporarily)
weberlo Nov 7, 2019
4cb9a2a
Remove old debug code
weberlo Nov 7, 2019
7f91d79
Partially address comments
weberlo Nov 8, 2019
8b72d2b
Enable ".s" files and add Apache header
weberlo Nov 8, 2019
ba8a88d
Add ASF headers and split host uTVM API defs
weberlo Nov 10, 2019
0d8f4f9
Lint
weberlo Nov 10, 2019
8ad3744
Lint
weberlo Nov 10, 2019
b8855e6
Lint
weberlo Nov 11, 2019
2129037
Lint
weberlo Nov 12, 2019
7b559b6
Fix rebase artifact
weberlo Nov 12, 2019
3fde102
Merge MicroTVM RPC server
weberlo Nov 12, 2019
c85b475
Lint
weberlo Nov 12, 2019
07a2129
Lint
weberlo Nov 14, 2019
5e38d2b
Address tqchen's comment
weberlo Nov 15, 2019
17715ee
Lint
weberlo Nov 15, 2019
aeb840f
Fix CI
weberlo Nov 20, 2019
70d607e
Move '-device_type=micro_dev' check to ndarray.py
weberlo Nov 20, 2019
3ecd4bf
Fix
weberlo Nov 20, 2019
98462b9
Fix binutil tests
weberlo Nov 21, 2019
1224eed
Fix
weberlo Nov 21, 2019
721ceb3
Fix
weberlo Nov 22, 2019
27897d6
Fix
weberlo Nov 22, 2019
013795e
Make quotes thicker
weberlo Nov 22, 2019
9d77f82
Address comments
weberlo Nov 24, 2019
3d594b7
Remove copyright lines
weberlo Nov 24, 2019
afd614e
Make create_micro_mod static
weberlo Nov 25, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 7 additions & 4 deletions python/tvm/_ffi/ndarray.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,10 +75,13 @@ def context(dev_type, dev_id=0):
assert tvm.context("cuda", 0) == tvm.gpu(0)
"""
if isinstance(dev_type, string_types):
dev_type = dev_type.split()[0]
if dev_type not in TVMContext.STR2MASK:
raise ValueError("Unknown device type %s" % dev_type)
dev_type = TVMContext.STR2MASK[dev_type]
if '-device=micro_dev' in dev_type:
dev_type = 'micro_dev'
else:
dev_type = dev_type.split()[0]
if dev_type not in TVMContext.STR2MASK:
raise ValueError("Unknown device type %s" % dev_type)
dev_type = TVMContext.STR2MASK[dev_type]
return TVMContext(dev_type, dev_id)


Expand Down
223 changes: 128 additions & 95 deletions python/tvm/contrib/binutil.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,81 @@
import os
import subprocess
from . import util
from .._ffi.base import py_str
from ..api import register_func

RELOCATION_LD_SCRIPT_TEMPLATE = """
/* linker symbol for use in UTVMInit */
_utvm_stack_pointer_init = 0x{stack_pointer_init:x};

SECTIONS
{{
. = 0x{text_start:x};
. = ALIGN({word_size});
.text :
{{
. = ALIGN({word_size});
KEEP(*(.text))
KEEP(*(.text*))
. = ALIGN({word_size});
}}

. = 0x{rodata_start:x};
. = ALIGN({word_size});
.rodata :
{{
. = ALIGN({word_size});
KEEP(*(.rodata))
KEEP(*(.rodata*))
. = ALIGN({word_size});
}}

. = 0x{data_start:x};
. = ALIGN({word_size});
.data :
{{
. = ALIGN({word_size});
KEEP(*(.data))
KEEP(*(.data*))
. = ALIGN({word_size});
}}

. = 0x{bss_start:x};
. = ALIGN({word_size});
.bss :
{{
. = ALIGN({word_size});
KEEP(*(.bss))
KEEP(*(.bss*))
. = ALIGN({word_size});
}}
}}
"""

def run_cmd(cmd):
weberlo marked this conversation as resolved.
Show resolved Hide resolved
"""Runs `cmd` in a subprocess and awaits its completion.

Parameters
----------
cmd : List[str]
list of command-line arguments

Returns
-------
output : str
resulting stdout capture from the subprocess
"""
proc = subprocess.Popen(
cmd,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT)
(output, _) = proc.communicate()
output = output.decode("utf-8")
if proc.returncode != 0:
cmd_str = " ".join(cmd)
msg = f"error while running command \"{cmd_str}\":\n{output}"
raise RuntimeError(msg)
return output


@register_func("tvm_callback_get_section_size")
def tvm_callback_get_section_size(binary_path, section_name, toolchain_prefix):
Expand All @@ -48,14 +120,7 @@ def tvm_callback_get_section_size(binary_path, section_name, toolchain_prefix):
raise RuntimeError("no such file \"{}\"".format(binary_path))
# We use the "-A" flag here to get the ".rodata" section's size, which is
# not included by default.
size_proc = subprocess.Popen(
["{}size".format(toolchain_prefix), "-A", binary_path], stdout=subprocess.PIPE)
(size_output, _) = size_proc.communicate()
size_output = size_output.decode("utf-8")
if size_proc.returncode != 0:
msg = "error in finding section size:\n"
msg += py_str(size_output)
raise RuntimeError(msg)
size_output = run_cmd(["{}size".format(toolchain_prefix), "-A", binary_path])

# TODO(weberlo): Refactor this method and `*relocate_binary` so they are
# both aware of [".bss", ".sbss", ".sdata"] being relocated to ".bss".
Expand All @@ -74,13 +139,15 @@ def tvm_callback_get_section_size(binary_path, section_name, toolchain_prefix):
continue
entry_name = tokens[0]
entry_size = int(tokens[1])
if entry_name in sections_to_sum:
section_size += entry_size
for section in sections_to_sum:
if entry_name.startswith(section):
section_size += entry_size
break

# NOTE: For some reason, the size of the BSS section on the RISC-V
# GCC is sometimes reported to be smaller than it is, so we need to adjust
# for this.
if "riscv" in toolchain_prefix and section_name == 'bss':
if "riscv" in toolchain_prefix and section_name == "bss":
# TODO(weberlo): Figure out why 32 is the minimum constant that works.
#
# The current hypothesis is that the last symbols in the ".bss" and
Expand All @@ -97,25 +164,38 @@ def tvm_callback_get_section_size(binary_path, section_name, toolchain_prefix):

@register_func("tvm_callback_relocate_binary")
def tvm_callback_relocate_binary(
binary_path, text_addr, rodata_addr, data_addr, bss_addr, toolchain_prefix):
binary_path,
word_size,
text_start,
rodata_start,
data_start,
bss_start,
stack_end,
toolchain_prefix):
"""Relocates sections in the binary to new addresses

Parameters
----------
binary_path : str
path of the binary file

text_addr : str
text section absolute address
word_size : int
word size on the target machine

text_start : int
text section address

rodata_start : int
rodata section address

rodata_addr : str
rodata section absolute address
data_start : int
data section address

data_addr : str
data section absolute address
bss_start : int
bss section address

bss_addr : str
bss section absolute address
stack_end : int
stack section end address

toolchain_prefix : str
prefix for binary names in target compiler toolchain
Expand All @@ -125,68 +205,29 @@ def tvm_callback_relocate_binary(
rel_bin : bytearray
the relocated binary
"""
tmp_dir = util.tempdir()
rel_obj_path = tmp_dir.relpath("relocated.o")
stack_pointer_init = stack_end - word_size
ld_script_contents = ""
# TODO(weberlo): There should be a better way to configure this for different archs.
if "riscv" in toolchain_prefix:
ld_script_contents += "OUTPUT_ARCH( \"riscv\" )\n\n"
# TODO(weberlo): Generate the script in a more procedural manner.
ld_script_contents += """
SECTIONS
{
. = %s;
. = ALIGN(8);
.text :
{
*(.text)
. = ALIGN(8);
*(.text*)
}
. = %s;
. = ALIGN(8);
.rodata :
{
*(.rodata)
. = ALIGN(8);
*(.rodata*)
}
. = %s;
. = ALIGN(8);
.data :
{
*(.data)
. = ALIGN(8);
*(.data*)
. = ALIGN(8);
*(.sdata)
}
. = %s;
. = ALIGN(8);
.bss :
{
*(.bss)
. = ALIGN(8);
*(.bss*)
. = ALIGN(8);
*(.sbss)
}
}
""" % (text_addr, rodata_addr, data_addr, bss_addr)
ld_script_contents += RELOCATION_LD_SCRIPT_TEMPLATE.format(
word_size=word_size,
text_start=text_start,
rodata_start=rodata_start,
data_start=data_start,
bss_start=bss_start,
stack_pointer_init=stack_pointer_init)

tmp_dir = util.tempdir()
rel_obj_path = tmp_dir.relpath("relocated.obj")
rel_ld_script_path = tmp_dir.relpath("relocated.lds")
with open(rel_ld_script_path, "w") as f:
f.write(ld_script_contents)
ld_proc = subprocess.Popen(["{}ld".format(toolchain_prefix), binary_path,
"-T", rel_ld_script_path,
"-o", rel_obj_path],
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT)
(out, _) = ld_proc.communicate()
if ld_proc.returncode != 0:
msg = "linking error using ld:\n"
msg += py_str(out)
raise RuntimeError(msg)

run_cmd([
"{}ld".format(toolchain_prefix),
binary_path,
"-T", rel_ld_script_path,
"-o", rel_obj_path])
with open(rel_obj_path, "rb") as f:
rel_bin = bytearray(f.read())
return rel_bin
Expand Down Expand Up @@ -217,16 +258,11 @@ def tvm_callback_read_binary_section(binary, section, toolchain_prefix):
tmp_section = tmp_dir.relpath("tmp_section.bin")
with open(tmp_bin, "wb") as out_file:
out_file.write(bytes(binary))
objcopy_proc = subprocess.Popen(["{}objcopy".format(toolchain_prefix), "--dump-section",
".{}={}".format(section, tmp_section),
tmp_bin],
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT)
(out, _) = objcopy_proc.communicate()
if objcopy_proc.returncode != 0:
msg = "error in using objcopy:\n"
msg += py_str(out)
raise RuntimeError(msg)
run_cmd([
"{}objcopy".format(toolchain_prefix),
"--dump-section",
".{}={}".format(section, tmp_section),
tmp_bin])
if os.path.isfile(tmp_section):
# Get section content if it exists.
with open(tmp_section, "rb") as f:
Expand Down Expand Up @@ -259,15 +295,12 @@ def tvm_callback_get_symbol_map(binary, toolchain_prefix):
tmp_obj = tmp_dir.relpath("tmp_obj.bin")
with open(tmp_obj, "wb") as out_file:
out_file.write(bytes(binary))
nm_proc = subprocess.Popen(["{}nm".format(toolchain_prefix), "-C", "--defined-only", tmp_obj],
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT)
(nm_output, _) = nm_proc.communicate()
if nm_proc.returncode != 0:
msg = "error in using nm:\n"
msg += py_str(nm_output)
raise RuntimeError(msg)
nm_output = nm_output.decode("utf8").splitlines()
nm_output = run_cmd([
"{}nm".format(toolchain_prefix),
"-C",
"--defined-only",
tmp_obj])
nm_output = nm_output.splitlines()
map_str = ""
for line in nm_output:
line = line.split()
Expand Down
52 changes: 51 additions & 1 deletion python/tvm/exec/rpc_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,22 @@
from __future__ import absolute_import

import argparse
import ast
import multiprocessing
import sys
import logging
import tvm
from tvm import micro
from .. import rpc

def main(args):
"""Main function"""
"""Main function

Parameters
----------
args : argparse.Namespace
parsed args from command-line invocation
"""
if args.tracker:
url, port = args.tracker.rsplit(":", 1)
port = int(port)
Expand All @@ -37,6 +45,9 @@ def main(args):
else:
tracker_addr = None

if args.utvm_dev_config or args.utvm_dev_id:
init_utvm(args)

server = rpc.Server(args.host,
args.port,
args.port_end,
Expand All @@ -48,6 +59,38 @@ def main(args):
server.proc.join()


def init_utvm(args):
"""MicroTVM-specific RPC initialization

Parameters
----------
args : argparse.Namespace
parsed args from command-line invocation
"""
if args.utvm_dev_config and args.utvm_dev_id:
raise RuntimeError('only one of --utvm-dev-config and --utvm-dev-id allowed')

if args.utvm_dev_config:
with open(args.utvm_dev_config, 'r') as dev_conf_file:
dev_config = json.load(dev_conf_file)
else:
dev_config_args = ast.literal_eval(args.utvm_dev_config_args)
default_config_func = micro.device.get_device_funcs(args.utvm_dev_id)['default_config']
dev_config = default_config_func(*dev_config_args)

if args.utvm_dev_config or args.utvm_dev_id:
# add MicroTVM overrides
@tvm.register_func('tvm.rpc.server.start', override=True)
def server_start():
# pylint: disable=unused-variable
session = micro.Session(dev_config)
session._enter()

@tvm.register_func('tvm.rpc.server.shutdown', override=True)
def server_shutdown():
session._exit()


if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument('--host', type=str, default="0.0.0.0",
Expand All @@ -71,6 +114,13 @@ def main(args):
and ROCM compilers.")
parser.add_argument('--custom-addr', type=str,
help="Custom IP Address to Report to RPC Tracker")
parser.add_argument('--utvm-dev-config', type=str,
help='JSON config file for the target device (if using MicroTVM)')
parser.add_argument('--utvm-dev-id', type=str,
help='Unique ID for the target device (if using MicroTVM)')
parser.add_argument('--utvm-dev-config-args', type=str,
help=('Python list of literals required to generate a default'
' MicroTVM config (if --utvm-dev-id is specified)'))

parser.set_defaults(fork=True)
args = parser.parse_args()
Expand Down
Loading