Matmul常量化算子性能提升案例

案例介绍

本案例呈现了在使用Matmul高阶API进行矩阵乘法计算时,使能Matmul Tiling常量化对算子性能的提升效果。Matmul Tiling常量化的介绍请参考Matmul Tiling常量化

Matmul API在初始化和迭代过程中有大量Scalar计算,Matmul初始化时的Scalar计算影响指令头开销,Matmul迭代间的Scalar计算可能阻塞MTE2流水。在调用Matmul API实现矩阵乘法时,通过使用全量常量化的MatmulApiStaticTiling模板参数,替代非常量TCubeTiling参数。将Scalar计算提前到编译期,以减少运行时的Scalar计算开销,实现算子性能的提升。

Matmul常量化的适用场景:

Matmul常量化需要在编译期确定部分Tiling参数,根据确定参数的不同,分为全量常量化和部分常量化两种场景,使用Matmul常量化需要满足两种场景中任一场景的条件:

其中,全量常量化场景比部分常量化场景可以减少更多的Scalar计算开销。

本案例的算子规格如下:

表1 算子规格

输入

Shape

Data type

Format

a

32, 2048

float16

ND

b

2048, 32

float16

ND

更多的使能Matmul Tiling常量化的完整样例请参考matmul_api_constant

获取性能数据

使用msProf工具获取算子的Profiling数据,重点分析Scalar的流水情况。

分析主要瓶颈点

图1 优化前Profiling数据

由以上Profiling数据,可以看出Scalar耗时占比较大,当前性能瓶颈点在于Scalar流水。性能优化前,算子执行多次的平均耗时为21.88us。

设计优化方案

使能Matmul Tiling常量化:在创建Matmul对象时,使用常量化模板参数。具体步骤如下。

  1. 调用获取MatmulConfig模板的接口GetMMConfig时,使用常数值设置MatmulShapeParams,得到带有常量化参数的自定义MatmulConfig模板。
  2. 调用GetMatmulApiTiling接口,将Tiling信息常量化,得到常量化模板参数,包括常量化的Matmul Tiling信息和MatmulConfig模板。
  3. 创建Matmul对象时,使用步骤2的常量化模板参数。

在该算子规格下,根据GetTiling接口获取的最优Tiling,singleCoreM/singleCoreN/singleCoreK的数值为32/32/2048,baseM/baseN/baseK的数值为32/32/256。在原始代码的基础上,仅需修改创建Matmul对象的部分,具体如下。

1
2
3
4
5
6
constexpr static MatmulShapeParams shapeParams = {32, 32, 2048, 32, 32, 256};
constexpr static MatmulConfig MM_CFG = GetMMConfig<MatmulConfigMode::CONFIG_NORM>(shapeParams);

constexpr MatmulApiStaticTiling static MM_CFG_CONSTANT = GetMatmulApiTiling<A_TYPE, B_TYPE, C_TYPE, BIAS_TYPE>(MM_CFG);

AscendC::MatmulImpl<A_TYPE, B_TYPE, C_TYPE, BIAS_TYPE, MM_CFG_CONSTANT> mm;

验证优化方案性能收益

性能优化后,算子执行多次的平均耗时为17.728us,其中Scalar计算减少了44.4%,较优化前有较大提升。

图2 优化后Profiling数据

总结

在Matmul单核、单次计算的Shape信息(singleCoreM/singleCoreN/singleCoreK、baseM/baseN/baseK)确定的情况下,可以考虑使能Matmul Tiling常量化,减少Scalar计算开销,提升算子性能。