Skip to content

Commit 31279d8

Browse files
committed
[FFI] Formalize ffi.Module
This PR formalizes original runtime::Module into ffi as ffi.Module and cleans the APIs around it. The goal is to stablize the Module API as extra API that can benefit the overall ffi interactions. We also refactors the c++ code that depends on the Module.
1 parent 537923a commit 31279d8

File tree

153 files changed

+2131
-1944
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

153 files changed

+2131
-1944
lines changed

apps/android_rpc/app/src/main/jni/tvm_runtime.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,20 +37,21 @@
3737
#include "../ffi/src/ffi/container.cc"
3838
#include "../ffi/src/ffi/dtype.cc"
3939
#include "../ffi/src/ffi/error.cc"
40+
#include "../ffi/src/ffi/extra/library_module.cc"
41+
#include "../ffi/src/ffi/extra/library_module_dynamic_lib.cc"
42+
#include "../ffi/src/ffi/extra/library_module_system_lib.cc"
43+
#include "../ffi/src/ffi/extra/module.cc"
4044
#include "../ffi/src/ffi/function.cc"
4145
#include "../ffi/src/ffi/ndarray.cc"
4246
#include "../ffi/src/ffi/object.cc"
4347
#include "../ffi/src/ffi/testing.cc"
4448
#include "../ffi/src/ffi/traceback.cc"
4549
#include "../src/runtime/cpu_device_api.cc"
4650
#include "../src/runtime/device_api.cc"
47-
#include "../src/runtime/dso_library.cc"
4851
#include "../src/runtime/file_utils.cc"
49-
#include "../src/runtime/library_module.cc"
5052
#include "../src/runtime/logging.cc"
5153
#include "../src/runtime/memory/memory_manager.cc"
5254
#include "../src/runtime/minrpc/minrpc_logger.cc"
53-
#include "../src/runtime/module.cc"
5455
#include "../src/runtime/ndarray.cc"
5556
#include "../src/runtime/profiling.cc"
5657
#include "../src/runtime/registry.cc"
@@ -62,7 +63,6 @@
6263
#include "../src/runtime/rpc/rpc_server_env.cc"
6364
#include "../src/runtime/rpc/rpc_session.cc"
6465
#include "../src/runtime/rpc/rpc_socket_impl.cc"
65-
#include "../src/runtime/system_library.cc"
6666
#include "../src/runtime/thread_pool.cc"
6767
#include "../src/runtime/threading_backend.cc"
6868
#include "../src/runtime/workspace_pool.cc"

apps/cpp_rpc/rpc_env.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ RPCEnv::RPCEnv(const std::string& wd) {
147147
std::string file_name = this->GetPath(path);
148148
file_name = BuildSharedLibrary(file_name);
149149
LOG(INFO) << "Load module from " << file_name << " ...";
150-
return Module::LoadFromFile(file_name, "");
150+
return ffi::Module::LoadFromFile(file_name);
151151
}));
152152

