Matmul高阶API使能纯Cube模式

案例介绍

本案例呈现了在矩阵乘算子场景中,使能Matmul高阶API的纯Cube模式对算子性能的提升效果。如下图所示,Matmul API默认使用MIX模式,即用户从AIV侧发起消息,通过消息通信框架中转消息后,在AIC侧执行Matmul计算。这套消息处理机制会带来额外的Scalar性能开销。相较于MIX模式,纯Cube模式可以直接跳过消息通信框架,完成Matmul计算,提升算子性能。

图1 默认MIX模式的Matmul流程示意图
表1 算子用例规格

输入

Shape

Data type

Format

a

128, 64

float16

ND

b

64, 30720

float16

ND

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

Tiling参数如下:

获取性能数据

使用msProf工具获取算子仿真流水图上板Profiling数据。因为纯Cube模式主要优化Scalar流水性能,可以重点分析Scalar的流水情况。

分析主要瓶颈点

设计优化方案

默认MIX模式下,用户在AIV侧发起消息,通过消息通信框架中转消息后,在AIC侧执行Matmul计算。基于这样的流程,用户使用Matmul高阶API编写算子代码时,可以使用REGIST_MATMUL_OBJ宏,无需区分AIV和AIC,但也因这套消息处理机制导致产生了额外的性能开销,如图1 默认MIX模式的Matmul流程示意图所示。

实现默认MIX模式的具体步骤如下:

  1. Kernel侧,定义Matmul对象。

    1
    2
    3
    4
    5
    6
    7
    #include "lib/matmul_intf.h"
    
    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>;
    AscendC::Matmul<A_TYPE, B_TYPE, C_TYPE, BIAS_TYPE, CFG_NORM> matmulObj;
    

  2. Host侧,Matmul多核Tiling对象调用SetDim接口设置参与运算的核数。

    1
    2
    3
    4
    auto ascendcPlatform = platform_ascendc::PlatformAscendCManager::GetInstance();
    matmul_tiling::MultiCoreMatmulTiling cubeTiling(*ascendcPlatform);
    int32_t numBlocks = ascendcPlatform->GetCoreNumAiv(); // MIX模式使用GetCoreNumAiv获取AI处理器可用的核数。
    cubeTiling.SetDim(numBlocks);
    

  3. 调用核函数,参考核函数定义和调用,设置核函数的numBlocks参数配置。

    1
    matmul_custom_do(ascendcPlatform->GetCoreNumAic(), stream, x1, x2, bias, y, workspaceDevice, tilingDevice); // MIX模式下,启动时,按照AIV和AIC组合启动,numBlocks用于设置启动多少个AI Core。
    

在没有矢量计算的算子场景下,可以跳过消息通信框架的机制,使能纯Cube模式完成Matmul计算,减少消息通信的性能开销,提升算子性能。

图2 纯Cube模式的Matmul流程示意图

Matmul API使能纯Cube模式的完整样例请参考Matmul API性能优化样例。使能纯Cube模式的主要步骤如下:

  1. Kernel侧,在定义Matmul对象的代码中,包含matmul_intf.h头文件前设置ASCENDC_CUBE_ONLY宏。

    1
    2
    3
    4
    5
    6
    7
    8
    #define ASCENDC_CUBE_ONLY // 在#include "lib/matmul_intf.h"前,设置ASCENDC_CUBE_ONLY宏
    #include "lib/matmul_intf.h"
    
    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>;
    AscendC::Matmul<A_TYPE, B_TYPE, C_TYPE, BIAS_TYPE, CFG_NORM> matmulObj;
    

  2. Host侧,Matmul多核Tiling对象调用SetDim接口设置参与运算的核数。

    1
    2
    3
    4
    auto ascendcPlatform = platform_ascendc::PlatformAscendCManager::GetInstance();
    matmul_tiling::MultiCoreMatmulTiling cubeTiling(*ascendcPlatform);
    int32_t numBlocks = ascendcPlatform->GetCoreNumAic(); // 纯Cube模式使用GetCoreNumAic接口获取AI处理器可用的核数。
    cubeTiling.SetDim(numBlocks);
    

  3. 调用核函数,参考核函数定义和调用,设置核函数的numBlocks参数配置。

    1
    matmul_custom_do(ascendcPlatform->GetCoreNumAic(), stream, x1, x2, bias, y, workspaceDevice, tilingDevice); // 仅包含Cube计算的算子,numBlocks用于设置启动多少个AIC。
    

  4. Kernel侧,核函数实现中增加AIV侧返回分支。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    extern "C" __global__ __aicore__ void matmul_custom(GM_ADDR a, GM_ADDR b,
        GM_ADDR bias, GM_ADDR c, GM_ADDR workspace, GM_ADDR tilingGm)
    {
        if (g_coreType == AscendC::AIV) { // 纯Cube模式,AIV侧直接return
            return;
        }
        ...
        // 其他代码
    }
    

验证优化方案性能收益

总结

在只有矩阵计算,没有矢量计算的场景下,可以考虑使能纯Cube模式,优化Matmul计算中的消息通信性能开销,提升算子性能。