1 通过导入模块初始化
1) 在tvm的package的__init__.py中,有下面几个和初始化相关的模块导入:
from ._ffi.runtime_ctypes import TypeCode
from ._ffi.function import Function
from ._ffi.base import TVMError, __version__
from .api import *
2) 导入tvm相关链接库
2 在tvm/_ffi/runtime_ctypes.py中,有from .base import _LIB, check_call,在base模块中找到相关语句如下:
def _load_lib():
lib_path = libinfo.find_lib_path()
lib = ctypes.CDLL(lib_path[0], ctypes.RTLD_GLOBAL)
return lib, os.path.basename(lib_path[0])
3 _LIB, _LIB_NAME = _load_lib()
load lib的时候主要用了python的ctypes.CDLL接口,在mac上做的实验结果显示lib_path为:
tvm/build/libtvm.dylib
tvm/build/libtvm_runtime.dylib
4 将c接口设置成python模块的内置函数
在tvm的各个模块中,可以发现如下的代码:
_init_api("tvm.api")
_init_api("tvm.ir_pass")
_init_api("tvm.make")
_init_api("tvm.arith")
_init_api("tvm.module")
_init_api("tvm.schedule")
_init_api("tvm.codegen")
_init_api("tvm.contrib.nnpack")
_init_api("tvm.contrib.random")
以其中的_init_api("tvm.api")为例,它会在from .api import *的时候被执行,具体做的工作如下:
1) 获取注册过的c接口名称
通过list_global_func_names中的_LIB.TVMFuncListGlobalNames来获取所有注册过的c接口名称
2) 通过注册名称获取相应的python接口
通过_LIB.TVMFuncGetGlobal来根据c接口名称得到其相应的函数句柄,再将其封装到一个python函数f中
3) 通过setattr注册进python的相关模块中
相关代码如下所示:
for name in list_global_func_names():
if prefix == "api":
fname = name
if name.startswith("_"):
target_module = sys.modules["tvm._api_internal"]
else:
target_module = module
else:
if not name.startswith(prefix):
continue
fname = name[len(prefix)+1:]
target_module = module
if fname.find(".") != -1:
continue
f = get_global_func(name)
ff = _get_api(f)
ff.__name__ = fname
ff.__doc__ = ("TVM PackedFunc %s. " % fname)
setattr(target_module, ff.__name__, ff)