自动调优流程
功能约束
- 单Device仅支持使用单个msKPP工具进行自动调优,且不推荐同时运行其他算子程序。
- 需确保先import mskpp再import acl,否则需要在运行前设置环境变量。
export LD_PRELOAD=${INSTALL_DIR}/lib64/libmspti.so
具体操作
本章节以模板库example/00_basic_matmul为例,介绍如何利用msKPP工具提供的Python接口实现自动调优功能。

在运行过程中出现任何异常,可通过设置环境变量的方式来查看debug日志以及保留中间文件,便于问题定位。
export MSKPP_LOG_LEVEL=0
- 完成算子kernel开发后,kernel函数的定义与实现在basic_matmul.cpp文件中,如下所示:
// basic_matmul.cpp // ... template <class LayoutA, class LayoutB, class LayoutC> ACT_GLOBAL void BasicMatmul( GemmCoord problemShape, GM_ADDR gmA, LayoutA layoutA, GM_ADDR gmB, LayoutB layoutB, GM_ADDR gmC, LayoutC layoutC ) { // Kernel 实现 } // ...
- 在examples/autotune目录中创建Python脚本文件basic_matmul_autotune.py。按照如下要求,定义算子kernel函数的Python接口:
- 在Python脚本中定义basic_matmul函数,其入参需与C++代码中的kernel函数保持一致。
- mskpp.compile中的build_script参数可直接使用模板库examples/autotune/helper目录下的jit_build.sh。
# basic_matmul_autotune.py import mskpp def get_kernel(): kernel_file = "../00_basic_matmul/basic_matmul.cpp" kernel_name = "BasicMatmul" build_script = "./helper/jit_build.sh" # kernel compile script config = mskpp.KernelInvokeConfig(kernel_file, kernel_name) gen_file = mskpp.Launcher(config).code_gen() kernel = mskpp.compile(build_script=build_script, launch_src_file=gen_file) return kernel def basic_matmul(problem_shape, a, layout_a, b, layout_b, c, layout_c): # 入参需与C++代码中的kernel函数保持一致 # This function's input arguments must exactly match the kernel function. kernel = get_kernel() blockdim = 20 return kernel[blockdim](problem_shape, a, layout_a, b, layout_b, c, layout_c, ) # invoke the kernel
- 参考如下代码实现,构造kernel入参,实现basic_matmul函数的正常运行。
- 若算子kernel函数入参是GM_ADDR,则构造入参需使用numpy.array类型。
- 若算子kernel函数入参是C++结构体对象,则需借助ctypes.Structure在Python中构建一个相同的结构体。针对模板库提供的结构体对象,如果在examples/autotune/helper/act_type.py中已进行Python实现,则可直接使用,比如GemmCoord、RowMajor、ColumnMajor等。
import numpy as np import mskpp from helper.act_type import GemmCoord, RowMajor if __name__ == "__main__": m = 256 n = 512 k = 1024 problem_shape = GemmCoord(m, n, k) layout_a = RowMajor(m, k) layout_b = RowMajor(k, n) layout_c = RowMajor(m, n) a = np.random.randint(1, 2, [m, k]).astype(np.half) b = np.random.randint(1, 2, [k, n]).astype(np.half) c = np.zeros([m, n]).astype(np.half) basic_matmul(problem_shape, a, layout_a, b, layout_b, c, layout_c) # check if the output tensor c is consistent with the golden data golden = np.matmul(a, b) is_equal = np.array_equal(c, golden) result = "success" if is_equal else "failed" print("compare {}.".format(result))
- 运行Python脚本,获得如下提示,说明算子Kernel已可正常通过Python接口拉起。
$ python3 basic_matmul_autotune.py compare success.
- 在算子代码程序basic_matmul.cpp中标识需调优的参数。
在模板参数的声明代码行末尾使用//tunable标记,用于替换"="号后的代码内容,tunable用于搜索空间索引。
using L1TileShape = GemmShape<128, 256, 256>; // tunable using L0TileShape = GemmShape<128, 256, 64>; // tunable
除tunable标识的方法之外,还可以在需要整行替换的代码行末尾使用// tunable: 别名(L0Shape)方式标记。其中,别名用于搜索空间索引。using L0TileShape = MatmulShape<128, 256, 64>; // tunable: L0Shape
- 通过autotune接口的configs入参定义参数搜索空间,每一类参数组合会替换算子kernel代码中被标记的代码行,然后进行编译、运行并完成kernel性能采集。搜索空间定义示例可参考如下所示。
- configs数量需小于等于16。
- 参数替换需合理,不能造成编译或运行错误。
- 参数替换原则如下(以configs中的第一行为例):
- 先替换// tunable: L0Shape方式标记的参数,将标记代码行(MatmulShape<128, 256, 64>)整行替换为configs中的value字符串(MatmulShape<128, 256, 64>)。
- 再替换// tunable方式标记的代码行,将"="号后的MatmulShape<128, 256, 256>替换为configs中value字符串MatmulShape<64, 64, 64>。
- 不同作用域中,可能会有两个同名的变量被声明。若两个变量均符合匹配规则时,仅第一个变量会被修改。
- 若其中一个config未匹配成功,该config对应的任务会停止并报错。但其他匹配成功的config将会成功进行参数替换。
@mskpp.autotune(configs=[ # add and try your own config here for a better kernel performance {'L1TileShape': 'GemmShape<64, 64, 64>', 'L0TileShape': 'GemmShape<64, 64, 64>'}, {'L1TileShape': 'GemmShape<64, 64, 128>', 'L0TileShape': 'GemmShape<64, 64, 64>'}, {'L1TileShape': 'GemmShape<64, 128, 128>', 'L0TileShape': 'GemmShape<64, 128, 64>'}, {'L1TileShape': 'GemmShape<128, 128, 128>', 'L0TileShape': 'GemmShape<128, 128, 64>'}, {'L1TileShape': 'GemmShape<128, 64, 128>', 'L0TileShape': 'GemmShape<128, 64, 64>'}, ], warmup=1000, repeat=10, device_ids=[0]) # set kernel warmup 1000us
- 执行basic_matmul_autotune.py文件运行算子,获得每种参数组合的耗时及最佳调优参数集合。下图展示了可能的一种命令行输出结果。
# python3 basic_matmul_autotune.py No.1: 24.532μs, {'L1TileShape': 'GemmShape<64, 64, 128>', 'L0TileShape': 'GemmShape<64, 64, 64>'} No.0: 27.693μs, {'L1TileShape': 'GemmShape<64, 64, 64>', 'L0TileShape': 'GemmShape<64, 64, 64>'} No.2: 16.986μs, {'L1TileShape': 'GemmShape<64, 128, 128>', 'L0TileShape': 'GemmShape<64, 128, 64>'} No.3: 20.192μs, {'L1TileShape': 'GemmShape<128, 128, 128>', 'L0TileShape': 'GemmShape<128, 128, 64>'} No.4: 21.540μs, {'L1TileShape': 'GemmShape<128, 64, 128>', 'L0TileShape': 'GemmShape<128, 64, 64>'} Best config: No.2 compare success.
通过对比得知,No.2为最佳调优参数集合。
父主题: 自动调优