From acf414e0c267866b32a0930bce70c259ce7ea288 Mon Sep 17 00:00:00 2001 From: Manupa Karunaratne Date: Fri, 27 Nov 2020 18:22:36 +0000 Subject: [PATCH 01/18] Created CSourceMetaData module for model metadata * Currently, there is a MetaData module to capture constants conditionaly if the runtime modules implement const init PackedFuncs. However, this one relies on a load process in which the metadata is created on volatile memory that may be not usable in uTVM environments. * There is a need for model level metadata that is valid across all runtime modules such as the func registry when creating a system-lib. * This commit implements a CSoureMetaData module to hold func registry that collects function names from the runtime module and generates a c source file to be linked with final artifact. * Modified and added export_library for utvm Change-Id: Ie2e8e2aea1a66520f03fe8af7cc5bdf27339ea10 --- python/tvm/driver/build_module.py | 8 + python/tvm/micro/build.py | 18 +- python/tvm/runtime/module.py | 21 ++- src/relay/backend/build_module.cc | 11 +- .../backend/contrib/codegen_c/codegen.cc | 21 ++- src/relay/backend/contrib/dnnl/codegen.cc | 3 +- src/relay/backend/vm/compiler.cc | 9 +- src/target/func_registry_generator.cc | 2 +- src/target/func_registry_generator.h | 7 +- src/target/llvm/codegen_cpu.cc | 47 ------ src/target/llvm/llvm_module.cc | 10 +- src/target/source/codegen_c_host.cc | 31 +--- src/target/source/codegen_c_host.h | 8 +- src/target/source/codegen_source_base.h | 18 +- src/target/source/source_module.cc | 159 +++++++++++++++--- tests/micro/qemu/test_zephyr.py | 30 +++- tests/python/contrib/test_onnx_model.py | 4 +- tests/python/relay/test_op_fast_math.py | 2 +- tests/python/relay/test_op_level2.py | 2 +- .../python/relay/test_pass_partition_graph.py | 14 +- tests/python/unittest/test_link_params.py | 2 +- .../unittest/test_target_codegen_llvm.py | 1 + 22 files changed, 268 insertions(+), 160 deletions(-) diff --git a/python/tvm/driver/build_module.py b/python/tvm/driver/build_module.py index 058bd62d6226..b1b4a0d28114 100644 --- a/python/tvm/driver/build_module.py +++ b/python/tvm/driver/build_module.py @@ -424,4 +424,12 @@ def build(inputs, args=None, target=None, target_host=None, name="default_functi for mdev in device_modules: if mdev: rt_mod_host.import_module(mdev) + + if not isinstance(target_host, Target): + target_host = Target(target_host) + if "system-lib" in target_host.attrs and target_host.attrs["system-lib"].value == 1: + create_csource_metadata_module = tvm._ffi.get_global_func( + "runtime.CreateCSourceMetadataModule" + ) + return create_csource_metadata_module([rt_mod_host], target_host) return rt_mod_host diff --git a/python/tvm/micro/build.py b/python/tvm/micro/build.py index 4aec9ea5ecbb..08d8c2d3cb85 100644 --- a/python/tvm/micro/build.py +++ b/python/tvm/micro/build.py @@ -74,8 +74,8 @@ def path(self): _CRT_DEFAULT_OPTIONS = { "cflags": ["-std=c11"] + _COMMON_CFLAGS, - "ccflags": ["-std=c++11"] + _COMMON_CFLAGS, - "ldflags": ["-std=c++11"], + "ccflags": ["-std=gnu++11"] + _COMMON_CFLAGS, + "ldflags": ["-std=gnu++11"], "include_dirs": [ f"{TVM_ROOT_DIR}/include", f"{TVM_ROOT_DIR}/3rdparty/dlpack/include", @@ -95,6 +95,7 @@ def path(self): # void* arg0 = (((TVMValue*)args)[0].v_handle); # int32_t arg0_code = ((int32_t*)arg_type_ids)[(0)]; _CRT_GENERATED_LIB_OPTIONS["cflags"].append("-Wno-unused-variable") +_CRT_GENERATED_LIB_OPTIONS["ccflags"].append("-Wno-unused-variable") # Many TVM-intrinsic operators (i.e. expf, in particular) @@ -159,9 +160,6 @@ def build_static_runtime( mod_build_dir = workspace.relpath(os.path.join("build", "module")) os.makedirs(mod_build_dir) mod_src_dir = workspace.relpath(os.path.join("src", "module")) - os.makedirs(mod_src_dir) - mod_src_path = os.path.join(mod_src_dir, "module.c") - module.save(mod_src_path, "cc") libs = [] for mod_or_src_dir in (extra_libs or []) + RUNTIME_LIB_SRC_DIRS: @@ -181,7 +179,15 @@ def build_static_runtime( libs.append(compiler.library(lib_build_dir, lib_srcs, lib_opts)) - libs.append(compiler.library(mod_build_dir, [mod_src_path], generated_lib_opts)) + mod_src_dir = workspace.relpath(os.path.join("src", "module")) + os.makedirs(mod_src_dir) + libs.append( + module.export_library( + mod_build_dir, + workspace_dir=mod_src_dir, + fcompile=lambda bdir, srcs, **kwargs: compiler.library(bdir, srcs, generated_lib_opts), + ) + ) runtime_build_dir = workspace.relpath(f"build/runtime") os.makedirs(runtime_build_dir) diff --git a/python/tvm/runtime/module.py b/python/tvm/runtime/module.py index cef617399bff..2adb591402a7 100644 --- a/python/tvm/runtime/module.py +++ b/python/tvm/runtime/module.py @@ -15,7 +15,7 @@ # specific language governing permissions and limitations # under the License. -# pylint: disable=invalid-name, unused-import, import-outside-toplevel +# pylint: disable=invalid-name, unused-import, import-outside-toplevel, inconsistent-return-statements """Runtime Module namespace.""" import os import ctypes @@ -252,7 +252,7 @@ def _collect_dso_modules(self): def _dso_exportable(self): return self.type_key == "llvm" or self.type_key == "c" - def export_library(self, file_name, fcompile=None, addons=None, **kwargs): + def export_library(self, file_name, fcompile=None, addons=None, workspace_dir=None, **kwargs): """Export the module and its imported device code one library. This function only works on host llvm modules. @@ -268,6 +268,11 @@ def export_library(self, file_name, fcompile=None, addons=None, **kwargs): If fcompile has attribute object_format, will compile host library to that format. Otherwise, will use default format "o". + workspace_dir : str, optional + The name of the workspace dir to create intermediary + artifacts for the process exporting of the library. + If this is not provided a temporary dir will be created. + kwargs : dict, optional Additional arguments passed to fcompile """ @@ -292,7 +297,9 @@ def export_library(self, file_name, fcompile=None, addons=None, **kwargs): return modules = self._collect_dso_modules() - temp = _utils.tempdir() + if workspace_dir is None: + temp = _utils.tempdir() + workspace_dir = temp.temp_dir files = addons if addons else [] is_system_lib = False has_c_module = False @@ -307,7 +314,7 @@ def export_library(self, file_name, fcompile=None, addons=None, **kwargs): assert module.type_key == "c" object_format = "cc" has_c_module = True - path_obj = temp.relpath("lib" + str(index) + "." + object_format) + path_obj = os.path.join(workspace_dir, f"lib{index}.{object_format}") module.save(path_obj) files.append(path_obj) is_system_lib = ( @@ -330,12 +337,12 @@ def export_library(self, file_name, fcompile=None, addons=None, **kwargs): if self.imported_modules: if enabled("llvm") and llvm_target_triple: - path_obj = temp.relpath("devc." + object_format) + path_obj = os.path.join(workspace_dir, f"devc.{object_format}") m = _ffi_api.ModulePackImportsToLLVM(self, is_system_lib, llvm_target_triple) m.save(path_obj) files.append(path_obj) else: - path_cc = temp.relpath("devc.cc") + path_cc = os.path.join(workspace_dir, "devc.cc") with open(path_cc, "w") as f: f.write(_ffi_api.ModulePackImportsToC(self, is_system_lib)) files.append(path_cc) @@ -348,7 +355,7 @@ def export_library(self, file_name, fcompile=None, addons=None, **kwargs): opts = options + ["-I" + path for path in find_include_path()] kwargs.update({"options": opts}) - fcompile(file_name, files, **kwargs) + return fcompile(file_name, files, **kwargs) def system_lib(): diff --git a/src/relay/backend/build_module.cc b/src/relay/backend/build_module.cc index a0828d1cac6c..0737e8635c4b 100644 --- a/src/relay/backend/build_module.cc +++ b/src/relay/backend/build_module.cc @@ -510,18 +510,15 @@ class RelayBuildModule : public runtime::ModuleNode { // If we cannot decide the target is LLVM, we create an empty CSourceModule. // The code content is initialized with ";" to prevent complaining // from CSourceModuleNode::SaveToFile. - ret_.mod = tvm::codegen::CSourceModuleCreate(";", ""); + ret_.mod = tvm::codegen::CSourceModuleCreate(";", "", Array{}); } } else { ret_.mod = tvm::build(lowered_funcs, target_host_); } - Array ext_mods = graph_codegen_->GetExternalModules(); - // TODO(zhiics) We should be able to completely switch to MetadataModule no - // matter whether there are external modules or not. - if (!ext_mods.empty()) { - ret_.mod = tvm::codegen::CreateMetadataModule(ret_.params, ret_.mod, ext_mods); - } + auto all_mods = graph_codegen_->GetExternalModules(); + all_mods.push_back(ret_.mod); + ret_.mod = tvm::codegen::CreateMetadataModule(ret_.params, all_mods, GetTargetHost()); } private: diff --git a/src/relay/backend/contrib/codegen_c/codegen.cc b/src/relay/backend/contrib/codegen_c/codegen.cc index 935ac16efb23..6e038bb46a80 100644 --- a/src/relay/backend/contrib/codegen_c/codegen.cc +++ b/src/relay/backend/contrib/codegen_c/codegen.cc @@ -215,7 +215,7 @@ class CodegenC : public MemoizedExprTranslator>, public Code class CSourceCodegen : public CSourceModuleCodegenBase { public: - std::pair> GenCFunc(const Function& func) { + std::tuple, String, String> GenCFunc(const Function& func) { ICHECK(func.defined()) << "Input error: expect a Relay function."; // Record the external symbol for runtime lookup. @@ -223,12 +223,16 @@ class CSourceCodegen : public CSourceModuleCodegenBase { CodegenC builder(sid); auto out = builder.VisitExpr(func->body); - code_stream_ << builder.JIT(out); - - return {sid, builder.const_vars_}; + return std::make_tuple(sid, builder.const_vars_, builder.ext_func_id_, builder.JIT(out)); } runtime::Module CreateCSourceModule(const ObjectRef& ref) override { + ICHECK(ref->IsInstance()); + auto res = GenCFunc(Downcast(ref)); + String sym = std::get<0>(res); + Array variables = std::get<1>(res); + String func_name = std::get<2>(res); + // Create headers code_stream_ << "#include \n"; code_stream_ << "#include \n"; @@ -259,18 +263,13 @@ class CSourceCodegen : public CSourceModuleCodegenBase { )op_macro"; code_stream_ << operator_macro << "\n\n"; - - ICHECK(ref->IsInstance()); - auto res = GenCFunc(Downcast(ref)); + code_stream_ << std::get<3>(res); std::string code = code_stream_.str(); - String sym = std::get<0>(res); - Array variables = std::get<1>(res); - // Create a CSource module const auto* pf = runtime::Registry::Get("runtime.CSourceModuleCreate"); ICHECK(pf != nullptr) << "Cannot find csource module to create the external runtime module"; - return (*pf)(code, "c", sym, variables); + return (*pf)(code, "c", Array{func_name}, sym, variables); } private: diff --git a/src/relay/backend/contrib/dnnl/codegen.cc b/src/relay/backend/contrib/dnnl/codegen.cc index bfc5c77d116b..7160758f2fb5 100644 --- a/src/relay/backend/contrib/dnnl/codegen.cc +++ b/src/relay/backend/contrib/dnnl/codegen.cc @@ -413,7 +413,8 @@ class DNNLModuleCodegen : public CSourceModuleCodegenBase { // Create a CSource module const auto* pf = runtime::Registry::Get("runtime.CSourceModuleCreate"); ICHECK(pf != nullptr) << "Cannot find csource module to create the external runtime module"; - return (*pf)(code, "c", sym, variables); + // TODO(@manupa-arm): pass the function names to enable system-lib creation + return (*pf)(code, "c", Array{}, sym, variables); } private: diff --git a/src/relay/backend/vm/compiler.cc b/src/relay/backend/vm/compiler.cc index bed2510cdf3c..21693b6ab17f 100644 --- a/src/relay/backend/vm/compiler.cc +++ b/src/relay/backend/vm/compiler.cc @@ -1136,7 +1136,7 @@ void VMCompiler::Codegen() { } auto compile_engine = CompileEngine::Global(); - auto ext_mods = compile_engine->LowerExternalFunctions(); + auto all_mods = compile_engine->LowerExternalFunctions(); if (funcs.size() > 0) { Map build_funcs; for (const auto& i : funcs) { @@ -1146,11 +1146,10 @@ void VMCompiler::Codegen() { } else { // There is no function handled by TVM. We create a virtual main module // to make sure a DSO module will be also available. - exec_->lib = codegen::CSourceModuleCreate(";", ""); - } - if (!ext_mods.empty()) { - exec_->lib = codegen::CreateMetadataModule(params_, exec_->lib, ext_mods); + exec_->lib = codegen::CSourceModuleCreate(";", "", Array{}); } + all_mods.push_back(exec_->lib); + exec_->lib = codegen::CreateMetadataModule(params_, all_mods, target_host_); } ExprDeviceMap VMCompiler::AnalyzeContext() const { diff --git a/src/target/func_registry_generator.cc b/src/target/func_registry_generator.cc index 402d0f8538e2..7c948d50cbb9 100644 --- a/src/target/func_registry_generator.cc +++ b/src/target/func_registry_generator.cc @@ -29,7 +29,7 @@ namespace tvm { namespace target { -std::string GenerateFuncRegistryNames(const std::vector& function_names) { +std::string GenerateFuncRegistryNames(const Array& function_names) { std::stringstream ss; ss << (unsigned char)(function_names.size()); for (auto f : function_names) { diff --git a/src/target/func_registry_generator.h b/src/target/func_registry_generator.h index 362fca872eb4..fb5964859352 100644 --- a/src/target/func_registry_generator.h +++ b/src/target/func_registry_generator.h @@ -24,13 +24,18 @@ #ifndef TVM_TARGET_FUNC_REGISTRY_GENERATOR_H_ #define TVM_TARGET_FUNC_REGISTRY_GENERATOR_H_ +#include + #include #include +using tvm::runtime::Array; +using tvm::runtime::String; + namespace tvm { namespace target { -std::string GenerateFuncRegistryNames(const std::vector& function_names); +std::string GenerateFuncRegistryNames(const Array& function_names); } // namespace target } // namespace tvm diff --git a/src/target/llvm/codegen_cpu.cc b/src/target/llvm/codegen_cpu.cc index fea5f8036678..0a33d34d8218 100644 --- a/src/target/llvm/codegen_cpu.cc +++ b/src/target/llvm/codegen_cpu.cc @@ -123,12 +123,6 @@ void CodeGenCPU::AddFunction(const PrimFunc& f) { << "CodeGenLLVM: Expect PrimFunc to have the global_symbol attribute"; export_system_symbols_.emplace_back( std::make_pair(global_symbol.value().operator std::string(), function_)); - } else if (target_c_runtime_) { - auto global_symbol = f->GetAttr(tvm::attr::kGlobalSymbol); - ICHECK(global_symbol.defined()) - << "CodeGenLLVM: Expect PrimFunc to have the global_symbol attribute"; - registry_functions_.emplace_back( - std::make_pair(global_symbol.value().operator std::string(), function_)); } AddDebugInformation(function_); } @@ -792,46 +786,6 @@ llvm::Value* CodeGenCPU::RuntimeTVMParallelBarrier() { } void CodeGenCPU::AddStartupFunction() { - if (registry_functions_.size() != 0) { - ICHECK(is_system_lib_) << "Loading of --system-lib modules is yet to be defined for C runtime"; - std::vector symbols; - std::vector funcs; - for (auto sym : registry_functions_) { - symbols.emplace_back(sym.first); - funcs.emplace_back(llvm::ConstantExpr::getBitCast( - sym.second, ftype_tvm_backend_packed_c_func_->getPointerTo())); - } - llvm::DataLayout layout(module_.get()); - llvm::ArrayType* t_tvm_crt_func_ptrs = - llvm::ArrayType::get(ftype_tvm_backend_packed_c_func_->getPointerTo(), funcs.size()); - llvm::GlobalVariable* func_registry_ptrs = new llvm::GlobalVariable( - *module_, t_tvm_crt_func_ptrs, true, llvm::GlobalValue::InternalLinkage, - llvm::ConstantArray::get(t_tvm_crt_func_ptrs, funcs), "_tvm_func_registry_ptrs"); - uint64_t align = layout.getTypeAllocSize(ftype_tvm_backend_packed_c_func_->getPointerTo()); -#if TVM_LLVM_VERSION >= 100 - func_registry_ptrs->setAlignment(llvm::Align(align)); -#else - func_registry_ptrs->setAlignment(align); -#endif - llvm::GlobalVariable* func_registry = new llvm::GlobalVariable( - *module_, t_tvm_crt_func_registry_, true, llvm::GlobalVariable::InternalLinkage, - llvm::ConstantStruct::get( - t_tvm_crt_func_registry_, - {GetConstString(::tvm::target::GenerateFuncRegistryNames(symbols)), - func_registry_ptrs}), - "_tvm_crt_func_registry"); - llvm::GlobalVariable* module = new llvm::GlobalVariable( - *module_, t_tvm_crt_module_, true, llvm::GlobalValue::InternalLinkage, - llvm::ConstantStruct::get(t_tvm_crt_module_, {func_registry}), "_tvm_crt_module"); - - // Now build TVMSystemLibEntryPoint. - llvm::FunctionType* ftype = llvm::FunctionType::get(t_void_p_, {}, false); - function_ = llvm::Function::Create(ftype, llvm::Function::ExternalLinkage, - "TVMSystemLibEntryPoint", module_.get()); - llvm::BasicBlock* entry_point_entry = llvm::BasicBlock::Create(*ctx_, "entry", function_); - builder_->SetInsertPoint(entry_point_entry); - builder_->CreateRet(builder_->CreateBitCast(module, t_void_p_)); - } else { llvm::FunctionType* ftype = llvm::FunctionType::get(t_void_, {}, false); function_ = llvm::Function::Create(ftype, llvm::Function::InternalLinkage, "__tvm_module_startup", module_.get()); @@ -844,7 +798,6 @@ void CodeGenCPU::AddStartupFunction() { } llvm::appendToGlobalCtors(*module_, function_, 65535); builder_->CreateRet(nullptr); - } } llvm::Value* CodeGenCPU::CreateIntrinsic(const CallNode* op) { diff --git a/src/target/llvm/llvm_module.cc b/src/target/llvm/llvm_module.cc index a0ab49d7dc85..19776c1488c4 100644 --- a/src/target/llvm/llvm_module.cc +++ b/src/target/llvm/llvm_module.cc @@ -60,6 +60,9 @@ class LLVMModuleNode final : public runtime::ModuleNode { if (name == "__tvm_is_system_module") { bool flag = (mptr_->getFunction("__tvm_module_startup") != nullptr); return PackedFunc([flag](TVMArgs args, TVMRetValue* rv) { *rv = flag; }); + } else if (name == "get_func_names") { + return PackedFunc( + [sptr_to_self, this](TVMArgs args, TVMRetValue* rv) { *rv = this->function_names_; }); } else if (name == "_get_target_triple") { std::string target_triple = tm_->getTargetTriple().str(); // getTargetTriple() doesn't include other flags besides the triple. Add back flags which are @@ -218,9 +221,10 @@ class LLVMModuleNode final : public runtime::ModuleNode { ICHECK(kv.second->IsInstance()) << "Can only lower IR Module with PrimFuncs, but got " << kv.second->GetTypeKey(); auto f = Downcast(kv.second); + auto global_symbol = f->GetAttr(tvm::attr::kGlobalSymbol); + ICHECK(global_symbol.defined()); + function_names_.push_back(global_symbol.value()); if (f->HasNonzeroAttr(tir::attr::kIsEntryFunc)) { - auto global_symbol = f->GetAttr(tvm::attr::kGlobalSymbol); - ICHECK(global_symbol.defined()); entry_func = global_symbol.value(); } funcs.push_back(f); @@ -377,6 +381,8 @@ class LLVMModuleNode final : public runtime::ModuleNode { std::unique_ptr module_; // the context. std::shared_ptr ctx_; + /* \brief names of the functions declared in this module */ + Array function_names_; }; TVM_REGISTER_GLOBAL("target.build.llvm") diff --git a/src/target/source/codegen_c_host.cc b/src/target/source/codegen_c_host.cc index 0a19fc1399b7..bee5441649c5 100644 --- a/src/target/source/codegen_c_host.cc +++ b/src/target/source/codegen_c_host.cc @@ -55,7 +55,7 @@ void CodeGenCHost::AddFunction(const PrimFunc& f) { auto global_symbol = f->GetAttr(tvm::attr::kGlobalSymbol); ICHECK(global_symbol.defined()) << "CodeGenCHost: Expect PrimFunc to have the global_symbol attribute"; - function_names_.emplace_back(global_symbol.value()); + function_names_.push_back(global_symbol.value()); CodeGenC::AddFunction(f); } @@ -73,7 +73,7 @@ void CodeGenCHost::LinkParameters(Map params) { << " out_ret_tcode[0] = " << kTVMNullptr << ";\n" << " return 0;\n"; - function_names_.emplace_back(tvm::runtime::symbol::tvm_lookup_linked_param); + function_names_.push_back(tvm::runtime::symbol::tvm_lookup_linked_param); for (auto kv : params) { decl_stream << "\n" << "#ifdef __cplusplus\n" @@ -322,29 +322,6 @@ inline void CodeGenCHost::PrintTernaryCondExpr(const T* op, const char* compare, << "? (" << a_id << ") : (" << b_id << "))"; } -void CodeGenCHost::GenerateFuncRegistry() { - decl_stream << "#include \n"; - stream << "static TVMBackendPackedCFunc _tvm_func_array[] = {\n"; - for (auto f : function_names_) { - stream << " (TVMBackendPackedCFunc)" << f << ",\n"; - } - stream << "};\n"; - auto registry = target::GenerateFuncRegistryNames(function_names_); - stream << "static const TVMFuncRegistry _tvm_func_registry = {\n" - << " \"" << ::tvm::support::StrEscape(registry.data(), registry.size(), true) << "\"," - << " _tvm_func_array,\n" - << "};\n"; -} - -void CodeGenCHost::GenerateCrtSystemLib() { - stream << "static const TVMModule _tvm_system_lib = {\n" - << " &_tvm_func_registry,\n" - << "};\n" - << "const TVMModule* TVMSystemLibEntryPoint(void) {\n" - << " return &_tvm_system_lib;\n" - << "}\n"; -} - runtime::Module BuildCHost(IRModule mod, Target target) { using tvm::runtime::Registry; bool output_ssa = false; @@ -380,12 +357,10 @@ runtime::Module BuildCHost(IRModule mod, Target target) { if (target->GetAttr("system-lib").value_or(Bool(false))) { ICHECK_EQ(target->GetAttr("runtime").value_or(""), "c") << "c target only supports generating C runtime SystemLibs"; - cg.GenerateFuncRegistry(); - cg.GenerateCrtSystemLib(); } std::string code = cg.Finish(); - return CSourceModuleCreate(code, "c"); + return CSourceModuleCreate(code, "c", cg.GetFunctionNames()); } TVM_REGISTER_GLOBAL("target.build.c").set_body_typed(BuildCHost); diff --git a/src/target/source/codegen_c_host.h b/src/target/source/codegen_c_host.h index b54b6fbfcfeb..97fe7ab39efa 100644 --- a/src/target/source/codegen_c_host.h +++ b/src/target/source/codegen_c_host.h @@ -59,18 +59,14 @@ class CodeGenCHost final : public CodeGenC { void VisitStmt_(const AssertStmtNode* op) final; // NOLINT(*) - /*! \brief Generate C runtime FuncRegistry global constant. */ - void GenerateFuncRegistry(); - - /*! \brief Generate C runtime SystemLib entry point. */ - void GenerateCrtSystemLib(); + Array GetFunctionNames() { return function_names_; } private: std::string module_name_; /* \brief tracks declared global variables which live despite GetUniqueName */ std::set declared_globals_; /* \brief names of the functions declared in this module */ - std::vector function_names_; + Array function_names_; /*! \brief whether to emit asserts in the resulting C code */ bool emit_asserts_; diff --git a/src/target/source/codegen_source_base.h b/src/target/source/codegen_source_base.h index 7e5e40324c47..3d458acdcf2c 100644 --- a/src/target/source/codegen_source_base.h +++ b/src/target/source/codegen_source_base.h @@ -136,25 +136,26 @@ runtime::Module SourceModuleCreate(std::string code, std::string fmt); * \brief Create a C source module for viewing and compiling GCC code. * \param code The code to be viewed. * \param fmt The code format. + * \param func_names The name of functions inside the runtime module. * \param symbol The symbol that the c source module represents. * \param const_vars. The constant variables that the c source module needs. * \return The created module. */ runtime::Module CSourceModuleCreate(const String& code, const String& fmt, - const String& symbol = "", + const Array& func_names, const String& symbol = "", const Array& const_vars = {}); /*! * \brief Wrap the submodules in a metadata module. * \param params The variable to constant mapping that is collected by the host * module. - * \param dso_module The host module to be wrapped. - * \param modules The modules to be wrapped. + * \param modules All the modules that needs to be imported inside the metadata module(s). + * \param target The target that all the modules are compiled for * \return The wrapped module. */ runtime::Module CreateMetadataModule( const std::unordered_map& params, - const runtime::Module& dso_module, const Array& modules); + const Array& ext_modules, Target target); /*! * \brief Create a source module for viewing and limited saving for device. @@ -167,6 +168,15 @@ runtime::Module CreateMetadataModule( runtime::Module DeviceSourceModuleCreate( std::string data, std::string fmt, std::unordered_map fmap, std::string type_key, std::function fget_source = nullptr); + +/*! + * \brief Wrap the submodules that are to be wrapped in a c-source metadata module. + * \param modules The modules to be wrapped. + * \param target the target the modules are compiled for. + * \return The wrapped module. + */ +runtime::Module CreateCSourceMetadataModule(const Array& modules, Target target); + } // namespace codegen } // namespace tvm #endif // TVM_TARGET_SOURCE_CODEGEN_SOURCE_BASE_H_ diff --git a/src/target/source/source_module.cc b/src/target/source/source_module.cc index 3be658aa0125..82e78e187ff8 100644 --- a/src/target/source/source_module.cc +++ b/src/target/source/source_module.cc @@ -27,6 +27,8 @@ #include "../../runtime/file_utils.h" #include "../../runtime/meta_data.h" +#include "../../support/str_escape.h" +#include "../func_registry_generator.h" #include "codegen_source_base.h" namespace tvm { @@ -46,20 +48,21 @@ using runtime::SaveBinaryToFile; * codegens, such as graph runtime codegen and the vm compiler. * * \param params The metadata for initialization of all modules. - * \param dso_module The DSO module that contains TVM primitives. - * \param modules The submodules that will be wrapped, e.g. CSource modules that - * contain vendor library calls or customized runtime modules. - * + * \param modules All the modules that needs to be imported inside the metadata module(s). + * \param target The target that all the modules are compiled for * \return The created metadata module that manages initialization of metadata. */ runtime::Module CreateMetadataModule( const std::unordered_map& params, - const runtime::Module& dso_module, const Array& modules) { + const Array& modules, Target target) { + Array csource_metadata_modules; + Array binary_metadata_modules; + // Wrap all submodules in the initialization wrapper. std::unordered_map> sym_metadata; - for (runtime::Module it : modules) { - auto pf_sym = it.GetFunction("get_symbol"); - auto pf_var = it.GetFunction("get_const_vars"); + for (tvm::runtime::Module mod : modules) { + auto pf_sym = mod.GetFunction("get_symbol"); + auto pf_var = mod.GetFunction("get_const_vars"); if (pf_sym != nullptr && pf_var != nullptr) { String symbol = pf_sym(); Array variables = pf_var(); @@ -69,17 +72,31 @@ runtime::Module CreateMetadataModule( } ICHECK_EQ(sym_metadata.count(symbol), 0U) << "Found duplicated symbol: " << symbol; sym_metadata[symbol] = arrays; + // We only need loading of serialized constant data + // if there are constants present and required by the + // runtime module to be initialized by the binary + // metadata module. If not rest of the modules are + // wrapped in c-source metadata module. + if (!variables.empty()) { + binary_metadata_modules.push_back(mod); + } else { + csource_metadata_modules.push_back(mod); + } + } else { + csource_metadata_modules.push_back(mod); } } - + auto c_meta_mod = CreateCSourceMetadataModule(csource_metadata_modules, target); // Wrap the modules. - runtime::Module init_m = runtime::MetadataModuleCreate(params, sym_metadata); - init_m.Import(dso_module); - for (const auto& it : modules) { - init_m.Import(it); + if (!binary_metadata_modules.empty()) { + runtime::Module binary_meta_mod = runtime::MetadataModuleCreate(params, sym_metadata); + binary_meta_mod.Import(c_meta_mod); + for (const auto& it : binary_metadata_modules) { + binary_meta_mod.Import(it); + } + return binary_meta_mod; } - - return init_m; + return c_meta_mod; } // Simulator function @@ -109,9 +126,10 @@ runtime::Module SourceModuleCreate(std::string code, std::string fmt) { // Simulator function class CSourceModuleNode : public runtime::ModuleNode { public: - CSourceModuleNode(const std::string& code, const std::string& fmt, const std::string& symbol, + CSourceModuleNode(const std::string& code, const std::string& fmt, + const Array& func_names, const std::string& symbol, const Array& const_vars) - : code_(code), fmt_(fmt), symbol_(symbol), const_vars_(const_vars) {} + : code_(code), fmt_(fmt), symbol_(symbol), const_vars_(const_vars), func_names_(func_names) {} const char* type_key() const { return "c"; } PackedFunc GetFunction(const std::string& name, const ObjectPtr& sptr_to_self) final { @@ -121,6 +139,9 @@ class CSourceModuleNode : public runtime::ModuleNode { } else if (name == "get_const_vars") { return PackedFunc( [sptr_to_self, this](TVMArgs args, TVMRetValue* rv) { *rv = this->const_vars_; }); + } else if (name == "get_func_names") { + return PackedFunc( + [sptr_to_self, this](TVMArgs args, TVMRetValue* rv) { *rv = this->func_names_; }); } else { return PackedFunc(nullptr); } @@ -144,15 +165,105 @@ class CSourceModuleNode : public runtime::ModuleNode { std::string fmt_; std::string symbol_; Array const_vars_; + Array func_names_; }; -runtime::Module CSourceModuleCreate(const String& code, const String& fmt, const String& symbol, +runtime::Module CSourceModuleCreate(const String& code, const String& fmt, + const Array& func_names, const String& symbol, const Array& const_vars) { auto n = make_object(code.operator std::string(), fmt.operator std::string(), - symbol.operator std::string(), const_vars); + func_names, symbol.operator std::string(), const_vars); return runtime::Module(n); } +class CSourceMetadataModuleNode : public runtime::ModuleNode { + public: + CSourceMetadataModuleNode(const Array& func_names, const std::string& fmt, Target target) + : fmt_(fmt), func_names_(func_names), target_(target) { + CreateSource(); + } + const char* type_key() const { return "c"; } + + std::string GetSource(const std::string& format) final { return code_.str(); } + + PackedFunc GetFunction(const std::string& name, const ObjectPtr& sptr_to_self) final { + return PackedFunc(nullptr); + } + + 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 == "cc") { + auto code_str = code_.str(); + ICHECK_NE(code_str.length(), 0); + SaveBinaryToFile(file_name, code_str); + } else { + ICHECK_EQ(fmt, fmt_) << "Can only save to format=" << fmt_; + } + } + + protected: + std::stringstream code_; + std::string fmt_; + Array func_names_; + Target target_; + + void CreateFuncRegistry() { + code_ << "#include \n"; + for (const auto& fname : func_names_) { + code_ << "extern \"C\" TVM_DLL int32_t " << fname.data(); + code_ << "(TVMValue* args, int* type_code, int num_args, TVMValue* out_value, int* " + "out_type_code);\n"; + } + code_ << "static TVMBackendPackedCFunc _tvm_func_array[] = {\n"; + for (auto f : func_names_) { + code_ << " (TVMBackendPackedCFunc)" << f << ",\n"; + } + code_ << "};\n"; + auto registry = target::GenerateFuncRegistryNames(func_names_); + code_ << "static const TVMFuncRegistry _tvm_func_registry = {\n" + << " \"" << ::tvm::support::StrEscape(registry.data(), registry.size(), true) << "\"," + << " _tvm_func_array,\n" + << "};\n"; + } + + void GenerateCrtSystemLib() { + code_ << "static const TVMModule _tvm_system_lib = {\n" + << " &_tvm_func_registry,\n" + << "};\n" + << "const TVMModule* TVMSystemLibEntryPoint(void) {\n" + << " return &_tvm_system_lib;\n" + << "}\n"; + } + + void CreateSource() { + if (target_->GetAttr("system-lib").value_or(Bool(false)) && !func_names_.empty()) { + CreateFuncRegistry(); + GenerateCrtSystemLib(); + } + code_ << ";"; + } +}; + +runtime::Module CreateCSourceMetadataModule(const Array& modules, Target target) { + Array func_names; + for (runtime::Module mod : modules) { + auto pf_funcs = mod.GetFunction("get_func_names"); + if (pf_funcs != nullptr) { + Array func_names_ = pf_funcs(); + for (const auto& fname : func_names_) { + func_names.push_back(fname); + } + } + } + auto n = make_object(func_names, "cc", target); + auto csrc_metadata_module = runtime::Module(n); + for (const auto& mod : modules) { + csrc_metadata_module.Import(mod); + } + return std::move(csrc_metadata_module); +} + // supports limited save without cross compile class DeviceSourceModuleNode final : public runtime::ModuleNode { public: @@ -209,8 +320,14 @@ runtime::Module DeviceSourceModuleCreate( TVM_REGISTER_GLOBAL("runtime.SourceModuleCreate").set_body_typed(SourceModuleCreate); TVM_REGISTER_GLOBAL("runtime.CSourceModuleCreate") - .set_body_typed([](String code, String fmt, String symbol, Array const_vars) { - return CSourceModuleCreate(code, fmt, symbol, const_vars); + .set_body_typed([](String code, String fmt, Array func_names, String symbol, + Array const_vars) { + return CSourceModuleCreate(code, fmt, func_names, symbol, const_vars); + }); + +TVM_REGISTER_GLOBAL("runtime.CreateCSourceMetadataModule") + .set_body_typed([](const Array& modules, Target target) { + return CreateCSourceMetadataModule(modules, target); }); } // namespace codegen diff --git a/tests/micro/qemu/test_zephyr.py b/tests/micro/qemu/test_zephyr.py index 2213203d55c1..3e73307f4aeb 100644 --- a/tests/micro/qemu/test_zephyr.py +++ b/tests/micro/qemu/test_zephyr.py @@ -29,7 +29,7 @@ import tvm import tvm.rpc import tvm.micro -import tvm.relay +import tvm.relay as relay from tvm.micro.contrib import zephyr from tvm.contrib import utils @@ -143,5 +143,33 @@ def test_basic_add(sess): test_basic_add(sess) +def test_relay(platform): + """Testing a simple relay graph""" + model, zephyr_board = PLATFORMS[platform] + shape = (10,) + dtype = "int8" + + # Construct Relay program. + x = relay.var("x", relay.TensorType(shape=shape, dtype=dtype)) + xx = relay.multiply(x, x) + z = relay.add(xx, relay.const(np.ones(shape=shape, dtype=dtype))) + func = relay.Function([x], z) + + target = tvm.target.target.micro(model) + with tvm.transform.PassContext(opt_level=3, config={"tir.disable_vectorize": True}): + graph, mod, params = tvm.relay.build(func, target=target) + + with _make_session(model, target, zephyr_board, mod) as session: + graph_mod = tvm.micro.create_local_graph_runtime( + graph, session.get_system_lib(), session.context + ) + graph_mod.set_input(**params) + x_in = np.random.randint(10, size=shape[0], dtype=dtype) + graph_mod.run(x=x_in) + result = graph_mod.get_output(0).asnumpy() + tvm.testing.assert_allclose(graph_mod.get_input(0).asnumpy(), x_in) + tvm.testing.assert_allclose(result, x_in * x_in + 1) + + if __name__ == "__main__": sys.exit(pytest.main([os.path.dirname(__file__)] + sys.argv[1:])) diff --git a/tests/python/contrib/test_onnx_model.py b/tests/python/contrib/test_onnx_model.py index a3f3717e3872..d4d6fda8c749 100644 --- a/tests/python/contrib/test_onnx_model.py +++ b/tests/python/contrib/test_onnx_model.py @@ -155,8 +155,8 @@ def test_partition(): graph_json, mod1, params = relay.build(mod, target) assert mod1.type_key == "metadata" - assert mod1.imported_modules[0].type_key == "llvm" - assert mod1.imported_modules[0].get_source() + assert mod1.imported_modules[0].imported_modules[0].type_key == "llvm" + assert mod1.imported_modules[0].imported_modules[0].get_source() assert mod1.imported_modules[1].type_key == "onnx" assert mod1.imported_modules[1].get_source() diff --git a/tests/python/relay/test_op_fast_math.py b/tests/python/relay/test_op_fast_math.py index 1658658be279..0c51fa9f5fac 100644 --- a/tests/python/relay/test_op_fast_math.py +++ b/tests/python/relay/test_op_fast_math.py @@ -40,7 +40,7 @@ def test_apply(relay_op, name, f_numpy, low, high, step, dtype="float32"): # Check that the op related to fast math have been convered to function in lib func_name = "fused_" + name - assert lib.get_function(func_name) + assert lib.imported_modules[0].get_function(func_name) ctx = tvm.cpu(0) m = graph_runtime.create(graph, lib, ctx) diff --git a/tests/python/relay/test_op_level2.py b/tests/python/relay/test_op_level2.py index 06bd01b4189a..e312622b58ae 100644 --- a/tests/python/relay/test_op_level2.py +++ b/tests/python/relay/test_op_level2.py @@ -1459,7 +1459,7 @@ def _compile(ic, oc, target, data_layout, kernel_layout, dtypes): with tvm.transform.PassContext(opt_level=3): graph, lib, params = relay.build(func, target, params=parameters) - assembly = lib.get_source("asm") + assembly = lib.imported_modules[0].get_source("asm") return assembly def _has_fast_int8_instructions(asm, target): diff --git a/tests/python/relay/test_pass_partition_graph.py b/tests/python/relay/test_pass_partition_graph.py index 059d0b4c8af8..6b7d4ef17a5d 100644 --- a/tests/python/relay/test_pass_partition_graph.py +++ b/tests/python/relay/test_pass_partition_graph.py @@ -172,9 +172,7 @@ def visit_call(self, call): return new_call -def check_result( - mod, map_inputs, out_shape, result, tol=1e-5, target="llvm", ctx=tvm.cpu(), params=None -): +def check_result(mod, map_inputs, out_shape, result, tol=1e-5, ctx=tvm.cpu(), params=None): if sys.platform == "win32": print("Skip test on Windows for now") return @@ -194,7 +192,7 @@ def update_lib(lib): return lib - def check_vm_result(): + def check_vm_result(target): compile_engine.get().clear() with tvm.transform.PassContext(opt_level=3): exe = relay.vm.compile(mod, target=target, params=params) @@ -208,7 +206,7 @@ def check_vm_result(): for out, ref in zip(outs, results): tvm.testing.assert_allclose(out.asnumpy(), ref, rtol=tol, atol=tol) - def check_graph_runtime_result(): + def check_graph_runtime_result(target): compile_engine.get().clear() with tvm.transform.PassContext(opt_level=3): json, lib, param = relay.build(mod, target=target, params=params) @@ -228,8 +226,10 @@ def check_graph_runtime_result(): out = rt_mod.get_output(idx, out) tvm.testing.assert_allclose(out.asnumpy(), results[idx], rtol=tol, atol=tol) - check_vm_result() - check_graph_runtime_result() + targets = ["llvm", "llvm -runtime=c --system-lib"] + for tgt in targets: + check_vm_result(tgt) + check_graph_runtime_result(tgt) def test_multi_node_compiler(): diff --git a/tests/python/unittest/test_link_params.py b/tests/python/unittest/test_link_params.py index e3bd63484aa1..da87a3177c7c 100644 --- a/tests/python/unittest/test_link_params.py +++ b/tests/python/unittest/test_link_params.py @@ -266,7 +266,7 @@ def test_c_link_params(): lib = tvm.relay.build(mod, target, params=param_init) assert set(lib.params.keys()) == {"p0", "p1"} # NOTE: op folded - src = lib.lib.get_source() + src = lib.lib.imported_modules[0].get_source() lib.lib.save("test.c", "cc") c_dtype = _get_c_datatype(dtype) src_lines = src.split("\n") diff --git a/tests/python/unittest/test_target_codegen_llvm.py b/tests/python/unittest/test_target_codegen_llvm.py index 4b67752367db..d7b34170d61c 100644 --- a/tests/python/unittest/test_target_codegen_llvm.py +++ b/tests/python/unittest/test_target_codegen_llvm.py @@ -745,6 +745,7 @@ def test_llvm_crt_static_lib(): d = te.compute((32,), lambda x: A[x] + B[x]) sch = te.create_schedule(d.op) module = tvm.build(sch, [A, B, d], target=tvm.target.Target("llvm --system-lib --runtime=c")) + module = module.imported_modules[0] print(module.get_source()) module.save("test.o") From 15c8d90b2068739f4c1f1915a884eca7977b5ccf Mon Sep 17 00:00:00 2001 From: Manupa Karunaratne Date: Tue, 1 Dec 2020 09:18:35 +0000 Subject: [PATCH 02/18] Created CSourceMetaData module for model metadata * fixed llvm_module to return null pfs for get_symbol and get_const_vars Change-Id: I84810e0695d4d6fb314af2469117f965eed71b51 --- src/target/llvm/llvm_module.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/target/llvm/llvm_module.cc b/src/target/llvm/llvm_module.cc index 19776c1488c4..43d20971404e 100644 --- a/src/target/llvm/llvm_module.cc +++ b/src/target/llvm/llvm_module.cc @@ -63,6 +63,10 @@ class LLVMModuleNode final : public runtime::ModuleNode { } else if (name == "get_func_names") { return PackedFunc( [sptr_to_self, this](TVMArgs args, TVMRetValue* rv) { *rv = this->function_names_; }); + } else if (name == "get_symbol") { + return PackedFunc(nullptr); + } else if (name == "get_const_vars") { + return PackedFunc(nullptr); } else if (name == "_get_target_triple") { std::string target_triple = tm_->getTargetTriple().str(); // getTargetTriple() doesn't include other flags besides the triple. Add back flags which are From 61444bf878164150ec2a161bbdf79b8d1baf9258 Mon Sep 17 00:00:00 2001 From: Manupa Karunaratne Date: Tue, 1 Dec 2020 11:31:19 +0000 Subject: [PATCH 03/18] Created CSourceMetaData module for model metadata *fixed bundle_deploy tests Change-Id: I0d1332a4abbb6830531784c59264021bbbd7148a --- apps/bundle_deploy/Makefile | 6 +++--- apps/bundle_deploy/build_model.py | 12 ++++++++---- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/apps/bundle_deploy/Makefile b/apps/bundle_deploy/Makefile index 8a5f1cf95571..707bfef286de 100644 --- a/apps/bundle_deploy/Makefile +++ b/apps/bundle_deploy/Makefile @@ -97,7 +97,7 @@ $(build_dir)/demo_static: demo_static.c ${build_dir}/bundle_static.o ${build_dir $(QUIET)mkdir -p $(@D) $(QUIET)gcc $(PKG_CFLAGS) -o $@ $^ $(PKG_LDFLAGS) $(BACKTRACE_LDFLAGS) $(BACKTRACE_CFLAGS) -$(build_dir)/test_static: test_static.c ${build_dir}/bundle_static.o ${build_dir}/test_model_c.o ${build_dir}/crt/libmemory.a ${build_dir}/crt/libgraph_runtime.a ${build_dir}/crt/libcommon.a $(BACKTRACE_OBJS) +$(build_dir)/test_static: test_static.c ${build_dir}/bundle_static.o ${build_dir}/test_model_c.o $(build_dir)/test_metadata_c.cc ${build_dir}/crt/libmemory.a ${build_dir}/crt/libgraph_runtime.a ${build_dir}/crt/libcommon.a $(BACKTRACE_OBJS) $(QUIET)mkdir -p $(@D) $(QUIET)gcc $(PKG_CFLAGS) -o $@ $^ $(BACKTRACE_LDFLAGS) @@ -135,11 +135,11 @@ $(build_dir)/bundle_c.so: bundle.c $(build_dir)/model_c.o ${build_dir}/crt/libme $(QUIET)mkdir -p $(@D) $(QUIET)gcc -shared $(PKG_CFLAGS) -fvisibility=hidden -o $@ $^ $(PKG_LDFLAGS) $(BACKTRACE_LDFLAGS) $(BACKTRACE_CFLAGS) -$(build_dir)/test_bundle.so: bundle.cc runtime.cc $(build_dir)/test_model_cpp.o +$(build_dir)/test_bundle.so: bundle.cc runtime.cc $(build_dir)/test_model_cpp.o $(build_dir)/test_model_cpp.o $(build_dir)/test_metadata_cpp.cc $(QUIET)mkdir -p $(@D) $(QUIET)g++ -shared $(PKG_CXXFLAGS) -fvisibility=hidden -o $@ $^ $(PKG_LDFLAGS) -$(build_dir)/test_bundle_c.so: bundle.c $(build_dir)/test_model_c.o ${build_dir}/crt/libmemory.a ${build_dir}/crt/libgraph_runtime.a ${build_dir}/crt/libcommon.a $(BACKTRACE_OBJS) +$(build_dir)/test_bundle_c.so: bundle.c $(build_dir)/test_model_c.o $(build_dir)/test_metadata_c.cc ${build_dir}/crt/libmemory.a ${build_dir}/crt/libgraph_runtime.a ${build_dir}/crt/libcommon.a $(BACKTRACE_OBJS) $(QUIET)mkdir -p $(@D) $(QUIET)gcc -shared $(PKG_CFLAGS) -fvisibility=hidden -o $@ $^ $(PKG_LDFLAGS) $(BACKTRACE_LDFLAGS) $(BACKTRACE_CFLAGS) diff --git a/apps/bundle_deploy/build_model.py b/apps/bundle_deploy/build_model.py index 623d24659cc5..fc0eca126c7e 100644 --- a/apps/bundle_deploy/build_model.py +++ b/apps/bundle_deploy/build_model.py @@ -51,8 +51,10 @@ def build_module(opts): build_dir = os.path.abspath(opts.out_dir) if not os.path.isdir(build_dir): os.makedirs(build_dir) - - lib.save(os.path.join(build_dir, file_format_str.format(name="model", ext="o"))) + lib.imported_modules[0].save( + os.path.join(build_dir, file_format_str.format(name="model", ext="o")) + ) + lib.save(os.path.join(build_dir, file_format_str.format(name="metadata", ext="cc"))) with open( os.path.join(build_dir, file_format_str.format(name="graph", ext="json")), "w" ) as f_graph_json: @@ -85,8 +87,10 @@ def build_test_module(opts): build_dir = os.path.abspath(opts.out_dir) if not os.path.isdir(build_dir): os.makedirs(build_dir) - - lib.save(os.path.join(build_dir, file_format_str.format(name="test_model", ext="o"))) + lib.imported_modules[0].save( + os.path.join(build_dir, file_format_str.format(name="test_model", ext="o")) + ) + lib.save(os.path.join(build_dir, file_format_str.format(name="test_metadata", ext="cc"))) with open( os.path.join(build_dir, file_format_str.format(name="test_graph", ext="json")), "w" ) as f_graph_json: From 04b1a7518f475966f253f9e0290ff51313de1f58 Mon Sep 17 00:00:00 2001 From: Manupa Karunaratne Date: Tue, 1 Dec 2020 13:06:42 +0000 Subject: [PATCH 04/18] Created CSourceMetaData module for model metadata *fixed export_library not to insert "options" when targeting tar *fixed unit tests Change-Id: Ia1686889498b71af66f1a0311a059154ad3c2c3e --- python/tvm/runtime/module.py | 2 +- tests/python/unittest/test_runtime_module_export.py | 2 +- tests/python/unittest/test_runtime_module_load.py | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/python/tvm/runtime/module.py b/python/tvm/runtime/module.py index 2adb591402a7..863f61ac9b73 100644 --- a/python/tvm/runtime/module.py +++ b/python/tvm/runtime/module.py @@ -347,7 +347,7 @@ def export_library(self, file_name, fcompile=None, addons=None, workspace_dir=No f.write(_ffi_api.ModulePackImportsToC(self, is_system_lib)) files.append(path_cc) - if has_c_module: + if has_c_module and not file_name.endswith(".tar"): options = [] if "options" in kwargs: opts = kwargs["options"] diff --git a/tests/python/unittest/test_runtime_module_export.py b/tests/python/unittest/test_runtime_module_export.py index 88b7af984073..6cc1288ca29e 100644 --- a/tests/python/unittest/test_runtime_module_export.py +++ b/tests/python/unittest/test_runtime_module_export.py @@ -58,7 +58,7 @@ def generate_engine_module(): import tvm.runtime._ffi_api gen_engine_header() - csource_module = tvm.runtime._ffi_api.CSourceModuleCreate(code, "cc", "", None) + csource_module = tvm.runtime._ffi_api.CSourceModuleCreate(code, "cc", [], "", None) return csource_module diff --git a/tests/python/unittest/test_runtime_module_load.py b/tests/python/unittest/test_runtime_module_load.py index 7befed3bbcdd..9d8fe2b4ec2d 100644 --- a/tests/python/unittest/test_runtime_module_load.py +++ b/tests/python/unittest/test_runtime_module_load.py @@ -194,8 +194,8 @@ def check_system_lib(): path1 = temp.relpath("myadd1.o") path2 = temp.relpath("myadd2.o") path_dso = temp.relpath("mylib.so") - fadd1.save(path1) - fadd2.save(path2) + fadd1.imported_modules[0].save(path1) + fadd2.imported_modules[0].save(path2) cc.create_shared(path_dso, [path1, path2]) # Load dll, will trigger system library registration dll = ctypes.CDLL(path_dso) From 4cc6f759660b926f32d315c6d716ee5ad392322d Mon Sep 17 00:00:00 2001 From: Manupa Karunaratne Date: Tue, 1 Dec 2020 17:38:49 +0000 Subject: [PATCH 05/18] Created CSourceMetaData module for model metadata * enable wasm to support csource metadata module * disabled non DSOExportables from using csource metadata module Change-Id: Ie09beaad35cbc2ef738d1d24d91e249b5e099569 --- python/tvm/runtime/module.py | 6 +++++- src/target/source/source_module.cc | 9 ++++++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/python/tvm/runtime/module.py b/python/tvm/runtime/module.py index 863f61ac9b73..4c7d74bbac2f 100644 --- a/python/tvm/runtime/module.py +++ b/python/tvm/runtime/module.py @@ -306,7 +306,11 @@ def export_library(self, file_name, fcompile=None, addons=None, workspace_dir=No llvm_target_triple = None for index, module in enumerate(modules): if fcompile is not None and hasattr(fcompile, "object_format"): - object_format = fcompile.object_format + if module.type_key == "c": + object_format = "cc" + has_c_module = True + else: + object_format = fcompile.object_format else: if module.type_key == "llvm": object_format = "o" diff --git a/src/target/source/source_module.cc b/src/target/source/source_module.cc index 82e78e187ff8..292a21bbf722 100644 --- a/src/target/source/source_module.cc +++ b/src/target/source/source_module.cc @@ -58,6 +58,10 @@ runtime::Module CreateMetadataModule( Array csource_metadata_modules; Array binary_metadata_modules; + auto DSOExportable = [](tvm::runtime::Module& mod) { + return !std::strcmp(mod->type_key(), "llvm") || !std::strcmp(mod->type_key(), "c"); + }; + // Wrap all submodules in the initialization wrapper. std::unordered_map> sym_metadata; for (tvm::runtime::Module mod : modules) { @@ -77,7 +81,10 @@ runtime::Module CreateMetadataModule( // runtime module to be initialized by the binary // metadata module. If not rest of the modules are // wrapped in c-source metadata module. - if (!variables.empty()) { + + // TODO(@manupa-arm) : we should be able to use csource_metadata + // if the variables are empty + if (!variables.empty() || !DSOExportable(mod)) { binary_metadata_modules.push_back(mod); } else { csource_metadata_modules.push_back(mod); From 7260b8a0b08244c8aeffe359ab80d2997e03b563 Mon Sep 17 00:00:00 2001 From: Manupa Karunaratne Date: Tue, 1 Dec 2020 21:27:24 +0000 Subject: [PATCH 06/18] Created CSourceMetaData module for model metadata * changed const pfs to be called only on external modules or DSOExportable modules Change-Id: I6ad28f166c0fc27a2548c851bf9287ec805550d1 --- src/relay/backend/build_module.cc | 5 ++--- src/relay/backend/vm/compiler.cc | 5 ++--- src/target/source/codegen_source_base.h | 5 +++-- src/target/source/source_module.cc | 18 ++++++++++++------ 4 files changed, 19 insertions(+), 14 deletions(-) diff --git a/src/relay/backend/build_module.cc b/src/relay/backend/build_module.cc index 0737e8635c4b..09b09668190e 100644 --- a/src/relay/backend/build_module.cc +++ b/src/relay/backend/build_module.cc @@ -516,9 +516,8 @@ class RelayBuildModule : public runtime::ModuleNode { ret_.mod = tvm::build(lowered_funcs, target_host_); } - auto all_mods = graph_codegen_->GetExternalModules(); - all_mods.push_back(ret_.mod); - ret_.mod = tvm::codegen::CreateMetadataModule(ret_.params, all_mods, GetTargetHost()); + auto ext_mods = graph_codegen_->GetExternalModules(); + ret_.mod = tvm::codegen::CreateMetadataModule(ret_.params, ret_.mod, ext_mods, GetTargetHost()); } private: diff --git a/src/relay/backend/vm/compiler.cc b/src/relay/backend/vm/compiler.cc index 21693b6ab17f..8fbe31edce3d 100644 --- a/src/relay/backend/vm/compiler.cc +++ b/src/relay/backend/vm/compiler.cc @@ -1136,7 +1136,7 @@ void VMCompiler::Codegen() { } auto compile_engine = CompileEngine::Global(); - auto all_mods = compile_engine->LowerExternalFunctions(); + auto ext_mods = compile_engine->LowerExternalFunctions(); if (funcs.size() > 0) { Map build_funcs; for (const auto& i : funcs) { @@ -1148,8 +1148,7 @@ void VMCompiler::Codegen() { // to make sure a DSO module will be also available. exec_->lib = codegen::CSourceModuleCreate(";", "", Array{}); } - all_mods.push_back(exec_->lib); - exec_->lib = codegen::CreateMetadataModule(params_, all_mods, target_host_); + exec_->lib = codegen::CreateMetadataModule(params_, exec_->lib, ext_mods, target_host_); } ExprDeviceMap VMCompiler::AnalyzeContext() const { diff --git a/src/target/source/codegen_source_base.h b/src/target/source/codegen_source_base.h index 3d458acdcf2c..b8e1c59c0641 100644 --- a/src/target/source/codegen_source_base.h +++ b/src/target/source/codegen_source_base.h @@ -149,12 +149,13 @@ runtime::Module CSourceModuleCreate(const String& code, const String& fmt, * \brief Wrap the submodules in a metadata module. * \param params The variable to constant mapping that is collected by the host * module. - * \param modules All the modules that needs to be imported inside the metadata module(s). + * \param target_module The main TIR-lowered internal runtime module + * \param modules All the external modules that needs to be imported inside the metadata module(s). * \param target The target that all the modules are compiled for * \return The wrapped module. */ runtime::Module CreateMetadataModule( - const std::unordered_map& params, + const std::unordered_map& params, runtime::Module target_module, const Array& ext_modules, Target target); /*! diff --git a/src/target/source/source_module.cc b/src/target/source/source_module.cc index 292a21bbf722..d100cc18f934 100644 --- a/src/target/source/source_module.cc +++ b/src/target/source/source_module.cc @@ -54,7 +54,7 @@ using runtime::SaveBinaryToFile; */ runtime::Module CreateMetadataModule( const std::unordered_map& params, - const Array& modules, Target target) { + tvm::runtime::Module target_module, const Array& ext_modules, Target target) { Array csource_metadata_modules; Array binary_metadata_modules; @@ -64,7 +64,7 @@ runtime::Module CreateMetadataModule( // Wrap all submodules in the initialization wrapper. std::unordered_map> sym_metadata; - for (tvm::runtime::Module mod : modules) { + for (tvm::runtime::Module mod : ext_modules) { auto pf_sym = mod.GetFunction("get_symbol"); auto pf_var = mod.GetFunction("get_const_vars"); if (pf_sym != nullptr && pf_var != nullptr) { @@ -93,17 +93,23 @@ runtime::Module CreateMetadataModule( csource_metadata_modules.push_back(mod); } } - auto c_meta_mod = CreateCSourceMetadataModule(csource_metadata_modules, target); - // Wrap the modules. + + if (DSOExportable(target_module)) { + csource_metadata_modules.push_back(target_module); + } + + if (!csource_metadata_modules.empty()) { + target_module = CreateCSourceMetadataModule(csource_metadata_modules, target); + } if (!binary_metadata_modules.empty()) { runtime::Module binary_meta_mod = runtime::MetadataModuleCreate(params, sym_metadata); - binary_meta_mod.Import(c_meta_mod); + binary_meta_mod.Import(target_module); for (const auto& it : binary_metadata_modules) { binary_meta_mod.Import(it); } return binary_meta_mod; } - return c_meta_mod; + return target_module; } // Simulator function From 9bc4c88aae6a3bc2b6b16e307000a64d13dc195f Mon Sep 17 00:00:00 2001 From: Manupa Karunaratne Date: Wed, 2 Dec 2020 09:35:21 +0000 Subject: [PATCH 07/18] Created CSourceMetaData module for model metadata * CSourceMetadata module wrapper is only created for c/llvm targets Change-Id: I13cb4140c17e2e1f91d495b15a1ff7eeab9fb14d --- src/target/source/source_module.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/target/source/source_module.cc b/src/target/source/source_module.cc index d100cc18f934..ed63e821247b 100644 --- a/src/target/source/source_module.cc +++ b/src/target/source/source_module.cc @@ -94,7 +94,7 @@ runtime::Module CreateMetadataModule( } } - if (DSOExportable(target_module)) { + if (target->kind->name == "llvm" || target->kind->name == "c") { csource_metadata_modules.push_back(target_module); } From 3ea831c77a029ad8fa92097e58759b5a22c0dc83 Mon Sep 17 00:00:00 2001 From: Manupa Karunaratne Date: Wed, 2 Dec 2020 13:26:04 +0000 Subject: [PATCH 08/18] Created CSourceMetaData module for model metadata *target should be defined to use csourcemetdata module Change-Id: Id8e55b23d0007a79c550334de2c0fec63d40171f --- src/target/source/source_module.cc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/target/source/source_module.cc b/src/target/source/source_module.cc index ed63e821247b..0d2ca892d9a3 100644 --- a/src/target/source/source_module.cc +++ b/src/target/source/source_module.cc @@ -94,8 +94,10 @@ runtime::Module CreateMetadataModule( } } - if (target->kind->name == "llvm" || target->kind->name == "c") { - csource_metadata_modules.push_back(target_module); + if (target.defined()) { + if (target->kind->name == "llvm" || target->kind->name == "c") { + csource_metadata_modules.push_back(target_module); + } } if (!csource_metadata_modules.empty()) { From 46a09e16a7f413605f95d9d5b2fd3d2c9e2d2844 Mon Sep 17 00:00:00 2001 From: Manupa Karunaratne Date: Wed, 16 Dec 2020 17:18:43 +0000 Subject: [PATCH 09/18] Created CSourceMetaData module for model metadata * reinstate llvm func registry Change-Id: I53e0754b6fb533637f08b25e98064d8c04092de4 --- apps/bundle_deploy/Makefile | 6 +-- apps/bundle_deploy/build_model.py | 10 +--- src/target/llvm/codegen_cpu.cc | 47 +++++++++++++++++++ src/target/source/source_module.cc | 2 +- tests/python/contrib/test_onnx_model.py | 4 +- tests/python/relay/test_op_fast_math.py | 2 +- tests/python/relay/test_op_level2.py | 2 +- .../unittest/test_runtime_module_load.py | 4 +- .../unittest/test_target_codegen_llvm.py | 1 - 9 files changed, 59 insertions(+), 19 deletions(-) diff --git a/apps/bundle_deploy/Makefile b/apps/bundle_deploy/Makefile index 707bfef286de..f4ef00de6df2 100644 --- a/apps/bundle_deploy/Makefile +++ b/apps/bundle_deploy/Makefile @@ -97,7 +97,7 @@ $(build_dir)/demo_static: demo_static.c ${build_dir}/bundle_static.o ${build_dir $(QUIET)mkdir -p $(@D) $(QUIET)gcc $(PKG_CFLAGS) -o $@ $^ $(PKG_LDFLAGS) $(BACKTRACE_LDFLAGS) $(BACKTRACE_CFLAGS) -$(build_dir)/test_static: test_static.c ${build_dir}/bundle_static.o ${build_dir}/test_model_c.o $(build_dir)/test_metadata_c.cc ${build_dir}/crt/libmemory.a ${build_dir}/crt/libgraph_runtime.a ${build_dir}/crt/libcommon.a $(BACKTRACE_OBJS) +$(build_dir)/test_static: test_static.c ${build_dir}/bundle_static.o ${build_dir}/test_model_c.o ${build_dir}/crt/libmemory.a ${build_dir}/crt/libgraph_runtime.a ${build_dir}/crt/libcommon.a $(BACKTRACE_OBJS) $(QUIET)mkdir -p $(@D) $(QUIET)gcc $(PKG_CFLAGS) -o $@ $^ $(BACKTRACE_LDFLAGS) @@ -135,11 +135,11 @@ $(build_dir)/bundle_c.so: bundle.c $(build_dir)/model_c.o ${build_dir}/crt/libme $(QUIET)mkdir -p $(@D) $(QUIET)gcc -shared $(PKG_CFLAGS) -fvisibility=hidden -o $@ $^ $(PKG_LDFLAGS) $(BACKTRACE_LDFLAGS) $(BACKTRACE_CFLAGS) -$(build_dir)/test_bundle.so: bundle.cc runtime.cc $(build_dir)/test_model_cpp.o $(build_dir)/test_model_cpp.o $(build_dir)/test_metadata_cpp.cc +$(build_dir)/test_bundle.so: bundle.cc runtime.cc $(build_dir)/test_model_cpp.o $(build_dir)/test_model_cpp.o $(QUIET)mkdir -p $(@D) $(QUIET)g++ -shared $(PKG_CXXFLAGS) -fvisibility=hidden -o $@ $^ $(PKG_LDFLAGS) -$(build_dir)/test_bundle_c.so: bundle.c $(build_dir)/test_model_c.o $(build_dir)/test_metadata_c.cc ${build_dir}/crt/libmemory.a ${build_dir}/crt/libgraph_runtime.a ${build_dir}/crt/libcommon.a $(BACKTRACE_OBJS) +$(build_dir)/test_bundle_c.so: bundle.c $(build_dir)/test_model_c.o ${build_dir}/crt/libmemory.a ${build_dir}/crt/libgraph_runtime.a ${build_dir}/crt/libcommon.a $(BACKTRACE_OBJS) $(QUIET)mkdir -p $(@D) $(QUIET)gcc -shared $(PKG_CFLAGS) -fvisibility=hidden -o $@ $^ $(PKG_LDFLAGS) $(BACKTRACE_LDFLAGS) $(BACKTRACE_CFLAGS) diff --git a/apps/bundle_deploy/build_model.py b/apps/bundle_deploy/build_model.py index fc0eca126c7e..a2513c8a46d0 100644 --- a/apps/bundle_deploy/build_model.py +++ b/apps/bundle_deploy/build_model.py @@ -51,10 +51,7 @@ def build_module(opts): build_dir = os.path.abspath(opts.out_dir) if not os.path.isdir(build_dir): os.makedirs(build_dir) - lib.imported_modules[0].save( - os.path.join(build_dir, file_format_str.format(name="model", ext="o")) - ) - lib.save(os.path.join(build_dir, file_format_str.format(name="metadata", ext="cc"))) + lib.save(os.path.join(build_dir, file_format_str.format(name="model", ext="o"))) with open( os.path.join(build_dir, file_format_str.format(name="graph", ext="json")), "w" ) as f_graph_json: @@ -87,10 +84,7 @@ def build_test_module(opts): build_dir = os.path.abspath(opts.out_dir) if not os.path.isdir(build_dir): os.makedirs(build_dir) - lib.imported_modules[0].save( - os.path.join(build_dir, file_format_str.format(name="test_model", ext="o")) - ) - lib.save(os.path.join(build_dir, file_format_str.format(name="test_metadata", ext="cc"))) + lib.save(os.path.join(build_dir, file_format_str.format(name="test_model", ext="o"))) with open( os.path.join(build_dir, file_format_str.format(name="test_graph", ext="json")), "w" ) as f_graph_json: diff --git a/src/target/llvm/codegen_cpu.cc b/src/target/llvm/codegen_cpu.cc index 0a33d34d8218..6143e7050495 100644 --- a/src/target/llvm/codegen_cpu.cc +++ b/src/target/llvm/codegen_cpu.cc @@ -123,6 +123,12 @@ void CodeGenCPU::AddFunction(const PrimFunc& f) { << "CodeGenLLVM: Expect PrimFunc to have the global_symbol attribute"; export_system_symbols_.emplace_back( std::make_pair(global_symbol.value().operator std::string(), function_)); + } else if (target_c_runtime_) { + auto global_symbol = f->GetAttr(tvm::attr::kGlobalSymbol); + ICHECK(global_symbol.defined()) + << "CodeGenLLVM: Expect PrimFunc to have the global_symbol attribute"; + registry_functions_.emplace_back( + std::make_pair(global_symbol.value().operator std::string(), function_)); } AddDebugInformation(function_); } @@ -786,6 +792,46 @@ llvm::Value* CodeGenCPU::RuntimeTVMParallelBarrier() { } void CodeGenCPU::AddStartupFunction() { + if (registry_functions_.size() != 0) { + ICHECK(is_system_lib_) << "Loading of --system-lib modules is yet to be defined for C runtime"; + Array symbols; + std::vector funcs; + for (auto sym : registry_functions_) { + symbols.push_back(sym.first); + funcs.emplace_back(llvm::ConstantExpr::getBitCast( + sym.second, ftype_tvm_backend_packed_c_func_->getPointerTo())); + } + llvm::DataLayout layout(module_.get()); + llvm::ArrayType* t_tvm_crt_func_ptrs = + llvm::ArrayType::get(ftype_tvm_backend_packed_c_func_->getPointerTo(), funcs.size()); + llvm::GlobalVariable* func_registry_ptrs = new llvm::GlobalVariable( + *module_, t_tvm_crt_func_ptrs, true, llvm::GlobalValue::InternalLinkage, + llvm::ConstantArray::get(t_tvm_crt_func_ptrs, funcs), "_tvm_func_registry_ptrs"); + uint64_t align = layout.getTypeAllocSize(ftype_tvm_backend_packed_c_func_->getPointerTo()); +#if TVM_LLVM_VERSION >= 100 + func_registry_ptrs->setAlignment(llvm::Align(align)); +#else + func_registry_ptrs->setAlignment(align); +#endif + llvm::GlobalVariable* func_registry = new llvm::GlobalVariable( + *module_, t_tvm_crt_func_registry_, true, llvm::GlobalVariable::InternalLinkage, + llvm::ConstantStruct::get( + t_tvm_crt_func_registry_, + {GetConstString(::tvm::target::GenerateFuncRegistryNames(symbols)), + func_registry_ptrs}), + "_tvm_crt_func_registry"); + llvm::GlobalVariable* module = new llvm::GlobalVariable( + *module_, t_tvm_crt_module_, true, llvm::GlobalValue::InternalLinkage, + llvm::ConstantStruct::get(t_tvm_crt_module_, {func_registry}), "_tvm_crt_module"); + + // Now build TVMSystemLibEntryPoint. + llvm::FunctionType* ftype = llvm::FunctionType::get(t_void_p_, {}, false); + function_ = llvm::Function::Create(ftype, llvm::Function::ExternalLinkage, + "TVMSystemLibEntryPoint", module_.get()); + llvm::BasicBlock* entry_point_entry = llvm::BasicBlock::Create(*ctx_, "entry", function_); + builder_->SetInsertPoint(entry_point_entry); + builder_->CreateRet(builder_->CreateBitCast(module, t_void_p_)); + } else { llvm::FunctionType* ftype = llvm::FunctionType::get(t_void_, {}, false); function_ = llvm::Function::Create(ftype, llvm::Function::InternalLinkage, "__tvm_module_startup", module_.get()); @@ -798,6 +844,7 @@ void CodeGenCPU::AddStartupFunction() { } llvm::appendToGlobalCtors(*module_, function_, 65535); builder_->CreateRet(nullptr); + } } llvm::Value* CodeGenCPU::CreateIntrinsic(const CallNode* op) { diff --git a/src/target/source/source_module.cc b/src/target/source/source_module.cc index 0d2ca892d9a3..b2bed9aa6bff 100644 --- a/src/target/source/source_module.cc +++ b/src/target/source/source_module.cc @@ -95,7 +95,7 @@ runtime::Module CreateMetadataModule( } if (target.defined()) { - if (target->kind->name == "llvm" || target->kind->name == "c") { + if (target->kind->name == "c") { csource_metadata_modules.push_back(target_module); } } diff --git a/tests/python/contrib/test_onnx_model.py b/tests/python/contrib/test_onnx_model.py index d4d6fda8c749..a3f3717e3872 100644 --- a/tests/python/contrib/test_onnx_model.py +++ b/tests/python/contrib/test_onnx_model.py @@ -155,8 +155,8 @@ def test_partition(): graph_json, mod1, params = relay.build(mod, target) assert mod1.type_key == "metadata" - assert mod1.imported_modules[0].imported_modules[0].type_key == "llvm" - assert mod1.imported_modules[0].imported_modules[0].get_source() + assert mod1.imported_modules[0].type_key == "llvm" + assert mod1.imported_modules[0].get_source() assert mod1.imported_modules[1].type_key == "onnx" assert mod1.imported_modules[1].get_source() diff --git a/tests/python/relay/test_op_fast_math.py b/tests/python/relay/test_op_fast_math.py index 0c51fa9f5fac..1658658be279 100644 --- a/tests/python/relay/test_op_fast_math.py +++ b/tests/python/relay/test_op_fast_math.py @@ -40,7 +40,7 @@ def test_apply(relay_op, name, f_numpy, low, high, step, dtype="float32"): # Check that the op related to fast math have been convered to function in lib func_name = "fused_" + name - assert lib.imported_modules[0].get_function(func_name) + assert lib.get_function(func_name) ctx = tvm.cpu(0) m = graph_runtime.create(graph, lib, ctx) diff --git a/tests/python/relay/test_op_level2.py b/tests/python/relay/test_op_level2.py index e312622b58ae..06bd01b4189a 100644 --- a/tests/python/relay/test_op_level2.py +++ b/tests/python/relay/test_op_level2.py @@ -1459,7 +1459,7 @@ def _compile(ic, oc, target, data_layout, kernel_layout, dtypes): with tvm.transform.PassContext(opt_level=3): graph, lib, params = relay.build(func, target, params=parameters) - assembly = lib.imported_modules[0].get_source("asm") + assembly = lib.get_source("asm") return assembly def _has_fast_int8_instructions(asm, target): diff --git a/tests/python/unittest/test_runtime_module_load.py b/tests/python/unittest/test_runtime_module_load.py index 9d8fe2b4ec2d..7befed3bbcdd 100644 --- a/tests/python/unittest/test_runtime_module_load.py +++ b/tests/python/unittest/test_runtime_module_load.py @@ -194,8 +194,8 @@ def check_system_lib(): path1 = temp.relpath("myadd1.o") path2 = temp.relpath("myadd2.o") path_dso = temp.relpath("mylib.so") - fadd1.imported_modules[0].save(path1) - fadd2.imported_modules[0].save(path2) + fadd1.save(path1) + fadd2.save(path2) cc.create_shared(path_dso, [path1, path2]) # Load dll, will trigger system library registration dll = ctypes.CDLL(path_dso) diff --git a/tests/python/unittest/test_target_codegen_llvm.py b/tests/python/unittest/test_target_codegen_llvm.py index d7b34170d61c..4b67752367db 100644 --- a/tests/python/unittest/test_target_codegen_llvm.py +++ b/tests/python/unittest/test_target_codegen_llvm.py @@ -745,7 +745,6 @@ def test_llvm_crt_static_lib(): d = te.compute((32,), lambda x: A[x] + B[x]) sch = te.create_schedule(d.op) module = tvm.build(sch, [A, B, d], target=tvm.target.Target("llvm --system-lib --runtime=c")) - module = module.imported_modules[0] print(module.get_source()) module.save("test.o") From 6fbfce1727a65b1d7efff1270a6ccf085c69d4cf Mon Sep 17 00:00:00 2001 From: Manupa Karunaratne Date: Wed, 16 Dec 2020 19:40:21 +0000 Subject: [PATCH 10/18] Created CSourceMetaData module for model metadata * addressed comments and fixed bugs Change-Id: I26401685dc803aeaf7642c865df88d683419e859 --- python/tvm/runtime/module.py | 11 ++++- .../backend/contrib/codegen_c/codegen.cc | 19 +++----- src/relay/backend/contrib/dnnl/codegen.cc | 2 +- src/target/source/codegen_source_base.h | 2 +- src/target/source/source_module.cc | 44 ++++++++++--------- .../python/relay/test_pass_partition_graph.py | 42 ++++++++++-------- .../unittest/test_runtime_module_export.py | 2 +- 7 files changed, 66 insertions(+), 56 deletions(-) diff --git a/python/tvm/runtime/module.py b/python/tvm/runtime/module.py index 4c7d74bbac2f..5a188a795781 100644 --- a/python/tvm/runtime/module.py +++ b/python/tvm/runtime/module.py @@ -269,12 +269,18 @@ def export_library(self, file_name, fcompile=None, addons=None, workspace_dir=No to that format. Otherwise, will use default format "o". workspace_dir : str, optional - The name of the workspace dir to create intermediary + the path to a directory used to create intermediary artifacts for the process exporting of the library. If this is not provided a temporary dir will be created. kwargs : dict, optional Additional arguments passed to fcompile + + Returns + ------- + result of fcompile() : unknown, optional + If the compilation function returns an artifact it would be returned via + export_library, if any. """ # NOTE: this function depends on contrib library features # which are only available in when TVM function is available. @@ -351,6 +357,9 @@ def export_library(self, file_name, fcompile=None, addons=None, workspace_dir=No f.write(_ffi_api.ModulePackImportsToC(self, is_system_lib)) files.append(path_cc) + # The imports could contain a c module but the object format could be tar + # Thus, it would not recognize the following include paths as options + # which are there assuming a c compiler is the fcompile. if has_c_module and not file_name.endswith(".tar"): options = [] if "options" in kwargs: diff --git a/src/relay/backend/contrib/codegen_c/codegen.cc b/src/relay/backend/contrib/codegen_c/codegen.cc index 6e038bb46a80..998393d450c2 100644 --- a/src/relay/backend/contrib/codegen_c/codegen.cc +++ b/src/relay/backend/contrib/codegen_c/codegen.cc @@ -215,23 +215,18 @@ class CodegenC : public MemoizedExprTranslator>, public Code class CSourceCodegen : public CSourceModuleCodegenBase { public: - std::tuple, String, String> GenCFunc(const Function& func) { + std::tuple, String, String> GenCFunc(const Function& func) { ICHECK(func.defined()) << "Input error: expect a Relay function."; - - // Record the external symbol for runtime lookup. - auto sid = GetExtSymbol(func); - - CodegenC builder(sid); + CodegenC builder(GetExtSymbol(func)); auto out = builder.VisitExpr(func->body); - return std::make_tuple(sid, builder.const_vars_, builder.ext_func_id_, builder.JIT(out)); + return std::make_tuple(builder.const_vars_, builder.ext_func_id_, builder.JIT(out)); } runtime::Module CreateCSourceModule(const ObjectRef& ref) override { ICHECK(ref->IsInstance()); auto res = GenCFunc(Downcast(ref)); - String sym = std::get<0>(res); - Array variables = std::get<1>(res); - String func_name = std::get<2>(res); + Array variables = std::get<0>(res); + String func_name = std::get<1>(res); // Create headers code_stream_ << "#include \n"; @@ -263,13 +258,13 @@ class CSourceCodegen : public CSourceModuleCodegenBase { )op_macro"; code_stream_ << operator_macro << "\n\n"; - code_stream_ << std::get<3>(res); + code_stream_ << std::get<2>(res); std::string code = code_stream_.str(); // Create a CSource module const auto* pf = runtime::Registry::Get("runtime.CSourceModuleCreate"); ICHECK(pf != nullptr) << "Cannot find csource module to create the external runtime module"; - return (*pf)(code, "c", Array{func_name}, sym, variables); + return (*pf)(code, "c", Array{func_name}, variables); } private: diff --git a/src/relay/backend/contrib/dnnl/codegen.cc b/src/relay/backend/contrib/dnnl/codegen.cc index 7160758f2fb5..32723ce5efe2 100644 --- a/src/relay/backend/contrib/dnnl/codegen.cc +++ b/src/relay/backend/contrib/dnnl/codegen.cc @@ -414,7 +414,7 @@ class DNNLModuleCodegen : public CSourceModuleCodegenBase { const auto* pf = runtime::Registry::Get("runtime.CSourceModuleCreate"); ICHECK(pf != nullptr) << "Cannot find csource module to create the external runtime module"; // TODO(@manupa-arm): pass the function names to enable system-lib creation - return (*pf)(code, "c", Array{}, sym, variables); + return (*pf)(code, "c", Array{}, variables); } private: diff --git a/src/target/source/codegen_source_base.h b/src/target/source/codegen_source_base.h index b8e1c59c0641..28aa8f0765d7 100644 --- a/src/target/source/codegen_source_base.h +++ b/src/target/source/codegen_source_base.h @@ -142,7 +142,7 @@ runtime::Module SourceModuleCreate(std::string code, std::string fmt); * \return The created module. */ runtime::Module CSourceModuleCreate(const String& code, const String& fmt, - const Array& func_names, const String& symbol = "", + const Array& func_names, const Array& const_vars = {}); /*! diff --git a/src/target/source/source_module.cc b/src/target/source/source_module.cc index b2bed9aa6bff..31b3a521a0bb 100644 --- a/src/target/source/source_module.cc +++ b/src/target/source/source_module.cc @@ -55,8 +55,8 @@ using runtime::SaveBinaryToFile; runtime::Module CreateMetadataModule( const std::unordered_map& params, tvm::runtime::Module target_module, const Array& ext_modules, Target target) { - Array csource_metadata_modules; - Array binary_metadata_modules; + Array csource_modules; + Array binary_modules; auto DSOExportable = [](tvm::runtime::Module& mod) { return !std::strcmp(mod->type_key(), "llvm") || !std::strcmp(mod->type_key(), "c"); @@ -84,29 +84,29 @@ runtime::Module CreateMetadataModule( // TODO(@manupa-arm) : we should be able to use csource_metadata // if the variables are empty - if (!variables.empty() || !DSOExportable(mod)) { - binary_metadata_modules.push_back(mod); + if (!variables.empty() || !DSOExportable(mod) || target->kind->name == "llvm") { + binary_modules.push_back(mod); } else { - csource_metadata_modules.push_back(mod); + csource_modules.push_back(mod); } } else { - csource_metadata_modules.push_back(mod); + csource_modules.push_back(mod); } } if (target.defined()) { if (target->kind->name == "c") { - csource_metadata_modules.push_back(target_module); + csource_modules.push_back(target_module); + if (!csource_modules.empty()) { + target_module = CreateCSourceMetadataModule(csource_modules, target); + } } } - if (!csource_metadata_modules.empty()) { - target_module = CreateCSourceMetadataModule(csource_metadata_modules, target); - } - if (!binary_metadata_modules.empty()) { + if (!binary_modules.empty()) { runtime::Module binary_meta_mod = runtime::MetadataModuleCreate(params, sym_metadata); binary_meta_mod.Import(target_module); - for (const auto& it : binary_metadata_modules) { + for (const auto& it : binary_modules) { binary_meta_mod.Import(it); } return binary_meta_mod; @@ -142,15 +142,18 @@ runtime::Module SourceModuleCreate(std::string code, std::string fmt) { class CSourceModuleNode : public runtime::ModuleNode { public: CSourceModuleNode(const std::string& code, const std::string& fmt, - const Array& func_names, const std::string& symbol, - const Array& const_vars) - : code_(code), fmt_(fmt), symbol_(symbol), const_vars_(const_vars), func_names_(func_names) {} + const Array& func_names, const Array& const_vars) + : code_(code), fmt_(fmt), const_vars_(const_vars), func_names_(func_names) {} const char* type_key() const { return "c"; } PackedFunc GetFunction(const std::string& name, const ObjectPtr& sptr_to_self) final { + // Currently c-source module is used as demonstration purposes with binary metadata module + // that expects get_symbol interface. When c-source module is used as external module, it + // will only contain one function. However, when its used as an internal module (e.g., target + // "c") it can have many functions. if (name == "get_symbol") { return PackedFunc( - [sptr_to_self, this](TVMArgs args, TVMRetValue* rv) { *rv = this->symbol_; }); + [sptr_to_self, this](TVMArgs args, TVMRetValue* rv) { *rv = this->func_names_[0]; }); } else if (name == "get_const_vars") { return PackedFunc( [sptr_to_self, this](TVMArgs args, TVMRetValue* rv) { *rv = this->const_vars_; }); @@ -178,16 +181,15 @@ class CSourceModuleNode : public runtime::ModuleNode { protected: std::string code_; std::string fmt_; - std::string symbol_; Array const_vars_; Array func_names_; }; runtime::Module CSourceModuleCreate(const String& code, const String& fmt, - const Array& func_names, const String& symbol, + const Array& func_names, const Array& const_vars) { auto n = make_object(code.operator std::string(), fmt.operator std::string(), - func_names, symbol.operator std::string(), const_vars); + func_names, const_vars); return runtime::Module(n); } @@ -335,9 +337,9 @@ runtime::Module DeviceSourceModuleCreate( TVM_REGISTER_GLOBAL("runtime.SourceModuleCreate").set_body_typed(SourceModuleCreate); TVM_REGISTER_GLOBAL("runtime.CSourceModuleCreate") - .set_body_typed([](String code, String fmt, Array func_names, String symbol, + .set_body_typed([](String code, String fmt, Array func_names, Array const_vars) { - return CSourceModuleCreate(code, fmt, func_names, symbol, const_vars); + return CSourceModuleCreate(code, fmt, func_names, const_vars); }); TVM_REGISTER_GLOBAL("runtime.CreateCSourceMetadataModule") diff --git a/tests/python/relay/test_pass_partition_graph.py b/tests/python/relay/test_pass_partition_graph.py index 6b7d4ef17a5d..d8f674eeff34 100644 --- a/tests/python/relay/test_pass_partition_graph.py +++ b/tests/python/relay/test_pass_partition_graph.py @@ -172,7 +172,9 @@ def visit_call(self, call): return new_call -def check_result(mod, map_inputs, out_shape, result, tol=1e-5, ctx=tvm.cpu(), params=None): +def check_result( + mod, map_inputs, out_shape, result, tol=1e-5, target="llvm", ctx=tvm.cpu(), params=None +): if sys.platform == "win32": print("Skip test on Windows for now") return @@ -192,7 +194,7 @@ def update_lib(lib): return lib - def check_vm_result(target): + def check_vm_result(): compile_engine.get().clear() with tvm.transform.PassContext(opt_level=3): exe = relay.vm.compile(mod, target=target, params=params) @@ -206,7 +208,7 @@ def check_vm_result(target): for out, ref in zip(outs, results): tvm.testing.assert_allclose(out.asnumpy(), ref, rtol=tol, atol=tol) - def check_graph_runtime_result(target): + def check_graph_runtime_result(): compile_engine.get().clear() with tvm.transform.PassContext(opt_level=3): json, lib, param = relay.build(mod, target=target, params=params) @@ -226,10 +228,8 @@ def check_graph_runtime_result(target): out = rt_mod.get_output(idx, out) tvm.testing.assert_allclose(out.asnumpy(), results[idx], rtol=tol, atol=tol) - targets = ["llvm", "llvm -runtime=c --system-lib"] - for tgt in targets: - check_vm_result(tgt) - check_graph_runtime_result(tgt) + check_vm_result() + check_graph_runtime_result() def test_multi_node_compiler(): @@ -273,19 +273,23 @@ def test_multi_node_compiler(): map_inputs = {"w{}".format(i): w_data[i] for i in range(8)} map_inputs["x"] = x_data - check_result( - mod, - map_inputs, - (30, 10), - np.concatenate( - ( - ((x_data + w_data[0]) - w_data[1]) * w_data[2], - ((x_data + w_data[3]) - w_data[4]) * w_data[5], - x_data + w_data[6] - w_data[7], + + targets = ["llvm", "c -runtime=c --system-lib"] + for tgt in targets: + check_result( + mod, + map_inputs, + (30, 10), + np.concatenate( + ( + ((x_data + w_data[0]) - w_data[1]) * w_data[2], + ((x_data + w_data[3]) - w_data[4]) * w_data[5], + x_data + w_data[6] - w_data[7], + ), + axis=0, ), - axis=0, - ), - ) + target=tgt, + ) def test_extern_ccompiler_single_op(): diff --git a/tests/python/unittest/test_runtime_module_export.py b/tests/python/unittest/test_runtime_module_export.py index 6cc1288ca29e..af9a8ab38065 100644 --- a/tests/python/unittest/test_runtime_module_export.py +++ b/tests/python/unittest/test_runtime_module_export.py @@ -58,7 +58,7 @@ def generate_engine_module(): import tvm.runtime._ffi_api gen_engine_header() - csource_module = tvm.runtime._ffi_api.CSourceModuleCreate(code, "cc", [], "", None) + csource_module = tvm.runtime._ffi_api.CSourceModuleCreate(code, "cc", [], None) return csource_module From 7d25e9e9d779926185b755c0c9c30c7ff0de03f0 Mon Sep 17 00:00:00 2001 From: Manupa Karunaratne Date: Wed, 16 Dec 2020 19:47:14 +0000 Subject: [PATCH 11/18] Created CSourceMetaData module for model metadata * addressed a missed comment Change-Id: I65e65c30bc780a946f3f1b8372c40a49a5c20582 --- src/target/source/source_module.cc | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/target/source/source_module.cc b/src/target/source/source_module.cc index 31b3a521a0bb..2ba5a0a6fcc2 100644 --- a/src/target/source/source_module.cc +++ b/src/target/source/source_module.cc @@ -48,9 +48,11 @@ using runtime::SaveBinaryToFile; * codegens, such as graph runtime codegen and the vm compiler. * * \param params The metadata for initialization of all modules. - * \param modules All the modules that needs to be imported inside the metadata module(s). - * \param target The target that all the modules are compiled for - * \return The created metadata module that manages initialization of metadata. + * \param target_module the internal module that is compiled by tvm. + * \param ext_modules The external modules that needs to be imported inside the metadata + * module(s). + * \param target The target that all the modules are compiled for \return The created + * metadata module that manages initialization of metadata. */ runtime::Module CreateMetadataModule( const std::unordered_map& params, From 18428d6801c19cab1fc04c66f61313b4f0ebb6f9 Mon Sep 17 00:00:00 2001 From: Manupa Karunaratne Date: Thu, 17 Dec 2020 16:01:58 +0000 Subject: [PATCH 12/18] Created CSourceMetaData module for model metadata * te build interface should only include c-source metadata if targetting "c" Change-Id: Ie23cb8c6231c1f2de6d2827084774e3510288098 --- python/tvm/driver/build_module.py | 6 +++++- tests/python/unittest/test_crt.py | 1 - 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/python/tvm/driver/build_module.py b/python/tvm/driver/build_module.py index b1b4a0d28114..47b2d75a4428 100644 --- a/python/tvm/driver/build_module.py +++ b/python/tvm/driver/build_module.py @@ -427,7 +427,11 @@ def build(inputs, args=None, target=None, target_host=None, name="default_functi if not isinstance(target_host, Target): target_host = Target(target_host) - if "system-lib" in target_host.attrs and target_host.attrs["system-lib"].value == 1: + if ( + "system-lib" in target_host.attrs + and target_host.attrs["system-lib"].value == 1 + and target_host.kind.name == "c" + ): create_csource_metadata_module = tvm._ffi.get_global_func( "runtime.CreateCSourceMetadataModule" ) diff --git a/tests/python/unittest/test_crt.py b/tests/python/unittest/test_crt.py index 07a4cfcd8b7d..1d84d4ecf16e 100644 --- a/tests/python/unittest/test_crt.py +++ b/tests/python/unittest/test_crt.py @@ -49,7 +49,6 @@ def _make_sess_from_op(workspace, op_name, sched, arg_bufs): def _make_session(workspace, mod): compiler = tvm.micro.DefaultCompiler(target=TARGET) opts = tvm.micro.default_options(os.path.join(tvm.micro.CRT_ROOT_DIR, "host")) - micro_binary = tvm.micro.build_static_runtime( # the x86 compiler *expects* you to give the exact same dictionary for both # lib_opts and bin_opts. so the library compiler is mutating lib_opts and From 947edaabc609db677f39e1d517b9d28ab99780f0 Mon Sep 17 00:00:00 2001 From: Manupa Karunaratne Date: Thu, 17 Dec 2020 18:17:12 +0000 Subject: [PATCH 13/18] Created CSourceMetaData module for model metadata * c_source modules should be created only if they are non-DSO exportable Change-Id: I53f2f8e9caa41f133446f8881b9dc541ebeee8cc --- src/relay/backend/contrib/dnnl/codegen.cc | 2 +- src/target/source/source_module.cc | 32 ++++++++++------------- 2 files changed, 15 insertions(+), 19 deletions(-) diff --git a/src/relay/backend/contrib/dnnl/codegen.cc b/src/relay/backend/contrib/dnnl/codegen.cc index 32723ce5efe2..c9a58282d13e 100644 --- a/src/relay/backend/contrib/dnnl/codegen.cc +++ b/src/relay/backend/contrib/dnnl/codegen.cc @@ -414,7 +414,7 @@ class DNNLModuleCodegen : public CSourceModuleCodegenBase { const auto* pf = runtime::Registry::Get("runtime.CSourceModuleCreate"); ICHECK(pf != nullptr) << "Cannot find csource module to create the external runtime module"; // TODO(@manupa-arm): pass the function names to enable system-lib creation - return (*pf)(code, "c", Array{}, variables); + return (*pf)(code, "c", Array{sym}, variables); } private: diff --git a/src/target/source/source_module.cc b/src/target/source/source_module.cc index 2ba5a0a6fcc2..c5e62e15df69 100644 --- a/src/target/source/source_module.cc +++ b/src/target/source/source_module.cc @@ -69,39 +69,35 @@ runtime::Module CreateMetadataModule( for (tvm::runtime::Module mod : ext_modules) { auto pf_sym = mod.GetFunction("get_symbol"); auto pf_var = mod.GetFunction("get_const_vars"); + std::vector arrays; if (pf_sym != nullptr && pf_var != nullptr) { String symbol = pf_sym(); Array variables = pf_var(); - std::vector arrays; for (size_t i = 0; i < variables.size(); i++) { arrays.push_back(variables[i].operator std::string()); } ICHECK_EQ(sym_metadata.count(symbol), 0U) << "Found duplicated symbol: " << symbol; sym_metadata[symbol] = arrays; - // We only need loading of serialized constant data - // if there are constants present and required by the - // runtime module to be initialized by the binary - // metadata module. If not rest of the modules are - // wrapped in c-source metadata module. - - // TODO(@manupa-arm) : we should be able to use csource_metadata - // if the variables are empty - if (!variables.empty() || !DSOExportable(mod) || target->kind->name == "llvm") { - binary_modules.push_back(mod); - } else { - csource_modules.push_back(mod); - } - } else { + } + // We only need loading of serialized constant data + // if there are constants present and required by the + // runtime module to be initialized by the binary + // metadata module. If not rest of the modules are + // wrapped in c-source metadata module. + + // TODO(@manupa-arm) : we should be able to use csource_metadata + // if the variables are empty when all the runtime modules implement get_func_names + if (arrays.empty() && DSOExportable(mod) && target->kind->name == "c") { csource_modules.push_back(mod); + } else { + binary_modules.push_back(mod); } } if (target.defined()) { if (target->kind->name == "c") { csource_modules.push_back(target_module); - if (!csource_modules.empty()) { - target_module = CreateCSourceMetadataModule(csource_modules, target); - } + target_module = CreateCSourceMetadataModule(csource_modules, target); } } From 9480b2d15c473880d8a0f2e5c4dd9bdb4de03f6a Mon Sep 17 00:00:00 2001 From: Manupa Karunaratne Date: Fri, 18 Dec 2020 06:41:17 +0000 Subject: [PATCH 14/18] Created CSourceMetaData module for model metadata * documetation misalignment in source_module.cc Change-Id: I83e2c29b1f2980ca65a694304720dc58a5cb7879 --- src/target/source/source_module.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/target/source/source_module.cc b/src/target/source/source_module.cc index c5e62e15df69..b048a6dddd89 100644 --- a/src/target/source/source_module.cc +++ b/src/target/source/source_module.cc @@ -51,8 +51,8 @@ using runtime::SaveBinaryToFile; * \param target_module the internal module that is compiled by tvm. * \param ext_modules The external modules that needs to be imported inside the metadata * module(s). - * \param target The target that all the modules are compiled for \return The created - * metadata module that manages initialization of metadata. + * \param target The target that all the modules are compiled for + * \return The created metadata module that manages initialization of metadata. */ runtime::Module CreateMetadataModule( const std::unordered_map& params, From d6227789de0be92f7bebcfb46bbcc1aace2868b8 Mon Sep 17 00:00:00 2001 From: Manupa Karunaratne Date: Fri, 18 Dec 2020 09:01:21 +0000 Subject: [PATCH 15/18] Created CSourceMetaData module for model metadata * typo : same object file written as a dependency in the Makefile Change-Id: I8becc4196d286cfb6372768687b3c836799dcb78 --- apps/bundle_deploy/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/bundle_deploy/Makefile b/apps/bundle_deploy/Makefile index f4ef00de6df2..8a5f1cf95571 100644 --- a/apps/bundle_deploy/Makefile +++ b/apps/bundle_deploy/Makefile @@ -135,7 +135,7 @@ $(build_dir)/bundle_c.so: bundle.c $(build_dir)/model_c.o ${build_dir}/crt/libme $(QUIET)mkdir -p $(@D) $(QUIET)gcc -shared $(PKG_CFLAGS) -fvisibility=hidden -o $@ $^ $(PKG_LDFLAGS) $(BACKTRACE_LDFLAGS) $(BACKTRACE_CFLAGS) -$(build_dir)/test_bundle.so: bundle.cc runtime.cc $(build_dir)/test_model_cpp.o $(build_dir)/test_model_cpp.o +$(build_dir)/test_bundle.so: bundle.cc runtime.cc $(build_dir)/test_model_cpp.o $(QUIET)mkdir -p $(@D) $(QUIET)g++ -shared $(PKG_CXXFLAGS) -fvisibility=hidden -o $@ $^ $(PKG_LDFLAGS) From aa5578f7e8911804ca94a93a2c3acfb85cc45fba Mon Sep 17 00:00:00 2001 From: Manupa Karunaratne Date: Fri, 18 Dec 2020 15:43:54 +0000 Subject: [PATCH 16/18] Created CSourceMetaData module for model metadata * removed unused param from a brief Change-Id: Ie4db2aca3b7ea147bd8c65ef5d1cc2146f530e76 --- src/target/source/codegen_source_base.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/target/source/codegen_source_base.h b/src/target/source/codegen_source_base.h index 28aa8f0765d7..ed838f825812 100644 --- a/src/target/source/codegen_source_base.h +++ b/src/target/source/codegen_source_base.h @@ -137,7 +137,6 @@ runtime::Module SourceModuleCreate(std::string code, std::string fmt); * \param code The code to be viewed. * \param fmt The code format. * \param func_names The name of functions inside the runtime module. - * \param symbol The symbol that the c source module represents. * \param const_vars. The constant variables that the c source module needs. * \return The created module. */ From 30e787d5f3d9352f30c572eb7c1799e69c2e7577 Mon Sep 17 00:00:00 2001 From: Manupa Karunaratne Date: Fri, 18 Dec 2020 19:07:27 +0000 Subject: [PATCH 17/18] Created CSourceMetaData module for model metadata * made export library use c as the format for c source modules Change-Id: Ie2fd6204414f0fa43988a8082d18af7a3225e237 --- python/tvm/micro/build.py | 4 ++-- python/tvm/runtime/module.py | 6 +++--- src/target/source/source_module.cc | 9 ++++++--- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/python/tvm/micro/build.py b/python/tvm/micro/build.py index 08d8c2d3cb85..cad385b9b190 100644 --- a/python/tvm/micro/build.py +++ b/python/tvm/micro/build.py @@ -74,8 +74,8 @@ def path(self): _CRT_DEFAULT_OPTIONS = { "cflags": ["-std=c11"] + _COMMON_CFLAGS, - "ccflags": ["-std=gnu++11"] + _COMMON_CFLAGS, - "ldflags": ["-std=gnu++11"], + "ccflags": ["-std=c++11"] + _COMMON_CFLAGS, + "ldflags": ["-std=c++11"], "include_dirs": [ f"{TVM_ROOT_DIR}/include", f"{TVM_ROOT_DIR}/3rdparty/dlpack/include", diff --git a/python/tvm/runtime/module.py b/python/tvm/runtime/module.py index 5a188a795781..63267969ab4e 100644 --- a/python/tvm/runtime/module.py +++ b/python/tvm/runtime/module.py @@ -313,7 +313,7 @@ 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 = "cc" + object_format = "c" has_c_module = True else: object_format = fcompile.object_format @@ -322,7 +322,7 @@ def export_library(self, file_name, fcompile=None, addons=None, workspace_dir=No object_format = "o" else: assert module.type_key == "c" - object_format = "cc" + object_format = "c" has_c_module = True path_obj = os.path.join(workspace_dir, f"lib{index}.{object_format}") module.save(path_obj) @@ -352,7 +352,7 @@ def export_library(self, file_name, fcompile=None, addons=None, workspace_dir=No m.save(path_obj) files.append(path_obj) else: - path_cc = os.path.join(workspace_dir, "devc.cc") + path_cc = os.path.join(workspace_dir, "devc.c") with open(path_cc, "w") as f: f.write(_ffi_api.ModulePackImportsToC(self, is_system_lib)) files.append(path_cc) diff --git a/src/target/source/source_module.cc b/src/target/source/source_module.cc index b048a6dddd89..e3ba00b79c18 100644 --- a/src/target/source/source_module.cc +++ b/src/target/source/source_module.cc @@ -168,7 +168,7 @@ class CSourceModuleNode : 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 == "cc") { + if (fmt == "c") { ICHECK_NE(code_.length(), 0); SaveBinaryToFile(file_name, code_); } else { @@ -208,7 +208,7 @@ class CSourceMetadataModuleNode : 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 == "cc") { + if (fmt == "c") { auto code_str = code_.str(); ICHECK_NE(code_str.length(), 0); SaveBinaryToFile(file_name, code_str); @@ -226,7 +226,10 @@ class CSourceMetadataModuleNode : public runtime::ModuleNode { void CreateFuncRegistry() { code_ << "#include \n"; for (const auto& fname : func_names_) { - code_ << "extern \"C\" TVM_DLL int32_t " << fname.data(); + code_ << "#ifdef __cplusplus\n"; + code_ << "extern \"C\"\n"; + code_ << "#endif\n"; + code_ << "TVM_DLL int32_t " << fname.data(); code_ << "(TVMValue* args, int* type_code, int num_args, TVMValue* out_value, int* " "out_type_code);\n"; } From df16f22730bed2545e0fbab4c61da488e919b973 Mon Sep 17 00:00:00 2001 From: Manupa Karunaratne Date: Sat, 19 Dec 2020 05:53:57 +0000 Subject: [PATCH 18/18] Created CSourceMetaData module for model metadata *addressed a nit Change-Id: I6084b8c06ddfaaece295439dbab589e6e202b664 --- src/target/source/source_module.cc | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/target/source/source_module.cc b/src/target/source/source_module.cc index e3ba00b79c18..4b4770a79816 100644 --- a/src/target/source/source_module.cc +++ b/src/target/source/source_module.cc @@ -94,11 +94,9 @@ runtime::Module CreateMetadataModule( } } - if (target.defined()) { - if (target->kind->name == "c") { - csource_modules.push_back(target_module); - target_module = CreateCSourceMetadataModule(csource_modules, target); - } + if (target.defined() && target->kind->name == "c") { + csource_modules.push_back(target_module); + target_module = CreateCSourceMetadataModule(csource_modules, target); } if (!binary_modules.empty()) {