From efe4aa9bd85367810279e1dc4105cddd5b584904 Mon Sep 17 00:00:00 2001 From: Philipp van Kempen Date: Wed, 19 Jan 2022 22:48:07 +0100 Subject: [PATCH] Add runtime.ModuleGetFormat method enabling export of BYOC generated sources which require a .cpp/.cc file extension (#9243) * Allow export of C++ kernels using correct file extension * [WIP] Set module_key=c for CSourceCrtMetadataModuleNode to temporarily fix failing tests I realized that the module format `cc` is currently already used by the `CSourceCrtMetadataModuleNode` declared in `src/target/source/source_module.cc`. This needs to be discussed first to decide if either the module_key should be changed or the test cases expecting the systemlib kernel (e.g. `default_lib0.c`) to have a `.c` extension. * Update Makefiles used by tests/python/relay/aot/ to support C++ file extensions AOT: Add c++ support to aot_test.mk AOT: Add c++ support to corstone300.mk * Add missing definition of GetFormat to cmsisnn and ethosn codegens (WIP) * Resolve PR comments * lint python/tvm/runtime/module.py * fix EthosUModuleNode for CI * Fix: detect empty module.format * Add error message to assertion * Lint python/tvm/runtime/module.py --- include/tvm/runtime/module.h | 5 +++++ python/tvm/micro/model_library_format.py | 4 +++- python/tvm/runtime/module.py | 22 +++++++++++++++++-- .../backend/contrib/ethosu/source_module.cc | 2 ++ src/runtime/module.cc | 9 ++++++++ src/target/source/source_module.cc | 11 +++++++--- tests/python/relay/aot/corstone300.mk | 12 +++++----- tests/python/relay/aot/default.mk | 13 ++++++++--- 8 files changed, 64 insertions(+), 14 deletions(-) diff --git a/include/tvm/runtime/module.h b/include/tvm/runtime/module.h index 71be8d218d2d..7b5326a44921 100644 --- a/include/tvm/runtime/module.h +++ b/include/tvm/runtime/module.h @@ -156,6 +156,11 @@ class TVM_DLL ModuleNode : public Object { * \return Possible source code when available. */ virtual std::string GetSource(const std::string& format = ""); + /*! + * \brief Get the format of the module, when available. + * \return Possible format when available. + */ + virtual std::string GetFormat(); /*! * \brief Get packed function from current module by name. * diff --git a/python/tvm/micro/model_library_format.py b/python/tvm/micro/model_library_format.py index bf54956503c2..9f65a0bef109 100644 --- a/python/tvm/micro/model_library_format.py +++ b/python/tvm/micro/model_library_format.py @@ -86,10 +86,12 @@ def _populate_codegen_dir(mod, codegen_dir: str, module_name: str = None): for dso_mod in dso_modules: if dso_mod.type_key == "c": + assert dso_mod.format in ["c", "cc", "cpp"] + ext = dso_mod.format index = mod_indices["src"] mod_indices["src"] += 1 parent_dir = os.path.join(host_codegen_dir, "src") - file_name = os.path.join(parent_dir, f"{lib_name}{index}.c") + file_name = os.path.join(parent_dir, f"{lib_name}{index}.{ext}") elif dso_mod.type_key == "llvm": index = mod_indices["lib"] mod_indices["lib"] += 1 diff --git a/python/tvm/runtime/module.py b/python/tvm/runtime/module.py index 25a57bbb1c36..37bab4a9b714 100644 --- a/python/tvm/runtime/module.py +++ b/python/tvm/runtime/module.py @@ -185,6 +185,11 @@ def type_key(self): """Get type key of the module.""" return _ffi_api.ModuleGetTypeKey(self) + @property + def format(self): + """Get the format of the module.""" + return _ffi_api.ModuleGetFormat(self) + def get_source(self, fmt=""): """Get source code from module, if available. @@ -402,7 +407,12 @@ def export_library(self, file_name, fcompile=None, addons=None, workspace_dir=No for index, module in enumerate(modules): if fcompile is not None and hasattr(fcompile, "object_format"): if module.type_key == "c": - object_format = "c" + assert module.format in [ + "c", + "cc", + "cpp", + ], "The module.format needs to be either c, cc or cpp" + object_format = module.format has_c_module = True else: object_format = fcompile.object_format @@ -411,7 +421,15 @@ def export_library(self, file_name, fcompile=None, addons=None, workspace_dir=No object_format = "o" else: assert module.type_key == "c" - object_format = "c" + if len(module.format) > 0: + assert module.format in [ + "c", + "cc", + "cpp", + ], "The module.format needs to be either c, cc or cpp" + object_format = module.format + else: + object_format = "c" if "cc" in kwargs: if kwargs["cc"] == "nvcc": object_format = "cu" diff --git a/src/relay/backend/contrib/ethosu/source_module.cc b/src/relay/backend/contrib/ethosu/source_module.cc index f56544aee99a..66955f8b201f 100644 --- a/src/relay/backend/contrib/ethosu/source_module.cc +++ b/src/relay/backend/contrib/ethosu/source_module.cc @@ -89,6 +89,8 @@ class EthosUModuleNode : public ModuleNode { std::string GetSource(const std::string& format) final { return c_source; } + std::string GetFormat() { return "c"; } + Array GetArtifacts() { return compilation_artifacts_; } /*! diff --git a/src/runtime/module.cc b/src/runtime/module.cc index 393d269222c1..097d6a2f53e7 100644 --- a/src/runtime/module.cc +++ b/src/runtime/module.cc @@ -127,6 +127,11 @@ const PackedFunc* ModuleNode::GetFuncFromEnv(const std::string& name) { } } +std::string ModuleNode::GetFormat() { + LOG(FATAL) << "Module[" << type_key() << "] does not support GetFormat"; + return ""; +} + bool RuntimeEnabled(const std::string& target) { std::string f_name; if (target == "cpu") { @@ -179,6 +184,10 @@ TVM_REGISTER_GLOBAL("runtime.ModuleGetTypeKey").set_body_typed([](Module mod) { return std::string(mod->type_key()); }); +TVM_REGISTER_GLOBAL("runtime.ModuleGetFormat").set_body_typed([](Module mod) { + return mod->GetFormat(); +}); + TVM_REGISTER_GLOBAL("runtime.ModuleLoadFromFile").set_body_typed(Module::LoadFromFile); TVM_REGISTER_GLOBAL("runtime.ModuleSaveToFile") diff --git a/src/target/source/source_module.cc b/src/target/source/source_module.cc index 43fc619133b5..8faac3f1d966 100644 --- a/src/target/source/source_module.cc +++ b/src/target/source/source_module.cc @@ -63,6 +63,8 @@ class SourceModuleNode : public runtime::ModuleNode { std::string GetSource(const std::string& format) final { return code_; } + std::string GetFormat() { return fmt_; } + protected: std::string code_; std::string fmt_; @@ -102,10 +104,12 @@ class CSourceModuleNode : public runtime::ModuleNode { std::string GetSource(const std::string& format) final { return code_; } + std::string GetFormat() { return fmt_; } + void SaveToFile(const std::string& file_name, const std::string& format) final { std::string fmt = GetFileFormat(file_name, format); std::string meta_file = GetMetaFilePath(file_name); - if (fmt == "c" || fmt == "cu") { + if (fmt == "c" || fmt == "cc" || fmt == "cpp" || fmt == "cu") { ICHECK_NE(code_.length(), 0); SaveBinaryToFile(file_name, code_); } else { @@ -160,6 +164,7 @@ class CSourceCrtMetadataModuleNode : public runtime::ModuleNode { std::string GetSource(const std::string& format) final { return code_.str(); } + std::string GetFormat() { return fmt_; } PackedFunc GetFunction(const std::string& name, const ObjectPtr& sptr_to_self) final { return PackedFunc(nullptr); } @@ -167,7 +172,7 @@ class CSourceCrtMetadataModuleNode : public runtime::ModuleNode { void SaveToFile(const std::string& file_name, const std::string& format) final { std::string fmt = GetFileFormat(file_name, format); std::string meta_file = GetMetaFilePath(file_name); - if (fmt == "c") { + if (fmt == "c" || fmt == "cc" || fmt == "cpp") { auto code_str = code_.str(); ICHECK_NE(code_str.length(), 0); SaveBinaryToFile(file_name, code_str); @@ -509,7 +514,7 @@ runtime::Module CreateCSourceCrtMetadataModule(const Array& mod } } } - auto n = make_object(func_names, "cc", target, runtime, metadata); + auto n = make_object(func_names, "c", target, runtime, metadata); auto csrc_metadata_module = runtime::Module(n); for (const auto& mod : modules) { csrc_metadata_module.Import(mod); diff --git a/tests/python/relay/aot/corstone300.mk b/tests/python/relay/aot/corstone300.mk index 8ff11e29e5e2..5a734f646d28 100644 --- a/tests/python/relay/aot/corstone300.mk +++ b/tests/python/relay/aot/corstone300.mk @@ -69,8 +69,10 @@ QUIET ?= @ $(endif) CRT_SRCS = $(shell find $(CRT_ROOT)) -CODEGEN_SRCS = $(shell find $(abspath $(CODEGEN_ROOT)/host/src/*.c)) -CODEGEN_OBJS = $(subst .c,.o,$(CODEGEN_SRCS)) +C_CODEGEN_SRCS = $(shell find $(abspath $(CODEGEN_ROOT)/host/src/*.c)) +CC_CODEGEN_SRCS = $(shell find $(abspath $(CODEGEN_ROOT)/host/src/*.cc)) +C_CODEGEN_OBJS = $(subst .c,.o,$(C_CODEGEN_SRCS)) +CC_CODEGEN_OBJS = $(subst .cc,.o,$(CC_CODEGEN_SRCS)) CMSIS_STARTUP_SRCS = $(shell find ${CMSIS_PATH}/Device/ARM/${ARM_CPU}/Source/*.c) UART_SRCS = $(shell find ${PLATFORM_PATH}/*.c) @@ -96,9 +98,9 @@ $(build_dir)/tvm_ethosu_runtime.o: $(TVM_ROOT)/src/runtime/contrib/ethosu/bare_m $(QUIET)mkdir -p $(@D) $(QUIET)$(CC) -c $(PKG_CFLAGS) -o $@ $^ -$(build_dir)/libcodegen.a: $(CODEGEN_SRCS) - $(QUIET)cd $(abspath $(CODEGEN_ROOT)/host/src) && $(CC) -c $(PKG_CFLAGS) $(CODEGEN_SRCS) - $(QUIET)$(AR) -cr $(abspath $(build_dir)/libcodegen.a) $(CODEGEN_OBJS) +$(build_dir)/libcodegen.a: $(C_CODEGEN_SRCS) $(CC_CODEGEN_SRCS) + $(QUIET)cd $(abspath $(CODEGEN_ROOT)/host/src) && $(CC) -c $(PKG_CFLAGS) $(C_CODEGEN_SRCS) $(CC_CODEGEN_SRCS) + $(QUIET)$(AR) -cr $(abspath $(build_dir)/libcodegen.a) $(C_CODEGEN_OBJS) $(CC_CODEGEN_OBJS) $(QUIET)$(RANLIB) $(abspath $(build_dir)/libcodegen.a) ${build_dir}/libcmsis_startup.a: $(CMSIS_STARTUP_SRCS) diff --git a/tests/python/relay/aot/default.mk b/tests/python/relay/aot/default.mk index f5edcb3d6422..b7258a3c6df8 100644 --- a/tests/python/relay/aot/default.mk +++ b/tests/python/relay/aot/default.mk @@ -22,6 +22,7 @@ ENABLE_TVM_PLATFORM_ABORT_BACKTRACE = 0 DMLC_CORE=$(TVM_ROOT)/3rdparty/dmlc-core PKG_COMPILE_OPTS = -g CC = gcc +#CC = g++ AR = ar RANLIB = ranlib CC_OPTS = CC=$(CC) AR=$(AR) RANLIB=$(RANLIB) @@ -39,10 +40,12 @@ $(endif) aot_test_runner: $(build_dir)/aot_test_runner -source_libs= $(wildcard $(build_dir)/../codegen/host/src/*.c) -lib_objs =$(source_libs:.c=.o) +c_source_libs= $(wildcard $(build_dir)/../codegen/host/src/*.c) +cc_source_libs= $(wildcard $(build_dir)/../codegen/host/src/*.cc) +c_lib_objs =$(c_source_libs:.c=.o) +cc_lib_objs =$(cc_source_libs:.cc=.o) -$(build_dir)/aot_test_runner: $(build_dir)/test.c $(source_libs) $(build_dir)/stack_allocator.o $(build_dir)/crt_backend_api.o +$(build_dir)/aot_test_runner: $(build_dir)/test.c $(c_source_libs) $(cc_source_libs) $(build_dir)/stack_allocator.o $(build_dir)/crt_backend_api.o $(QUIET)mkdir -p $(@D) $(QUIET)$(CC) $(CFLAGS) $(PKG_CFLAGS) -o $@ $^ $(PKG_LDFLAGS) $(BACKTRACE_LDFLAGS) $(BACKTRACE_CFLAGS) -lm @@ -50,6 +53,10 @@ $(build_dir)/%.o: $(build_dir)/../codegen/host/src/%.c $(QUIET)mkdir -p $(@D) $(QUIET)$(CC) $(CFLAGS) -c $(PKG_CFLAGS) -o $@ $^ $(BACKTRACE_CFLAGS) +$(build_dir)/%.o: $(build_dir)/../codegen/host/src/%.cc + $(QUIET)mkdir -p $(@D) + $(QUIET)$(CC) $(CFLAGS) -c $(PKG_CFLAGS) -o $@ $^ $(BACKTRACE_CFLAGS) + $(build_dir)/stack_allocator.o: $(STANDALONE_CRT_DIR)/src/runtime/crt/memory/stack_allocator.c $(QUIET)mkdir -p $(@D) $(QUIET)$(CC) $(CFLAGS) -c $(PKG_CFLAGS) -o $@ $^ $(BACKTRACE_CFLAGS)