算子编译部署
编译前准备
- 编译Ascend C算子kernel侧代码实现文件*.cpp,分为源码发布和二进制发布两种方式。
- 源码发布:不对算子kernel侧实现进行编译,保留算子kernel源码文件*.cpp。该方式可以支持算子的在线编译、通过ATC模型转换的方式编译算子的场景。
- 二进制发布:对算子kernel侧实现进行编译,生成描述算子相关信息的json文件*.json和算子二进制文件*.o。如果需要直接调用算子二进制,则使用该编译方式。
- 编译Ascend C算子host侧代码实现文件*.cpp、*.h。
- 将原型定义和shape推导实现编译成算子原型定义动态库libcust_opsproto_*.so,并生成算子原型对外接口op_proto.h。
- 将算子信息库定义编译成信息库定义文件*.json。
- 将Tiling实现编译成Tiling动态库liboptiling.so等。
- 自动生成单算子API调用代码和头文件aclnn_*.h,并编译生成单算子API调用的动态库libcust_opapi.so。
编译流程
完成算子kernel、host侧的开发后,需要对算子工程进行编译,生成自定义算子安装包*.run,具体编译操作流程请参考图1。
操作步骤
- 修改工程目录下的CMakePresets.json cacheVariables的配置项,完成工程编译相关配置。CMakePresets.json文件内容如下,参数说明请参见表1。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
{ "version": 1, "cmakeMinimumRequired": { "major": 3, "minor": 19, "patch": 0 }, "configurePresets": [ { "name": "default", "displayName": "Default Config", "description": "Default build using Unix Makefiles generator", "generator": "Unix Makefiles", "binaryDir": "${sourceDir}/build_out", "cacheVariables": { "CMAKE_BUILD_TYPE": { "type": "STRING", "value": "Release" }, "ENABLE_SOURCE_PACKAGE": { "type": "BOOL", "value": "True" }, "ENABLE_BINARY_PACKAGE": { "type": "BOOL", "value": "True" }, "ASCEND_COMPUTE_UNIT": { "type": "STRING", "value": "ascendxxx" }, "ENABLE_TEST": { "type": "BOOL", "value": "True" }, "vendor_name": { "type": "STRING", "value": "customize" }, "ASCEND_PYTHON_EXECUTABLE": { "type": "STRING", "value": "python3" }, "CMAKE_INSTALL_PREFIX": { "type": "PATH", "value": "${sourceDir}/build_out" }, "ENABLE_CROSS_COMPILE": { //使能交叉编译,请根据实际环境进行配置 "type": "BOOL", "value": "False" }, "CMAKE_CROSS_PLATFORM_COMPILER": { //请替换为交叉编译工具安装后的实际路径 "type": "PATH", "value": "/usr/bin/aarch64-linux-gnu-g++" } } } ] }
- 支持自定义编译选项。通过修改算子工程op_kernel目录下的CMakeLists.txt文件,使用add_ops_compile_options来增加编译选项。
add_ops_compile_options(OpType COMPUTE_UNIT soc_version1 soc_version2 ... OPTIONS option1 option2 ...)
表2 具体参数介绍 参数名称
可选/必选
参数描述
算子类型
必选
第一个参数应传入算子类型,如果需要对算子工程中的所有算子生效,需要配置为ALL。
COMPUTE_UNIT
可选
标识编译选项在哪些AI处理器型号上生效,多个型号之间通过空格间隔。不配置时表示对所有AI处理器型号生效。
说明:COMPUTE_UNIT具体配置如下:
- 在安装昇腾AI处理器的服务器执行npu-smi info命令进行查询,获取Chip Name信息。实际配置值为AscendChip Name,例如Chip Name取值为xxxyy,实际配置值为Ascendxxxyy。
OPTIONS
必选
自定义的编译选项。多个编译选项之间通过空格间隔。
说明:- 增加-sanitizer等调试用编译选项,使能msSanitizer工具的msOpGen算子工程编译场景。
add_ops_compile_options(ALL OPTIONS -sanitizer)
- 增加-g等调试用编译选项,使能msProf工具的msProf仿真场景下的代码调用栈和热点图功能。
add_ops_compile_options(ALL COMPUTE_UNIT Ascendxxxyy OPTIONS -g)
- 增加-g -O0等调试用编译选项,使能msDebug工具。
add_ops_compile_options(ALL OPTIONS -g -O0)
- 在算子工程目录下执行如下命令,进行算子工程编译。
./build.sh
编译成功后,会在当前目录下创建build_out目录,并在build_out目录下生成自定义算子安装包custom_opp_<target os>_<target architecture>.run。
算子实现文件名称、核函数名称需相同,均为算子类型转换为下划线命名方式后的值。
下文描述了通过算子类型转换成算子实现文件名称和核函数名称的过程:- 首字符的大写字符转换为小写字符。例如:Abc -> abc。
- 大写字符的前一个字符为小写字符或数字,则在大写字符前插一个下划线“_“,并将该字符转换为小写字符。例如:AbcDef -> abc_def。
- 大写字符前一个字符为大写字符且后一个字符是小写字符,则在大写字符前插一个下划线“_“,并将该字符转换为小写字符。例如:AbcAAc -> abc_a_ac。
- 其他大写字符转换为小写字符,小写字符保持不变。
- 进行算子包部署。
算子包部署
- 自定义算子安装包部署。
在自定义算子包所在路径下,执行如下命令,安装自定义算子包。
./custom_opp_<target os>_<target architecture>.run --install-path=<path>
--install-path为可选参数,用于指定自定义算子包的安装目录。支持指定绝对路径,运行用户需要对指定的安装路径有可读写权限。
下文描述中的<vendor_name>为算子工程编译时CMakePresets.json配置文件中字段“vendor_name”的取值,默认为“customize”。- 默认安装场景,不配置--install-path参数,安装成功后会将编译生成的自定义算子相关文件部署到$HOME/Ascend/ascend-toolkit/latest/opp/vendors/<vendor_name>目录。
- 指定目录安装场景,配置--install-path参数,安装成功后会将编译生成的自定义算子相关文件部署到<path>/vendors/<vendor_name>目录,并在<path>/vendors/<vendor_name>/bin目录下新增set_env.bash,写入当前自定义算子包相关的环境变量。
如果部署算子包时通过配置--install-path参数指定了算子包的安装目录,则在使用自定义算子前,需要执行source <path>/vendors/<vendor_name>/bin/set_env.bash命令,set_env.bash脚本中将自定义算子包的安装路径追加到环境变量ASCEND_CUSTOM_OPP_PATH中,使自定义算子在当前环境中生效。
命令执行成功后,自定义算子包中的相关文件将部署至当前环境中。
- 以默认安装场景为例,可查看部署后的目录结构,如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
├── opp //算子库目录 │ ├── vendors //自定义算子所在目录 │ ├── config.ini │ └── vendor_name1 // 存储对应厂商部署的自定义算子,此名字为编译自定义算子安装包时配置的vendor_name,若未配置,默认值为customize │ ├── framework //自定义算子插件库 │ ├── op_api │ │ ├── include │ │ │ └── aclnn_xx.h //算子调用API声明文件 │ │ └── lib │ │ └── libcust_opapi.so │ ├── op_impl │ │ └── ai_core │ │ └── tbe │ │ ├── config │ │ │ └── ${soc_version} //昇腾AI处理器类型 │ │ │ └── aic-${soc_version}-ops-info.json //自定义算子信息库文件 │ │ ├── vendor_name1_impl //自定义算子实现代码文件 │ │ │ └── dynamic │ │ │ ├── xx.cpp │ │ │ └── xx.py │ │ ├── kernel //自定义算子二进制文件 │ │ │ └── ${soc_version} //昇腾AI处理器类型 │ │ │ └── config │ │ └── op_tiling │ │ ├── lib │ │ └── liboptiling.so │ └── op_proto //自定义算子原型库所在目录 │ ├── inc │ │ └── op_proto.h │ └── lib │ ├── vendor_name2 // 存储厂商vendor_name2部署的自定义算子
- 在安装昇腾AI处理器的服务器执行npu-smi info命令进行查询,获取Chip Name信息。实际配置值为AscendChip Name,例如Chip Name取值为xxxyy,实际配置值为Ascendxxxyy。
- 配置自定义算子优先级。多算子包共存的情况下,若不同的算子包目录下存在相同OpType的自定义算子,则以优先级高的算子包目录下的算子为准。下面介绍如何配置算子包优先级:
- 默认安装场景
当“opp/vendors”目录下存在多个厂商的自定义算子时,您可通过配置“opp/vendors”目录下的“config.ini”文件,配置自定义算子包的优先级。
“config.ini”文件的配置示例如下:
load_priority=vendor_name1,vendor_name2,vendor_name3
- “load_priority”:优先级配置序列的关键字,不允许修改。
- “vendor_name1,vendor_name2,vendor_name3”:自定义算子厂商的优先级序列,按照优先级从高到低的顺序进行排列。
- 指定目录安装场景
指定目录安装场景下,如果需要多个自定义算子包同时生效,分别执行各算子包安装路径下的set_env.bash脚本即可。每次脚本执行都会将当前算子包的安装路径追加到ASCEND_CUSTOM_OPP_PATH环境变量的最前面。因此可以按照脚本执行顺序确定优先级:脚本执行顺序越靠后,算子包优先级越高。
比如先执行source <path>/vendor_name1/bin/set_env.bash,后执行source <path>/vendor_name2/bin/set_env.bash,vendor_name2算子包的优先级高于vendor_name1。ASCEND_CUSTOM_OPP_PATH示例如下:
ASCEND_CUSTOM_OPP_PATH=<path>/vendor_name2:<path>/vendor_name1:
- 指定目录安装场景下安装的算子包优先级高于默认方式安装的算子包。
- 默认安装场景
- 基于msOpST工具,进行算子kernel测试,验证算子的功能。
- 基于msSanitizer工具,进行算子内存和异常检测,定位算子精度异常。
- 基于msDebug工具,进行算子上板调试,逐步确认算子精度异常。
- 基于msProf工具,生成计算内存热力图、指令流水图、及算子指令热点图统计信息,协助用户进一步优化算子性能。
- 经过以上操作步骤,确定算子精度和性能达到交付标准后,方可正常使用。