Matmul高阶API使能Tiling全量常量化

案例介绍

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

本案例的算子规格如下:

表1 算子规格

输入

Shape

Data type

Format

a

128, 64

float16

ND

b

64, 30720

float16

ND

当前案例使用的AI处理器共24个核,每个核中包含1个AIC核和2个AIV核。

Tiling参数如下:

获取性能数据

使用msProf工具获取算子仿真流水图上板Profiling数据。相较于基础场景,Tiling常量化在编译期期间将部分或全部Tiling参数由变量转化为常数值,在算子执行时直接使用常量化的Tiling参数,可以减少Scalar性能开销,所以重点分析Scalar流水。

分析主要瓶颈点

设计优化方案

如下图所示,默认不使能Tiling常量化功能时,开发者在host侧创建Tiling对象,通过调用API自动获取Tiling参数。然后将Tiling参数从Host侧传递到Kernel侧,在Kernel侧初始化操作时传入。在算子执行时,使用Tiling变量参数完成矩阵乘操作。

图1 默认不使能Tiling常量化的Matmul计算流程示意图

如下图所示,使能Tiling常量化功能时,开发者只需要在Kernel侧创建Matmul对象时,调用GetMatmulApiTiling接口在编译期获取常量化Tiling信息,即可完成Tiling常量化。在算子执行时,使用常量化的Tiling参数完成矩阵乘操作,减少Scalar计算开销。

图2 使能Tiling常量化的Matmul计算流程示意图

Matmul API使能Tiling全量常量化的完整样例请参考Matmul Tiling常量化的算子样例。使能Tiling全量常量化功能的步骤如下:

  1. 调用获取MatmulConfig模板的接口GetMMConfig时,使用常数值设置MatmulShapeParams,得到带有常量化参数的自定义MatmulConfig模板CUSTOM_CFG。

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    constexpr int32_t MAX_M = 10000; // custom matmul kernel support max value of M Dim shape
    constexpr int32_t MAX_N = 10000; // custom matmul kernel support max value of N Dim shape
    constexpr int32_t MAX_K = 10000; // custom matmul kernel support max value of K Dim shape
    constexpr int32_t BASE_M = 128;  // BASE_M * BASE_K * sizeof(typeA) <=L0A size
    constexpr int32_t BASE_N = 256;  // BASE_N * BASE_K * sizeof(typeB) <=L0B size
    constexpr int32_t BASE_K = 64;   // BASE_M * BASE_N * sizeof(typeC) <=L0C size
    constexpr MatmulShapeParams shapeParams = { MAX_M,
                                                MAX_N,
                                                MAX_K,
                                                BASE_M,
                                                BASE_N,
                                                BASE_K };
    constexpr MatmulConfig CUSTOM_CFG = GetMMConfig<MatmulConfigMode::CONFIG_MDL>(shapeParams);
    

  2. 创建Matmul对象。首先调用GetMatmulApiTiling接口,将Tiling信息常量化,得到常量化模板参数CONSTANT_CFG,包括常量化的Matmul Tiling信息和MatmulConfig模板。创建Matmul对象时,使用常量化模板参数CONSTANT_CFG。

    1
    2
    3
    4
    5
    6
    using A_TYPE = AscendC::MatmulType<AscendC::TPosition::GM, CubeFormat::ND, aType>;
    using B_TYPE = AscendC::MatmulType<AscendC::TPosition::GM, CubeFormat::ND, bType>;
    using C_TYPE = AscendC::MatmulType<AscendC::TPosition::GM, CubeFormat::ND, cType>;
    using BIAS_TYPE = AscendC::MatmulType<AscendC::TPosition::GM, CubeFormat::ND, biasType>;
    constexpr static auto CONSTANT_CFG = AscendC::GetMatmulApiTiling<A_TYPE, B_TYPE, C_TYPE, BIAS_TYPE>(CUSTOM_CFG);
    AscendC::Matmul<A_TYPE, B_TYPE, C_TYPE, BIAS_TYPE, CONSTANT_CFG> matmulObj;
    

  3. 初始化操作。全量常量化时,可以在REGIST_MATMUL_OBJ接口的入参传递Tiling参数的位置,使用空指针替代。部分常量化时,在Kernel侧使用REGIST_MATMUL_OBJ接口初始化Matmul对象时,仍需要使用Tiling。

    1
    2
    3
    4
    5
    // 全量常量化场景,初始化操作示例
    REGIST_MATMUL_OBJ(&pipe, GetSysWorkSpacePtr(), matmulObj, (TCubeTiling*)nullptr);
    
    // 部分常量化场景,初始化操作示例
    REGIST_MATMUL_OBJ(&pipe, GetSysWorkSpacePtr(), matmulObj, &tiling);
    

验证优化方案性能收益

总结

算子在调用Matmul API完成矩阵乘计算时,若Matmul初始化时的Scalar计算较多,影响了指令头开销,或Matmul迭代间的Scalar计算较多,阻塞了MTE2流水。在这两类场景下,满足上文提及的Tiling常量化使能条件(全量常量化部分常量化),可以考虑使能Tiling常量化,减少Scalar计算开销,提升算子性能。