参考文档
Module(模块)
在TVM中Module是用来表示 the compiled object (已编译对象)的容器。在TVM可以在两个地方看到Module:
- python/tvm/module.py
- src/runtime/module.cc
下面将分别介绍Module的Python层和C++层的相关代码。
Python层
Module的Python层主要是C++层的外层封装,以方便Python用户的使用。
python/tvm/module.py
def enabled(target):
"""Whether module runtime is enabled for target
"""
return _Enabled(target)
C++层
作为Module的C++层主要是提供了Module的具体实现细节。
下面用Module类下面的RuntimeEnabled方法来讲解C++函数是如何注册到Python类中的。
TVM_REGISTER_GLOBAL("module._Enabled")
.set_body([](TVMArgs args, TVMRetValue *ret) {
*ret = RuntimeEnabled(args[0]);
});
/* 解析:
TVM_REGISTER_GLOBAL创建一个tvm::runtime::Registry::Register对象实例之后,调用set_body函数设置具体的执行函数。
另外值得注意的是这段代码使用了lambda表达式作为函数的参数
*/
参考源代码1:set_body函数体
/src/runtime/registry.cc
Registry& Registry::set_body(PackedFunc f) { // NOLINT(*)
func_ = f;
return *this;
}
/*!
* \brief Register a function globally.
*/
#define TVM_REGISTER_GLOBAL(OpName) \
TVM_STR_CONCAT(TVM_FUNC_REG_VAR_DEF, __COUNTER__) = \
::tvm::runtime::Registry::Register(OpName)
/* 解析:
__COUNTER__是一个编译器内建的宏,参考文档1中有详细的解释。简单来解释就是__COUNTER__和##连接符配合使用
(__COUNTER__从0开始递增),用来生成具有唯一性的标识符。在TVM中使用__COUNTER__主要是为了保证多次注册的函数标识符的唯一性。
结合后面对TVM_FUNC_REG_VAR_DEF的理解来看TVM_REGISTER_GLOBAL的功能就是调用tvm::runtime::Registry::Register(OpName)
赋给了一个tvm::runtime::Registry&类型的变量
*/
#define TVM_STR_CONCAT_(__x, __y) __x##__y
#define TVM_STR_CONCAT(__x, __y) TVM_STR_CONCAT_(__x, __y)
#define TVM_FUNC_REG_VAR_DEF \
static TVM_ATTRIBUTE_UNUSED ::tvm::runtime::Registry& __mk_ ## TVM
/* 解析:
##在C++中是一个连接符号,用于连接符号前后的字符串
TVM_ATTRIBUTE_UNUSED是一个GCC特有的函数属性符,属于编译制导语法
*/
#if defined(__GNUC__)
#define TVM_ATTRIBUTE_UNUSED __attribute__((unused))
#else
#define TVM_ATTRIBUTE_UNUSED
#endif
/* 解析:
__attribute__((unused))为GCC编译器特有,其他编译器可能不存在这个函数属性
__attribute__((unused))的用法是告诉编译器这个函数可能不会被使用,让编译器取消对这个函数的编译警告
*/