From 555e95bab693a0c680a4817c334630f248f57404 Mon Sep 17 00:00:00 2001 From: Gustavo Romero Date: Thu, 11 Feb 2021 22:52:19 +0000 Subject: [PATCH 1/5] =?UTF-8?q?[=C2=B5TVM]=20Print=20.elf=20statistics=20f?= =?UTF-8?q?or=20a=20model=20runtime=20built=20with=20Zephyr?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently there isn't any statistics about the used resources by a model runtime built with Zephyr, making it difficult to have any idea about, for instance, the amount of memory taken by the operations necessary to run the model. Since Zephyr's SDK already exposes the statistics about various memory regions on linking by passing '--print-memory-usage' to the linker, it's possible to use it to have an idea about the amount of memory used by the model and how much memory is left on the device. That commit adds a simple method to extract the memory region information out of the build output and then uses it to show memory usage statistics for various memory regions when Zephyr finishes building the image to be flashed to the target device. Signed-off-by: Gustavo Romero --- python/tvm/micro/contrib/zephyr.py | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/python/tvm/micro/contrib/zephyr.py b/python/tvm/micro/contrib/zephyr.py index ed1c9866c741..a7909a568492 100644 --- a/python/tvm/micro/contrib/zephyr.py +++ b/python/tvm/micro/contrib/zephyr.py @@ -55,7 +55,7 @@ def run(self, cmd, **kw): for k, v in self.default_overrides.items(): env[k] = v - return subprocess.check_output(cmd, env=env, **kw) + return subprocess.check_output(cmd, env=env, **kw, text=True) class ProjectNotFoundError(Exception): @@ -204,6 +204,22 @@ def library(self, output, sources, options=None): ) return tvm.micro.MicroLibrary(build_dir, [f"lib{project_name}.a"]) + def _print_make_statistics(self, output): + print("==================") + output = output.splitlines() + lines = iter(output) + for line in lines: + if line.startswith("Memory region"): + # print statistics header + print(line) + line = next(lines) + # while there is a region print it + while ":" in line: + print(line) + line = next(lines) + else: + break + def binary(self, output, objects, options=None, link_main=True, main_options=None): assert link_main, "Must pass link_main=True" assert self._project_dir is not None, "Must supply project_dir= to build binaries" @@ -224,7 +240,9 @@ def binary(self, output, objects, options=None, link_main=True, main_options=Non cmake_args.append(f'-DTVM_LIBS={";".join(copied_libs)}') self._subprocess_env.run(cmake_args, cwd=output) - self._subprocess_env.run(["make"], cwd=output) + make_output = self._subprocess_env.run(["make"], cwd=output) + + self._print_make_statistics(make_output) return tvm.micro.MicroBinary( output, From 1c8ad69a6831d7701a34b4e11895aeb5fe02da22 Mon Sep 17 00:00:00 2001 From: Gustavo Romero Date: Fri, 12 Feb 2021 17:08:18 +0000 Subject: [PATCH 2/5] v2: Fixes accordingly to Andrew review - Catch StopIteration in case of a weird output or no additional lines after the last memory region - Use of _LOG.info() instead of plain print() for better control over the output by the main script - Set log level in micro_tflite.py script as an example on how to get the new memory usage statistics and also because currently that's the main script used to test microTVM + Zephyr's SDK - Improve statistics header Signed-off-by: Gustavo Romero --- python/tvm/micro/contrib/zephyr.py | 17 ++++++++++------- tutorials/micro/micro_tflite.py | 6 ++++++ 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/python/tvm/micro/contrib/zephyr.py b/python/tvm/micro/contrib/zephyr.py index a7909a568492..8b466ab8780b 100644 --- a/python/tvm/micro/contrib/zephyr.py +++ b/python/tvm/micro/contrib/zephyr.py @@ -205,20 +205,23 @@ def library(self, output, sources, options=None): return tvm.micro.MicroLibrary(build_dir, [f"lib{project_name}.a"]) def _print_make_statistics(self, output): - print("==================") output = output.splitlines() lines = iter(output) for line in lines: if line.startswith("Memory region"): # print statistics header - print(line) + _LOG.info(line) + _LOG.info("--------------------- ---------- ------------ ---------") line = next(lines) # while there is a region print it - while ":" in line: - print(line) - line = next(lines) - else: - break + try: + while ":" in line: + _LOG.info(line) + line = next(lines) + else: + break + except: + pass def binary(self, output, objects, options=None, link_main=True, main_options=None): assert link_main, "Must pass link_main=True" diff --git a/tutorials/micro/micro_tflite.py b/tutorials/micro/micro_tflite.py index c979216d0c6b..e822485c947f 100644 --- a/tutorials/micro/micro_tflite.py +++ b/tutorials/micro/micro_tflite.py @@ -122,6 +122,8 @@ import os import numpy as np +import logging + import tvm import tvm.micro as micro from tvm.contrib.download import download_testdata @@ -227,6 +229,10 @@ # ) # # opts = tvm.micro.default_options(f"{project_dir}/crt") +# +# enable printing memory usage statistics of the runtime image +# generated by Zephyr compiler for the physical hardware +# logging.basicConfig(level="INFO") workspace = tvm.micro.Workspace() micro_binary = tvm.micro.build_static_runtime( From 387a9ebbc6687100af1df3c39d70464e3e5eaa93 Mon Sep 17 00:00:00 2001 From: Gustavo Romero Date: Fri, 12 Feb 2021 19:10:47 +0000 Subject: [PATCH 3/5] Fix build It seems build system is using Python < 3.7, so 'text' argument is not present as an alias for 'universal_newlines'. To satisfy it use old 'universal_newlines' argument which is available prior to Python 3.7. --- python/tvm/micro/contrib/zephyr.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/tvm/micro/contrib/zephyr.py b/python/tvm/micro/contrib/zephyr.py index 8b466ab8780b..c6862a1eed6b 100644 --- a/python/tvm/micro/contrib/zephyr.py +++ b/python/tvm/micro/contrib/zephyr.py @@ -55,7 +55,7 @@ def run(self, cmd, **kw): for k, v in self.default_overrides.items(): env[k] = v - return subprocess.check_output(cmd, env=env, **kw, text=True) + return subprocess.check_output(cmd, env=env, **kw, universal_newlines=True) class ProjectNotFoundError(Exception): From 39aece982c4b850ec8c075e6501576ab6c004bcd Mon Sep 17 00:00:00 2001 From: Gustavo Romero Date: Fri, 12 Feb 2021 19:20:58 +0000 Subject: [PATCH 4/5] Fix build Avoid exception anti-pattern when catching StopIteration --- python/tvm/micro/contrib/zephyr.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/tvm/micro/contrib/zephyr.py b/python/tvm/micro/contrib/zephyr.py index c6862a1eed6b..29bb5ecdbe6f 100644 --- a/python/tvm/micro/contrib/zephyr.py +++ b/python/tvm/micro/contrib/zephyr.py @@ -220,7 +220,7 @@ def _print_make_statistics(self, output): line = next(lines) else: break - except: + except StopIteration: pass def binary(self, output, objects, options=None, link_main=True, main_options=None): From 6ebd7fe0a1b12986b7d4f943804cb7bc9632d148 Mon Sep 17 00:00:00 2001 From: Gustavo Romero Date: Fri, 12 Feb 2021 20:31:25 +0000 Subject: [PATCH 5/5] Retrigger CI