TVM设备添加以及代码生成
因为要添加的设备是一种类似于GPU的加速卡,TVM中提供了对GPU编译器的各种支持,有openCl,OpenGL和CUDA等,这里我们选取比较熟悉的CUDA进行模仿生成。从总体上来看,TVM是一个多层的结构
从上一个文档(TVM调试)中,基本可以发现,TVM在python这一层提供了相关的设备接口,然后使用tvm.build真正的编译,然后调用get_source函数来获得想要的源码(或者IR,比如llvm选项提供的是LLVM的IR,或者PTX选项提供的就是NVPTX类型的IR)。
因此,添加新设备(device)推测的步骤就是:
- 补全相应的python接口
- 找到python和C交互的接口
- 正确维护中间代码的IR pass变换中新设备引入的特性
- 代码生成对新设备和新特性的支持
- 添加编译选项支持(非必须)
以下就分别就这4个步骤进行介绍。
1. 补全相应的python接口
我之前给的那个测试代码中使用的是字符串解析的方式,但是从其他tutorial中发现,还存在一种tvm.target.cuda()的设备建立方式,这个很明显比字符串解析相对找起来容易(字符串最终对应的也是这种方式)。按照这种方式找到了tvm/python/tvm/target.py文件中,这个类中定义了现在能支持的target。添加新的target叫做dpu
def dpu(model='unknown', options=None): """Returns a dpu target.
Parameters
----------
model: str
The model of dpu device
options : str or list of str
Additional options
"""
opts = _merge_opts(['-model=%s' % model], options)
return _api_internal._TargetCreate("dpu", *opts)
每个设备都包括硬件自身的上下文信息和硬件上运行软件运行时也就是runtime,在TVM中相关的软件运行时信息在tvm/python/tvm/_ffi/runtime_ctypes.py文件中,添加对dpu的支持
在class TVMContext的两个掩码MASK2STR和STR2MASK中分别添加:
13: 'dpu',
和
'dpu':13,
2. 找到python和C交互的接口
回到刚才的target.py文件中来,核心的代码只有两句
opts = _merge_opts(['-model=%s' % model], options)
return _api_internal._TargetCreate("dpu", *opts)
第一句是将model和相关的options组合在一起,就是个字符串相关的拼接,没有特别多需要关注的内容,而后边有一个_api_internel._TargetCreate的函数调用,从名字上看起来非常的重要,是创建真正的Target的,但是,我们在tvm/python文件中无论如何都找不到该函数的实现
前边已经提到过TVM中使用的是python提供接口,真正的实现都是在C++中,因此,这里我们猜测是调用了C语言的实现。下面列一下TVM相关的文件夹
3rdparty是很多第三方库的实现
build 目录是我们建立的编译后的.so文件所在的位置
docs 是相关的文档
include C++代码的include的主目录
jvm 是java相关的文件夹
nnvm 是中间的nnvm算子所在的目录
python 是python文件所在的目录,所有与python相关的都在该目录中
rust apps conda docker golang web verilog都是特有领域中的内容,对一般项目没有影响
tests 是测试文件,中间包含了作者写的很多测试,是学习TVM的另一个手段
Tutorial是官网上相关的历程
vta 是TVM的软件栈
cmake包含了所有的编译配置文件,和CmakeLists.txt共同工作
src 是全部的C++代码
topi 是Tensor Operator Index Library,后续进行详细介绍
在src目录下搜索_TargetCreate,得到src/codegen/build_module.cc:116中有相关的内容
TVM_REGISTER_API("_TargetCreate")
.set_body([](TVMArgs args, TVMRetValue* ret) {
std::string target_name = args[];
std::vector<std::string> options;
for (int i = ; i < args.num_args; ++i) {
std::string arg = args[i];
options.push_back(arg);
}
*ret = CreateTarget(target_name, options);
});
这段代码的意思就是通过一种TVM_REGISTER_API的注册机制,注册_TargetCreate函数,真正的函数体是.set_body内执行的,实际上C++中tvm::CreateTarget函数。TVM_REGISTER_API的注册机制在TVM项目中非常普遍,其实现在项目中也有,不是我们主要的研究内容,不需要改,所以不另行赘述。
3. 正确维护中间代码的IR pass变换中新设备引入的特性
上边提到,在src/codegen/build_module.cc文件中的tvm::CreateTarget函数中添加对dpu的支持
else if (target_name == "dpu") {
t->device_type = kDLDPU;
}
这里边的kDLDPU是一个DLDeviceType类型值,实现是在3rdparty/dlpack/include/dlpack/dlpack.h中添加的
kDLDPU =,
同时在include/tvm/runtime/device_api.h:200补充对kDLDPU的支持
case kDLDPU: return "dpu";
Target部分添加完了,还需要补充运行时的内容。
运行时的内容在src/runtime/目录下,需要在module.cc中添加对dpu 的支持。
在RuntimeEnabled函数中,添加
else if (target == "dpu") {
f_name = "device_api.dpu";
}
这只是添加了一个名字的支持,还需要新建一个dpu目录,里边存放DPUModuleNode、DPUWorkspace等支持,测试代码的getSource函数的真正实现也存放在这里边,主要模仿CUDA和openCl的实现进行。目前存放有dpu_common.h、dpu_device_api.cc、dpu_module.cc、dpu_module.h四个文件,大概1K行代码,实现逻辑也不是很复杂。
4. 代码生成对新设备和新特性的支持
上边准备好了module部分,也就是运行时,但是我们这里第一步想要实现的是一个能在dpu编译器上运行的C代码。因此需要在codegen部分添加对dpu这个设备的支持。
codegen是在tvm.build(Python)中形成的,在其对应的C++实现上是codegen/build_module.cc文件,之前添加了名字的支持,现在还需要添加这个真正的Target调用点
Target DPU(const std::vector<std::string>& options ) {
return CreateTarget("dpu", options);
}
最主要的codegen对DPU的支持是新建CodeGenDPU类,这个类的实现在该目录的codegen_dpu.h和codegen_dpu.cc文件内。特别说一下这个部分,其他的函数可以不实现,有两个函数必须实现
runtime::Module BuildDPU(Array<LoweredFunc> funcs) {
using tvm::runtime::Registry;
bool output_ssa = false;
CodeGenDPU cg;
cg.Init(output_ssa);
for (LoweredFunc f : funcs) {
cg.AddFunction(f);
}
std::string code = cg.Finish();
if (const auto* f = Registry::Get("tvm_callback_dpu_postproc")) {
code = (*f)(code).operator std::string();
}
return DPUModuleCreate(code, "dpu", ExtractFuncInfo(funcs), code);
} TVM_REGISTER_API("codegen.build_dpu")
.set_body([](TVMArgs args, TVMRetValue* rv) {
*rv = BuildDPU(args[]);
});
5. 添加编译选项支持
上边可以说是完成了从设备添加到代码生成的部分,但是如果只有上边的话,新添加的设备一直无法运行。但如果仅是对一个设备进行修改的话,这部分并没有必要。后来排查发现是部分代码未编译进去导致的。所以开始修改cmake配置。
在上一个TVM调试文档中提到,编译需要打开LLVM和CUDA选项,这里新添加了dpu的设备,需要增加一个新的编译选项,在cmake/config.cmake中添加
#Build DPU
set(USE_DPU ON)
cmake目录下还存在着modules和util目录,modules是指定了相关设备的目录等配置,util文件夹下的内容用来寻找比如CUDA等的配置。暂时我们只需要modules下添加DPU.cmake
这部分的配置代码相对比较简单,就是指定runtime对应的目录
# DPU Module if(USE_DPU)
message(STATUS "Build with DPU support")
file(GLOB RUNTIME_DPU_SRCS src/runtime/dpu/*.cc)
list(APPEND RUNTIME_SRCS ${RUNTIME_DPU_SRCS})
else()
message(STATUS "NOT BUILD DPU SUPPORT")
endif(USE_DPU)
这里修改完config.cmake,需要重新拷贝到build目录下,以使下次配置生效。我在上边也提到了,编译tvm时是cmake目录下的config.cmake和CMakeLists.txt共同工作生效。在CMakeLists.txt中添加
tvm_option(USE_DPU "Build with DPU" ON)
include(cmake/modules/DPU.cmake)
然后在build目录下,运行cmake命令,重新编译生效。
cmake -DCMAKE_BUILD_TYPE=Debug ../
make
这里不加-DCMAKE_BUILD_TYPE=Debug的话,C++代码无法进行调试。
TVM设备添加以及代码生成的更多相关文章
- 为Android设备添加A2SD支持
相信很多用Android设备的用户都有这个问题,内部存储太小导致应用只能装那么几个,虽然rom也有提供移动到sd卡的选项,但是仅仅是移动程序文件到sd卡,并不能解决多少问题,多装几个还是会 ...
- 给网卡设备添加两个IP别名(一个网卡绑定多个ip)
首先执行ifconfig,查看网卡设备名称 [root@localhost conf]# ifconfig ens33: flags=4163<UP,BROADCAST,RUNNING,MULT ...
- Android系统移植与调试之------->如何修改Android设备添加重启、飞行模式、静音模式等功能(二)
今天要说的是为Android设备添加重启.飞行模式.静音模式按钮,客户需求中需要添加这项功能,在长按电源键弹出的菜单中没有这些选项,谨以此文记录自己添加这个功能的过程. 首先找到长按电源键弹出的对话框 ...
- jq 动态判断设备添加对应meta viewport属性内同
1.常见的单位 dip, dp, px, sp之间的区别: dip: device independent pixels(设备独立像素). 不同设备有不同的显示效果,这个和设备硬件有关,一般我们为了支 ...
- [置顶] Android系统移植与调试之------->如何修改Android设备添加3G上网功能
1.首先先来看一下修改前后的效果对比图 step1.插上3G设备前 step2.插上3G设备后,获取信号中.... step3.插上3G设备后,获取到信号 step4.使用3G信号浏览网页 2.下面讲 ...
- LabVIEW--为设备添加配置文件.ini
需求:我同一个程序下载到两台机器人上,有些参数是不一样的,比如说服务器的ID或者端口,以及存放文件的位置,如果我每次下载之前改程序的话就非常麻烦了(虽然在程序里面是作为全局变量来存的),不利于后期的更 ...
- Android系统移植与调试之------->如何修改Android设备添加3G上网功能
1.首先先来看一下修改前后的效果对比图 step1.插上3G设备前 step2.插上3G设备后,获取信号中.... step3.插上3G设备后,获取到信号 step4.使用3G信号浏览网页 2.下面讲 ...
- linux采用模块方法,添加一个新的设备
该文转载自:http://rangercyh.blog.51cto.com/1444712/521244 系统调用是操作系统内核和应用程序之间的接口,而设备驱动程序是操作系统内核和机器硬件之间的接口. ...
- TVM:
Hello TVM 发表于 2019-06-29 TVM 是什么?A compiler stack,graph level / operator level optimization,目的是(不同框 ...
随机推荐
- HttpURLConnection 多线程下载
影响下载的速度 * 宽带的带宽 * 服务器的限制 * 服务器的资源固定,开启的线程越多抢占的资源就越多 import java.io.InputStream; import java.io.Rando ...
- php版本:实现过滤掉广告、色情、政治相关的敏感词
现在网络上还是很乱,尤其充斥着各种广告.色情.政治相关的内容,很明显这是不符合我们国家的法律的,所以为了一个产品能够健康长久的活下去,最好还是采用一定的策略过滤或者提醒用户不要发这种内容.不过说起来容 ...
- 质量保障&&质量体系建设
一.质量保障 先引用一段 百度百科 上对软件质量保障的解释:软件质量保障是建立一套有计划,系统的方法,来向管理层保证拟定出的标准.步骤.实践和方法能够正确地被项目所采用.软件质量保证的目的是使软件过程 ...
- C2B电商三种主要模式的分析_数据分析师
C2B电商三种主要模式的分析_数据分析师 在过去的一年中电商领域血雨腥风,尤其是天猫.京东.苏宁.当当.易讯等B2C电商打得不亦乐乎.而随着B2C领域竞争进入白热化阶段,C2B模式也在天猫" ...
- 增强for循环的简单总结
整体来说:增强型for循环使用起来比较方便,代码也比较简单,如果只是操作集合中元素的而不使用索引的话,建议用此方法.对于普通for循环,如果需要使用索引进行其它操作的话,建议用这个. 详细来说:1,区 ...
- zabbix3.0升级到4.0
升级步鄹: 3.0->3.2 1.停服务 service zabbix-server stop 2.备份配置文件 #cp /etc/zabbix/zabbix_server.conf /data ...
- cocos2dx-android-添加64位编译
Application.mk: APP_ABI := armeabi arm64-v8a build.gradle: android{ ndk{ abiFilters "armeabi&qu ...
- 无监督异常检测之LSTM组成的AE
我本来就是处理时间序列异常检测的,之前用了全连接层以及CNN层组成的AE去拟合原始时间序列,发现效果不佳.当利用LSTM组成AE去拟合时间序列时发现,拟合的效果很好.但是,利用重构误差去做异常检测这条 ...
- 【机器学习】Matlab中实现QQ-plot的一个好工具gqqplot
Matlab中实现QQ-plot的一个好工具gqqplot 26JUN June 26, 2013 这几天看了一下QQ-plot以及在Matlab中的实现,可是Matlab自带的qqplot函数不能满 ...
- Thinkphp 使用小结
分页中带查询参数 ...->paginate(15,false,['query'=>request()->param()]); 队列后台自动开启运行 nohup php think ...