---
title: DSL简介
description: "为了方便开发者进行自定义算子开发，TBE（Tensor Boost Engine）提供了一套计算接口供开发者用于组装算子的计算逻辑，这套计算接口称之为DSL（Domain-Specific Language）。基于DSL开发的算子，可以直接使用TBE提供的Auto Schedule机制，自动完成调度过程，省去最复杂的调度编写过程。"
url: https://www.hiascend.com/document/detail/zh/canncommercial/latest/others/tbeaicpudevg/atlasopdev_10_0032.html
sourcePath: /source/zh/canncommercial/900/others/tbeaicpudevg/atlasopdev_10_0032.html
indexId: 1a378dac7c867056cf29c86c36977f46402ed97bdc4f122de05ce6aafd3a7b9273
---
# DSL简介

为了方便开发者进行自定义算子开发，TBE（Tensor Boost Engine）提供了一套计算接口供开发者用于组装算子的计算逻辑，这套计算接口称之为DSL（Domain-Specific Language）。基于DSL开发的算子，可以直接使用TBE提供的Auto Schedule机制，自动完成调度过程，省去最复杂的调度编写过程。

#### DSL功能框架

TBE DSL算子的功能框架如图1所示。

图1 TBE DSL功能框架

1. 开发者调用TBE提供的DSL接口进行计算逻辑的描述，指明算子的计算方法和步骤。
2. 计算逻辑开发完成后，开发者可调用Auto Schedule接口，启动自动调度，自动调度时TBE会根据计算类型自动选择合适的调度模板，完成数据切块和数据流向的划分，确保在硬件执行上达到最优。
3. Auto Schedule调度完成后，会生成类似于TVM的IR（Intermediate Representation）的中间表示。
4. 编译优化（Pass）会对算子生成的IR进行编译优化，优化的方式有双缓冲（Double Buffer）、流水线（Pipeline）同步、内存分配管理、指令映射、分块适配矩阵计算单元等。
5. 算子经Pass处理后，由CodeGen生成类C代码的临时文件，这个临时代码文件可通过编译器生成算子的实现文件，可被网络模型直接加载调用。

代码示例如下所示：

```
//初始化输入tensor，为输入tensor进行占位
data_x = tvm.placeholder(shape_x, name="data_1", dtype=input_data_type)
data_y = tvm.placeholder(shape_y, name="data_2", dtype=input_data_type)
//调用计算接口实现data_x + data_y
res = tbe.dsl.vadd(data_x, data_y)
//调用auto_schedule接口实现自动调度
with tvm.target.cce():
schedule = tbe.dsl.auto_schedule(res)
//配置编译参数并进行编译
config = {"name":
kernel_name
,
"tensor_list": (data_x, data_y, res)}
tbe.dsl.build(schedule, config)
```


#### DSL计算接口介绍

TBE DSL提供的计算接口主要涵盖向量运算，包括Math、NN、Reduce、卷积、矩阵计算等接口。

详细的接口介绍请参见TBE DSL API。


#### Auto Schedule介绍

算子的计算逻辑实现完后，如果要让计算逻辑在硬件中执行，还需要考虑如下问题：- 计算指令在硬件中按照什么顺序执行？
- 数据如何在硬件内存中存储？


Schedule（调度）就是为了解决如上问题，通过调整计算逻辑、优化计算过程，使得计算更加高效，并保证计算过程中占用的硬件存储空间不会超过上限。

TBE DSL提供了Auto Schedule机制，以上Schedule操作无需用户关注。用户通过组合DSL接口表达算子的计算逻辑后，直接调用Auto Schedule接口即可实现自动调度，完成数据切块和数据流向的划分。Auto Schedule机制是TBE底层的默认Schedule调优机制，开发者无法在算子开发代码过程中进行控制，下面简要介绍Auto Schedule的原理。

如下是基于DSL进行算子开发的示例，实现对x取指数，然后在轴0上进行累加降维，再取倒数的功能。

```
x = tvm.placeholder((512, 1024), "float16")
exp_x = tbe.dsl.vexp(x)
reduce_exp_x = tbe.dsl.sum(exp_x, axis = 0)
res = tbe.dsl.vrec(reduce_exp_x)
with tvm.target.cce():
sch = tbe.dsl.auto_schedule(res)
```

开发者调用tbe.dsl.auto_schedule接口开启TBE的自动调度，自动调度的总体流程如图2所示。

图2 Auto Schedule总体流程

1. 调用Auto Schedule接口的时候，就是传递了一个compute的语法树，TBE中每一个compute语句在进行编译的时候都会被加上tag_scope标志，如下所示。
  添加tag_scope的操作如下：

```
with tvm.tag_scope(op):
tmp = tvm.compute(shape, lambda_func, name=name)
```


  如图3所示，左侧的compute语法树，也叫抽象语法树（Abstract Syntax Tree: AST），编译过程中，会对每一个compute语句加上tag_scope标志。

  图3 计算语句与tag_scope标志对应示例

2. 根据scope标识，识别出对应pattern，TBE当前支持的pattern类型有：elewise、reduce、segment、concat、conv、depthwise、pooling2d等。TBE会按照pattern规则对AST进行切分，例如最简单的一条pattern规则是elewise可以和其他的pattern连在一起，reduce、segment、concat不能在一个AST子图内。
3. 完成AST子图切分后，TBE会创建并初始化Schedule对象。
4. Schedule执行过程中首先找到AST子图的边界，然后对每一个子图根据其pattern选择一个合适的Schedule模板进行调度。调度过程主要包括数据流管理、tiling以及指令映射等。
