CubeResGroupHandle用于在分离架构中对AI Core计算资源分组。分组后,开发者可以对不同的分组指定不同的计算任务。一个AI Core分组可包含多个AIV和AIC,AIV和AIC之间采取Client和Server架构进行任务处理。AIV为Client,每一个Cube计算任务为一个消息,AIV发送消息至消息队列,AIC作为Server,遍历消息队列的消息,根据消息类型及内容执行对应的计算任务。一个CubeResGroupHandle中可以有一个或多个AIC,同一个AIC只能属于一个CubeResGroupHandle,AIV无此限制,即同一个AIV可以属于多个CubeResGroupHandle。
如下图所示,CubeResGroupHandle1中有2个AIC,10个AIV,AIC为Block0和Block1。其中Block0与Queue0、Queue1、Queue2、Queue3、Queue4进行通信,Block1与Queue 5、Queue 6、Queue 7、Queue 8、Queue9进行通信。每一个消息队列对应一个AIV,消息队列的深度固定为4,即一次性最多可以容纳4个消息。CubeResGroupHandle2的消息队列个数为12,表明有12个AIV。CubeResGroupHandle的消息处理顺序如CubeResGroupHandle2中黑色箭头所示。
基于CubeResGroupHandle实现AI Core计算资源分组步骤如下:
下文仅提供示例代码片段,更多完整样例请参考CubeGroup样例。
用户根据实际需求,自定义AIC所需要的计算对象类型,或者高阶API已提供的Matmul类型。例如,创建Matmul类型如下,其中A_TYPE、B_TYPE、 C_TYPE、BIAS_TYPE、CFG_NORM等含义请参考Matmul模板参数。
1 2 |
// A_TYPE, B_TYPE, C_TYPE, BIAS_TYPE, CFG_NORM根据实际需求场景构造 using MatmulApiType = MatmulImpl<A_TYPE, B_TYPE, C_TYPE, C_TYPE, CFG_NORM>; |
1 2 |
// 创建KfcWorkspace对象前,需要对该workspaceGM清零 KfcWorkspace desc(workspaceGM); |
参数名称 |
含义 |
||
---|---|---|---|
CubeMsgBody |
用户自定义的消息结构体。结构体名称可自定义,结构体大小需要64字节对齐。
|
参数名称 |
含义 |
---|---|
msgState |
表明该位置的消息状态。参数取值如下:
|
aivID |
发送消息的AIV的序号。 |
1 2 3 4 5 6 7 8 9 10 11 |
template<class MatmulApiCfg, class CubeMsgBody> struct NormalCallbackFuncs { __aicore__ inline static void Call(MatmulApiCfg &mm, __gm__ CubeMsgBody *rcvMsg, CubeResGroupHandle<CubeMsgBody> &handle){ // 用户自行实现逻辑 }; __aicore__ inline static void Init(NormalCallbackFuncs<MatmulApiCfg, CubeMsgBody> &foo, MatmulApiCfg &mm, GM_ADDR tilingGM){ // 用户自行实现逻辑 }; }; |
计算逻辑结构体的模板参数请参考表3。
参数 |
说明 |
---|---|
MatmulApiCfg |
用户自定义的AIC上计算所需要对象的数据类型,参考步骤1,该模板参数必须填入。 |
CubeMsgBody |
用户自定义的消息结构体,该模板参数必须填入。 |
用户自定义回调计算结构体中需要包含固定的Init函数和Call函数,函数原型如下所示。其中,Init函数的参数说明请参考表4,Call函数的参数说明请参考表5。
1 2 3 4 |
// 该函数的参数和名称为固定格式,函数实现根据业务逻辑自行实现。 __aicore__ inline static void Init(MyCallbackFunc<MatmulApiCfg, CubeMsgBody> &myCallBack, MatmulApiCfg &mm, GM_ADDR tilingGM){ // 用户自行实现内部逻辑 } |
参数 |
输入/输出 |
说明 |
---|---|---|
myCallBack |
输入 |
用户自定义的带模板参数的回调计算结构体。 |
mm |
输入 |
AIC上计算对象,多为Matmul对象。 |
tilingGM |
输入 |
用户传入的tiling指针。 |
1 2 3 4 |
// 该函数的参数和名称为固定格式,函数实现根据业务逻辑自行实现。 __aicore__ inline static void Call(MatmulApiCfg &mm, __gm__ CubeMsgBody *rcvMsg, CubeResGroupHandle<CubeMsgBody> &handle){ // 用户自行实现内部逻辑 } |
参数 |
输入/输出 |
说明 |
---|---|---|
mm |
输入 |
AIC上计算对象,多为Matmul对象。 |
rcvMsg |
输入 |
用户自定义的消息结构体指针。 |
handle |
输入 |
分组管理Handle,用户调用其接口进行收发消息,释放消息等。 |
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 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
// 用户自定义的回调计算逻辑 template<class MatmulApiCfg, typename CubeMsgBody> struct MyCallbackFunc { template<int32_t funcId> __aicore__ inline static typename IsEqual<funcId, 0>::Type CubeGroupCallBack(MatmulApiCfg &mm, __gm__ CubeMsgBody *rcvMsg, CubeResGroupHandle<CubeMsgBody> &handle) { GlobalTensor<int64_t> msgGlobal; msgGlobal.SetGlobalBuffer(reinterpret_cast<__gm__ int64_t *> (rcvMsg) + sizeof(int64_t)); DataCacheCleanAndInvalid<int64_t, CacheLine::SINGLE_CACHE_LINE, DcciDst::CACHELINE_OUT> (msgGlobal); using SrcAT = typename MatmulApiCfg::AType::T; auto skipNum = 0; for (int i = 0; i < skipNum + 1; ++i) { auto tmpId = handle.FreeMessage(rcvMsg + i); // msgPtr process is complete } handle.SetSkipMsg(skipNum); } template<int32_t funcId> __aicore__ inline static typename IsEqual<funcId, 1>::Type CubeGroupCallBack(MatmulApiCfg &mm, __gm__ CubeMsgBody *rcvMsg, CubeResGroupHandle<CubeMsgBody> &handle) { GlobalTensor<int64_t> msgGlobal; msgGlobal.SetGlobalBuffer(reinterpret_cast<__gm__ int64_t *> (rcvMsg) + sizeof(int64_t)); DataCacheCleanAndInvalid<int64_t, CacheLine::SINGLE_CACHE_LINE, DcciDst::CACHELINE_OUT> (msgGlobal); using SrcAT = typename MatmulApiCfg::AType::T; LocalTensor<SrcAT> tensor_temp; auto skipNum = 3; auto tmpId = handle.FreeMessage(rcvMsg, CubeMsgState::VALID); for (int i = 1; i < skipNum + 1; ++i) { auto tmpId = handle.FreeMessage(rcvMsg + i, CubeMsgState::FAKE); } handle.SetSkipMsg(skipNum); // notify the cube not to process } __aicore__ inline static void Call(MatmulApiCfg &mm, __gm__ CubeMsgBody *rcvMsg, CubeResGroupHandle<CubeMsgBody> &handle) { if (rcvMsg->funcId == 0) { CubeGroupCallBack<0> (mm, rcvMsg, handle); } else if(rcvMsg->funcId == 1) { CubeGroupCallBack<1> (mm, rcvMsg, handle); } } __aicore__ inline static void Init(MyCallbackFunc<MatmulApiCfg, CubeMsgBody> &foo, MatmulApiCfg &mm, GM_ADDR tilingGM) { auto tempTilingGM = (__gm__ uint32_t*)tilingGM; auto tempTiling = (uint32_t*)&(foo.tiling); for (int i = 0; i < sizeof(TCubeTiling) / sizeof(int32_t); ++i, ++tempTilingGM, ++tempTiling) { *tempTiling = *tempTilingGM; } mm.SetSubBlockIdx(0); mm.Init(&foo.tiling, GetTPipePtr()); } TCubeTiling tiling; }; |
1 2 3 4 5 6 7 8 9 |
/* * groupID为用户自定义的CreateCubeResGroup的groupID * MatmulApiType为步骤1定义好的AIC上计算对象的类型 * MyCallbackFunc为步骤4定义好的自定义回调计算结构体 * CubeMsgBody为步骤3中的自定义消息结构体 * desc为步骤2中的用户初始化好的通信区域描述 * groupID为1,blockStart为0,blockSize为12,msgQueueSize为48,tilingGm为指针,存储了用户在AIC上所需要的tiling信息 */ auto handle = AscendC::CreateCubeResGroup<groupID, MatmulApiType, MyCallbackFunc, CubeMsgBody>(desc, 0, 12, 48, tilingGM); |
1 2 |
// handle为步骤5中CreateCubeResGroup创建的CubeResGroupHandle对象 handle.AssignQueue(queIdx); |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
CubeGroupMsgHead head = {CubeMsgState::VALID, (uint8_t)queIdx}; CubeMsgBody aCubeMsgBody {head, 0, 0, 0, false, false, false, false, 0, 0, 0, 0, 0, 0, 0, 0}; CubeMsgBody bCubeMsgBody {head, 1, 0, 0, false, false, false, false, 0, 0, 0, 0, 0, 0, 0, 0}; auto offset = 0; if (GetBlockIdx() == 0) { auto msgPtr = handle.template AllocMessage(); // alloc for queue space offset = handle.template PostMessage(msgPtr, bCubeMsgBody); // post true msgPtr bool waitState = handle.template Wait<true> (offset); // wait until the msgPtr is proscessed } else if (GetBlockIdx() < 4) { auto msgPtr = handle.AllocMessage(); offset = handle.PostFakeMsg(msgPtr); // post fake msgPtr bool waitState = handle.template Wait<true> (offset); // wait until the msgPtr is proscessed } else { auto msgPtr = handle.template AllocMessage(); offset = handle.template PostMessage(msgPtr, aCubeMsgBody); bool waitState = handle.template Wait<true> (offset); // wait until the msgPtr is proscessed } |
1 2 |
auto msgPtr = handle.AllocMessage(); // 获取消息空间指针msgPtr handle.SetQuit(msgPtr); // 发送退出消息 |