Developers
资源
[object Object][object Object]

在定义Tiling结构体时,可以使用标准C++语法定义一个POD类型(Plain Old Data),即与C语言兼容的数据类型。具体步骤如下。完整样例请参考

  1. 使用C++语法定义Tiling结构体。

    [object Object]

    用户在使用高阶API的Tiling结构体时,通过AscendC::tiling命名空间引用"kernel_tiling/kernel_tiling.h"中预定义的Tiling结构体,如下代码所示。

    [object Object]
  2. Host侧Tiling函数中对Tiling结构体赋值。

    • 需要包含Tiling结构体定义头文件。
    • 通过GetTilingData获取Tiling结构体指针,并对其成员变量进行赋值。
    [object Object]
  3. Kernel侧注册Tiling结构体,解析Tiling数据至TilingData结构并使用。

    • 需要包含Tiling结构体定义头文件。
    • 通过或者注册Tiling结构体;通过解析Tiling数据至TilingData结构并使用。其中REGISTER_TILING_DEFAULT同时也用于标识使用标准C++语法定义TilingData结构体。
    [object Object]
[object Object]

相比较使用BEGIN_TILING_DATA_DEF等宏进行定义的方式,该方式不仅更符合C++开发者的开发习惯,并且提供了强大的灵活性。

  • 支持bool类型,支持数组、结构体数组及列表初始化。

    [object Object]
  • 不同算子可以支持定义同名但结构不同的Tiling结构体,通过算子引用对应的头文件即可实现区分。这种方式允许每个算子使用符合自身需求的Tiling结构定义,而不会与其他算子产生冲突。

    相比之下,使用BEGIN_TILING_DATA_DEF等宏方式定义同名但结构不同的Tiling结构体时,由于这些结构体会被注册到全局的Tiling结构体管理变量中,可能导致后续通过结构体名称访问时,无法准确获取当前算子实际使用的Tiling结构体,从而引发未定义行为。

    算子A:

    [object Object]

    算子B:

    [object Object]
  • 支持自定义Tiling赋值,用户可以通过访问Tiling结构体成员变量直接赋值,或自定义Tiling赋值函数(宏定义方式下,用户仅可通过框架生成的set_xx/get_xx方法赋值/访问)

    Tiling结构体定义:

    [object Object]

    Host侧Tiling函数:

    [object Object]
[object Object]

使用标准C++语法定义Tiling结构体时存在如下约束限制:

  • Tiling结构体内不支持定义成员函数,因为成员函数存在Device侧和Host侧的差异(Device侧的函数需要__aicore__修饰符),而Tiling结构体Device侧和Host侧共用,所以会在编译或执行时出现问题:

    [object Object]
  • Tiling结构体成员变量不支持指针、引用类型,此类数据类型会导致Host侧到Device侧数据解析异常:

    [object Object]
  • Tiling结构体仅支持POD类型,没有虚函数、虚继承等面向对象特性,也不支持模板类:

    [object Object]
  • GetTilingData获取的Tiling不包含初值,需显式赋值或在Tiling结构体定义并调用Tiling赋值函数;

    [object Object]
  • host侧和kernel侧的Tiling结构体支持传入模板参数。由于宏函数中逗号运算符的特殊性,在kernel侧宏函数(REGISTER_TILING_DEFAULT或者REGISTER_TILING_FOR_TILINGKEY)使用带逗号的模板类型(如:template<int32_t sizeA, int32_t sizeB>),存在编译异常,因此需要使用别名方式来定义带逗号的模板类型(如:using size = template<int32_t sizeA, int32_t sizeB>)。具体示例如下:

    [object Object]
[object Object]

本节介绍如何将使用BEGIN_TILING_DATA_DEF等宏进行定义的方式改造成使用标准C++语法的方式。

  1. 首先将之前位于op_host目录下的Tiling结构体定义头文件移至op_kernel目录下,内容前后对比如下,注意此时包含的头文件变化,不需要再包含宏定义相关的头文件

    表 1 两种方式对比

    [object Object][object Object]

    [object Object]

    namespace optiling { BEGIN_TILING_DATA_DEF(MatmulCustomTilingData) TILING_DATA_FIELD_DEF(uint64_t, localMemSize); TILING_DATA_FIELD_DEF_STRUCT(TCubeTiling, cubeTilingData); END_TILING_DATA_DEF; REGISTER_TILING_DATA_CLASS(MatmulCustom, MatmulCustomTilingData) } // namespace optiling[object Object]

    [object Object]

    struct MatmulCustomTilingData { uint64_t localMemSize; AscendC::tiling::TCubeTiling cubeTilingData; };[object Object]

    [object Object]
  2. 然后修改Host侧的Tiling函数实现,此时对Tiling结构体的成员变量赋值无需使用宏定义生成的set方法,而是使用用户熟悉的C++指针赋值方式。

    表 2 两种方式对比

    [object Object][object Object]

    [object Object]
    [object Object]

    } } // namespace optiling[object Object]

    [object Object]

    namespace optiling { static ge::graphStatus TilingFunc(gert::TilingContext *context) { ... MultiCoreMatmulTiling cubeTiling(ascendcPlatform); ... MatmulCustomTilingData *tiling = context->GetTilingData<MatmulCustomTilingData>(); if (cubeTiling.GetTiling(tiling->cubeTilingData) == -1) { return ge::GRAPH_FAILED; } uint64_t localMemSize; ascendcPlatform.GetCoreMemSize(platform_ascendc::CoreMemType::UB, localMemSize); tiling->localMemSize = localMemSize; // 使用用户友好的C++指针方式赋值成员变量 ... return ge::GRAPH_SUCCESS; } } // namespace optiling[object Object]

    [object Object]
  3. 最后,在Kernel 函数入口处新增调用,用于注册Tiling结构体。该注册操作的作用是:告知框架用户已使用标准 C++ 语法定义Tiling结构体,并明确其类型,以便框架在进行Tiling数据解析时能够正确识别和使用该结构体。

    [object Object]