使用msOpGen工具创建算子工程时,相关编译脚本被固化在本地,若需使用算子工程提供的新特性(比如支持MC2算子等),需重新运行msOpGen工具生成工程。为了解决开发者因功能更新而频繁重建工程的问题,将算子工程的cmake脚本打包到CANN软件包中。开发者可通过find_package的形式来查找对应的cmake modules包,从而使用算子工程对外提供的cmake函数接口。
该开发方式下,开发者参考如下工程目录,自行组织算子工程。目录结构与通过msOpGen生成的目录结构类似, 但无需再创建cmake与scripts目录,这些目录被打包至CANN软件包中。以AddCustom算子为例,目录结构如下:
AddCustom ├── CMakeLists.txt // 算子工程顶层CMakeLists.txt ├── CMakePresets.json // 编译配置项,cmake内置功能,若使能则需3.19及以上cmake版本 ├── framework // AI框架适配时,算子插件实现文件目录 ├── op_host // Host侧实现文件 │ ├── add_custom.cpp // 算子原型注册、Shape推导、Tiling实现等内容文件 │ ├── add_custom_tiling.h // 算子Tiling定义文件 │ └── CMakeLists.txt // Host侧CMakeLists文件 ├── op_kernel // Kernel侧实现文件 │ ├── Add │ │ ├── add_custom.cpp // 算子代码实现文件 └ └── CMakeLists.txt // Kernel侧CMakeLists文件
cmake_minimum_required(VERSION 3.16.0) # 指定所需的最低cmake版本号
project(opp)
# 1、使用find_package找到对应的编译库。
# ${ASCEND_CANN_PACKAGE_PATH}为对应的CANN软件包路径,开发者可直接使用
find_package(ASC REQUIRED HINTS ${ASCEND_CANN_PACKAGE_PATH}/compiler/tikcpp/ascendc_kernel_cmake)
# 2、使用npu_op_package设置算子工程的编译产物形态。
set(package_name ${vendor_name})
npu_op_package(${package_name} # package name
# RUN模式下会使用该name命名算子部署后的目录,静态库模式下输出产物为lib${package_name}.a
TYPE RUN # 指定编译产物形态,[RUN|STATIC|SHARED]
CONFIG
ENABLE_SOURCE_PACKAGE True # 是否将源码打包到run包中
ENABLE_BINARY_PACKAGE True # 是否编译Kernel二进制, SHARED/STATIC模式下必须指定为True, 默认值为True
INSTALL_PATH ${CMAKE_BINARY_DIR}/ # package的安装位置
)
#3、添加需要进行编译的子目录。
if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/op_host)
add_subdirectory(op_host) # 添加子目录op_host进行编译
endif()
if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/op_kernel)
add_subdirectory(op_kernel) # 添加子目录op_kernel进行编译
endif()
aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR} ops_srcs)
#1、使用npu_op_code_gen生成aclnn单算子调用代码、入图所需的原型定义代码等。
npu_op_code_gen(
SRC ${ops_srcs} # Host侧实现文件集合
PACKAGE ${package_name} # 与npu_op_package的package_name对应
COMPILE_OPTIONS -g # 编译选项
OUT_DIR ${ASCEND_AUTOGEN_PATH} # 指定生成文件的保存路径
JOIN_OP_DEF False # 可选参数,默认为False。设置为False,仅编译CMakePreset.json中设置的AI处理器型号对应的算子;设置成True,则编译CMakePreset.json和算子原型注册中共有的AI处理器型号对应的算子。
)
#2、单算子调用场景,使用npu_op_library编译aclnn单算子调用库。
file(GLOB autogen_aclnn_src ${ASCEND_AUTOGEN_PATH}/aclnn_*.cpp) # 将通过npu_op_code_gen生成的aclnn相关源文件添加至源文件列表中
set_source_files_properties(${autogen_aclnn_src} PROPERTIES GENERATED TRUE) # 设置对应的文件属性为编译过程中生成的文件
npu_op_library(cust_opapi ACLNN # 指定library名称与类型,以及参与编译的源文件
${autogen_aclnn_src}
)
target_compile_options(cust_opapi PRIVATE # 为对应library添加编译选项,与通用的cmake语法一致
-fvisibility=hidden
)
#3、算子入图场景,使用npu_op_library编译算子入图所需的算子原型库。
file(GLOB proto_src ${ASCEND_AUTOGEN_PATH}/op_proto.cc) # 将通过npu_op_code_gen生成的原型定义相关源文件添加至源文件列表中
set_source_files_properties(${proto_src} PROPERTIES GENERATED TRUE) # 设置对应的文件属性为编译过程中生成的文件
npu_op_library(cust_op_proto GRAPH # 指定library名称与类型,以及参与编译的源文件
${ops_srcs}
${proto_src}
)
target_compile_options(cust_op_proto PRIVATE # 为对应library添加编译选项,与通用的cmake语法一致
-fvisibility=hidden
)
#4、使用npu_op_library编译Tiling相关库。
file(GLOB fallback_src ${ASCEND_AUTOGEN_PATH}/fallback_*.cpp) # 将通过npu_op_code_gen生成的Tiling相关源文件添加至源文件列表中
# 若算子配置了EnableFallBack会生成该文件
set_source_files_properties(${fallback_src} PROPERTIES GENERATED TRUE) # 设置对应的文件属性为编译过程中生成的文件
npu_op_library(cust_optiling TILING # 指定library名称与类型,以及参与编译的源文件
${ops_srcs}
${fallback_src}
)
target_compile_options(cust_optiling PRIVATE # 为对应library添加编译选项,与通用的cmake语法一致
-fvisibility=hidden
)
#5、使用npu_op_package_add添加上述Host侧库到对应package中。
npu_op_package_add(${package_name} # 与npu_op_package的package_name对应
LIBRARY # 添加Host侧相关library,library名称与前述步骤的library名称对应
cust_optiling
cust_opapi
cust_op_proto
)
#1、使用npu_op_kernel_options添加算子编译选项。
npu_op_kernel_options(ascendc_kernels ALL OPTIONS --save-temp-files -g)# 为算子添加编译选项
#2、使用npu_op_kernel_sources指定算子特定目录与编译源文件。
npu_op_kernel_sources(ascendc_kernels # 对应的Kernel库名称,与npu_op_kernel_library保持一致
OP_TYPE AddCustom # 若算子的Kernel实现cpp文件需要自定义命名,需配置算子类型
KERNEL_DIR ./Add # 将KERNEL_DIR目录与SRC_BASE目录进行拼接,作为Kernel实现cpp文件所在的目录
COMPUTE_UNIT Ascendxxxyy # 设置KERNEL_FILE在Ascendxxxyy型号生效
KERNEL_FILE add_custom.cpp # 若算子的Kernel实现cpp文件需要自定义命名,需配置Kernel实现cpp文件名
)
#3、使用npu_op_kernel_library编译Kernel库。
npu_op_kernel_library(ascendc_kernels # Kernel库名称
SRC_BASE ${CMAKE_SOURCE_DIR}/op_kernel/ # 指定kernel侧源码的根目录
TILING_LIBRARY cust_optiling # 指定依赖的Tiling库
)
#4、添加kernel侧library到package
npu_op_package_add(${package_name} # 与npu_op_package的package_name对应
LIBRARY ascendc_kernels # 添加Kernel侧相关library,library名称与前述步骤的library名称对应
)
下表列出了供用户配置和使用的编译环境选项:
类型 |
环境选项 |
默认值 |
说明 |
|---|---|---|---|
STRING |
vendor_name |
customize |
标识自定义算子所属厂商的名称。建议开发者自行指定所属厂商名称,避免和其他厂商提供的算子包冲突。 |
STRING |
ASCEND_COMPUTE_UNIT |
- |
AI处理器型号。编译对应型号的package。 |
PATH |
ASCEND_AUTOGEN_PATH |
<CMAKE_BINARY_DIR>/autogen |
通过npu_op_code_gen生成的aclnn单算调用、入图所需算子原型库等源文件存放路径。 |
BOOL |
ENABLE_SOURCE_PACKAGE |
TRUE |
是否开启源码编译。 如果使用npu_op_package配置了源码和二进制编译相关配置,npu_op_package配置的优先级更高。 |
BOOL |
ENABLE_BINARY_PACKAGE |
TRUE |
是否开启二进制编译。 package的类型配置为SHARED或STATIC时,必须指定为TRUE。 如果使用npu_op_package配置了源码和二进制编译相关配置,npu_op_package配置的优先级更高。 |
PATH |
ASCEND_CANN_PACKAGE_PATH |
- |
CANN软件包路径,默认情况下用户无需配置。开发者可以在编写cmake文件时直接使用。 路径示例如下:/usr/local/Ascend/cann。 |
上述编译环境选项可通过两种方式进行配置:
# CMakeLists.txt直接使用 set(vendor_name "customize") set(ASCEND_COMPUTE_UNIT "ascendxxxyy")
{
"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": {
"ASCEND_COMPUTE_UNIT": {
"type": "STRING",
"value": "ascendxxxyy"
},
"vendor_name": {
"type": "STRING",
"value": "customize"
}
}
}
]
}
然后使用如下命令进行构建,根据--preset指定的preset进行编译。
// Shell环境中cmake构建编译 cmake -S . -B build_out --preset=default // 在当前目录(.)中寻找CMakePresets.json
package的类型配置为RUN时,可参考如下编译命令进行编译,使用cmake的pack能力生成run包。
# 工程根目录下执行
mkdir -p build_out
rm -rf build_out/*
cmake -S . -B build_out --preset=default
cmake --build build_out --target binary -j${nproc}
cmake --build build_out --target package -j${nproc}
package的类型配置为SHARED或STATIC时,可参考如下编译命令进行编译:
# 工程根目录下执行
mkdir -p build_out
rm -rf build_out/*
cmake -S . -B build_out --preset=default
cmake --build build_out --target binary -j${nproc}
cmake --build build_out --target install -j${nproc}
提供如下cmake函数供开发者使用:
类型 |
接口 |
功能 |
|---|---|---|
package |
创建一个package。 |
|
将目标或文件添加到package中。 |
||
library |
创建Host侧库。 |
|
创建Kernel侧库。 |
||
添加Kernel目标编译选项。 |
||
描述Kernel目标的源码信息。 |
||
创建Device侧Tiling库。 |
||
其他 |
执行代码生成过程,生成aclnn单算子调用代码和入图所需的原型定义代码。 |
npu_op_package(<package_name> TYPE <type> [CONFIG] [ENABLE_SOURCE_PKG <value>] [ENABLE_BINARY_PACKAGE <value>] [INSTALL_PATH <path>])
# 添加目标 npu_op_package_add(<package_name> LIBRARY <target_name1> [<target_name2>...] ) # 添加文件,仅给run包模式使用 npu_op_package_add(<package_name> FILES <file_name1> [<file_name2>...] [TYPE <target_type>] [PACKAGE_PATH <pkg_path>])
参数说明如下:
npu_op_library(<library_name> TYPE <library_type> <files>)
参数说明如下:
npu_op_kernel_library(<target_name> SRC_BASE <path> TILING_LIBRARY <tiling_target>)
参数说明如下:
npu_op_kernel_options(<target_name> <op_type> [COMPUTE_UNIT <soc_version>] OPTIONS …)
参数说明如下:
<soc_version>具体配置如下:
其中,id为设备id,通过npu-smi info -l命令查出的NPU ID即为设备id。
描述Kernel目标的源码信息,包括设置算子的Kernel实现文件和源码路径等。
npu_op_kernel_sources(<target_name> [OP_TYPE <op_type>] [KERNEL_DIR <path>] [COMPUTE_UNIT <soc_version>] [KERNEL_FILE <file>])
参数说明如下:
若算子的源码文件没有平铺在SRC_BASE目录(通过npu_op_kernel_library设置)下,可以通过KERNEL_DIR指定特定目录。
若算子的Kernel实现cpp文件需要自定义命名,需同时指定OP_TYPE(算子类型)和KERNEL_FILE(Kernel实现cpp文件名),以配置两者之间的对应关系。不配置时,Kernel实现cpp文件名和OpType之间需满足转换规则。
创建Device侧Tiling库。使用该选项时,package的类型仅支持配置为RUN(run包模式)。
npu_op_device_tiling_library(<target_name> <type> <files>)
参数说明如下:
执行代码生成过程,生成aclnn单算子调用代码和入图所需的原型定义代码。
npu_op_code_gen(SRC <src_files> OUT_DIR <output_dir> PACKAGE <pkg_name> [COMPILE_OPTIONS ...])
参数说明如下: