When defining a tiling structure, you can use the standard C++ syntax to define a Plain Old Data (POD) type, that is, a data type compatible with the C language. The procedure is described below. For details about the complete sample, see sample of defining the Tiling structure using standard C++ syntax.
The header file of the structure definition must be stored in the op_kernel directory of the operator project. Only files in this directory are packed into the operator package for online compilation. If required files are stored in other directories, online compilation may fail because related files cannot be found.
1 2 3 4 5 6 7 8 9 10 |
#ifndef MATMUL_CUSTOM_TILING_H #define MATMUL_CUSTOM_TILING_H #include <cstdint> #include "kernel_tiling/kernel_tiling.h" // for TCubeTiling struct MatmulCustomTilingData { uint64_t localMemSize; AscendC::tiling::TCubeTiling cubeTilingData; }; #endif // MATMUL_CUSTOM_TILING_H |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
#include "../op_kernel/matmul_custom_tiling.h" // Contain the header file of the tiling structure definition. ... namespace optiling { static ge::graphStatus TilingFunc(gert::TilingContext *context) { ... MultiCoreMatmulTiling cubeTiling(ascendcPlatform); ... // Obtain the pointer to the tiling structure. MatmulCustomTilingData *tiling = context->GetTilingData<MatmulCustomTilingData>(); // Assign values to the member variables of the tiling structure. if (cubeTiling.GetTiling(tiling->cubeTilingData) == -1) { return ge::GRAPH_FAILED; } uint64_t localMemSize; ascendcPlatform.GetCoreMemSize(platform_ascendc::CoreMemType::UB, localMemSize); tiling->localMemSize = localMemSize; ... return ge::GRAPH_SUCCESS; } } // namespace optiling |
1 2 3 4 5 6 7 8 9 10 11 12 13 |
#include "kernel_operator.h" #include "matmul_custom_tiling.h" // Contain the header file of the tiling structure definition. extern "C" __global__ __aicore__ void matmul_custom(GM_ADDR a, GM_ADDR b, GM_ADDR bias, GM_ADDR c, GM_ADDR workspace, GM_ADDR tiling) { REGISTER_TILING_DEFAULT(MatmulCustomTilingData); GET_TILING_DATA(tilingData, tiling); MatmulKernel<half, half, float, float> matmulKernel; AscendC::TPipe pipe; REGIST_MATMUL_OBJ(&pipe, GetSysWorkSpacePtr(), matmulKernel.matmulObj, &tilingData.cubeTilingData); // Initialize the matmul object. matmulKernel.Init(a, b, bias, c, workspace, tilingData.localMemSize, tilingData.cubeTilingData); ... } |
Compared with the method of using macros such as BEGIN_TILING_DATA_DEF for definition, this method is more in line with the development habits of C++ developers and provides powerful flexibility.
class A {
public:
bool xxx;
uint32_t xxx[2][128] = {0};
};
class B {
public:
bool xxx = false;
uint8_t xxx[2][2]{0};
A[10];
};In contrast, when macros such as BEGIN_TILING_DATA_DEF are used to define tiling structures with the same name but different layouts, these structures are registered with a global tiling structure management variable. In this case, accessing a structure by name may fail to retrieve the one intended for the current operator, leading to undefined behavior.
class TilingData {
public:
uint32_t length;
};
Operator B:
class TilingData {
public:
uint32_t length;
uint16_t coreNum;
};
class TilingData {
public:
uint32_t xxx1;
uint32_t xxx2;
uint8_t xxx3;
bool xxx4;
};
Tiling function on the host:
#include "../op_kernel/xxx_custom_tiling.h" // Contain the header file of the tiling structure definition.
...
namespace optiling {
static void ComputeTiling(TilingData* tiling, ...)
{
// Calculate the tiling logic.
...
tiling->xxx1 = xxx;
tiling->xxx2 = xxx;
tiling->xxx3 = xxx;
tiling->bool = xxx;
}
static ge::graphStatus TilingFunc(gert::TilingContext *context)
{
...
TilingData *tiling = context->GetTilingData<TilingData>();
...
ComputeTiling(tiling, ...)
...
return ge::GRAPH_SUCCESS;
}
} // namespace optiling
When the standard C++ syntax is used to define a tiling structure, the following restrictions apply:
class TilingData {
public:
uint32_t xxx;
__aicore__ funcA() { ... } // Error. The __aicore__ modifier is not supported during compilation on the host, resulting in a compilation error.
void func() { ... } // Error. The __aicore__ modifier is missing on the device, resulting in execution failure.
};
1 2 3 4 5 |
class TilingData { public: uint32_t* totalLength; // The pointer type is not supported. The host cannot pass the pointer to the device. uint32_t& tileNum; // The reference scenario is not supported. The host cannot pass the pointer to the device. }; |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
class A { public: uint32_t totalLength; uint32_t tileNum; }; class B: public A { public: uint32_t xxx; uint32_t xxx; }; static ge::graphStatus TilingFunc(gert::TilingContext* context) { // Incorrect use B *tiling = context->GetTilingData<A>(); // Not supported. Unknown issues will be triggered. // Correct use B *tiling = context->GetTilingData<B>(); ...... return ge::GRAPH_SUCCESS; } |
1 2 3 4 5 6 7 8 9 10 |
static ge::graphStatus TilingFunc(gert::TilingContext* context) { TilingData *tiling = context->GetTilingData<TilingData>(); // Obtain the tiling structure. In this case, totalLength and tileNum are 0, and no initial values exist. ...... // Explicit value assignment is required. tiling->totalLength = totalLength; // Assign a value to a member variable of the tiling structure. tiling->tileNum = TILE_NUM; // Assign a value to a member variable of the tiling structure. ...... return ge::GRAPH_SUCCESS; } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
// Scenario where more than one template parameter is used template<int32_t sizeA, int32_t sizeB> class A { public: uint32_t totalLength; uint32_t tileNum; uint32_t dataArray[sizeA]; }; // Scenario where one template parameter is used template<int32_t sizeA> class B { public: uint32_t totalLength; uint32_t tileNum; uint32_t dataArray[sizeA]; }; // The tiling structure and corresponding template parameters can be directly passed on the host. static ge::graphStatus TilingFunc(gert::TilingContext* context) { // If the number of template parameters is greater than or equal to 1, the parameters can be directly passed. A<3, 5> *tiling = context->GetTilingData<A<3,5>>(); B<3> *tiling = context->GetTilingData<B<3>>(); ...... return ge::GRAPH_SUCCESS; } // Code on the kernel #include "kernel_operator.h" #include "add_custom_tiling.h" // Contain the header file of the tiling structure definition. extern "C" __global__ __aicore__ void add_custom(GM_ADDR x, GM_ADDR y, GM_ADDR z, GM_ADDR workspace, GM_ADDR tiling) { using aa = A<3,5>; REGISTER_TILING_DEFAULT(aa); // If the number of template parameters is greater than 1, use using to specify the number. REGISTER_TILING_FOR_TILINGKEY("TILING_KEY_VAR == 2", B<3>); // If there is only one template parameter, you can directly specify the template parameter. ...... } |
This section describes how to change the tiling structure definition mode from using macros such as BEGIN_TILING_DATA_DEF to using the standard C++ syntax.
|
Macro |
Standard C++ Syntax |
|---|---|
#include "register/tilingdata_base.h"
#include "tiling/tiling_api.h" // The TCubeTiling structure is defined using macros.
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 |
#include <cstdint>
#include "kernel_tiling/kernel_tiling.h" // The TCubeTiling structure is defined using the C++ syntax.
struct MatmulCustomTilingData {
uint64_t localMemSize;
AscendC::tiling::TCubeTiling cubeTilingData;
}; |
|
Macro |
Standard C++ Syntax |
|---|---|
namespace optiling {
static ge::graphStatus TilingFunc(gert::TilingContext *context)
{
...
MultiCoreMatmulTiling cubeTiling(ascendcPlatform);
...
MatmulCustomTilingData tiling;
if (cubeTiling.GetTiling(tiling.cubeTilingData) == -1) { // Get matmul tiling.
return ge::GRAPH_FAILED;
}
uint64_t localMemSize;
ascendcPlatform.GetCoreMemSize(platform_ascendc::CoreMemType::UB, localMemSize);
tiling.set_localMemSize(localMemSize); // The set method generated through macros is required.
...
// Save local variables to the context.
tiling.SaveToBuffer(context->GetRawTilingData()->GetData(), context->GetRawTilingData()->GetCapacity());
...
return ge::GRAPH_SUCCESS;
}
} // namespace optiling |
#include "../op_kernel/matmul_custom_tiling.h" // Contain the header file of the tiling structure definition.
...
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; // Assign value to a member variable using user-friendly C++ pointers.
...
return ge::GRAPH_SUCCESS;
}
} // namespace optiling |
#include "matmul_custom_tiling.h"
...
extern "C" __global__ __aicore__ void matmul_custom(GM_ADDR a, GM_ADDR b, GM_ADDR bias, GM_ADDR c, GM_ADDR workspace, GM_ADDR tiling)
{
REGISTER_TILING_DEFAULT(MatmulCustomTilingData); // Add the REGISTER_TILING_DEFAULT call to register the tiling structure.
...
}