glad you were able to solve the dladdr problems.
there are a couple of ways to run TVM operators in a bare-metal environment. a lot of the recent work has centered around creating a firmware binary that includes compiled TVM operators plus an RPC server which can be commanded to run them over e.g. a UART. this is slightly different from what you’re asking, but let me give you some pointers to that code since the generated operators are compatible (actually, exactly the same at present) between this approach and a fully standalone firmware binary:
first i’d point you to the recent
test_zephyr.py as a starting point. I know you want to run without Zephyr–the generated code is agnostic to the presence or absence of Zephyr. you will need to provide some replacement platform hooks, but i’ve tried this and it’s not intended to be difficult.
another resource i’ll point you to is my recently uploaded virtual machine branch (soon, PR), which makes a couple changes to the transport layer to make things work with real hardware using a UART connection. it also checks in a Vagrant base box + another Vagrantfile, to be used together to bring up a local Virtual Machine with Zephyr + cross compilers for ARM, RISC-V, etc. I’ve tested this same script (
test_zephyr.py) against both real hardware and QEMU on this branch.
now as to the question of creating a standalone binary: the main difference is that the TVM Graph Runtime needs to execute on the device.
apps/bundle_deploy demonstrates a way to run Graph Runtime in a separate application from TVM; however, it relies on some linux filesystem calls to load data. you could run standalone on bare-metal by porting
apps/bundle_deploy to your SoC. here’s roughly what I think you need to do to create a standalone µTVM firmware image that runs your model:
- as you mentioned, adjust the target string to
'c --system-lib -mcpu=cortex-mN' (you can follow the examples here). (you can also use
llvm in place of
c as bundle_deploy does, but this may be less readable).
- create a version of
apps/bundle_deploy/demo_static.c (note: only
demo_static is worth trying to port, no other
bundle_deploy targets are portable to bare metal) that loads
input_storage using whichever way your platform provides. i’d imagine for a simple bare-metal ARM example, you could use just a flash array in the same way
build_graph_c_json is handled. Presumably you could also read this from a sensor.
- create the binary firmware image: take the generated
.c (if using
c target) or
.o (if using
llvm target) file created by
apps/bundle_deploy/build_model.py, link it against your revised
demo_static.c and the required runtime libraries in
I should also mention that
test_zephyr.py is doing something slightly different from
apps/bundle_deploy, but I’m giving instructions for something similar to
bundle_deploy since that’s what you’re trying to do. specifically,
test_zephyr.py is building a firmware image containing a TVM RPC server, then sending it commands to execute operators over a UART. the firmware created with
test_zephyr.py cannot run a model without the PC connected.
here are some answers to your questions:
I know I have to change here to
relay.build('llvm -mtriple=arm-none-eabi') so that the right llvm target machine is used. Anything else I need to set here?
Could you maybe elaborate on what
see docs here
I also know that the Makefile requires some changes since it does not seem to account for 'arm-none-eabi’gcc prefix. Weirdly enough the Makefile for the crt libraries does accept this prefix. Am I missing something here?
bundle_deploy is not targeted to a cross-compiled nor bare-metal system. it’s meant to be compiled on the host it runs on, and expects linux for basic file operations. the actual model execution part in
demo_static is portable. this part is made up of CRT libraries and the operator code generated by
build_model.py. The Makefile for the CRT libraries is thus a little more flexible and can be retargeted with
PREFIX=. Please make sure you’re using
build/standalone_crt/Makefile when trying to use that build system–even though it’s the same file, you can’t use the Makefile placed at
src/runtime/crt/Makefile because it expects certain paths to be placed in the correct spot (see
Could you help me with defining the flags required for compiling in this case? (I see that some flags are defined in the Makefile, but I cant imagine that those are enough for arm embedded bare metal target)
I can’t give too many specifics as I don’t know what SoC you’re compiling for. I’d say SoC-specific bringup will be hit-or-miss here, because it’s fairly specialize to your project–this is why we’ve opted to link against RTOS such as Zephyr in the hopes of producing something more broadly useful. Hopefully you can work off of some example code there to start with.
That said, feel free to ask if you have compilation or runtime problems and I or others will try and help as we can. I’m also particularly interested in talking about any improvements to the overall compilation flow or the CRT libraries that would make µTVM easier to use in everyone’s projects, since there will always be constraints from other projects that developers don’t know about.
Do you know of any reason why any of the modules required for the bundle or libraries are not bare metal compatible? (I tried to set up a compilation pipeline but I was getting newlib errors and it felt it had something to do with exception handling but I am not sure. I did however always try to compile with backtracing on).
No, the generated modules and CRT is bare-metal compatible.
apps/bundle_deploy, however, defines 3 possible execution flows:
demo_static using CRT
demo_dynamic using CRT
demo_dynamic using C++ runtime (I.e. parts of
if you try to link the code from the latter two, you’ll run into exception problems and problems with
hope this helps–feel free to ask more questions and i’ll try and help as I can.