已合并
modify quick_op_invocation #2641
chenjiao创建于 5月8日
modify quick_op_invocation #2641
已合并
chenjiao创建于 5月8日
2 个文件变更+226-309
Mdocs/CONTRIBUTING_DOCS.md+4-105
@@ -94,110 +94,9 @@
941. 查阅现有文档:模板或规范有问题,请先查阅项目已有的指南、API文档或README等。941. 查阅现有文档:模板或规范有问题,请先查阅项目已有的指南、API文档或README等。
952. 发起讨论:您可以新建Issue或直接在相关Issue或PR中留言。952. 发起讨论:您可以新建Issue或直接在相关Issue或PR中留言。
96 96 
97-## 算子README模板97+## 文档模板
98 98 
99-针对`experimental`新贡献算子,算子README是必备文档交付件,您可以参考本节提供的**简单模板**,也支持您基于本模板进行内容拓展99+算子交付件中涉及的关键文档主要包括如下具体写作格式、内容要求请参考模板。
100 100 
101-- 文档格式:推荐Markdown文件格式,支持使用原生或Html语法,请确保所有语法须符合官方规范。101+- [算子RAEDME文档模板](https://gitcode.com/cann/ops-math/wiki/%E7%AE%97%E5%AD%90README%E6%96%87%E6%A1%A3%E6%A8%A1%E6%9D%BF)
102-- 文档作用:阐述清楚算子功能、实现原理、参数规格以及算子调用方式等。102+- [aclnn API文档模板](https://gitcode.com/cann/ops-math/wiki/aclnn%20API%E6%96%87%E6%A1%A3%E6%A8%A1%E6%9D%BF)
103-- 章节标题:优先使用模板章节名(如功能说明、参数说明等),标题层级为##,如有特殊情况层级请按序增加。支持章节自定义拓展,可选章节视情况呈现。
104-- 内容要求:每章内容写作目标、写作规范请参考下文详细描述,为方便理解,将以[AddExample](../examples/add_example/README.md)算子README为例。
105- 
106-### 产品支持情况
107- 
108-> **写作规范**:推荐表格形式,罗列支持的产品型号,并打√,产品形态介绍请参见[昇腾产品形态说明](https://www.hiascend.com/document/redirect/CannCommunityProductForm)。
109- 
110-| 产品 | 是否支持 |
111-| :----------------------------------------- | :------:|
112-| Atlas A3 训练系列产品/Atlas A3 推理系列产品 | √ |
113-| Atlas A2 训练系列产品/Atlas A2 推理系列产品 | √ |
114- 
115-### 功能说明
116- 
117-> [!NOTE]
118->
119-> **写作目标**:阐明算子功能、计算原理、参数规格、调用方式、使用场景等。
120->
121-> **写作规范**:推荐无序列表形式,一般包括如下维度
122->
123-> - 算子功能(必选):请以一句话形式简洁明了阐述功能。
124-> - 计算公式(可选):复杂功能可借助公式介绍算子实现原理或不同场景下的计算过程。
125-> - 其他维度(可选):支持无序列表拓展,请根据实际情况自定义,比如计算示例、流程图等。
126- 
127-- 算子功能:完成张量加法计算。
128-- 计算公式:
129- $$
130- y = x1 + x2
131- $$
132- 
133-### 参数说明
134- 
135-> [!NOTE]
136->
137-> **写作目标**:阐明算子定义的参数含义、作用、规格等信息。
138->
139-> **写作规范**:采用表格形式,一般包括如下维度
140->
141-> - 参数名:解释算子定义文件中的参数,顺序保持一致,例如`op_host/add_example_def.cpp`或`op_graph/add_example_proto.h`。
142-> - 输入/输出/属性:明确参数定位,默认是必选,若为可选一般为可选输入/可选输出/可选属性。
143-> - 描述:提供参数含义、功能、使用场景等介绍,包括与上述公式变量的映射关系。
144-> - 数据类型:参数支持的data type,张量数据类型一般为`DT_XXX`形式。为方便写作,可不带`DT_`前缀。
145-> - 数据格式:参数支持的数据排布方式,张量format一般为`FORMAT_xxx`形式。为方便写作,可不带`FORMAT_`前缀。
146-> - 其他维度(可选):支持表格字段扩展,请根据实际情况自定义,比如shape规格等。
147- 
148-|参数名|输入/输出/属性|描述|数据类型|数据格式|
149-|-----|-----------|----|---------|------|
150-|x1|输入|表示add_example计算的第一个张量,即公式中`x1`。|FLOAT、FLOAT16、INT32|ND|
151-|x2|输入|表示add_example计算的第二个张量,即公式中`x2`。|数据类型与x1保持一致|ND|
152-|y| 输出 | 表示add_example计算结果张量,即公式中`y`。 |FLOAT、FLOAT16、INT32|ND|
153- 
154-### 约束说明(可选)
155- 
156-> [!NOTE]
157->
158-> **写作目标**: 阐明算子使用过程中的注意事项,例如参数组合约束、适用场景、对业务影响、算子性能或精度等。
159->
160-> **写作规范****本章为可选**,若无约束可不呈现本章内容;若有请采用无序列表形式。
161- 
162-
163- 
164-### 调用说明
165- 
166-> [!NOTE]
167->
168-> **写作目标**: 提供算子调用方法,尽量是可直接拷贝运行的示例代码,方便快速验证。
169->
170-> **写作规范**:推荐表格形式,如果内容复杂可采用其他形式。
171->
172-> - 调用方式:支持aclnn、图模式等方式调用,也支持您自定义,请提供至少一种方式。
173-> - 样例代码:请在算子的`examples`目录提供调用示例代码,例如`examples/test_aclnn_add_example.cpp`。文件命名规则为test\_\$\{invoke\_mode\}\_\${op_name},\$\{invoke\_mode\}表示调用方式,\${op_name}表示算子名。
174-> - 说明:不同调用方式的补充说明,例如调用场景、调用原理、编译运行指导等,请根据实际情况自定义。
175- 
176-<table><thead>
177- <tr>
178- <th>调用方式</th>
179- <th>调用样例</th>
180- <th>说明</th>
181- </tr></thead>
182-<tbody>
183- <tr>
184- <td>aclnn调用</td>
185- <td><a href="../examples/add_example/examples/test_aclnn_add_example.cpp">test_aclnn_add_example</a></td>
186- <td rowspan="2">参见<a href="./zh/invocation/quick_op_invocation.md">算子调用</a>完成算子编译和验证。</td>
187- </tr>
188- <tr>
189- <td>图模式调用</td>
190- <td><a href="../examples/add_example/examples/test_geir_add_example.cpp">test_geir_add_example</a></td>
191- </tr>
192-</tbody>
193-</table>
194- 
195-### 参考资源(可选)
196- 
197-> [!NOTE]
198->
199-> **写作目标**: 提供除算子功能、规格、调用外的其他补充介绍,例如算子设计文档(Tiling/Kernel设计)、参考文献等。
200->
201-> **写作规范****本章为可选**,若无约束可不呈现本章内容;若有请采用无序列表形式。
202- 
203-
Mdocs/zh/invocation/quick_op_invocation.md+222-204
@@ -2,16 +2,38 @@
2 2 
3## 使用须知3## 使用须知
4 4 
5-- 前提说明:算子调用前,请参考本项目README完成环境准备和源码下载,再完成[源码构建](../install/compile.md),此处不再赘述。5+- 前提说明:算子调用前,请参考本项目README完成环境准备和源码下载,此处不再赘述。
6-- 调用算子:支持调用非experimental目录算子(内置算子,清单详见[算子列表](../op_list.md))和experimental目录算子(贡献算子)。
7 6 
8-## 调用算子样例7+- 调用范围:支持调用的算子清单参见[算子列表](../op_list.md),此外还支持调用experimental贡献目录的算子。
9 8 
10-如何快速调用项目中的算子,本章介绍最简调用方法,通过build.sh命令执行算子样例9+- 调用场景: 请根据实际场景诉求选择合适的算子调用方
10+ 
11+ |调用场景|场景说明|特点|
12+ |--------|----|-----|
13+ |[快速调用算子](#快速调用算子)|适用于快速体验和验证算子功能的场景。|**无需搭建调用工程**,基于源码编译包和项目脚本build.sh可直接调用算子样例。|
14+ |[业务应用集成算子](#业务应用集成算子)|适用于将算子灵活集成到实际业务应用中。|**需自行搭建调用工程**,手动创建调用脚本/CMake工程,灵活实现算子编译和运行。|
15+ 
16+- 调用方式:当前主要提供如下算子调用方式,请按需选择。
17+ 
18+ |调用方式|说明|
19+ |--------|----|
20+ |[PyTorch API](#pytorch-api)|将算子Kernel注册到PyTorch原生框架,以类似于Torch原生API方式实现算子调用。|
21+ |[aclnn API](#aclnn-api)|针对算子提供相应的C语言API(前缀为aclnn),无需提供IR定义,实现API直接调用算子。|
22+ |[GE图模式](#ge图模式)|通过算子IR(Intermediate Representation)定义,以构图方式实现算子调用。|
23+ 
24+## 快速调用算子
25+ 
26+**如需快速体验或验证项目中已有算子功能,可参考本章最简调用方法,通过build.sh执行算子样例**
27+ 
28+该方法特点是无需搭建调用工程(即创建编译/运行脚本等),简单易操作。
11 29 
12> **说明**:对于Ascend 950PR产品,可通过Simulator仿真工具执行算子样例,详见[仿真指导](../debug/op_debug_prof.md#方式二针对ascend-950pr)。30> **说明**:对于Ascend 950PR产品,可通过Simulator仿真工具执行算子样例,详见[仿真指导](../debug/op_debug_prof.md#方式二针对ascend-950pr)。
13 31 
14-- 基于**自定义算子包**执行算子样例,包安装后,执行如下命令32+**步骤1**:参考[源码构建指南](../install/compile.md)完成源码包编译和部署。
33+ 
34+**步骤2**:执行项目中已有算子的样例。
35+ 
36+- 基于**自定义算子包**执行算子样例,命令如下:
15 37 
16 ```bash38 ```bash
17 bash build.sh --run_example ${op} ${mode} ${pkg_mode} [--vendor_name=${vendor_name}] [--soc=${soc_version}] [--experimental]39 bash build.sh --run_example ${op} ${mode} ${pkg_mode} [--vendor_name=${vendor_name}] [--soc=${soc_version}] [--experimental]
@@ -21,27 +43,27 @@
21 # bash build.sh --experimental --run_example abs eager cust --vendor_name=custom43 # bash build.sh --experimental --run_example abs eager cust --vendor_name=custom
22 ```44 ```
23 45 
24- - \$\{op\}:表示待执行算子,算子名小写下划线形式,如abs。46+ - \$\{op\}:表示待执行算子,算子名小写下划线形式,如abs。
25- - \$\{mode\}:表示调用方式,目前支持eager(aclnn调用)、graph(图模式调用)。47+ - \$\{mode\}:表示调用方式,目前支持eager(aclnn调用)、graph(图模式调用)。
26- - \$\{pkg_mode\}:表示包模式,目前仅支持cust,即自定义算子包。 48+ - \$\{pkg_mode\}:表示包模式,目前仅支持cust,即自定义算子包。
27- - \$\{vendor\_name\}(可选):与构建的自定义算子包设置一致,默认名为custom。 49+ - \$\{vendor\_name\}(可选):与构建的自定义算子包设置一致,默认名为custom。
28- - \$\{soc_version\}(可选):表示NPU型号。50+ - \$\{soc_version\}(可选):表示NPU型号。
29- - \$\{experimental\}(可选):表示执行用户保存在experimental贡献目录下的算子。51+ - \$\{experimental\}(可选):表示执行用户保存在experimental贡献目录下的算子。
30- 52+ 
31 说明:\$\{mode\}为graph时,不指定\$\{pkg_mode\}和\$\{vendor\_name\}53 说明:\$\{mode\}为graph时,不指定\$\{pkg_mode\}和\$\{vendor\_name\}
32 54 
33-- 基于**ops-math包**执行算子样例,安装后,执行如下命令:55+- 基于**ops-math包**执行算子样例,命令如下
34 56 
35 ```bash57 ```bash
36 bash build.sh --run_example ${op} ${mode} [--soc=${soc_version}]58 bash build.sh --run_example ${op} ${mode} [--soc=${soc_version}]
37 # 以Abs算子example执行为例59 # 以Abs算子example执行为例
38 # bash build.sh --run_example abs eager60 # bash build.sh --run_example abs eager
39 ```61 ```
40- 62+ 
41- - \$\{op\}:表示待执行算子,算子名小写下划线形式,如abs。63+ - \$\{op\}:表示待执行算子,算子名小写下划线形式,如abs。
42- - \$\{mode\}:表示算子执行模式,目前支持eager(aclnn调用)、graph(图模式调用)。64+ - \$\{mode\}:表示算子执行模式,目前支持eager(aclnn调用)、graph(图模式调用)。
43- - \$\{soc_version\}(可选):表示NPU型号。65+ - \$\{soc_version\}(可选):表示NPU型号。
44- 66+ 
45- 基于**ops-math静态库**执行算子样例:67- 基于**ops-math静态库**执行算子样例:
46 68 
47 1. **前提条件**69 1. **前提条件**
@@ -59,7 +81,7 @@
59 ```bash81 ```bash
60 # 静态库文件路径82 # 静态库文件路径
61 static_lib_path=""83 static_lib_path=""
62- 84+
63 # 环境变量生效85 # 环境变量生效
64 if [ -n "$ASCEND_INSTALL_PATH" ]; then86 if [ -n "$ASCEND_INSTALL_PATH" ]; then
65 _ASCEND_INSTALL_PATH=$ASCEND_INSTALL_PATH87 _ASCEND_INSTALL_PATH=$ASCEND_INSTALL_PATH
@@ -68,9 +90,9 @@
68 else90 else
69 _ASCEND_INSTALL_PATH="/usr/local/Ascend/cann"91 _ASCEND_INSTALL_PATH="/usr/local/Ascend/cann"
70 fi92 fi
71- 93+
72 source ${_ASCEND_INSTALL_PATH}/bin/setenv.bash94 source ${_ASCEND_INSTALL_PATH}/bin/setenv.bash
73- 95+
74 # 编译可执行文件96 # 编译可执行文件
75 g++ test_aclnn_abs.cpp \97 g++ test_aclnn_abs.cpp \
76 -I ${static_lib_path}/include \98 -I ${static_lib_path}/include \
@@ -83,145 +105,144 @@
83 -lpthread -lmmpa -lmetadef -lascendalog -lregister -lopp_registry -lops_base -lascendcl -ltiling_api -lplatform \105 -lpthread -lmmpa -lmetadef -lascendalog -lregister -lopp_registry -lops_base -lascendcl -ltiling_api -lplatform \
84 -ldl -lc_sec -lnnopbase -lruntime -lerror_manager -lunified_dlog \106 -ldl -lc_sec -lnnopbase -lruntime -lerror_manager -lunified_dlog \
85 -o test_aclnn_abs # 替换为实际算子可执行文件名107 -o test_aclnn_abs # 替换为实际算子可执行文件名
86- 108+
87 # 执行程序109 # 执行程序
88 ./test_aclnn_abs110 ./test_aclnn_abs
89 ```111 ```
90 112 
91 \$\{static\_lib\_path\}表示静态库统一放置路径; \$\{ASCEND\_INSTALL\_PATH\}已通过环境变量配置,表示CANN toolkit包安装路径; 最终可执行文件名请替换为**实际算子可执行文件名**。 113 \$\{static\_lib\_path\}表示静态库统一放置路径; \$\{ASCEND\_INSTALL\_PATH\}已通过环境变量配置,表示CANN toolkit包安装路径; 最终可执行文件名请替换为**实际算子可执行文件名**。
92- 114+ 
93- 其中lcann\_math\_static、lcann\_legacy\_static表示算子依赖的静态库文件,从静态库统一放置路径\$\{static\_lib\_path\}中获取; 115+ 其中lcann\_math\_static、lcann\_legacy\_static表示算子依赖的静态库文件,从静态库统一放置路径\$\{static\_lib\_path\}中获取;
94- lgraph、lmetadef等表示算子依赖的底层库文件,可在CANN toolkit包获取。 116+ lgraph、lmetadef等表示算子依赖的底层库文件,可在CANN toolkit包获取。
95- 117+ 
96 3. **执行run.sh**118 3. **执行run.sh**
97 119 
98 ```bash120 ```bash
99 bash run.sh121 bash run.sh
100 ```122 ```
101 123 
102-无论上述哪种方式,算子样例执行后会打印结果,以Abs算子为例:124+**步骤3**:检查执行结果
103 125 
104-```bash126+算子样例执行后会打印结果,以Abs算子结果为例:
105-abs result[0] is: 1.000000
106-abs result[1] is: 1.000000
107-abs result[2] is: 1.000000
108-abs result[3] is: 2.000000
109-abs result[4] is: 2.000000
110-abs result[5] is: 2.000000
111-abs result[6] is: 3.000000
112-abs result[7] is: 3.000000
113-```
114 127 
115-## 调用方式128+ ```text
129+ abs result[0] is: 1.000000
130+ abs result[1] is: 1.000000
131+ abs result[2] is: 1.000000
132+ abs result[3] is: 2.000000
133+ abs result[4] is: 2.000000
134+ abs result[5] is: 2.000000
135+ abs result[6] is: 3.000000
136+ abs result[7] is: 3.000000
137+ ```
116 138 
117-通过build.sh执行算子时,其底层调用算子的原理目前包括如下几种方式:139+## 业务应集成算子
118 140 
119-- PyTorch调用**(建设中)**:通过`<<<>>>`方式启动算子Kernel极简,实现PyTorch方式调用NPU算子。141+**如需将算子集成到实际业务应用中可参考本章自行搭建调用工。通过自定义调用脚本/CMake工程等,实现算子编译和运行**
120 142 
121-- aclnn调用 **(推荐)**:Host侧提供算子对应的C语言API(前缀aclnn)无需提供IR定义实现aclnn API方式调用算子143+该方法特点是手动搭建调用工程场景灵活度高可移植性强
122 144 
123-- 图模式调用:提供IR(Intermediate Representation)定义,实现构图方式调用算子145+不同调用方式对应的编译工程不同,当前支持PyTorch API、aclnn API、GE图模式调用方式调用方法和实践请参考下文,请按需选择
124 146 
125-### PyTorch调用(建设中)147+### PyTorch API
126 148 
127-该方式提供一套基于Ascend Extension for PyTorch(torch_npu)框架调用NPU算子的方法,具体调用原理和过程请参考[examples/fast_kernel_launch_example](../../../examples/fast_kernel_launch_example/README.md),内容仍在建设和优化中,欢迎您提问和建议149+该方式将算子Kernel注册到PyTorch原生框架,以类似于Torch原生API方式实现算子调用。
128 150 
129-### aclnn调用151+具体调用原理和过程请参考[examples/fast_kernel_launch_example](../../../examples/fast_kernel_launch_example/README.md),内容仍在建设和优化中,欢迎您提问和建议。
152+ 
153+### aclnn API
130 154 
131#### 调用流程155#### 调用流程
132 156 
133-该方式也称“单算子API调用通过提供一套基于C的API(以aclnn为前缀API)实现算子调用,无需提供算子IR(Intermediate Representation)定义。aclnn API调用流程如下:157+方便调用算子Host侧提供算子对应C语言API(以aclnn为前缀API)实现算子调用,无需提供算子IR(Intermediate Representation)定义。aclnn API调用流程如下:
134 158 
135![原理图](../figures/aclnn调用.png)159![原理图](../figures/aclnn调用.png)
136 160 
137-aclnn API调用示例以`AddExample`算子为例,代码示例如下,仅供参考,全量代码参见[test_aclnn_add_example.cpp](../../../examples/add_example/examples/test_aclnn_add_example.cpp)。调用前,请按照环境安装的提示信息设置环境变量。161+#### 编译运行
138 162 
139-> 注意:如需调用项目已实现的算子可访问目标算子`examples`目录下test\_aclnn\_\$\{op\_name\}.cpp,\$\{op\_name\}表算子名163+> 注意:操作过程中,遇到日志提示设置环境变量请按提操作
140 164 
141-```Cpp165+1. 创建调用脚本。
142-int main()
143-{
144- // 1. 调用acl进行device/stream初始化
145- int32_t deviceId = 0;
146- aclrtStream stream;
147- auto ret = Init(deviceId, &stream);
148- CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("Init acl failed. ERROR: %d\n", ret); return ret);
149 166 
150- // 2. 构造输入与输出,需要根据API的接口自定义构造167+ 在目标算子`examples`目录下,新建调用脚本test\_aclnn\_\$\{op\_name\}.cpp,\$\{op\_name\}表示目标算子名。以`AddExample`算子为例,调用脚本如下,仅供参考,全量代码参见[test_aclnn_add_example.cpp](../../../examples/add_example/examples/test_aclnn_add_example.cpp)。
151- aclTensor* selfX = nullptr;
152- void* selfXDeviceAddr = nullptr;
153- std::vector<int64_t> selfXShape = {32, 4, 4, 4};
154- std::vector<float> selfXHostData(2048, 1);
155- ret = CreateAclTensor(selfXHostData, selfXShape, &selfXDeviceAddr, aclDataType::ACL_FLOAT, &selfX);
156- CHECK_RET(ret == ACL_SUCCESS, return ret);
157 168 
158- aclTensor* selfY = nullptr;169+ ```Cpp
159- void* selfYDeviceAddr = nullptr;170+ int main()
160- std::vector<int64_t> selfYShape = {32, 4, 4, 4};171+ {
161- std::vector<float> selfYHostData(2048, 1);172+ // 1. 调用acl进行device/stream初始化
162- ret = CreateAclTensor(selfYHostData, selfYShape, &selfYDeviceAddr, aclDataType::ACL_FLOAT, &selfY);173+ int32_t deviceId = 0;
163- CHECK_RET(ret == ACL_SUCCESS, return ret);174+ aclrtStream stream;
164- 175+ auto ret = Init(deviceId, &stream);
165- aclTensor* out = nullptr;176+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("Init acl failed. ERROR: %d\n", ret); return ret);
166- void* outDeviceAddr = nullptr;177+
167- std::vector<int64_t> outShape = {32, 4, 4, 4};178+ // 2. 构造输入与输出,需要根据API的接口自定义构造
168- std::vector<float> outHostData(2048, 1);179+ aclTensor* selfX = nullptr;
169- ret = CreateAclTensor(outHostData, outShape, &outDeviceAddr, aclDataType::ACL_FLOAT, &out);180+ void* selfXDeviceAddr = nullptr;
170- CHECK_RET(ret == ACL_SUCCESS, return ret);181+ std::vector<int64_t> selfXShape = {32, 4, 4, 4};
171- 182+ std::vector<float> selfXHostData(2048, 1);
172- // 3. 调用CANN算子库API,需要修改为具体的Api名称183+ ret = CreateAclTensor(selfXHostData, selfXShape, &selfXDeviceAddr, aclDataType::ACL_FLOAT, &selfX);
173- uint64_t workspaceSize = 0;184+ CHECK_RET(ret == ACL_SUCCESS, return ret);
174- aclOpExecutor* executor;185+
175- 186+ aclTensor* selfY = nullptr;
176- // 4. 调用aclnnAddExample第一段接口187+ void* selfYDeviceAddr = nullptr;
177- ret = aclnnAddExampleGetWorkspaceSize(selfX, selfY, out, &workspaceSize, &executor);188+ std::vector<int64_t> selfYShape = {32, 4, 4, 4};
178- CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnAddExampleGetWorkspaceSize failed. ERROR: %d\n", ret); return ret);189+ std::vector<float> selfYHostData(2048, 1);
179- 190+ ret = CreateAclTensor(selfYHostData, selfYShape, &selfYDeviceAddr, aclDataType::ACL_FLOAT, &selfY);
180- // 根据第一段接口计算出的workspaceSize申请device内存191+ CHECK_RET(ret == ACL_SUCCESS, return ret);
181- void* workspaceAddr = nullptr;192+
182- if (workspaceSize > static_cast<uint64_t>(0)) {193+ aclTensor* out = nullptr;
183- ret = aclrtMalloc(&workspaceAddr, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST);194+ void* outDeviceAddr = nullptr;
184- CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("allocate workspace failed. ERROR: %d\n", ret); return ret);195+ std::vector<int64_t> outShape = {32, 4, 4, 4};
185- }196+ std::vector<float> outHostData(2048, 1);
186- 197+ ret = CreateAclTensor(outHostData, outShape, &outDeviceAddr, aclDataType::ACL_FLOAT, &out);
187- // 5. 调用aclnnAddExample第二段接口198+ CHECK_RET(ret == ACL_SUCCESS, return ret);
188- ret = aclnnAddExample(workspaceAddr, workspaceSize, executor, stream);199+
189- CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnAddExample failed. ERROR: %d\n", ret); return ret);200+ // 3. 调用CANN算子库API,需要修改为具体的Api名称
190- 201+ uint64_t workspaceSize = 0;
191- // 6. (固定写法)同步等待任务执行结束202+ aclOpExecutor* executor;
192- ret = aclrtSynchronizeStream(stream);203+
193- CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSynchronizeStream failed. ERROR: %d\n", ret); return ret);204+ // 4. 调用aclnnAddExample第一段接口
194- 205+ ret = aclnnAddExampleGetWorkspaceSize(selfX, selfY, out, &workspaceSize, &executor);
195- // 7. 获取输出的值,将device侧内存上的结果拷贝至host侧,需要根据具体API的接口定义修改206+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnAddExampleGetWorkspaceSize failed. ERROR: %d\n", ret); return ret);
196- PrintOutResult(outShape, &outDeviceAddr);207+
197- 208+ // 根据第一段接口计算出的workspaceSize申请device内存
198- // 8. 释放aclTensor,需要根据具体API的接口定义修改209+ void* workspaceAddr = nullptr;
199- aclDestroyTensor(selfX);210+ if (workspaceSize > static_cast<uint64_t>(0)) {
200- aclDestroyTensor(selfY);211+ ret = aclrtMalloc(&workspaceAddr, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST);
201- aclDestroyTensor(out);212+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("allocate workspace failed. ERROR: %d\n", ret); return ret);
202- 213+ }
203- // 9. 释放device资源214+
204- aclrtFree(selfXDeviceAddr);215+ // 5. 调用aclnnAddExample第二段接口
205- aclrtFree(selfYDeviceAddr);216+ ret = aclnnAddExample(workspaceAddr, workspaceSize, executor, stream);
206- aclrtFree(outDeviceAddr);217+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnAddExample failed. ERROR: %d\n", ret); return ret);
207- if (workspaceSize > static_cast<uint64_t>(0)) {218+
208- aclrtFree(workspaceAddr);219+ // 6. (固定写法)同步等待任务执行结束
209- }220+ ret = aclrtSynchronizeStream(stream);
210- aclrtDestroyStream(stream);221+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSynchronizeStream failed. ERROR: %d\n", ret); return ret);
211- aclrtResetDevice(deviceId);222+
212- 223+ // 7. 获取输出的值,将device侧内存上的结果拷贝至host侧,需要根据具体API的接口定义修改
213- // 9. acl去初始化224+ PrintOutResult(outShape, &outDeviceAddr);
214- aclFinalize();225+
215- return 0;226+ // 8. 释放aclTensor,需要根据具体API的接口定义修改
216-}227+ aclDestroyTensor(selfX);
217-```228+ aclDestroyTensor(selfY);
218- 229+ aclDestroyTensor(out);
219-#### 编译与运行230+
220- 231+ // 9. 释放device资源
221->说明:对于本项目内已实现的算子(非自定义算子),可通过根目录下build.sh直接运行算子,操作请参考[调用算子样例](#调用算子样例)232+ aclrtFree(selfXDeviceAddr);
222- 233+ aclrtFree(selfYDeviceAddr);
223-1. 前提条件。234+ aclrtFree(outDeviceAddr);
224- 请参考本项目[源码编译](./quick_op_invocation.md#源码编译)完成目标算子的编译部署。235+ if (workspaceSize > static_cast<uint64_t>(0)) {
236+ aclrtFree(workspaceAddr);
237+ }
238+ aclrtDestroyStream(stream);
239+ aclrtResetDevice(deviceId);
240+
241+ // 9. acl去初始化
242+ aclFinalize();
243+ return 0;
244+ }
245+ ```
225 246 
2262. 创建CMakeLists.txt文件。2472. 创建CMakeLists.txt文件。
227 248 
@@ -231,28 +252,28 @@ int main()
231 cmake_minimum_required(VERSION 3.14)252 cmake_minimum_required(VERSION 3.14)
232 # 设置工程名253 # 设置工程名
233 project(ACLNN_EXAMPLE)254 project(ACLNN_EXAMPLE)
234- 255+
235 # 设置C++编译标准256 # 设置C++编译标准
236 add_compile_options(-std=c++11)257 add_compile_options(-std=c++11)
237- 258+
238 # 设置编译输出目录为当前目录下的bin文件夹259 # 设置编译输出目录为当前目录下的bin文件夹
239 set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "./bin") 260 set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "./bin")
240- 261+
241 # 设置调试和发布模式的编译选项262 # 设置调试和发布模式的编译选项
242 set(CMAKE_CXX_FLAGS_DEBUG "-fPIC -O0 -g -Wall")263 set(CMAKE_CXX_FLAGS_DEBUG "-fPIC -O0 -g -Wall")
243 set(CMAKE_CXX_FLAGS_RELEASE "-fPIC -O2 -Wall")264 set(CMAKE_CXX_FLAGS_RELEASE "-fPIC -O2 -Wall")
244- 265+
245 # 添加可执行文件(请替换为实际算子可执行文件),指定算子调用的*.cpp文件266 # 添加可执行文件(请替换为实际算子可执行文件),指定算子调用的*.cpp文件
246 add_executable(test_aclnn_add_example 267 add_executable(test_aclnn_add_example
247 test_aclnn_add_example.cpp) 268 test_aclnn_add_example.cpp)
248- 269+
249 # ASCEND_PATH(CANN软件包目录,请根据实际路径修改)270 # ASCEND_PATH(CANN软件包目录,请根据实际路径修改)
250 if(NOT "$ENV{ASCEND_HOME_PATH}" STREQUAL "") 271 if(NOT "$ENV{ASCEND_HOME_PATH}" STREQUAL "")
251 set(ASCEND_PATH $ENV{ASCEND_HOME_PATH})272 set(ASCEND_PATH $ENV{ASCEND_HOME_PATH})
252 else()273 else()
253 set(ASCEND_PATH "/usr/local/Ascend/cann")274 set(ASCEND_PATH "/usr/local/Ascend/cann")
254 endif()275 endif()
255- 276+
256 # 获取自定义算子包名称,存在多个自定义算子包时,只会使用其中一个277 # 获取自定义算子包名称,存在多个自定义算子包时,只会使用其中一个
257 set(VENDORS_DIR "${ASCEND_PATH}/opp/vendors")278 set(VENDORS_DIR "${ASCEND_PATH}/opp/vendors")
258 file(GLOB CUSTOM_DIRS "${VENDORS_DIR}/*")279 file(GLOB CUSTOM_DIRS "${VENDORS_DIR}/*")
@@ -261,11 +282,11 @@ int main()
261 set(TARGET_SUBDIR ${CUSTOM_DIR})282 set(TARGET_SUBDIR ${CUSTOM_DIR})
262 endif()283 endif()
263 endforeach()284 endforeach()
264- 285+
265 if(NOT DEFINED TARGET_SUBDIR)286 if(NOT DEFINED TARGET_SUBDIR)
266 message(FATAL_ERROR "在路径${ASCEND_PATH}中未找到自定义算子包") 287 message(FATAL_ERROR "在路径${ASCEND_PATH}中未找到自定义算子包")
267 endif()288 endif()
268- 289+
269 # 设置头文件路径290 # 设置头文件路径
270 set(INCLUDE_BASE_DIR "${ASCEND_PATH}/include")291 set(INCLUDE_BASE_DIR "${ASCEND_PATH}/include")
271 include_directories(292 include_directories(
@@ -276,7 +297,7 @@ int main()
276 include_directories(297 include_directories(
277 ${INCLUDE_BASE_DIR}298 ${INCLUDE_BASE_DIR}
278 )299 )
279- 300+
280 # 链接所需的动态库301 # 链接所需的动态库
281 target_link_libraries(test_aclnn_add_example PRIVATE # 替换实际算子可执行文件302 target_link_libraries(test_aclnn_add_example PRIVATE # 替换实际算子可执行文件
282 ${ASCEND_PATH}/lib64/libascendcl.so303 ${ASCEND_PATH}/lib64/libascendcl.so
@@ -287,15 +308,15 @@ int main()
287 target_link_options(test_aclnn_add_example PRIVATE308 target_link_options(test_aclnn_add_example PRIVATE
288 "-Wl,-rpath,${TARGET_SUBDIR}/op_api/lib" # 仅自定义算子需要309 "-Wl,-rpath,${TARGET_SUBDIR}/op_api/lib" # 仅自定义算子需要
289 )310 )
290- 311+
291 # 安装目标文件到bin目录 312 # 安装目标文件到bin目录
292 install(TARGETS test_aclnn_add_example DESTINATION ${CMAKE_RUNTIME_OUTPUT_DIRECTORY})313 install(TARGETS test_aclnn_add_example DESTINATION ${CMAKE_RUNTIME_OUTPUT_DIRECTORY})
293 ```314 ```
294 315 
2953. 创建run.sh文件。3163. 创建run.sh文件。
296- 317+ 
297 在test\_aclnn\_\$\{op\_name\}.cpp同级目录下创建run.sh文件,以`AddExample`算子为例,示例如下,请根据实际情况自行修改。318 在test\_aclnn\_\$\{op\_name\}.cpp同级目录下创建run.sh文件,以`AddExample`算子为例,示例如下,请根据实际情况自行修改。
298- 319+ 
299 ```bash320 ```bash
300 if [ -n "$ASCEND_INSTALL_PATH" ]; then # 实际CANN包安装路径321 if [ -n "$ASCEND_INSTALL_PATH" ]; then # 实际CANN包安装路径
301 _ASCEND_INSTALL_PATH=$ASCEND_INSTALL_PATH322 _ASCEND_INSTALL_PATH=$ASCEND_INSTALL_PATH
@@ -304,7 +325,7 @@ int main()
304 else325 else
305 _ASCEND_INSTALL_PATH="/usr/local/Ascend/cann"326 _ASCEND_INSTALL_PATH="/usr/local/Ascend/cann"
306 fi327 fi
307- 328+
308 source ${_ASCEND_INSTALL_PATH}/bin/setenv.bash329 source ${_ASCEND_INSTALL_PATH}/bin/setenv.bash
309 330
310 rm -rf build331 rm -rf build
@@ -315,86 +336,83 @@ int main()
315 cd bin336 cd bin
316 ./test_aclnn_add_example # 替换为实际算子可执行文件名337 ./test_aclnn_add_example # 替换为实际算子可执行文件名
317 ```338 ```
318- 339+ 
3194. 运行run.sh文件。3404. 运行run.sh文件。
320- 在run.sh文件所在路径执行如下命令:341+ 在run.sh文件所在路径执行如下命令:
321 342 
322 ```bash343 ```bash
323 bash run.sh344 bash run.sh
324 ```345 ```
325- 346+ 
326 默认在当前执行路径 `/build/bin`下生成可执行文件test\_aclnn\_add\_example,运行结果如下:347 默认在当前执行路径 `/build/bin`下生成可执行文件test\_aclnn\_add\_example,运行结果如下:
327 348 
328- ```bash349+ ```
329 mean result[2046] is 2.000000350 mean result[2046] is 2.000000
330 mean result[2047] is 2.000000351 mean result[2047] is 2.000000
331 ```352 ```
332 353 
333-### 图模式调用354+### GE图模式
334 355 
335#### 调用流程356#### 调用流程
336 357 
337-该方式采用算子IR(Intermediate Representation)构图方式调用算子,调用流程如下:358+该方式基于算子GE IR(Intermediate Representation)定义,以构图方式调用算子,调用流程如下:
338 359 
339![原理图](../figures/IR调用.png)360![原理图](../figures/IR调用.png)
340 361 
341-调用示例以`AddExample`算子为例,代码示例如下,仅供参考,全量代码参见[test_geir_add_example.cpp](../../../examples/add_example/examples/test_geir_add_example.cpp)。调用前,请按照环境安装的提示信息设置环境变量。362+#### 编译运行
342 363 
343-> 说明:如需调用项目已实现算子可访问目标算子`examples`目录下test\_geir\_\$\{op\_name\}.cpp,$\{op\_name\}表算子名364+> 注意操作过程中,遇到日志提示设置环境变量请按提操作
344 365 
345-```CPP366+1. 创建调用脚本。
346-int main() {
347- // 1. 创建图对象
348- Graph graph(graphName);
349 367 
350- // 2. 图全局编译选项初始化368+ 在目标算子`examples`目录下,新建调用脚本test\_geir\_\$\{op\_name\}.cpp,\$\{op\_name\}表示目标算子名。以`AddExample`算子为例,调用脚本如下,仅供参考,全量代码参见[test_geir_add_example.cpp](../../../examples/add_example/examples/test_geir_add_example.cpp)。
351- Status ret = ge::GEInitialize(globalOptions);
352 369 
353- // 3. 创建AddExample算子实例370+ ```CPP
354- auto add1 = op::AddExample("add1");371+ int main() {
372+ // 1. 创建图对象
373+ Graph graph(graphName);
374+
375+ // 2. 图全局编译选项初始化
376+ Status ret = ge::GEInitialize(globalOptions);
377+
378+ // 3. 创建AddExample算子实例
379+ auto add1 = op::AddExample("add1");
380+
381+ // 4. 定义图输入输出向量
382+ std::vector<Operator> inputs{};
383+ std::vector<Operator> outputs{};
384+
385+ // 5. 准备输入数据
386+ std::vector<int64_t> xShape = {32,4,4,4};
387+ // 宏展开方式处理变量赋值
388+ ADD_INPUT(1, x1, inDtype, xShape);
389+ ADD_INPUT(2, x2, inDtype, xShape);
390+ ADD_OUTPUT(1, y, inDtype, xShape);
391+
392+ outputs.push_back(add1);
393+
394+ // 6. 设置图对象的输入算子和输出算子
395+ graph.SetInputs(inputs).SetOutputs(outputs);
396+
397+ // 7. 创建session对象
398+ ge::Session* session = new Session(buildOptions);
399+
400+ // 8. session添加图
401+ ret = session->AddGraph(graphId, graph, graphOptions);
402+
403+ // 9. 运行图
404+ ret = session->RunGraph(graphId, input, output);
405+
406+ // 10. 释放资源
407+ GEFinalize();
408+
409+ return 0;
410+ }
411+ ```
355 412 
356- // 4. 定义图输入输出向量413+2. 创建CMakeLists.txt文件。
357- std::vector<Operator> inputs{};
358- std::vector<Operator> outputs{};
359 414 
360- // 5. 准备输入数415+ 在test\_geir\_\$\{op\_name\}.cpp同级目录下创建CMakeLists.txt文件,以`AddExample`算子为例,示例如下,请根实际情况自行修改。
361- std::vector<int64_t> xShape = {32,4,4,4};
362- // 宏展开方式处理变量赋值
363- ADD_INPUT(1, x1, inDtype, xShape);
364- ADD_INPUT(2, x2, inDtype, xShape);
365- ADD_OUTPUT(1, y, inDtype, xShape);
366- 
367- outputs.push_back(add1);
368- 
369- // 6. 设置图对象的输入算子和输出算子
370- graph.SetInputs(inputs).SetOutputs(outputs);
371- 
372- // 7. 创建session对象
373- ge::Session* session = new Session(buildOptions);
374- 
375- // 8. session添加图
376- ret = session->AddGraph(graphId, graph, graphOptions);
377- 
378- // 9. 运行图
379- ret = session->RunGraph(graphId, input, output);
380- 
381- // 10. 释放资源
382- GEFinalize();
383- 
384- return 0;
385-}
386-```
387- 
388-#### 编译与运行
389- 
390->说明:对于本项目内已实现的算子(非自定义算子),可通过根目录下build.sh直接运行算子,操作请参考[调用算子样例](#调用算子样例)。
391- 
392-1. 前提条件。
393- 请参考本项目[源码编译](./quick_op_invocation.md#源码编译)完成目标算子的编译部署。
394- 
395-2. 创建CMakelist文件。
396- 
397- 在test\_geir\_\$\{op\_name\}.cpp同级目录下创建CMakelist文件,以`AddExample`算子为例,示例如下,请根据实际情况自行修改。
398 416 
399 ```bash417 ```bash
400 cmake_minimum_required(VERSION 3.14)418 cmake_minimum_required(VERSION 3.14)
@@ -467,13 +485,13 @@ int main() {
467 485 
4684. 运行run.sh脚本。4864. 运行run.sh脚本。
469 在run.sh文件所在路径执行如下命令:487 在run.sh文件所在路径执行如下命令:
470- 488+ 
471 ```bash489 ```bash
472 bash run.sh490 bash run.sh
473 ```491 ```
474- 492+ 
475 默认在当前执行路径 `/build/bin`下生成可执行文件test\_geir\_add\_example,运行结果如下:493 默认在当前执行路径 `/build/bin`下生成可执行文件test\_geir\_add\_example,运行结果如下:
476- 494+ 
477- ```bash495+ ```
478 INFO - [XIR]: Finalize ir graph session success496 INFO - [XIR]: Finalize ir graph session success
479 ```497 ```