* 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 group_quant_base.h
* \brief
*/
#ifndef ASCENDC_GROUP_QUANT
#define ASCENDC_GROUP_QUANT
#include "kernel_operator.h"
#include "kernel_tiling/kernel_tiling.h"
#include "kernel_utils.h"
namespace GroupQuant {
using namespace AscendC;
template <typename T1, typename T2, typename T3, typename T4, typename T5>
class GroupQuantBase {
public:
__aicore__ inline GroupQuantBase() {};
__aicore__ inline void Init(GM_ADDR x, GM_ADDR scale, GM_ADDR groupIndex, GM_ADDR offset, GM_ADDR y,
const GroupQuantTilingData* tilingData);
__aicore__ inline void Process();
private:
__aicore__ inline void ParseTilingData(const GroupQuantTilingData* tilingData);
__aicore__ inline void Compute();
__aicore__ inline void PerLoopCompute(int64_t hIdx);
__aicore__ inline void CopyInOffset();
__aicore__ inline void CopyInScale(int64_t scaleAddr);
__aicore__ inline void CopyInX(int64_t xAddr, int64_t perSSize);
__aicore__ inline void VecCompute(uint32_t dataCount, int64_t scaleExpandLoop, LocalTensor<int8_t> outputLocal);
__aicore__ inline void CopyOutY(int64_t xAddr, int64_t perSSize, LocalTensor<int8_t> outputLocal);
__aicore__ inline void LoadGrpIdxFirstBatch(LocalTensor<T3> grpIdxUb, LocalTensor<T3> xRowCntUb,
int64_t grpIdxGmOffset, int64_t loadElems);
__aicore__ inline void LoadGrpIdxMoreBatch(LocalTensor<T3> grpIdxUb, LocalTensor<T3> xRowCntUb,
int64_t grpIdxGmOffset, int64_t loadElems);
__aicore__ inline void CheckGrpIdxOneBatch(LocalTensor<T3> grpIdxUb, int64_t loadElems,
LocalTensor<T3> xRowCntUb, LocalTensor<T3> grpIdxInt32TmpUb,
LocalTensor<float> grpIdxFp32Ub, LocalTensor<float> grpIdxDiffUb,
LocalTensor<float> grpIdxWorkLocalUb);
__aicore__ inline void CheckGrpIdxLastValue(LocalTensor<T3> grpIdxUb);
__aicore__ inline void CheckGrpIdxAllValue();
__aicore__ inline void CheckGrpIdxAll(int64_t grpIdxGmOffset, int64_t loadElems, LocalTensor<T3> grpIdxUb,
LocalTensor<T3> xRowCntUb, LocalTensor<T3> grpIdxInt32TmpUb,
LocalTensor<float> grpIdxFp32Ub, LocalTensor<float> grpIdxDiffUb,
LocalTensor<float> grpIdxWorkLocalUb);
__aicore__ inline void CalcGrpCnt(LocalTensor<T3> grpIdxUb, int64_t loadElems, LocalTensor<T3> xRowCntUb);
__aicore__ inline void WalkGrpIdx(LocalTensor<T3> grpIdxUb, LocalTensor<T3> xRowCntUb);
__aicore__ inline void LookupExpertStateful(int64_t xStartRowCurCore, int64_t xRowNumCurCore);
private:
TPipe pipe;
TBuf<QuePosition::VECCALC> tmpBuf1_;
TBuf<QuePosition::VECCALC> tmpBuf2_;
TBuf<QuePosition::VECCALC> tmpBuf3_;
TBuf<QuePosition::VECCALC> scaleBuf_;
TBuf<QuePosition::VECCALC> mulBuf_;
TBuf<QuePosition::VECCALC> offsetBuf_;
TBuf<QuePosition::VECCALC> outBuf_;
TBuf<QuePosition::VECCALC> grpIdxBuf;
TBuf<QuePosition::VECCALC> xRowCntBuf;
TBuf<QuePosition::VECCALC> grpIdxInt32TmpBuf;
TBuf<QuePosition::VECCALC> grpIdxFp32Buf;
TBuf<QuePosition::VECCALC> grpIdxDiffBuf;
TBuf<QuePosition::VECCALC> grpIdxWorkLocalBuf;
GlobalTensor<T1> gmX_;
GlobalTensor<T2> gmScale_;
GlobalTensor<T3> gmGrpIdx_;
GlobalTensor<T4> gmOffset_;
GlobalTensor<int8_t> gmY_;
#if (defined(__NPU_ARCH__) && (__NPU_ARCH__ == 3003 || __NPU_ARCH__ == 3113))
constexpr static int64_t UB_TENSOE_BUF = 16 * 1024;
#else
constexpr static int64_t UB_TENSOE_BUF = 32 * 1024;
#endif
constexpr static int64_t OFFEST_TENSOE_BUF = 256;
constexpr static int64_t PEER_H = 8 * 1024;
constexpr static int64_t BLOCK_SIZE = 32;
constexpr static int64_t ALIGN_SIZE = 64;
constexpr static int64_t INT4_NUMS_IN_INT8_SPACE = 2;
constexpr static int64_t GROUP_INDEX_UB_SIZE = 1024;
int64_t blockIdx = 0;
int64_t currExpertIdx = -1;
int64_t xRowCntOfCurrExpert = 0;
int64_t grpIdxUbCursor = 0;
int64_t dimS_ = 0;
int64_t dimE_ = 0;
int64_t dimH_ = 0;
int64_t hasOffset_ = 0;
int64_t needCoreNum_ = 0;
int64_t preCoreNum_ = 0;
int64_t xRowNum_ = 0;
int64_t xRowIndex_ = 0;
int64_t xRowNumPreCore_ = 0;
int64_t xRowNumPostCore_ = 0;
int64_t calH = 0;
int64_t calHBlock = 0;
int64_t maxSSize = 1;
float offset_ = 0;
};
template <typename T1, typename T2, typename T3, typename T4, typename T5>
__aicore__ inline void GroupQuantBase<T1, T2, T3, T4, T5>::ParseTilingData(const GroupQuantTilingData* tilingData) {
dimS_ = tilingData->dimS;
dimE_ = tilingData->dimE;
dimH_ = tilingData->dimH;
hasOffset_ = tilingData->hasOffset;
needCoreNum_ = tilingData->needCoreNum;
preCoreNum_ = tilingData->preCoreNum;
xRowNumPreCore_ = tilingData->xRowNumPreCore;
xRowNumPostCore_ = tilingData->xRowNumPostCore;
xRowNum_ = xRowNumPreCore_;
}
template <typename T1, typename T2, typename T3, typename T4, typename T5>
__aicore__ inline void GroupQuantBase<T1, T2, T3, T4, T5>::Init(GM_ADDR x,
GM_ADDR scale,
GM_ADDR groupIndex,
GM_ADDR offset,
GM_ADDR y,
const GroupQuantTilingData* tilingData) {
blockIdx = GetBlockIdx();
ParseTilingData(tilingData);
gmX_.SetGlobalBuffer((__gm__ T1 *)x);
gmScale_.SetGlobalBuffer((__gm__ T2 *)scale);
gmGrpIdx_.SetGlobalBuffer((__gm__ T3 *)groupIndex);
gmOffset_.SetGlobalBuffer((__gm__ T4 *)offset);
gmY_.SetGlobalBuffer((__gm__ int8_t *)y);
pipe.InitBuffer(tmpBuf1_, UB_TENSOE_BUF);
pipe.InitBuffer(tmpBuf2_, UB_TENSOE_BUF);
pipe.InitBuffer(tmpBuf3_, UB_TENSOE_BUF);
pipe.InitBuffer(scaleBuf_, UB_TENSOE_BUF);
pipe.InitBuffer(mulBuf_, UB_TENSOE_BUF);
pipe.InitBuffer(outBuf_, PEER_H);
if (hasOffset_) {
pipe.InitBuffer(offsetBuf_, OFFEST_TENSOE_BUF);
}
pipe.InitBuffer(grpIdxBuf, GROUP_INDEX_UB_SIZE);
pipe.InitBuffer(xRowCntBuf, GROUP_INDEX_UB_SIZE);
pipe.InitBuffer(grpIdxInt32TmpBuf, GROUP_INDEX_UB_SIZE);
pipe.InitBuffer(grpIdxFp32Buf, GROUP_INDEX_UB_SIZE);
pipe.InitBuffer(grpIdxDiffBuf, GROUP_INDEX_UB_SIZE);
pipe.InitBuffer(grpIdxWorkLocalBuf, GROUP_INDEX_UB_SIZE);
}
template <typename T1, typename T2, typename T3, typename T4, typename T5>
__aicore__ inline void GroupQuantBase<T1, T2, T3, T4, T5>::LoadGrpIdxFirstBatch(LocalTensor<T3> grpIdxUb,
LocalTensor<T3> xRowCntUb,
int64_t grpIdxGmOffset,
int64_t loadElems) {
event_t eventIdSToMte2 = static_cast<event_t>(GetTPipePtr()->FetchEventID(HardEvent::S_MTE2));
SetFlag<HardEvent::S_MTE2>(eventIdSToMte2);
WaitFlag<HardEvent::S_MTE2>(eventIdSToMte2);
DataCopyExtParams copyParams0;
copyParams0.blockCount = 1;
copyParams0.blockLen = loadElems * sizeof(T3);
copyParams0.srcStride = 0;
copyParams0.dstStride = 0;
DataCopyPadExtParams<T3> padParams0{false, 0, 0, 0};
DataCopyPad(grpIdxUb, gmGrpIdx_[grpIdxGmOffset], copyParams0, padParams0);
if (loadElems == 1) {
DataCopyExtParams copyParams1;
copyParams1.blockCount = 1;
copyParams1.blockLen = sizeof(T3);
copyParams1.srcStride = 0;
copyParams1.dstStride = 0;
DataCopyPadExtParams<T3> padParams1{true, 1, 0, 0};
DataCopyPad(xRowCntUb, gmGrpIdx_[grpIdxGmOffset], copyParams1, padParams1);
} else {
DataCopyExtParams copyParams1;
copyParams1.blockCount = 1;
copyParams1.blockLen = (loadElems - 1) * sizeof(T3);
copyParams1.srcStride = 0;
copyParams1.dstStride = 0;
DataCopyPadExtParams<T3> padParams1{true, 1, 0, 0};
DataCopyPad(xRowCntUb, gmGrpIdx_[grpIdxGmOffset], copyParams1, padParams1);
}
}
template <typename T1, typename T2, typename T3, typename T4, typename T5>
__aicore__ inline void GroupQuantBase<T1, T2, T3, T4, T5>::LoadGrpIdxMoreBatch(LocalTensor<T3> grpIdxUb,
LocalTensor<T3> xRowCntUb,
int64_t grpIdxGmOffset,
int64_t loadElems) {
event_t eventIdSToMte2 = static_cast<event_t>(GetTPipePtr()->FetchEventID(HardEvent::S_MTE2));
SetFlag<HardEvent::S_MTE2>(eventIdSToMte2);
WaitFlag<HardEvent::S_MTE2>(eventIdSToMte2);
DataCopyExtParams copyParams0;
copyParams0.blockCount = 1;
copyParams0.blockLen = loadElems * sizeof(T3);
copyParams0.srcStride = 0;
copyParams0.dstStride = 0;
DataCopyPadExtParams<T3> padParams0{false, 0, 0, 0};
DataCopyPad(grpIdxUb, gmGrpIdx_[grpIdxGmOffset], copyParams0, padParams0);
DataCopyExtParams copyParams1;
copyParams1.blockCount = 1;
copyParams1.blockLen = loadElems * sizeof(T3);
copyParams1.srcStride = 0;
copyParams1.dstStride = 0;
DataCopyPadExtParams<T3> padParams1{false, 0, 0, 0};
DataCopyPad(xRowCntUb, gmGrpIdx_[grpIdxGmOffset - 1], copyParams1, padParams1);
}
template <typename T1, typename T2, typename T3, typename T4, typename T5>
__aicore__ inline void GroupQuantBase<T1, T2, T3, T4, T5>::CheckGrpIdxOneBatch(LocalTensor<T3> grpIdxUb,
int64_t loadElems,
LocalTensor<T3> xRowCntUb,
LocalTensor<T3> grpIdxInt32TmpUb,
LocalTensor<float> grpIdxFp32Ub,
LocalTensor<float> grpIdxDiffUb,
LocalTensor<float> grpIdxWorkLocalUb) {
if constexpr (IsSameType<T3, int32_t>::value) {
event_t eventIdMte2ToV = static_cast<event_t>(GetTPipePtr()->FetchEventID(HardEvent::MTE2_V));
SetFlag<HardEvent::MTE2_V>(eventIdMte2ToV);
WaitFlag<HardEvent::MTE2_V>(eventIdMte2ToV);
PipeBarrier<PIPE_V>();
Cast(grpIdxFp32Ub, grpIdxUb, RoundMode::CAST_NONE, loadElems);
PipeBarrier<PIPE_V>();
ReduceMin(grpIdxDiffUb, grpIdxFp32Ub, grpIdxWorkLocalUb, loadElems, false);
event_t eventVS = static_cast<event_t>(GetTPipePtr()->FetchEventID(HardEvent::V_S));
SetFlag<HardEvent::V_S>(eventVS);
WaitFlag<HardEvent::V_S>(eventVS);
if (grpIdxDiffUb.GetValue(0) < 0.0f) {
Trap();
}
PipeBarrier<PIPE_V>();
Adds(grpIdxInt32TmpUb, grpIdxUb, static_cast<T3>(-1 * dimS_), loadElems);
PipeBarrier<PIPE_V>();
Cast(grpIdxFp32Ub, grpIdxInt32TmpUb, RoundMode::CAST_NONE, loadElems);
PipeBarrier<PIPE_V>();
ReduceMax(grpIdxDiffUb, grpIdxFp32Ub, grpIdxWorkLocalUb, loadElems, false);
event_t eventVS1 = static_cast<event_t>(GetTPipePtr()->FetchEventID(HardEvent::V_S));
SetFlag<HardEvent::V_S>(eventVS1);
WaitFlag<HardEvent::V_S>(eventVS1);
if (grpIdxDiffUb.GetValue(0) > 0.0f) {
Trap();
}
PipeBarrier<PIPE_V>();
Sub(grpIdxInt32TmpUb, grpIdxUb, xRowCntUb, loadElems);
PipeBarrier<PIPE_V>();
Cast(grpIdxFp32Ub, grpIdxInt32TmpUb, RoundMode::CAST_NONE, loadElems);
PipeBarrier<PIPE_V>();
ReduceMin(grpIdxDiffUb, grpIdxFp32Ub, grpIdxWorkLocalUb, loadElems, false);
PipeBarrier<PIPE_V>();
event_t eventVS2 = static_cast<event_t>(GetTPipePtr()->FetchEventID(HardEvent::V_S));
SetFlag<HardEvent::V_S>(eventVS2);
WaitFlag<HardEvent::V_S>(eventVS2);
if (grpIdxDiffUb.GetValue(0) < 0.0f) {
Trap();
}
} else {
event_t eventIdMte2ToS = static_cast<event_t>(GetTPipePtr()->FetchEventID(HardEvent::MTE2_S));
SetFlag<HardEvent::MTE2_S>(eventIdMte2ToS);
WaitFlag<HardEvent::MTE2_S>(eventIdMte2ToS);
for (int64_t i = 0; i < loadElems; i++) {
int64_t valueOfGroupIndex = grpIdxUb.GetValue(i);
if ((valueOfGroupIndex < 0) || (valueOfGroupIndex > dimS_) || (valueOfGroupIndex - xRowCntUb.GetValue(i) < 0)) {
Trap();
}
}
}
}
template <typename T1, typename T2, typename T3, typename T4, typename T5>
__aicore__ inline void GroupQuantBase<T1, T2, T3, T4, T5>::CheckGrpIdxLastValue(LocalTensor<T3> grpIdxUb) {
PipeBarrier<PIPE_ALL>();
DataCopyExtParams copyParams0;
copyParams0.blockCount = 1;
copyParams0.blockLen = sizeof(T3);
copyParams0.srcStride = 0;
copyParams0.dstStride = 0;
DataCopyPadExtParams<T3> padParams0{false, 0, 0, 0};
DataCopyPad(grpIdxUb, gmGrpIdx_[dimE_ - 1], copyParams0, padParams0);
event_t eventIdMte2ToS = static_cast<event_t>(GetTPipePtr()->FetchEventID(HardEvent::MTE2_S));
SetFlag<HardEvent::MTE2_S>(eventIdMte2ToS);
WaitFlag<HardEvent::MTE2_S>(eventIdMte2ToS);
int64_t lastValueOfGroupIndex = static_cast<int64_t>(grpIdxUb.GetValue(0));
int64_t firstDimOfXShape = dimS_;
if (lastValueOfGroupIndex != firstDimOfXShape) {
Trap();
}
}
template <typename T1, typename T2, typename T3, typename T4, typename T5>
__aicore__ inline void GroupQuantBase<T1, T2, T3, T4, T5>::CheckGrpIdxAllValue() {
LocalTensor<T3> grpIdxUb = grpIdxBuf.Get<T3>();
if (dimE_ > 1) {
LocalTensor<T3> xRowCntUb = xRowCntBuf.Get<T3>();
LocalTensor<T3> grpIdxInt32TmpUb = grpIdxInt32TmpBuf.Get<T3>();
LocalTensor<float> grpIdxFp32Ub = grpIdxFp32Buf.Get<float>();
LocalTensor<float> grpIdxDiffUb = grpIdxDiffBuf.Get<float>();
LocalTensor<float> grpIdxWorkLocalUb = grpIdxWorkLocalBuf.Get<float>();
int64_t grpIdxBaseNum = GROUP_INDEX_UB_SIZE / sizeof(T3);
int64_t grpIdxGmOffset = 0;
int64_t loadElems = grpIdxBaseNum;
if (loadElems > dimE_) {
loadElems = dimE_;
}
LoadGrpIdxFirstBatch(grpIdxUb, xRowCntUb, grpIdxGmOffset, loadElems);
CheckGrpIdxOneBatch(grpIdxUb, loadElems, xRowCntUb,
grpIdxInt32TmpUb, grpIdxFp32Ub, grpIdxDiffUb, grpIdxWorkLocalUb);
if (dimE_ > grpIdxBaseNum) {
int64_t loopTimes = dimE_ / grpIdxBaseNum;
for (int64_t i = 1; i < loopTimes; ++i) {
grpIdxGmOffset = i * grpIdxBaseNum;
loadElems = grpIdxBaseNum;
CheckGrpIdxAll(grpIdxGmOffset, loadElems, grpIdxUb, xRowCntUb,
grpIdxInt32TmpUb, grpIdxFp32Ub, grpIdxDiffUb, grpIdxWorkLocalUb);
}
int64_t tailE = dimE_ % grpIdxBaseNum;
if (tailE > 0) {
grpIdxGmOffset = dimE_ / grpIdxBaseNum * grpIdxBaseNum;
loadElems = tailE;
CheckGrpIdxAll(grpIdxGmOffset, loadElems, grpIdxUb, xRowCntUb,
grpIdxInt32TmpUb, grpIdxFp32Ub, grpIdxDiffUb, grpIdxWorkLocalUb);
}
}
}
CheckGrpIdxLastValue(grpIdxUb);
}
template <typename T1, typename T2, typename T3, typename T4, typename T5>
__aicore__ inline void GroupQuantBase<T1, T2, T3, T4, T5>::CheckGrpIdxAll(int64_t grpIdxGmOffset,
int64_t loadElems,
LocalTensor<T3> grpIdxUb,
LocalTensor<T3> xRowCntUb,
LocalTensor<T3> grpIdxInt32TmpUb,
LocalTensor<float> grpIdxFp32Ub,
LocalTensor<float> grpIdxDiffUb,
LocalTensor<float> grpIdxWorkLocalUb) {
if constexpr (IsSameType<T3, int32_t>::value) {
event_t eventIdVToMte2 = static_cast<event_t>(GetTPipePtr()->FetchEventID(HardEvent::V_MTE2));
SetFlag<HardEvent::V_MTE2>(eventIdVToMte2);
WaitFlag<HardEvent::V_MTE2>(eventIdVToMte2);
} else {
event_t eventIdSToMte2 = static_cast<event_t>(GetTPipePtr()->FetchEventID(HardEvent::S_MTE2));
SetFlag<HardEvent::S_MTE2>(eventIdSToMte2);
WaitFlag<HardEvent::S_MTE2>(eventIdSToMte2);
}
LoadGrpIdxMoreBatch(grpIdxUb, xRowCntUb, grpIdxGmOffset, loadElems);
CheckGrpIdxOneBatch(grpIdxUb, loadElems, xRowCntUb,
grpIdxInt32TmpUb, grpIdxFp32Ub, grpIdxDiffUb, grpIdxWorkLocalUb);
}
template <typename T1, typename T2, typename T3, typename T4, typename T5>
__aicore__ inline void GroupQuantBase<T1, T2, T3, T4, T5>::CalcGrpCnt(LocalTensor<T3> grpIdxUb,
int64_t loadElems,
LocalTensor<T3> xRowCntUb) {
if constexpr (IsSameType<T3, int32_t>::value) {
event_t eventIdMte2ToV = static_cast<event_t>(GetTPipePtr()->FetchEventID(HardEvent::MTE2_V));
SetFlag<HardEvent::MTE2_V>(eventIdMte2ToV);
WaitFlag<HardEvent::MTE2_V>(eventIdMte2ToV);
Sub(xRowCntUb, grpIdxUb, xRowCntUb, loadElems);
event_t eventIdVToS = static_cast<event_t>(GetTPipePtr()->FetchEventID(HardEvent::V_S));
SetFlag<HardEvent::V_S>(eventIdVToS);
WaitFlag<HardEvent::V_S>(eventIdVToS);
} else {
event_t eventIdMte2ToS = static_cast<event_t>(GetTPipePtr()->FetchEventID(HardEvent::MTE2_S));
SetFlag<HardEvent::MTE2_S>(eventIdMte2ToS);
WaitFlag<HardEvent::MTE2_S>(eventIdMte2ToS);
for (int64_t i = 0; i < loadElems; i++) {
xRowCntUb.SetValue(i, grpIdxUb.GetValue(i) - xRowCntUb.GetValue(i));
}
}
}
template <typename T1, typename T2, typename T3, typename T4, typename T5>
__aicore__ inline void GroupQuantBase<T1, T2, T3, T4, T5>::WalkGrpIdx(LocalTensor<T3> grpIdxUb,
LocalTensor<T3> xRowCntUb) {
if (currExpertIdx < 0) {
int64_t grpIdxGmOffset = 0;
int64_t loadElems = GROUP_INDEX_UB_SIZE / sizeof(T3);
if (loadElems > dimE_) {
loadElems = dimE_;
}
LoadGrpIdxFirstBatch(grpIdxUb, xRowCntUb, grpIdxGmOffset, loadElems);
CalcGrpCnt(grpIdxUb, loadElems, xRowCntUb);
currExpertIdx = 0;
grpIdxUbCursor = 0;
} else if (grpIdxUbCursor + 1 == GROUP_INDEX_UB_SIZE / sizeof(T3)) {
int64_t grpIdxGmOffset = currExpertIdx + 1;
int64_t loadElems = GROUP_INDEX_UB_SIZE / sizeof(T3);
if (grpIdxGmOffset + loadElems > dimE_) {
loadElems = dimE_ - grpIdxGmOffset;
}
LoadGrpIdxMoreBatch(grpIdxUb, xRowCntUb, grpIdxGmOffset, loadElems);
CalcGrpCnt(grpIdxUb, loadElems, xRowCntUb);
currExpertIdx = currExpertIdx + 1;
grpIdxUbCursor = 0;
} else {
currExpertIdx = currExpertIdx + 1;
grpIdxUbCursor = grpIdxUbCursor + 1;
}
}
template <typename T1, typename T2, typename T3, typename T4, typename T5>
__aicore__ inline void GroupQuantBase<T1, T2, T3, T4, T5>::LookupExpertStateful(int64_t xStartRowCurrCore,
int64_t xRowNumCurrCore) {
LocalTensor<T3> grpIdxUb = grpIdxBuf.Get<T3>();
LocalTensor<T3> xRowCntUb = xRowCntBuf.Get<T3>();
while (currExpertIdx < dimE_) {
WalkGrpIdx(grpIdxUb, xRowCntUb);
int64_t grpCumSum = static_cast<int64_t>(grpIdxUb.GetValue(grpIdxUbCursor));
int64_t grpCnt = static_cast<int64_t>(xRowCntUb.GetValue(grpIdxUbCursor));
if (grpCumSum > xStartRowCurrCore && grpCnt > 0) {
int64_t preXptEndRow = grpCumSum - grpCnt;
if (preXptEndRow < xStartRowCurrCore) {
if (xStartRowCurrCore + xRowNumCurrCore < grpCumSum) {
xRowCntOfCurrExpert = xRowNumCurrCore;
} else {
xRowCntOfCurrExpert = grpCumSum - xStartRowCurrCore;
}
} else {
if (xStartRowCurrCore + xRowNumCurrCore < grpCumSum) {
xRowCntOfCurrExpert = xStartRowCurrCore + xRowNumCurrCore - preXptEndRow;
} else {
xRowCntOfCurrExpert = grpCnt;
}
}
break;
}
}
}
template <typename T1, typename T2, typename T3, typename T4, typename T5>
__aicore__ inline void GroupQuantBase<T1, T2, T3, T4, T5>::CopyInOffset()
{
if (hasOffset_) {
LocalTensor<T4> offsetLocal = offsetBuf_.Get<T4>();
DataCopyExtParams copyParams;
copyParams.blockCount = 1;
copyParams.blockLen = sizeof(T4);
copyParams.srcStride = 0;
copyParams.dstStride = 0;
DataCopyPadExtParams<T4> padParams = {false, 0, 0, 0};
DataCopyPad(offsetLocal, gmOffset_, copyParams, padParams);
event_t eventIdMTE2ToS = static_cast<event_t>(GetTPipePtr()->FetchEventID(HardEvent::MTE2_S));
SetFlag<HardEvent::MTE2_S>(eventIdMTE2ToS);
WaitFlag<HardEvent::MTE2_S>(eventIdMTE2ToS);
if constexpr (IsSameType<DTYPE_SCALE, bfloat16_t>::value) {
offset_ = ToFloat(offsetLocal.GetValue(0));
} else {
offset_ = static_cast<float>(*((__ubuf__ T4 *)offsetLocal.GetPhyAddr()));
}
}
}
template <typename T1, typename T2, typename T3, typename T4, typename T5>
__aicore__ inline void GroupQuantBase<T1, T2, T3, T4, T5>::CopyInX(int64_t xAddr, int64_t perSSize)
{
LocalTensor<T1> tmpLocal = tmpBuf1_.Get<T1>();
DataCopyExtParams copyParams;
copyParams.blockCount = (uint16_t)perSSize;
copyParams.blockLen = calH * sizeof(T1);
copyParams.srcStride = (dimH_ - calH) * sizeof(T1);
copyParams.dstStride = (calHBlock - calH) * sizeof(T1) / BLOCK_SIZE;
DataCopyPadExtParams<T1> padParams = {false, 0, 0, 0};
DataCopyPad(tmpLocal, gmX_[xAddr], copyParams, padParams);
}
template <typename T1, typename T2, typename T3, typename T4, typename T5>
__aicore__ inline void GroupQuantBase<T1, T2, T3, T4, T5>::CopyInScale(int64_t scaleAddr)
{
LocalTensor<T2> scaleLocal = scaleBuf_.Get<T2>();
DataCopyExtParams copyParams;
copyParams.blockCount = 1;
copyParams.blockLen = calH * sizeof(T2);
copyParams.srcStride = 0;
copyParams.dstStride = 0;
DataCopyPadExtParams<T2> padParams = {false, 0, 0, 0};
DataCopyPad(scaleLocal, gmScale_[scaleAddr], copyParams, padParams);
}
template <typename T1, typename T2, typename T3, typename T4, typename T5>
__aicore__ inline void GroupQuantBase<T1, T2, T3, T4, T5>::VecCompute(uint32_t dataCount, int64_t scaleExpandLoop,
LocalTensor<int8_t> outputLocal)
{
event_t eventMte2ToV = static_cast<event_t>(GetTPipePtr()->FetchEventID(HardEvent::MTE2_V));
SetFlag<HardEvent::MTE2_V>(eventMte2ToV);
WaitFlag<HardEvent::MTE2_V>(eventMte2ToV);
event_t eventIdSToV = static_cast<event_t>(GetTPipePtr()->FetchEventID(HardEvent::S_V));
SetFlag<HardEvent::S_V>(eventIdSToV);
WaitFlag<HardEvent::S_V>(eventIdSToV);
LocalTensor<T2> oriScaleLocal = scaleBuf_.Get<T2>();
LocalTensor<T1> tmpLocal1 = tmpBuf1_.Get<T1>();
LocalTensor<float> tmpLocal2 = tmpBuf2_.Get<float>();
LocalTensor<float> tmpLocal3 = tmpBuf3_.Get<float>();
LocalTensor<float> xLocal;
LocalTensor<float> scaleLocal;
LocalTensor<float> mulLocal = mulBuf_.Get<float>();;
if constexpr (IsSameType<T1, float>::value) {
xLocal = tmpLocal1;
} else {
Cast(tmpLocal2, tmpLocal1, RoundMode::CAST_NONE, dataCount);
xLocal = tmpLocal2;
}
if constexpr (IsSameType<T2, float>::value) {
scaleLocal = oriScaleLocal;
} else {
PipeBarrier<PIPE_V>();
Cast(tmpLocal3, oriScaleLocal, RoundMode::CAST_NONE, calHBlock);
scaleLocal = tmpLocal3;
}
if (scaleExpandLoop > 1) {
for (int64_t eIdx = 0; eIdx < scaleExpandLoop; eIdx++) {
int64_t scaleAddr = eIdx * calHBlock;
PipeBarrier<PIPE_V>();
Muls(scaleLocal[scaleAddr], scaleLocal, 1.0f, calHBlock);
}
}
PipeBarrier<PIPE_V>();
Mul(mulLocal, xLocal, scaleLocal, dataCount);
PipeBarrier<PIPE_V>();
event_t eventVToMte2 = static_cast<event_t>(GetTPipePtr()->FetchEventID(HardEvent::V_MTE2));
SetFlag<HardEvent::V_MTE2>(eventVToMte2);
WaitFlag<HardEvent::V_MTE2>(eventVToMte2);
if (hasOffset_) {
Adds(mulLocal, mulLocal, (float)offset_, dataCount);
PipeBarrier<PIPE_V>();
}
Cast(mulLocal.ReinterpretCast<int32_t>(), mulLocal, RoundMode::CAST_RINT, dataCount);
PipeBarrier<PIPE_V>();
SetDeqScale((half)1.000000e+00f);
PipeBarrier<PIPE_V>();
Cast(mulLocal.ReinterpretCast<half>(), mulLocal.ReinterpretCast<int32_t>(), RoundMode::CAST_NONE, dataCount);
PipeBarrier<PIPE_V>();
if (ORIG_DTYPE_Y == DT_INT4) {
Cast(outputLocal.ReinterpretCast<int4b_t>(),
mulLocal.ReinterpretCast<half>(),
RoundMode::CAST_RINT, dataCount);
return;
}
Cast(outputLocal, mulLocal.ReinterpretCast<half>(), RoundMode::CAST_RINT, dataCount);
}
template <typename T1, typename T2, typename T3, typename T4, typename T5>
__aicore__ inline void GroupQuantBase<T1, T2, T3, T4, T5>::CopyOutY(int64_t xAddr, int64_t perSSize,
LocalTensor<int8_t> outputLocal)
{
event_t eventVToMte3 = static_cast<event_t>(GetTPipePtr()->FetchEventID(HardEvent::V_MTE3));
SetFlag<HardEvent::V_MTE3>(eventVToMte3);
WaitFlag<HardEvent::V_MTE3>(eventVToMte3);
int64_t yLenReal = calH;
if (ORIG_DTYPE_Y == DT_INT4) {
yLenReal = yLenReal / INT4_NUMS_IN_INT8_SPACE;
}
DataCopyExtParams copyParams;
copyParams.blockCount = (uint16_t)perSSize;
copyParams.blockLen = yLenReal * sizeof(int8_t);
if (ORIG_DTYPE_Y == DT_INT4) {
copyParams.srcStride = (calHBlock / INT4_NUMS_IN_INT8_SPACE - yLenReal) * sizeof(int8_t) / BLOCK_SIZE;
copyParams.dstStride = (dimH_ / INT4_NUMS_IN_INT8_SPACE - yLenReal) * sizeof(int8_t);
DataCopyPad(gmY_[xAddr / INT4_NUMS_IN_INT8_SPACE], outputLocal, copyParams);
} else {
copyParams.srcStride = (calHBlock - yLenReal) * sizeof(int8_t) / BLOCK_SIZE;
copyParams.dstStride = (dimH_ - yLenReal) * sizeof(int8_t);
DataCopyPad(gmY_[xAddr], outputLocal, copyParams);
}
event_t eventMte3ToV = static_cast<event_t>(GetTPipePtr()->FetchEventID(HardEvent::MTE3_V));
SetFlag<HardEvent::MTE3_V>(eventMte3ToV);
WaitFlag<HardEvent::MTE3_V>(eventMte3ToV);
}
template <typename T1, typename T2, typename T3, typename T4, typename T5>
__aicore__ inline void GroupQuantBase<T1, T2, T3, T4, T5>::PerLoopCompute(int64_t hIdx)
{
currExpertIdx = -1;
int64_t cumSum = 0;
int64_t sSizePerCore = 0;
while (cumSum < xRowNum_) {
LookupExpertStateful(xRowIndex_, xRowNum_);
cumSum += xRowCntOfCurrExpert;
int64_t eSize = currExpertIdx;
int64_t hNumPerE = xRowCntOfCurrExpert;
int64_t loopS = Ceil(hNumPerE, maxSSize);
int64_t perSSize = maxSSize;
int64_t lastSSize = hNumPerE - (loopS - 1) * maxSSize;
int64_t scaleAddr = eSize * dimH_ + hIdx * PEER_H;
event_t eventIdSToMte2 = static_cast<event_t>(GetTPipePtr()->FetchEventID(HardEvent::S_MTE2));
SetFlag<HardEvent::S_MTE2>(eventIdSToMte2);
WaitFlag<HardEvent::S_MTE2>(eventIdSToMte2);
CopyInScale(scaleAddr);
for (int64_t loopSIdx = 0; loopSIdx < loopS; loopSIdx ++) {
if (loopSIdx == loopS - 1) {
perSSize = lastSSize;
}
int64_t xAddr = (xRowIndex_ + sSizePerCore) * dimH_ + hIdx * PEER_H;
uint32_t dataCount = perSSize * calHBlock;
CopyInX(xAddr, perSSize);
LocalTensor<int8_t> outputLocal = outBuf_.Get<int8_t>();
VecCompute(dataCount, perSSize, outputLocal);
CopyOutY(xAddr, perSSize, outputLocal);
sSizePerCore += perSSize;
}
}
}
template <typename T1, typename T2, typename T3, typename T4, typename T5>
__aicore__ inline void GroupQuantBase<T1, T2, T3, T4, T5>::Compute()
{
int64_t loopH = Ceil(dimH_, PEER_H);
calH = PEER_H;
int64_t lastH = dimH_ - (loopH - 1) * PEER_H;
CopyInOffset();
for (int64_t loopIdx = 0; loopIdx < loopH; loopIdx ++) {
if (loopIdx == loopH - 1) {
calH = lastH;
}
calHBlock = Ceil(calH, ALIGN_SIZE) * ALIGN_SIZE;
if (calHBlock != 0) {
maxSSize = UB_TENSOE_BUF / sizeof(float) / calHBlock;
}
PerLoopCompute(loopIdx);
}
}
template <typename T1, typename T2, typename T3, typename T4, typename T5>
__aicore__ inline void GroupQuantBase<T1, T2, T3, T4, T5>::Process() {
if (blockIdx >= needCoreNum_) {
return;
}
if (dimS_ == 0 || dimH_ == 0) {
return;
}
int64_t firstDimOfScaleShape = dimE_;
if (firstDimOfScaleShape <= 0) {
Trap();
}
CheckGrpIdxAllValue();
PipeBarrier<PIPE_ALL>();
if (blockIdx >= preCoreNum_) {
xRowNum_ = xRowNumPostCore_;
}
xRowIndex_ = (blockIdx < preCoreNum_) ? blockIdx * xRowNumPreCore_ :
preCoreNum_ * xRowNumPreCore_ + (blockIdx - preCoreNum_) * xRowNumPostCore_;
Compute();
}
}
#endif