kernel makefile 添加自定义include路径_为tvm添加一个新的后端

本文介绍了如何在TVM中添加一个新的后端,涉及Python和C++层面的修改,包括在`target.py`中定义新后端、在`ndarray.py`和`__init__.py`中添加声明、`_ffi/runtime_ctypes.py`中添加掩码。C++端的修改包括在`runtime/module.cc`中添加设备名支持,以及在`target/target.cc`和`codegen_llvm.cc`中实现代码生成。
摘要由CSDN通过智能技术生成

前言

我是去年5月份开始接触tvm的,再加上各位大佬都非常活跃,tvm已经更新了N个版本。这是本人在tvm学习中的一些总结,能力有限比较浅显,如有大佬发现错误,请及时指出,同时欢迎大佬们交流。

关于tvm是什么,以及安装之类的问题,网上已经有很全的信息,这里推荐蓝色大佬的文章,以及tvm的官方网址(ps:幸好当初看的第一篇tvm的文章就是蓝大的,少走了很多弯路,在这里表示感谢>.<):

Redirecting…​tvm.ai 蓝色:手把手带你遨游TVM​zhuanlan.zhihu.com
6a7aa5a9ce2b3bc4ebef18bd566dbdcf.png

再贴一个源码github地址

https://github.com/apache/incubator-tvm​github.com

代码库结构

首先是代码结构,有如下几个目录:

a18fc2dc805b6555e542ffcaa1ae3f61.png
代码库的文件结构

现在介绍每个目录的作用。

3rdparty是第三方库的实现,包括以前的Halide IR,但为了代码结构更加合理,现在大部分都集成到其他地方

cmake包含了所有的编译配置文件

docs 是相关的文档,官方文档在这里都能找到,是学习tvm的一个重要途径

include 是C++代码的头文件目录

jvm 是java相关的文件夹

nnvm 是中间的nnvm所在的目录,现在用处不大

python 是python文件所在的目录,所有与python相关的都在该目录中

tests 是测试文件,包含了作者写的很多测试,是学习tvm的另一个手段

topi 是tvm算子库,是为了让tvm可以同时手工定制和自动优化计算Kernel函数

1tutorial 是官网上相关的教程,同样是学习的好途径

vta 是tvm的软件栈,是一个类似tpu的硬件架构

rust apps conda docker golang web verilog 都是特有领域中的内容,对一般项目没有影响

src 是全部的C++代码,很多主要功能实现都在这里面,包括codegen,runtime等等,下面会对这个文件夹继续说明

1f6e360d69513de06d56a25ead8162b4.png
src文件夹的组成

runtime: 最小运行时代码。(说实话,我也查阅了一些资料,但是对于runtime这个概念还不是很明白,希望有大佬指导)

node: IR/AST 节点

ir: 通用ir基础架构

tir: 张量级ir

te: DSL张量表达式

arith: 算术表达式

relay: Relay IR,NNVM IR的更高级别

autotvm: 自动优化的tvm

api: API 函数注册.

driver: 编译驱动程序API

添加新的后端

上面大概介绍了代码库的结构,下面开始进入主题,添加一个新的后端。

tvm现在支持的后端有llvm,cuda,opencl,nvptx等等。

tvm有一个很重要,同时也十分有意思的特点,就是Python和c++互相调用的机制——PackedFunc。PackedFunc是一个实现C ++和Python互操作方案。

提供了一个最小化的C语言API,可以通过C语言API把PackedFunc嵌入到任何编程语言中。TVM函数通过PackedFunc暴露接口给前端语言,已经被编译的模块也通过PackedFunc返回已编译的函数。

想要具体了解可以进tvm教程查看。

tvm在Python层提供了相关的设备接口,然后使用tvm.build真正的编译,所以首先在Python端进行添加。

1,文件路径:tvm/python/tvm/target.py,这个类中定义了有关target,我们将新添加的后端命名为rpu。下面这个函数的作用是两点,一个是字符串的拼接——_merge_opts;

一个是target的创建——TargetCreate。

def rpu(model='unknown', options=None):

    """Returns a rpu target.
    Parameters
    ----------
    model: str
        The model of rpu device
    options : str or list of str
        Additional options
    """

    opts = _merge_opts(['-model=%s' % model], options)
return _api_internal._TargetCreate("rpu", *opts)

2,在 python/tvm/runtime/ndarray.py 添加关于rpu的声明。

def rpu(dev_id=0):
    ""
    dev_id : int, optional
        The integer device id

    Returns
    -------
    ctx : TVMContext
        The created context
    
    """
    return TVMContext(12, dev_id)

3,在python/tvm/runtime/__init__.py 下添加上面加的名称。

from .ndarray import vpi, rocm, opengl, ext_dev, micro_dev,rpu

4,在python/tvm/_ffi/runtime_ctypes.py添加rpu的两个掩码。

STR2MASK= {'rpu': 13,    } MASK2STR= {13: 'rpu',    }

Python端添加完毕了,接下来添加C++端。

  • runtime部分

1,在/src/runtime/http://module.cc的RuntimeEnabled函数添加新设备的名字支持。

else if (target == "rpu") {
    f_name = "device_api.rpu";
  }

2,还需要新建一个rpu目录,里边存放ModuleNode、Workspace等支持,主要模仿已有的其他后端实现进行。(ps:这一块没有弄明白,暂时先放着)

  • 代码生成部分

1,首先在include/tvm/target/target.h添加rpu用以构造Target实例

TVM_DLL Target rpu(const std::vector<std::string>& options = 
                      std::vector<std::string>());

2,在include/dlpack/dlpack.h中把rpu加入设备枚举类型,为后面target的创建做准备。

kDLRpu = 12,

同时在include/tvm/runtime/device_api.h补充对kDLRPU的支持

case kDLRPU: return "rpu";

3,在src/target/http://target.cc中添加CreateTarget的支持,以便tvm.build()传进来的target字符串能够被识别。

Target rpu(const std::vector<std::string>& options) {
  return CreateTarget("rpu", options);
}

4,在CreateTarget函数里添加对rpu的判断。

else if (target_name == "rpu") {    t->device_type = kDLRPU;}

5,最重要的代码生成部分可以参考其他后端。

我假定添加的后端拥有LLVM工具链的支持,所以可以复用大部分http://codegen_llvm.cc的代码,我的操作是调用LLVM的init方法以及AddFunction这两个主要方法。详细的代码等验证正确性之后再上传

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值