153153
ffi::Function::SetGlobal("tvm.rpc.server.download_linked_module",

apps/hexagon_launcher/launcher_core.cc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ const tvm::ffi::Function get_runtime_func(const std::string& name) {
144144
}
145145

146146
const tvm::ffi::Function get_module_func(tvm::runtime::Module module, const std::string& name) {
147-
return module.GetFunction(name, false);
147+
return module->GetFunction(name, false).value_or(tvm::ffi::Function());
148148
}
149149

150150
void reset_device_api() {
@@ -153,7 +153,7 @@ void reset_device_api() {
153153
}
154154

155155
tvm::runtime::Module load_module(const std::string& file_name) {
156-
static const tvm::ffi::Function loader = get_runtime_func("runtime.module.loadfile_hexagon");
156+
static const tvm::ffi::Function loader = get_runtime_func("ffi.Module.load_from_file.hexagon");
157157
tvm::ffi::Any rv = loader(file_name);
158158
if (rv.type_code() == kTVMModuleHandle) {
159159
ICHECK_EQ(rv.type_code(), kTVMModuleHandle)

apps/ios_rpc/tvmrpc/TVMRuntime.mm

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333

3434
#if defined(USE_CUSTOM_DSO_LOADER) && USE_CUSTOM_DSO_LOADER == 1
3535
// internal TVM header to achieve Library class
36-
#include <../../../src/runtime/library_module.h>
36+
#include <../../../ffi/src/ffi/extra/library_module.h>
3737
#include <custom_dlfcn.h>
3838
#endif
3939

@@ -70,7 +70,7 @@ void LogMessageImpl(const std::string& file, int lineno, int level, const std::s
7070
NSBundle* bundle = [NSBundle mainBundle];
7171
base = [[bundle privateFrameworksPath] stringByAppendingPathComponent:@"tvm"];
7272

73-
if (tvm::ffi::Function::GetGlobal("runtime.module.loadfile_dylib_custom")) {
73+
if (tvm::ffi::Function::GetGlobal("ffi.Module.load_from_file.dylib_custom")) {
7474
// Custom dso loader is present. Will use it.
7575
base = NSTemporaryDirectory();
7676
fmt = "dylib_custom";
@@ -114,11 +114,11 @@ void Init(const std::string& name) {
114114
// Add UnsignedDSOLoader plugin in global registry
115115
TVM_FFI_STATIC_INIT_BLOCK({
116116
namespace refl = tvm::ffi::reflection;
117-
refl::GlobalDef().def_packed("runtime.module.loadfile_dylib_custom",
117+
refl::GlobalDef().def_packed("ffi.Module.load_from_file.dylib_custom",
118118
[](ffi::PackedArgs args, ffi::Any* rv) {
119119
auto n = make_object<UnsignedDSOLoader>();
120120
n->Init(args[0]);
121-
*rv = CreateModuleFromLibrary(n);
121+
*rv = tvm::ffi::CreateLibraryModule(n);
122122
});
123123
});
124124

ffi/CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,10 @@ if (TVM_FFI_USE_EXTRA_CXX_API)
6969
"${CMAKE_CURRENT_SOURCE_DIR}/src/ffi/extra/json_writer.cc"
7070
"${CMAKE_CURRENT_SOURCE_DIR}/src/ffi/extra/serialization.cc"
7171
"${CMAKE_CURRENT_SOURCE_DIR}/src/ffi/extra/reflection_extra.cc"
72+
"${CMAKE_CURRENT_SOURCE_DIR}/src/ffi/extra/module.cc"
73+
"${CMAKE_CURRENT_SOURCE_DIR}/src/ffi/extra/library_module.cc"
74+
"${CMAKE_CURRENT_SOURCE_DIR}/src/ffi/extra/library_module_system_lib.cc"
75+
"${CMAKE_CURRENT_SOURCE_DIR}/src/ffi/extra/library_module_dynamic_lib.cc"
7276
)
7377
endif()
7478

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
/*!
20+
* \file tvm/ffi/extra/c_env_api.h
21+
* \brief Extra environment API.
22+
*/
23+
#ifndef TVM_FFI_EXTRA_C_ENV_API_H_
24+
#define TVM_FFI_EXTRA_C_ENV_API_H_
25+
26+
#include <tvm/ffi/c_api.h>
27+
28+
#ifdef __cplusplus
29+
extern "C" {
30+
#endif
31+
32+
/*!
33+
* \brief FFI function to lookup a function from a module's imports.
34+
*
35+
* This is a helper function that is used by generated code.
36+
*
37+
* \param library_ctx The library context module handle.
38+
* \param func_name The name of the function.
39+
* \param out The result function.
40+
* \note The returned function is a weak reference that is cached/owned by the module.
41+
* \return 0 when no error is thrown, -1 when failure happens
42+
*/
43+
TVM_FFI_DLL int TVMFFIEnvLookupFromImports(TVMFFIObjectHandle library_ctx, const char* func_name,
44+
TVMFFIObjectHandle* out);
45+
46+
/*
47+
* \brief Register a symbol value that will be initialized when a library with the symbol is loaded.
48+
*
49+
* This function can be used to make context functions to be available in the library
50+
* module that wants to avoid an explicit link dependency
51+
*
52+
* \param name The name of the symbol.
53+
* \param symbol The symbol to register.
54+
* \return 0 when success, nonzero when failure happens
55+
*/
56+
TVM_FFI_DLL int TVMFFIEnvRegisterContextSymbol(const char* name, void* symbol);
57+
58+
/*!
59+
* \brief Register a symbol that will be initialized when a system library is loaded.
60+
*
61+
* \param name The name of the symbol.
62+
* \param symbol The symbol to register.
63+
* \return 0 when success, nonzero when failure happens
64+
*/
65+
TVM_FFI_DLL int TVMFFIEnvRegisterSystemLibSymbol(const char* name, void* symbol);
66+
67+
#ifdef __cplusplus
68+
} // extern "C"
69+
#endif
70+
#endif // TVM_FFI_EXTRA_C_ENV_API_H_

ffi/include/tvm/ffi/extra/module.h

Lines changed: 224 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,224 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
/*!
20+
* \file tvm/ffi/module.h
21+
* \brief A managed dynamic module in the TVM FFI.
22+
*/
23+
#ifndef TVM_FFI_EXTRA_MODULE_H_
24+
#define TVM_FFI_EXTRA_MODULE_H_
25+
26+
#include <tvm/ffi/container/array.h>
27+
#include <tvm/ffi/container/map.h>
28+
#include <tvm/ffi/extra/base.h>
29+
#include <tvm/ffi/function.h>
30+
31+
namespace tvm {
32+
namespace ffi {
33+
34+
// forward declare Module
35+
class Module;
36+
37+
/*!
38+
* \brief A module that can dynamically load ffi::Functions or exportable source code.
39+
*/
40+
class TVM_FFI_EXTRA_CXX_API ModuleObj : public Object {
41+
public:
42+
/*!
43+
* \return The per module type key.
44+
* \note This key is used to for serializing custom modules.
45+
*/
46+
virtual const char* kind() const = 0;
47+
/*!
48+
* \brief Get the property mask of the module.
49+
* \return The property mask of the module.
50+
*
51+
* \sa Module::ModulePropertyMask
52+
*/
53+
virtual int GetPropertyMask() const { return 0b000; }
54+
/*!
55+
* \brief Get a ffi::Function from the module.
56+
* \param name The name of the function.
57+
* \return The function.
58+
*/
59+
virtual Optional<Function> GetFunction(const String& name) = 0;
60+
/*!
61+
* \brief Returns true if this module has a definition for a function of \p name.
62+
*
63+
* Note that even if this function returns true the corresponding \p GetFunction result
64+
* may be nullptr if the function is not yet callable without further compilation.
65+
*
66+
* The default implementation just checks if \p GetFunction is non-null.
67+
* \param name The name of the function.
68+
* \return True if the module implements the function, false otherwise.
69+
*/
70+
virtual bool ImplementsFunction(const String& name) { return GetFunction(name).defined(); }
71+
/*!
72+
* \brief Write the current module to file with given format (for further compilation).
73+
*
74+
* \param file_name The file to be saved to.
75+
* \param format The format of the file.
76+
*
77+
* \note This function is mainly used by modules that
78+
*/
79+
virtual void WriteToFile(const String& file_name, const String& format) const {
80+
TVM_FFI_THROW(RuntimeError) << "Module[" << kind() << "] does not support WriteToFile";
81+
}
82+
/*!
83+
* \brief Get the possible write formats of the module, when available.
84+
* \return Possible write formats when available.
85+
*/
86+
virtual Array<String> GetWriteFormats() const { return Array<String>(); }
87+
/*!
88+
* \brief Serialize the the module to bytes.
89+
* \return The serialized module.
90+
*/
91+
virtual Bytes SaveToBytes() const {
92+
TVM_FFI_THROW(RuntimeError) << "Module[" << kind() << "] does not support SaveToBytes";
93+
TVM_FFI_UNREACHABLE();
94+
}
95+
/*!
96+
* \brief Get the source code of module, when available.
97+
* \param format Format of the source code, can be empty by default.
98+
* \return Possible source code when available, or empty string if not available.
99+
*/
100+
virtual String InspectSource(const String& format = "") const { return String(); }
101+
/*!
102+
* \brief Import another module.
103+
* \param other The module to import.
104+
*/
105+
virtual void ImportModule(const Module& other);
106+
/*!
107+
* \brief Clear all imported modules.
108+
*/
109+
virtual void ClearImports();
110+
/*!
111+
* \brief Overloaded function to optionally query from imports.
112+
* \param name The name of the function.
113+
* \param query_imports Whether to query imported modules.
114+
* \return The function.
115+
*/
116+
Optional<Function> GetFunction(const String& name, bool query_imports);
117+
/*!
118+
* \brief Overloaded function to optionally query from imports.
119+
* \param name The name of the function.
120+
* \param query_imports Whether to query imported modules.
121+
* \return True if the module implements the function, false otherwise.
122+
*/
123+
bool ImplementsFunction(const String& name, bool query_imports);
124+
/*!
125+
* \brief Get the imports of the module.
126+
* \return The imports of the module.
127+
* \note Note the signature is not part of the public API.
128+
*/
129+
const Array<Any>& imports() const { return this->imports_; }
130+
131+
struct InternalUnsafe;
132+
133+
static constexpr const int32_t _type_index = TypeIndex::kTVMFFIModule;
134+
static constexpr const char* _type_key = StaticTypeKey::kTVMFFIModule;
135+
static const constexpr bool _type_final = true;
136+
TVM_FFI_DECLARE_STATIC_OBJECT_INFO(ModuleObj, Object);
137+
138+
protected:
139+
friend struct InternalUnsafe;
140+
141+
/*!
142+
* \brief The modules that this module depends on.
143+
* \note Use ObjectRef to avoid circular dep on Module.
144+
*/
145+
Array<Any> imports_;
146+
147+
private:
148+
/*!
149+
* \brief cache used by TVMFFIModuleLookupFromImports
150+
*/
151+
Map<String, ffi::Function> import_lookup_cache_;
152+
};
153+
154+
/*!
155+
* \brief Reference to module object.
156+
*/
157+
class Module : public ObjectRef {
158+
public:
159+
/*!
160+
* \brief Property of ffi::Module
161+
*/
162+
enum ModulePropertyMask : int {
163+
/*!
164+
* \brief The module can be serialized to bytes.
165+
*
166+
* This prooperty indicates that module implements SaveToBytes.
167+
* The system also registers a GlobalDef function
168+
* `ffi.Module.load_from_bytes.<kind>` with signature (Bytes) -> Module.
169+
*/
170+
kBinarySerializable = 0b001,
171+
/*!
172+
* \brief The module can directly get runnable functions.
173+
*
174+
* This property indicates that module implements GetFunction that returns
175+
* runnable ffi::Functions.
176+
*/
177+
kRunnable = 0b010,
178+
/*!
179+
* \brief The module can be exported to a object file or source file that then be compiled.
180+
*
181+
* This property indicates that module implements WriteToFile with a given format
182+
* that can be queried by GetLibExportFormat.
183+
*
184+
* Examples include modules that can be exported to .o, .cc, .cu files.
185+
*
186+
* Such modules can be exported, compiled and loaded back as a dynamic library module.
187+
*/
188+
kCompilationExportable = 0b100
189+
};
190+
191+
/*!
192+
* \brief Load a module from file.
193+
* \param file_name The name of the host function module.
194+
* \param format The format of the file.
195+
* \note This function won't load the import relationship.
196+
* Re-create import relationship by calling Import.
197+
*/
198+
TVM_FFI_EXTRA_CXX_API static Module LoadFromFile(const String& file_name);
199+
/*
200+
* \brief Query context symbols that is registered via TVMEnvRegisterSymbols.
201+
* \param callback The callback to be called with the symbol name and address.
202+
* \note This helper can be used to implement custom Module that needs to access context symbols.
203+
*/
204+
TVM_FFI_EXTRA_CXX_API static void VisitContextSymbols(
205+
const ffi::TypedFunction<void(String, void*)>& callback);
206+
207+
TVM_FFI_DEFINE_MUTABLE_NOTNULLABLE_OBJECT_REF_METHODS(Module, ObjectRef, ModuleObj);
208+
};
209+
210+
/*
211+
* \brief Symbols for library module.
212+
*/
213+
namespace symbol {
214+
/*! \brief Global variable to store context pointer for a library module. */
215+
constexpr const char* tvm_ffi_library_ctx = "__tvm_ffi_library_ctx";
216+
/*! \brief Global variable to store binary data alongside a library module. */
217+
constexpr const char* tvm_ffi_library_bin = "__tvm_ffi_library_bin";
218+
/*! \brief Default entry function of a library module. */
219+
constexpr const char* tvm_ffi_main = "__tvm_ffi_main__";
220+
} // namespace symbol
221+
} // namespace ffi
222+
} // namespace tvm
223+
224+
#endif // TVM_FFI_EXTRA_MODULE_H_

0 commit comments

Comments
 (0)