* Copyright (c) 2025 Huawei Technologies Co., Ltd.
* This program is free software, you can redistribute it and/or modify it under the terms and conditions of
* CANN Open Software License Agreement Version 2.0 (the "License").
* Please refer to the License for details. You may not use this file except in compliance with the License.
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
* See LICENSE in the root of the software repository for the full text of the License.
*/
* \file ffn_to_attention.h
* \brief
*/
#ifndef FFN_TO_ATTENTION_H
#define FFN_TO_ATTENTION_H
#if ASC_DEVKIT_MAJOR >= 9
#include "basic_api/kernel_basic_intf.h"
#else
#include "kernel_operator.h"
#endif
#include "kernel_tiling/kernel_tiling.h"
#include "ffn_to_attention_tiling.h"
#if __has_include("../common/op_kernel/moe_distribute_base.h")
#include "../common/op_kernel/moe_distribute_base.h"
#include "../common/op_kernel/mc2_kernel_utils.h"
#else
#include "../../common/op_kernel/moe_distribute_base.h"
#include "../../common/op_kernel/mc2_kernel_utils.h"
#endif
namespace FFNToAttentionImpl {
constexpr uint8_t BUFFER_NUM = 2;
constexpr uint32_t UB_ALIGN = 32;
constexpr uint8_t WIN_OFFSET_CNT = 2;
constexpr uint64_t WIN_ADDR_ALIGN = 512UL;
#define TemplateFFNToAttentionTypeClass typename xType, bool isInputRankTable
#define TemplateFFNToAttentionTypeFunc xType, isInputRankTable
using namespace AscendC;
template <TemplateFFNToAttentionTypeClass>
class FFNToAttention {
public:
__aicore__ inline FFNToAttention() {};
__aicore__ inline void Init(GM_ADDR x, GM_ADDR sessionIds, GM_ADDR microBatchIds, GM_ADDR tokenIds, GM_ADDR expertOffsets,
GM_ADDR actualTokenNum, GM_ADDR attnRankTable, GM_ADDR workspaceGM, TPipe *pipe,
const FFNToAttentionTilingData *tilingData);
__aicore__ inline void Process();
private:
__aicore__ inline GM_ADDR GetWindowAddr(uint32_t curAttenWorkRank);
__aicore__ inline void ReadTokenMetaData(ReadTokenMetaDataStruct& metaDataStruct, uint32_t YOffset);
TPipe *tpipe_{nullptr};
GlobalTensor<xType> xGMTensor_;
GlobalTensor<int32_t> layerIdsGMTensor_;
GlobalTensor<int32_t> sessionIdsGMTensor_;
GlobalTensor<int32_t> microBatchIdsGMTensor_;
GlobalTensor<int32_t> tokenIdsGMTensor_;
GlobalTensor<int32_t> expertOffsetsGMTensor_;
GlobalTensor<int64_t> actualTokenNumGMTensor_;
GlobalTensor<int32_t> attnRankTableGMTensor_;
LocalTensor<xType> xTmpTensor_;
LocalTensor<int32_t> statusTensor_;
TBuf<> statusBuf_;
TQueBind<QuePosition::VECIN, QuePosition::VECOUT, 1> xQueue_;
uint32_t aivId_{0};
uint64_t actualTokenNum_{0};
uint32_t axisH_{0};
uint32_t axisHS_{0};
uint32_t axisA_{0};
uint32_t microBatchNum_{0};
uint32_t axisBS_{0};
uint32_t expertNumPerToken_{0};
uint32_t aivNum_{0};
uint32_t worldSize_{0};
uint32_t batchSizeSendCnt_{0};
uint64_t perMicroBatchOffset_{0};
uint64_t perExpertOffset_{0};
uint64_t hSize_{0};
uint64_t winTokenInfoTableSize_{0};
uint8_t windowType_{0};
__gm__ HcclOpResParam *winContext_{nullptr};
};
template <TemplateFFNToAttentionTypeClass>
__aicore__ inline void FFNToAttention<TemplateFFNToAttentionTypeFunc>::Init(GM_ADDR x, GM_ADDR sessionIds, GM_ADDR microBatchIds,
GM_ADDR tokenIds, GM_ADDR expertOffsets, GM_ADDR actualTokenNum, GM_ADDR attnRankTable, GM_ADDR workspaceGM,
TPipe *pipe, const FFNToAttentionTilingData *tilingData)
{
tpipe_ = pipe;
aivId_ = GetBlockIdx();
auto contextGM0 = AscendC::GetHcclContext<HCCL_GROUP_ID_0>();
winContext_ = (__gm__ HcclOpResParam *)AscendC::GetHcclContext<HCCL_GROUP_ID_0>();
axisBS_ = tilingData->ffnToAttentionInfo.BS;
axisH_ = tilingData->ffnToAttentionInfo.H;
axisHS_ = tilingData->ffnToAttentionInfo.HS;
axisA_ = tilingData->ffnToAttentionInfo.A;
microBatchNum_ = tilingData->ffnToAttentionInfo.microBatchNum;
expertNumPerToken_ = tilingData->ffnToAttentionInfo.expertNumPerToken;
aivNum_ = tilingData->ffnToAttentionInfo.aivNum;
worldSize_ = tilingData->ffnToAttentionInfo.worldSize;
windowType_ = tilingData->ffnToAttentionInfo.windowType;
xGMTensor_.SetGlobalBuffer((__gm__ xType*)x);
sessionIdsGMTensor_.SetGlobalBuffer((__gm__ int32_t*)sessionIds);
microBatchIdsGMTensor_.SetGlobalBuffer((__gm__ int32_t*)microBatchIds);
tokenIdsGMTensor_.SetGlobalBuffer((__gm__ int32_t*)tokenIds);
expertOffsetsGMTensor_.SetGlobalBuffer((__gm__ int32_t*)expertOffsets);
actualTokenNumGMTensor_.SetGlobalBuffer((__gm__ int64_t*)actualTokenNum);
if constexpr (isInputRankTable) {
attnRankTableGMTensor_.SetGlobalBuffer((__gm__ int32_t*)(attnRankTable));
}
DataCacheCleanAndInvalid<int64_t, CacheLine::SINGLE_CACHE_LINE, DcciDst::CACHELINE_OUT>(actualTokenNumGMTensor_);
actualTokenNum_ = actualTokenNumGMTensor_.GetValue(0);
hSize_ = axisH_ * sizeof(xType);
tpipe_->InitBuffer(xQueue_, BUFFER_NUM, hSize_);
tpipe_->InitBuffer(statusBuf_, UB_ALIGN);
statusTensor_ = statusBuf_.Get<int32_t>();
statusTensor_(0) = 1;
batchSizeSendCnt_ = axisBS_ * expertNumPerToken_;
perMicroBatchOffset_ = batchSizeSendCnt_ * axisHS_;
perExpertOffset_ = expertNumPerToken_ * axisHS_;
winTokenInfoTableSize_ = Ceil(microBatchNum_ * batchSizeSendCnt_ * sizeof(int32_t), WIN_ADDR_ALIGN) * WIN_ADDR_ALIGN;
}
template <TemplateFFNToAttentionTypeClass>
__aicore__ inline GM_ADDR FFNToAttention<TemplateFFNToAttentionTypeFunc>::GetWindowAddr(uint32_t curAttenWorkRank)
{
if (winContext_->userMemType == 0) {
return (__gm__ uint8_t*)(((HcclRankRelationResV2 *)(winContext_->remoteRes[curAttenWorkRank].nextDevicePtr))->windowsIn);
} else {
return (__gm__ uint8_t*)(winContext_->userMemRes[curAttenWorkRank].addr);
}
}
template <TemplateFFNToAttentionTypeClass>
__aicore__ inline void FFNToAttention<TemplateFFNToAttentionTypeFunc>::ReadTokenMetaData(ReadTokenMetaDataStruct& metaDataStruct, uint32_t YOffset)
{
DataCacheCleanAndInvalid<int32_t, CacheLine::SINGLE_CACHE_LINE, DcciDst::CACHELINE_OUT>(sessionIdsGMTensor_[YOffset]);
metaDataStruct.curAttenWorkIds = sessionIdsGMTensor_(YOffset);
metaDataStruct.curAttenWorkRank = metaDataStruct.curAttenWorkIds;
if constexpr (isInputRankTable) {
DataCacheCleanAndInvalid<int32_t, CacheLine::SINGLE_CACHE_LINE, DcciDst::CACHELINE_OUT>(attnRankTableGMTensor_[metaDataStruct.curAttenWorkIds]);
metaDataStruct.curAttenWorkRank = attnRankTableGMTensor_(metaDataStruct.curAttenWorkIds);
}
DataCacheCleanAndInvalid<int32_t, CacheLine::SINGLE_CACHE_LINE, DcciDst::CACHELINE_OUT>(microBatchIdsGMTensor_[YOffset]);
metaDataStruct.curMicroBatchIds = microBatchIdsGMTensor_(YOffset);
DataCacheCleanAndInvalid<int32_t, CacheLine::SINGLE_CACHE_LINE, DcciDst::CACHELINE_OUT>(tokenIdsGMTensor_[YOffset]);
metaDataStruct.curTokenBatchOffset = tokenIdsGMTensor_(YOffset);
DataCacheCleanAndInvalid<int32_t, CacheLine::SINGLE_CACHE_LINE, DcciDst::CACHELINE_OUT>(expertOffsetsGMTensor_[YOffset]);
metaDataStruct.curTokenTopkOffset = expertOffsetsGMTensor_(YOffset);
}
template <TemplateFFNToAttentionTypeClass>
__aicore__ inline void FFNToAttention<TemplateFFNToAttentionTypeFunc>::Process()
{
if ASCEND_IS_AIV {
uint32_t calStartTokenId = 0;
uint32_t sendTokenNum = actualTokenNum_ / aivNum_;
uint32_t remainderRankNum = actualTokenNum_ % aivNum_;
if (aivId_ < remainderRankNum) {
sendTokenNum += 1;
calStartTokenId += aivId_;
} else {
calStartTokenId += remainderRankNum;
}
if (calStartTokenId >= actualTokenNum_) {
sendTokenNum = 0;
}
GM_ADDR curRankWinAddr;
GlobalTensor<xType> tokenDataGMTensor;
GlobalTensor<int32_t> tokenInfoTableGMTensor;
DataCopyExtParams dataCopyParams = {1U, sizeof(int32_t), 0U, 0U, 0U};
DataCopyExtParams xCopyParams = {1U, static_cast<uint32_t>(axisH_ * sizeof(xType)), 0U, 0U, 0U};
DataCopyPadExtParams<xType> copyPadExtParams{false, 0U, 0U, 0U};
for (uint32_t tokenCnt = 0; tokenCnt < sendTokenNum; ++tokenCnt) {
uint32_t YOffset = aivId_ + (tokenCnt * aivNum_);
xTmpTensor_ = xQueue_.AllocTensor<xType>();
DataCopyPad(xTmpTensor_, xGMTensor_[YOffset * axisH_], xCopyParams, copyPadExtParams);
ReadTokenMetaDataStruct metaDataStruct;
ReadTokenMetaData(metaDataStruct, YOffset);
curRankWinAddr = GetWindowAddr(metaDataStruct.curAttenWorkRank);
uint64_t tokenInfoTableOffset = metaDataStruct.curMicroBatchIds * batchSizeSendCnt_;
uint64_t tokenDataOffset = (metaDataStruct.curMicroBatchIds * perMicroBatchOffset_ + metaDataStruct.curTokenBatchOffset * perExpertOffset_ + metaDataStruct.curTokenTopkOffset * axisHS_) * sizeof(xType);
tokenInfoTableGMTensor.SetGlobalBuffer((__gm__ int32_t*)(curRankWinAddr + (tokenInfoTableOffset + metaDataStruct.curTokenBatchOffset * expertNumPerToken_ + metaDataStruct.curTokenTopkOffset) * sizeof(int32_t)));
tokenDataGMTensor.SetGlobalBuffer((__gm__ xType*)(curRankWinAddr + winTokenInfoTableSize_ + tokenDataOffset));
if(tokenCnt == 0) {
SyncFunc<AscendC::HardEvent::S_MTE3>();
}
xQueue_.EnQue(xTmpTensor_);
xTmpTensor_ = xQueue_.DeQue<xType>();
DataCopyPad(tokenDataGMTensor, xTmpTensor_, xCopyParams);
xQueue_.FreeTensor<xType>(xTmpTensor_);
PipeBarrier<PIPE_MTE3>();
DataCopyPad(tokenInfoTableGMTensor, statusTensor_, dataCopyParams);
}
}
}
}
#endif