init v0.23.0

Signed-off-by: Sun Ruoxi <sunruoxi@4paradigm.com>
This commit is contained in:
2026-08-27 15:11:51 +08:00
parent b582a8e7d1
commit 7f8a1b1f7a
2849 changed files with 712887 additions and 22001 deletions

View File

@@ -0,0 +1,408 @@
/**
 * Copyright (c) 2026 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 compressor_block_cube_perf.h
* \brief
*/
#ifndef COMPRESSOR_BLOCK_CUBE_PERF_H
#define COMPRESSOR_BLOCK_CUBE_PERF_H
#include "compressor_comm.h"
#include "compressor_tools.h"
using namespace AscendC;
namespace Compressor {
template<typename COMP> class CompressorBlockCubePerf {
using MM1_OUT_T = float;
public:
__aicore__ inline CompressorBlockCubePerf(){};
__aicore__ inline void InitParams(const ConstInfo &constInfo, const CompressorTools<COMP> &tools);
__aicore__ inline void Init(
__gm__ uint8_t *x,
__gm__ uint8_t *wKv,
__gm__ uint8_t *wGate,
__gm__ uint8_t *stateCache,
__gm__ uint8_t *ape,
__gm__ uint8_t *normWeight,
__gm__ uint8_t *ropeSin,
__gm__ uint8_t *ropeCos,
__gm__ uint8_t *stateBlockTable,
__gm__ uint8_t *cuSeqlens,
__gm__ uint8_t *seqUsed,
__gm__ uint8_t *startPos,
__gm__ uint8_t *cmpKvOut);
__aicore__ inline void InitBuffers(TPipe *pipe);
__aicore__ inline void InitGlobalBuffers(const GlobalTensor<MM1_OUT_T>& kvMm1ResGm, const GlobalTensor<MM1_OUT_T>& scoreMm1ResGm);
__aicore__ inline void AllocEventID(TPipe *pipe);
__aicore__ inline void FreeEventID(TPipe *pipe);
__aicore__ inline void ComputeMm1(const RunInfo &info);
private:
using T = float;
using X_T = typename AscendC::Conditional<COMP::xDtype == X_DTYPE::BF16, bfloat16_t, half>::type;
__aicore__ inline uint32_t GetMSize(const RunInfo &info, uint32_t coffId);
__aicore__ inline void CopyXGmToL1(const RunInfo &info, LocalTensor<X_T> xL1Tensor, uint32_t hIdx, uint32_t kBase);
__aicore__ inline void CopyWeightGmToL1(LocalTensor<X_T> wL1Tensor,
uint32_t hIdx, uint32_t kBase, uint32_t coffId);
__aicore__ inline void LoadAToL0(const RunInfo &info, LocalTensor<X_T> aL0Tensor, LocalTensor<X_T> xL1Tensor,
uint32_t kStart, uint32_t kBase, uint32_t mStart, uint32_t mDealSize);
__aicore__ inline void LoadBToL0(LocalTensor<X_T> bL0Tensor, LocalTensor<X_T> wL1Tensor,
uint32_t kStart, uint32_t kBase);
__aicore__ inline void MatrixMmad(LocalTensor<T> cL0Tensor, LocalTensor<X_T> aL0Tensor,
LocalTensor<X_T> bL0Tensor, uint32_t mActSize, uint32_t nDealSize, uint32_t kActSize, bool isInitL0C);
__aicore__ inline void CopyOutMm1Res(const RunInfo &info, LocalTensor<T> cL0Tensor,
uint32_t coffId, uint32_t mStart, uint32_t mDealSize);
ConstInfo constInfo_ = {};
CompressorTools<COMP> tools_;
// GM
GlobalTensor<X_T> xGm_;
GlobalTensor<X_T> wkvGm_;
GlobalTensor<X_T> wgateGm_;
GlobalTensor<MM1_OUT_T>kvMm1ResGm;
GlobalTensor<MM1_OUT_T>scoreMm1ResGm;
GlobalTensor<int32_t> cuSeqlensGm_;
GlobalTensor<int32_t> sequsedGm_;
GlobalTensor<int32_t> startPosGm_;
bool isExistSeqUsed = false;
// =================================L1 Buffer=================================
static constexpr uint32_t L1_X_SIZE = 128 * 1024;
static constexpr uint32_t L1_W_SIZE = 64 * 1024;
// L1 Buffer
TBuf<TPosition::A1> xBufL1;
TBuf<TPosition::A1> wBufL1;
// =================================L0 Buffer=================================
// L0 buffer size
static constexpr uint32_t L0A_PP_SIZE = 32 * 1024; // 128 * 128 * 2 = 32k
static constexpr uint32_t L0B_PP_SIZE = 32 * 1024; // 128 * 128 * 2 = 32k
static constexpr uint32_t L0C_PP_SIZE = 64 * 1024; // (128 * 2) * 64 * 4 = 64k
// L0_A
TBuf<TPosition::A2> tmpBufL0A;
// L0_B
TBuf<TPosition::B2> tmpBufL0B;
// L0_C
TBuf<TPosition::CO1> tmpBufL0C;
// =================================Event&Buffer ID===========================
// mte2 <> mte1 EventID
static constexpr uint32_t X_EVENT0 = EVENT_ID0;
static constexpr uint32_t X_EVENT1 = EVENT_ID1;
uint32_t xBufId = 0; // 用于DB计数
static constexpr uint32_t W_EVENT0 = EVENT_ID4;
static constexpr uint32_t W_EVENT1 = EVENT_ID5;
static constexpr uint32_t W_EVENT2 = EVENT_ID6;
static constexpr uint32_t W_EVENT3 = EVENT_ID7;
uint32_t wBufId = 0; // 用于DB计数
// mte1 <> mmad EventID
static constexpr uint32_t L0AB_EVENT0 = EVENT_ID3;
static constexpr uint32_t L0AB_EVENT1 = EVENT_ID4;
uint32_t l0abBufId = 0;
// mmad <> fixpipe EventID
static constexpr uint32_t L0C_EVENT0 = EVENT_ID0; // 每块L0C单独分配EVENT_ID
static constexpr uint32_t L0C_EVENT1 = EVENT_ID1;
uint32_t l0cBufId = 0;
// =================================Loop======================================
uint32_t curBIdx_ = 0;
uint32_t curSIdx_ = 0;
};
template <typename COMP>
__aicore__ inline void CompressorBlockCubePerf<COMP>::InitParams(const ConstInfo &constInfo, const CompressorTools<COMP> &tools)
{
this->constInfo_ = constInfo;
this->tools_ = tools;
}
template <typename COMP> __aicore__ inline void CompressorBlockCubePerf<COMP>::Init(
__gm__ uint8_t *x,
__gm__ uint8_t *wKv,
__gm__ uint8_t *wGate,
__gm__ uint8_t *stateCache,
__gm__ uint8_t *ape,
__gm__ uint8_t *normWeight,
__gm__ uint8_t *ropeSin,
__gm__ uint8_t *ropeCos,
__gm__ uint8_t *stateBlockTable,
__gm__ uint8_t *cuSeqlens,
__gm__ uint8_t *seqUsed,
__gm__ uint8_t *startPos,
__gm__ uint8_t *cmpKvOut)
{
xGm_.SetGlobalBuffer((__gm__ X_T *)x);
wkvGm_.SetGlobalBuffer((__gm__ X_T *)wKv);
wgateGm_.SetGlobalBuffer((__gm__ X_T *)wGate);
startPosGm_.SetGlobalBuffer((__gm__ int32_t *)startPos);
isExistSeqUsed = (seqUsed != nullptr);
if (isExistSeqUsed) {
sequsedGm_.SetGlobalBuffer((__gm__ int32_t *)seqUsed);
}
if constexpr (COMP::xLayout == X_LAYOUT::TH) {
cuSeqlensGm_.SetGlobalBuffer((__gm__ int32_t *)cuSeqlens);
}
}
template <typename COMP>
__aicore__ inline void CompressorBlockCubePerf<COMP>::InitBuffers(TPipe *pipe)
{
// L1
// 1. coff=1时, mBase=256, kL1=256, X单次拷贝到L1的数据量最大为mBase*kL1*sizeof(BF16/FP16)=256*256*2=128K
// 2. coff=2时, mBase=128, kL1=256, r最大为128, X单次拷贝到L1的最大数据量为(128+r)*kL1*sizeof(BF16/FP16)<=128K
pipe->InitBuffer(xBufL1, L1_X_SIZE * 2);
// dBaseSize<=64, wkv和wgate各一份, kL1=256, 右矩阵为dBaseSize*2*sizeof(BF16/FP16)<=64K
// cur和pre循环使用, 2份buffer就足够
pipe->InitBuffer(wBufL1, L1_W_SIZE * 4);
// L0
pipe->InitBuffer(tmpBufL0A, L0A_PP_SIZE * 2);
pipe->InitBuffer(tmpBufL0B, L0B_PP_SIZE * 2);
pipe->InitBuffer(tmpBufL0C, L0C_PP_SIZE * 2);
}
template <typename COMP>
__aicore__ inline void CompressorBlockCubePerf<COMP>::InitGlobalBuffers(const GlobalTensor<MM1_OUT_T>& kvMm1ResGm, const GlobalTensor<MM1_OUT_T>& scoreMm1ResGm)
{
this->kvMm1ResGm = kvMm1ResGm;
this->scoreMm1ResGm = scoreMm1ResGm;
}
template <typename COMP>
__aicore__ inline void CompressorBlockCubePerf<COMP>::AllocEventID(TPipe *pipe)
{
SetFlag<HardEvent::MTE1_MTE2>(X_EVENT0);
SetFlag<HardEvent::MTE1_MTE2>(X_EVENT1);
SetFlag<HardEvent::MTE1_MTE2>(W_EVENT0);
SetFlag<HardEvent::MTE1_MTE2>(W_EVENT1);
SetFlag<HardEvent::MTE1_MTE2>(W_EVENT2);
SetFlag<HardEvent::MTE1_MTE2>(W_EVENT3);
SetFlag<HardEvent::M_MTE1>(L0AB_EVENT0);
SetFlag<HardEvent::M_MTE1>(L0AB_EVENT1);
SetFlag<HardEvent::FIX_M>(L0C_EVENT0);
SetFlag<HardEvent::FIX_M>(L0C_EVENT1);
}
template <typename COMP>
__aicore__ inline void CompressorBlockCubePerf<COMP>::FreeEventID(TPipe *pipe)
{
WaitFlag<HardEvent::MTE1_MTE2>(X_EVENT0);
WaitFlag<HardEvent::MTE1_MTE2>(X_EVENT1);
WaitFlag<HardEvent::MTE1_MTE2>(W_EVENT0);
WaitFlag<HardEvent::MTE1_MTE2>(W_EVENT1);
WaitFlag<HardEvent::MTE1_MTE2>(W_EVENT2);
WaitFlag<HardEvent::MTE1_MTE2>(W_EVENT3);
WaitFlag<HardEvent::M_MTE1>(L0AB_EVENT0);
WaitFlag<HardEvent::M_MTE1>(L0AB_EVENT1);
WaitFlag<HardEvent::FIX_M>(L0C_EVENT0);
WaitFlag<HardEvent::FIX_M>(L0C_EVENT1);
}
template <typename COMP>
__aicore__ inline void CompressorBlockCubePerf<COMP>::CopyXGmToL1(const RunInfo &info, LocalTensor<X_T> xL1Tensor,
uint32_t hIdx, uint32_t kBase)
{
uint32_t tStart = tools_.GetTIdxByBatch(info.bStart) + info.sStart; // 此基本块在整个序列中的位置
uint32_t copySeqCnt = info.dealSeqCnt; // 此基本块处理的长度
uint32_t xL1Offset = 0 * (32 / sizeof(X_T));
uint64_t sIdx = tStart; // 起始s在整个T的起始点
uint64_t gmOffset = sIdx * constInfo_.hSize + hIdx;
uint32_t nValue = copySeqCnt;
uint32_t dValue = kBase; // 拷贝的列数kBase
uint32_t srcDValue = constInfo_.hSize;
uint32_t dstNzC0Stride = (copySeqCnt + 15) / 16 * 16; // 1行变2行的行方向的偏移,需要16对齐
CopySingleMatrixNDToNZ(xL1Tensor[xL1Offset], xGm_[gmOffset], nValue, dValue, srcDValue, dstNzC0Stride);
}
template <typename COMP>
__aicore__ inline void CompressorBlockCubePerf<COMP>::CopyWeightGmToL1(LocalTensor<X_T> wL1Tensor,
uint32_t hIdx, uint32_t kBase, uint32_t coffId)
{
// coffId=0, 搬运左矩阵的数据; coffId=1, 搬运右矩阵的数据
uint64_t gmOffset = coffId * constInfo_.headDim * constInfo_.hSize + constInfo_.dIdx * constInfo_.hSize + hIdx;
uint32_t wkvL1Offset = 0;
uint32_t wgateL1Offset = constInfo_.dBaseSize * (32 / sizeof(X_T)); // wgate与wkv的起始点相隔dBaseSize个32B
uint32_t nValue = constInfo_.dBaseSize;
uint32_t dValue = kBase;
uint32_t srcDValue = constInfo_.hSize;
uint32_t dstNzC0Stride = 2 * constInfo_.dBaseSize; // 2: wkv和wgate各搬运dBaseSize行, dBaseSize需保证8的倍数
CopySingleMatrixNDToNZ(wL1Tensor[wkvL1Offset], wkvGm_[gmOffset], nValue, dValue, srcDValue, dstNzC0Stride);
CopySingleMatrixNDToNZ(wL1Tensor[wgateL1Offset], wgateGm_[gmOffset], nValue, dValue, srcDValue, dstNzC0Stride);
}
template <typename COMP>
__aicore__ inline void CompressorBlockCubePerf<COMP>::LoadAToL0(const RunInfo &info, LocalTensor<X_T> aL0Tensor,
LocalTensor<X_T> xL1Tensor, uint32_t kStart, uint32_t kBase, uint32_t mStart, uint32_t mDealSize)
{
uint32_t mSize = info.dealSeqCnt;
uint32_t mSizeAlign = Align(mSize, 16U);
uint32_t xTensorOffset = kStart * mSizeAlign + mStart * (32 / sizeof(X_T));
uint32_t mLoop = Align(mDealSize, 16U) / 16;
for (uint32_t i = 0; i < mLoop; i++) {
LoadData2DParams loadData2DParams;
loadData2DParams.startIndex = i;
loadData2DParams.repeatTimes = kBase / (32 / sizeof(X_T));
loadData2DParams.srcStride = mSizeAlign / 16;
loadData2DParams.dstGap = 0;
loadData2DParams.ifTranspose = false;
LoadData(aL0Tensor[i * 16 * kBase], xL1Tensor[xTensorOffset], loadData2DParams); // 16: 一个分型的行数
}
}
template <typename COMP>
__aicore__ inline void CompressorBlockCubePerf<COMP>::LoadBToL0(LocalTensor<X_T> bL0Tensor, LocalTensor<X_T> wL1Tensor,
uint32_t kStart, uint32_t kBase)
{
uint32_t rowCnt = 2 * constInfo_.dBaseSize; // 2: wkv和wgate各搬运dBaseSize行, dBaseSize需保证8的倍数
uint64_t wTensorOffset = rowCnt * kStart;
LoadData2DParams loadData2DParams;
loadData2DParams.startIndex = 0;
loadData2DParams.repeatTimes = (rowCnt / 16) * (kBase / (32 / sizeof(X_T)));
loadData2DParams.srcStride = 1;
loadData2DParams.dstGap = 0;
loadData2DParams.ifTranspose = false;
LoadData(bL0Tensor, wL1Tensor[wTensorOffset], loadData2DParams);
}
template <typename COMP>
__aicore__ inline void CompressorBlockCubePerf<COMP>::MatrixMmad(LocalTensor<T> cL0Tensor, LocalTensor<X_T> aL0Tensor,
LocalTensor<X_T> bL0Tensor, uint32_t mActSize, uint32_t nDealSize, uint32_t kActSize, bool isInitL0C)
{
MmadParams mmadParams;
mmadParams.m = (mActSize + 15) / 16 * 16;
mmadParams.n = nDealSize;
mmadParams.k = kActSize;
mmadParams.cmatrixInitVal = isInitL0C;
mmadParams.cmatrixSource = false;
Mmad(cL0Tensor, aL0Tensor, bL0Tensor, mmadParams);
PipeBarrier<PIPE_M>();
}
template <typename COMP>
__aicore__ inline void CompressorBlockCubePerf<COMP>::CopyOutMm1Res(const RunInfo &info, LocalTensor<T> cL0Tensor,
uint32_t coffId, uint32_t mStart, uint32_t mDealSize)
{
// coffId=0, 存左矩阵的数据; coffId=1, 存右矩阵的数据
FixpipeParamsV220 fixParams;
fixParams.mSize = mDealSize;
fixParams.nSize = constInfo_.dBaseSize;
fixParams.srcStride = (mDealSize + 15) / 16 * 16; // 需要16对齐
fixParams.dstStride = (uint32_t)COMP::coff * constInfo_.headDim;
fixParams.ndNum = 1;
uint64_t dbOffset = info.cubeDbIdx * constInfo_.dbSize;
uint64_t gmOffset = coffId * constInfo_.headDim + constInfo_.dIdx + mStart * fixParams.dstStride + dbOffset;
uint32_t kvOffset = 0;
uint32_t scoreOffset = (mDealSize + 15) / 16 * 16 * constInfo_.dBaseSize;
Fixpipe(kvMm1ResGm[gmOffset], cL0Tensor[kvOffset], fixParams);
Fixpipe(scoreMm1ResGm[gmOffset], cL0Tensor[scoreOffset], fixParams);
}
template <typename COMP>
__aicore__ inline uint32_t CompressorBlockCubePerf<COMP>::GetMSize(const RunInfo &info, uint32_t coffId)
{
return info.dealSeqCnt;
}
template <typename COMP>
__aicore__ inline void CompressorBlockCubePerf<COMP>::ComputeMm1(const RunInfo &info)
{
static constexpr uint32_t K_SIZE = 512;
static constexpr uint32_t K_L1_BASE = 256;
static constexpr uint32_t M_L0_BASE = 128;
static constexpr uint32_t K_L0_BASE = 128;
uint32_t nCoff = (uint32_t)COMP::coff;
// hSize为K_SIZE=512的倍数
uint32_t hSize = constInfo_.hSize;
uint32_t hIdxStart = (constInfo_.aiCoreIdx % constInfo_.dBasicBlockNum) * K_L1_BASE; // 每组核内的h循环起始不同
for (uint32_t h = 0; h < hSize; h += K_SIZE) {
for (uint32_t k = 0; k < K_SIZE; k += K_L1_BASE) {
bool isFirst = (h == 0 && k == 0);
bool isLast = ((h + K_SIZE >= hSize) && (k + K_L1_BASE >= K_SIZE));
uint32_t hIdx = (h + k + hIdxStart) % hSize; // h方向错位搬运
WaitFlag<HardEvent::MTE1_MTE2>(X_EVENT0 + xBufId);
LocalTensor<X_T> xL1Tensor = xBufL1.GetWithOffset<X_T>(L1_X_SIZE / sizeof(X_T), xBufId * L1_X_SIZE);
CopyXGmToL1(info, xL1Tensor, hIdx, K_L1_BASE);
SetFlag<HardEvent::MTE2_MTE1>(X_EVENT0 + xBufId);
WaitFlag<HardEvent::MTE2_MTE1>(X_EVENT0 + xBufId);
for (uint32_t i = nCoff; i > 0; i--) {
// coffId=0, 计算pre数据; coffId=1, 计算cur数据
uint32_t coffId = i - 1;
WaitFlag<HardEvent::MTE1_MTE2>(W_EVENT0 + wBufId);
LocalTensor<X_T> wL1Tensor = wBufL1.GetWithOffset<X_T>(L1_W_SIZE / sizeof(X_T), wBufId * L1_W_SIZE);
CopyWeightGmToL1(wL1Tensor, hIdx, K_L1_BASE, coffId);
SetFlag<HardEvent::MTE2_MTE1>(W_EVENT0 + wBufId);
WaitFlag<HardEvent::MTE2_MTE1>(W_EVENT0 + wBufId);
uint32_t mSize = GetMSize(info, coffId);
uint32_t actMDealSize = M_L0_BASE;
for (uint32_t mL0 = 0; mL0 < mSize; mL0 += M_L0_BASE) {
if (mL0 + M_L0_BASE > mSize) {
actMDealSize = mSize - mL0;
}
l0cBufId = coffId + (mL0 / M_L0_BASE);
LocalTensor<T> cL0Tensor = tmpBufL0C.GetWithOffset<T>((L0C_PP_SIZE / sizeof(T)), l0cBufId * L0C_PP_SIZE);
if (isFirst) {
WaitFlag<HardEvent::FIX_M>(L0C_EVENT0 + l0cBufId);
}
uint32_t nDealSize = 2 * constInfo_.dBaseSize; // 2: wkv和wgate各搬运dBaseSize行, dBaseSize需保证8的倍数
for (uint32_t kL0 = 0; kL0 < K_L1_BASE; kL0 += K_L0_BASE) {
WaitFlag<HardEvent::M_MTE1>(L0AB_EVENT0 + l0abBufId);
LocalTensor<X_T> aL0Tensor = tmpBufL0A.GetWithOffset<X_T>(L0A_PP_SIZE / sizeof(X_T), l0abBufId * L0A_PP_SIZE);
LocalTensor<X_T> bL0Tensor = tmpBufL0B.GetWithOffset<X_T>(L0B_PP_SIZE / sizeof(X_T), l0abBufId * L0B_PP_SIZE);
LoadAToL0(info, aL0Tensor, xL1Tensor, kL0, K_L0_BASE, mL0, actMDealSize);
LoadBToL0(bL0Tensor, wL1Tensor, kL0, K_L0_BASE);
SetFlag<HardEvent::MTE1_M>(L0AB_EVENT0 + l0abBufId);
WaitFlag<HardEvent::MTE1_M>(L0AB_EVENT0 + l0abBufId);
bool isInitL0C = isFirst && (kL0 == 0);
MatrixMmad(cL0Tensor, aL0Tensor, bL0Tensor, actMDealSize, nDealSize, K_L0_BASE, isInitL0C);
SetFlag<HardEvent::M_MTE1>(L0AB_EVENT0 + l0abBufId);
l0abBufId = (l0abBufId + 1) % 2;
}
if (isLast) {
SetFlag<HardEvent::M_FIX>(L0C_EVENT0 + l0cBufId);
WaitFlag<HardEvent::M_FIX>(L0C_EVENT0 + l0cBufId);
CopyOutMm1Res(info, cL0Tensor, coffId, mL0, actMDealSize);
SetFlag<HardEvent::FIX_M>(L0C_EVENT0 + l0cBufId);
}
}
SetFlag<HardEvent::MTE1_MTE2>(W_EVENT0 + wBufId);
wBufId = (wBufId + 1) % 4;
}
SetFlag<HardEvent::MTE1_MTE2>(X_EVENT0 + xBufId);
xBufId = (xBufId + 1) % 2;
}
}
}
} // namespace Compressor
#endif // COMPRESSOR_BLOCK_CUBE_PERF_H

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,341 @@
/**
 * Copyright (c) 2026 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 compressor_comm.h
* \brief
*/
#ifndef COMPRESSOR_COMM_H
#define COMPRESSOR_COMM_H
#include "kernel_operator.h"
#include "kernel_operator_list_tensor_intf.h"
#include "kernel_tiling/kernel_tiling.h"
#include "lib/matmul_intf.h"
#include "lib/matrix/matmul/tiling.h"
using namespace AscendC;
namespace Compressor {
template <typename T>
__aicore__ inline T CeilDivT(T num1, T num2)
{
if (num2 == 0) {
return static_cast<T>(0);
}
return (num1 + num2 - 1) / num2;
}
template <typename T>
__aicore__ inline T Align(T num, T rnd)
{
return (((rnd) == 0) ? 0 : (((num) + (rnd)-1) / (rnd) * (rnd)));
}
template <typename T>
__aicore__ inline T Trunc(T num, T rnd)
{
return ((rnd) == 0) ? 0 : (((num) / (rnd) * (rnd)));
}
template <typename T>
__aicore__ inline T FloorPow2(T num)
{
if (num == 0) return 1;
for(uint32_t i = 1; i < sizeof(T) * 8; i <<= 1) {
num |= (num >> i);
}
return num - (num >> 1);
}
template <typename T>
__aicore__ inline T CeilPow2(T num)
{
if (num <= 1) return 1;
num --;
for(uint32_t i = 1; i < sizeof(T) * 8; i <<= 1) {
num |= (num >> i);
}
num ++;
return num;
}
enum class X_LAYOUT : std::uint8_t {
BSH = static_cast<std::uint8_t>(0),
TH = static_cast<std::uint8_t>(1)
};
enum class X_DTYPE : std::uint8_t {
BF16 = static_cast<std::uint8_t>(0),
FP16 = static_cast<std::uint8_t>(1)
};
enum class ROPE_DTYPE : std::uint8_t {
SAME_AS_X = static_cast<std::uint8_t>(0),
FP32 = static_cast<std::uint8_t>(1)
};
enum class COFF : std::uint8_t {
DISABLE = static_cast<std::uint8_t>(1),
OVERLAP = static_cast<std::uint8_t>(2)
};
enum class ROTARY_MODE : std::uint8_t {
HALF = static_cast<std::uint8_t>(1),
INTERLEAVE = static_cast<std::uint8_t>(2)
};
enum class CACHE_MODE : std::uint8_t {
CONTINUOUS = static_cast<std::uint8_t>(1),
CYCLE = static_cast<std::uint8_t>(2)
};
enum class TEMPLATE_ID : uint8_t {
NORMAL = 0,
EMPTY_X = 1,
PERF = 2
};
template <X_LAYOUT X_L, X_DTYPE X_T, ROPE_DTYPE R_T, COFF C, ROTARY_MODE Rotary_Mode, typename... Args>
struct COMPType {
static constexpr X_LAYOUT xLayout = X_L;
static constexpr X_DTYPE xDtype = X_T;
static constexpr ROPE_DTYPE ropeDtype = R_T;
static constexpr COFF coff = C;
static constexpr ROTARY_MODE rotaryMode = Rotary_Mode;
};
struct ConstInfo {
// 整个AICORE的任务信息, 左闭右开区间[ (bStart, s2Start), (bEnd, s2End) )
uint32_t bStart = 0U;
uint32_t sStart = 0U;
uint32_t bEnd = 0U;
uint32_t sEnd = 0U;
// 分核相关
uint32_t usedCoreNum = 0;
uint32_t dBaseSize = 0;
uint32_t mBaseSize = 0;
uint32_t tcSize = 0;
uint32_t tcBaseSize = 0;
uint32_t tcBasicBlockNum = 0;
uint32_t dBasicBlockNum = 0;
uint32_t coreGroupNum = 0;
uint32_t singleCoreDealTcBasicNum = 0;
uint32_t dIdx = 0;
uint32_t bIdxOfLastTc = 0;
uint32_t sIdxOfLastTc = 0;
// shape及参数
uint32_t batchSize = 0;
uint32_t hSize = 0;
uint32_t sSize = 0;
uint32_t headDim = 0;
uint32_t ropeHeadDim = 0;
uint32_t cmpRatio = 0;
float normEps = 1e-6;
float reciprocalD = 0;
uint32_t curGroupIdx = 0;
uint32_t tailGroupIdx = 0;
uint32_t tailBasicBlockNum = 0;
uint32_t realDealBasicBlockNum = 0;
// pageAttention
uint32_t blockNum = 0;
uint32_t blockSize = 0;
uint32_t maxBlockNumPerBatch = 0;
uint64_t stateCacheStrideDim0 = 0;
// workSpace
uint32_t dbWorkspaceRatio = 1;
uint32_t mm1KvResSize = 0;
uint32_t mm1ScoreResSize = 0;
uint32_t vec1TailCacheSize = 0;
uint32_t vec1ResSize = 0;
uint32_t mm1ResSize = 0; // 所有cube输出kv/score结果的总大小
uint32_t aiCoreIdx = 0;
uint32_t nSize = 0;
uint32_t dbSize = 0;
};
struct RunInfo {
bool isValid = false;
uint32_t cubeDbIdx = 0; // kernel主循环索引
// 增加字段
uint32_t dealTcNum = 0;
// 右边相关信息
uint32_t bStart = 0;
uint32_t sStart = 0;
uint32_t dealSeqCnt = 0;
// 左边相关信息
uint32_t preBStart = 0;
uint32_t preSStart = 0;
uint32_t preDealSeqCnt = 0; // 左边需要处理的s大小
uint32_t preFirstSeqCnt = 0; // 左边首块大小
uint32_t bEnd = 0;
uint32_t sEnd = 0;
uint32_t bStartSeqIdx = 0;
uint32_t bEndSeqIdx = 0;
// v2分核信息 sc是左闭右开
uint32_t scStart = 0;
uint32_t scEnd = 0;
uint32_t dealScSize = 0;
// vec1Res offset
uint64_t vec1ResOffset = 0;
};
struct Vec1RunInfo {
// vec相关信息,一次syncAll需处理数据的起始索引
bool resetResFlag = false; // v1积攒N轮 是否是N轮的起始轮
uint32_t c1v1DbIdx = 0; // vec1 doubleBuffer索引
uint32_t v1v2DbIdx = 0; // v1v2 doubleBuffer索引
uint32_t bStart = 0;
uint32_t sStart = 0;
uint32_t dealTcNum = 0;
uint32_t dealScSize = 0;
};
struct Vec2RunInfo {
// uint32_t bStart = 0;
uint32_t v2DbIdx = 0; // v2 doubleBuffer索引
uint32_t sStart = 0;
uint32_t bEnd = 0;
uint32_t sEnd = 0;
// v2分核信息 sc是左闭右开
uint32_t scStart = 0;
uint32_t scEnd = 0;
// uint32_t dealScSize = 0;
// 增加字段
uint32_t bStart = 0;
uint32_t compressedId = 0;
uint32_t bCompressedId = 0;
uint32_t dealScSize = 0;
};
struct MSplitInfo {
uint32_t vecStartB = 0U;
uint32_t vecStartS = 0U;
uint32_t vecEndB = 0U;
uint32_t vecEndS = 0U;
uint32_t dealTcNum = 0U;
// vec1Res offset
uint64_t vec1StartOffset = 0;
uint64_t vec1ResOffset = 0;
};
struct BlockInfo {
__aicore__ inline BlockInfo(uint32_t bIdx, uint32_t sIdx, uint32_t dealSeqSize) :
bIdx(bIdx), sIdx(sIdx), dealSeqSize(dealSeqSize) {};
uint32_t bIdx = 0U;
uint32_t sIdx = 0U;
uint32_t dealSeqSize = 0;
uint32_t isFirst = true;
uint32_t bSeqUsed = 0U;
uint32_t bStartPos = 0U;
uint32_t headHolderSeqCnt = 0U;
uint32_t validSeqCnt = 0U;
uint32_t tailHolderSeqCnt = 0U;
uint32_t dealTcSize = 0U;
uint32_t tailValidSeqCnt = 0U;
uint32_t compressTcSize = 0U;
};
// BUFFER的字节数
inline constexpr uint32_t BUFFER_SIZE_BYTE_32B = 32;
inline constexpr uint32_t BUFFER_SIZE_BYTE_64B = 64;
inline constexpr uint32_t BUFFER_SIZE_BYTE_256B = 256;
inline constexpr uint32_t BUFFER_SIZE_BYTE_512B = 512;
inline constexpr uint32_t BUFFER_SIZE_BYTE_1K = 1024;
inline constexpr uint32_t BUFFER_SIZE_BYTE_2K = 2048;
inline constexpr uint32_t BUFFER_SIZE_BYTE_4K = 4096;
inline constexpr uint32_t BUFFER_SIZE_BYTE_8K = 8192;
inline constexpr uint32_t BUFFER_SIZE_BYTE_16K = 16384;
inline constexpr uint32_t BUFFER_SIZE_BYTE_32K = 32768;
inline constexpr uint32_t BUFFER_SIZE_BYTE_64K = 65536;
// BLOCK和REPEAT的字节数
inline constexpr uint64_t BYTE_BLOCK = 32UL;
inline constexpr uint32_t REPEAT_BLOCK_BYTE = 256U;
// BLOCK和REPEAT的FP32元素数
inline constexpr uint32_t FP32_BLOCK_ELEMENT_NUM = BYTE_BLOCK / sizeof(float); // 8
inline constexpr uint32_t FP32_REPEAT_ELEMENT_NUM = REPEAT_BLOCK_BYTE / sizeof(float); // 64
inline constexpr uint32_t REPEAT_STRIDE_NUM = REPEAT_BLOCK_BYTE / BYTE_BLOCK; // 8
inline constexpr uint32_t REPEAT_MAX_NUM = 255;
inline constexpr uint32_t BRCB_NUM = 8;
inline constexpr uint32_t MAX_R = 256;
template <typename T>
__aicore__ inline void CopySingleMatrixNDToNZ(LocalTensor<T> l1Tensor, const GlobalTensor<T> gmTensor,
uint32_t nValue, uint32_t dValue, uint32_t srcDValue, uint32_t dstNzC0Stride)
{
Nd2NzParams nd2nzPara;
nd2nzPara.ndNum = 1;
nd2nzPara.nValue = nValue; // nd矩阵的行数
if constexpr (IsSameType<T, int4b_t>::value) {
constexpr uint32_t HALF_SIZE_DIVISOR = 2;
nd2nzPara.dValue = dValue / HALF_SIZE_DIVISOR;
nd2nzPara.srcDValue = srcDValue / HALF_SIZE_DIVISOR;
} else {
nd2nzPara.dValue = dValue; // nd矩阵的列数
nd2nzPara.srcDValue = srcDValue; // 同一nd矩阵相邻行起始地址间的偏移
}
nd2nzPara.dstNzC0Stride = dstNzC0Stride;
nd2nzPara.dstNzNStride = 1;
nd2nzPara.srcNdMatrixStride = 0;
nd2nzPara.dstNzMatrixStride = 0;
DataCopy(l1Tensor, gmTensor, nd2nzPara);
}
template <typename T>
__aicore__ inline void DumpTensorForDim2(GlobalTensor<T> tensor, uint32_t desc, uint32_t dumpSize, uint32_t row, uint32_t col)
{
uint32_t array2[] = {static_cast<uint32_t>(row), static_cast<uint32_t>(col)};
AscendC::ShapeInfo shapeInfo(2, array2);
// AscendC::DumpTensor(tensor, desc, dumpSize, shapeInfo);
}
template <typename T>
__aicore__ inline void DumpTensorForDim2(LocalTensor<T> tensor, uint32_t desc, uint32_t dumpSize, uint32_t row, uint32_t col)
{
uint32_t array2[] = {static_cast<uint32_t>(row), static_cast<uint32_t>(col)};
AscendC::ShapeInfo shapeInfo(2, array2);
// AscendC::DumpTensor(tensor, desc, dumpSize, shapeInfo);
}
template <typename T>
__aicore__ inline void DumpTensorForDim2(LocalTensor<T> tensor, uint32_t desc, uint32_t dumpSize)
{
uint32_t col = 32 / sizeof(T);
uint32_t array2[] = {static_cast<uint32_t>(dumpSize / col), static_cast<uint32_t>(col)};
AscendC::ShapeInfo shapeInfo(2, array2);
// AscendC::DumpTensor(tensor, desc, dumpSize, shapeInfo);
}
template <typename T>
__aicore__ inline void DumpTensorForDim2(GlobalTensor<T> tensor, uint32_t desc, uint32_t dumpSize)
{
uint32_t col = 32 / sizeof(T);
uint32_t array2[] = {static_cast<uint32_t>(dumpSize / col), static_cast<uint32_t>(col)};
AscendC::ShapeInfo shapeInfo(2, array2);
// AscendC::DumpTensor(tensor, desc, dumpSize, shapeInfo);
}
} // namespace Compressor
#endif

View File

@@ -0,0 +1,86 @@
/**
 * Copyright (c) 2026 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 compressor_kernel.h
* \brief
*/
#ifndef COMPRESSOR_KERNEL
#define COMPRESSOR_KERNEL
#include "compressor_comm.h"
#include "compressor_template_tiling_key.h"
#include "compressor_kernel_perf.h"
#include "compressor_tiling_data.h"
#include "compressor_tools.h"
using namespace AscendC;
namespace Compressor {
template <typename COMP>
class CompressorKernel {
public:
__aicore__ inline CompressorKernel(TPipe* pipe, const optiling::CompressorTilingData* __restrict tilingData)
: pipe_(pipe), tilingData_(tilingData) {}
__aicore__ inline void Init(
__gm__ uint8_t *x,
__gm__ uint8_t *wKv,
__gm__ uint8_t *wGate,
__gm__ uint8_t *stateCache,
__gm__ uint8_t *ape,
__gm__ uint8_t *normWeight,
__gm__ uint8_t *ropeSin,
__gm__ uint8_t *ropeCos,
__gm__ uint8_t *stateBlockTable,
__gm__ uint8_t *cuSeqlens,
__gm__ uint8_t *seqUsed,
__gm__ uint8_t *startPos,
__gm__ uint8_t *cmpKvOut,
__gm__ uint8_t *workspace);
__aicore__ inline void Process();
// ==============================TilingData&TPipe==============================
TPipe* pipe_;
const optiling::CompressorTilingData* __restrict tilingData_;
};
template <typename COMP>
__aicore__ inline void CompressorKernel<COMP>::Init(
__gm__ uint8_t *x,
__gm__ uint8_t *wKv,
__gm__ uint8_t *wGate,
__gm__ uint8_t *stateCache,
__gm__ uint8_t *ape,
__gm__ uint8_t *normWeight,
__gm__ uint8_t *ropeSin,
__gm__ uint8_t *ropeCos,
__gm__ uint8_t *stateBlockTable,
__gm__ uint8_t *cuSeqlens,
__gm__ uint8_t *seqUsed,
__gm__ uint8_t *startPos,
__gm__ uint8_t *cmpKvOut,
__gm__ uint8_t *workspace)
{
}
template <typename COMP>
__aicore__ inline void CompressorKernel<COMP>::Process()
{
}
} // namespace Compressor
#endif // COMPRESSOR_KERNEL

View File

@@ -0,0 +1,695 @@
/**
 * Copyright (c) 2026 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 compressor_kernel_perf.h
* \brief
*/
#ifndef COMPRESSOR_KERNEL_PERF_H
#define COMPRESSOR_KERNEL_PERF_H
#include "compressor_comm.h"
#include "compressor_template_tiling_key.h"
#include "compressor_tiling_data.h"
#include "compressor_tools.h"
#include "compressor_block_cube_perf.h"
#include "compressor_block_vec_perf.h"
using namespace AscendC;
namespace Compressor {
struct CmpBlockInfo {
__aicore__ inline CmpBlockInfo() {};
__aicore__ inline CmpBlockInfo(uint32_t bIdx, uint32_t sIdx, bool needReset = false) : bIdx(bIdx), sIdx(sIdx), needReset(needReset) {};
uint32_t bIdx = 0U;
uint32_t sIdx = 0U;
uint32_t bSeqUsed = 0U;
uint32_t bStartPos = 0U;
bool needReset = false;
bool isFirst = true;
uint32_t headSeqCnt = 0U;
uint32_t validSeqCnt = 0U;
uint32_t tailSeqCnt = 0U;
bool isCompress = 0U;
};
struct BasicBlockInfo {
uint32_t bIdx = 0;
uint32_t sIdx = 0;
uint32_t compressedTcNum = 0;
uint32_t dealSeqCnt = 0;
uint32_t dealTcNum = 0;
};
struct BatchInfo {
uint32_t tcNum = 0;
uint32_t compressedTcNum = 0;
uint32_t remSeqCnt = 0;
uint32_t seqCnt = 0;
uint32_t seqUsedCnt = 0;
uint32_t headHolderSeq = 0;
uint32_t bStartPos = 0;
uint32_t bIdx = 0;
uint32_t sIdx = 0;
};
template <typename COMP>
class CompressorKernelPerf {
public:
__aicore__ inline CompressorKernelPerf(TPipe* pipe, const optiling::CompressorTilingData* __restrict tilingData)
: pipe_(pipe), tilingData_(tilingData) {}
__aicore__ inline void Init(
__gm__ uint8_t *x,
__gm__ uint8_t *wKv,
__gm__ uint8_t *wGate,
__gm__ uint8_t *stateCache,
__gm__ uint8_t *ape,
__gm__ uint8_t *normWeight,
__gm__ uint8_t *ropeSin,
__gm__ uint8_t *ropeCos,
__gm__ uint8_t *stateBlockTable,
__gm__ uint8_t *cuSeqlens,
__gm__ uint8_t *seqUsed,
__gm__ uint8_t *startPos,
__gm__ uint8_t *cmpKvOut,
__gm__ uint8_t *workspace);
__aicore__ inline void Process();
private:
// ================================Init functions==================================
__aicore__ inline void InitWorkspace(__gm__ uint8_t *workspace);
// ================================Process functions================================
__aicore__ inline void InitTilingData();
__aicore__ inline void SetBaseSize();
// 获取基本块数量
__aicore__ inline uint32_t GetLoopTimes();
__aicore__ inline void SkipInvalidBatch(BatchInfo &batchInfo);
__aicore__ inline void UpdateCurGroup(BasicBlockInfo &basicBlockInfo, BatchInfo batchInfo, uint32_t &curGroupQuota, uint32_t curDealSeq);
__aicore__ inline BasicBlockInfo SkipOneLoop(BatchInfo &batchInfo);
// 计算分核基本信息
__aicore__ inline void CalcSplitCoreInfo();
__aicore__ inline void AllocEventID();
__aicore__ inline void FreeEventID();
__aicore__ inline void ComputeMm1(const RunInfo &info, bool isNeedExcute);
__aicore__ inline void ComputeVec1(const Vec1RunInfo &info);
__aicore__ inline void ComputeVec2(const Vec2RunInfo &info);
__aicore__ inline bool IsNeedExcuteC1(RunInfo info);
__aicore__ inline bool IsNeedSyncAll(uint32_t curBasicBlockIdx);
__aicore__ inline void CalcC1V1Params(RunInfo &info, Vec1RunInfo &vec1Info, BatchInfo &batchInfo, uint32_t loopIdx);
__aicore__ inline void UpdateVec2Info(Vec2RunInfo &vec2Info, uint32_t curBasicBlockIdx, const Vec1RunInfo &info);
__aicore__ inline bool IsNeedExcuteV2(Vec2RunInfo &vec2Info);
using X_T = typename AscendC::Conditional<COMP::xDtype == X_DTYPE::BF16, bfloat16_t, half>::type;
using T = float;
using MM1_OUT_T = T;
using VEC1_OUT_T = T;
// 常量
static constexpr uint64_t SYNC_MODE0 = 0;
static constexpr uint64_t SYNC_MODE2 = 2;
static constexpr uint32_t SYNC_C1_FLAG = 3;
static constexpr uint32_t SYNC_V1_FLAG = 4;
static constexpr uint32_t SYNC_V1_FLAG2 = 5;
static constexpr uint32_t SYNC_C1_V1_FLAG = 6;
static constexpr uint32_t SYNC_V1_C1_FLAG = 8;
// ==============================TilingData&TPipe==============================
TPipe* pipe_;
const optiling::CompressorTilingData* __restrict tilingData_;
// ===========================Workspace Global Tensor===========================
GlobalTensor<MM1_OUT_T> mm1KvResGm;
GlobalTensor<MM1_OUT_T> mm1ScoreResGm;
GlobalTensor<MM1_OUT_T> vec1KvCacheGm;
GlobalTensor<MM1_OUT_T> vec1ScoreCacheGm;
GlobalTensor<MM1_OUT_T> Vec1InputKvGm;
GlobalTensor<MM1_OUT_T> Vec1InputScoreGm;
GlobalTensor<VEC1_OUT_T> vec1ResGm;
GlobalTensor<VEC1_OUT_T> vec2InputGm;
// ================================Task Info====================================
CompressorTools<COMP> tools_;
ConstInfo constInfo{};
uint32_t aiCoreIdx = 0;
// ==============================Service Define==============================
CompressorBlockCubePerf<COMP> blockCube_;
CompressorBlockVectorPerf<COMP> blockVec_;
uint32_t allCompressedTcNum_ = 0;
uint32_t curCompressedTcNum_ = 0;
uint32_t accDealSize = 0;
uint32_t loopTimes = 0;
uint32_t cubeLoop = 0;
uint32_t vec1Loop = 0;
uint32_t vec2Loop = 0;
bool isFirstUpdateCurGroup = true;
};
template <typename COMP>
__aicore__ inline void CompressorKernelPerf<COMP>::Init(
__gm__ uint8_t *x,
__gm__ uint8_t *wKv,
__gm__ uint8_t *wGate,
__gm__ uint8_t *stateCache,
__gm__ uint8_t *ape,
__gm__ uint8_t *normWeight,
__gm__ uint8_t *ropeSin,
__gm__ uint8_t *ropeCos,
__gm__ uint8_t *stateBlockTable,
__gm__ uint8_t *cuSeqlens,
__gm__ uint8_t *seqUsed,
__gm__ uint8_t *startPos,
__gm__ uint8_t *cmpKvOut,
__gm__ uint8_t *workspace)
{
if ASCEND_IS_AIV {
constInfo.aiCoreIdx = GetBlockIdx() / 2;
} else {
constInfo.aiCoreIdx = GetBlockIdx();
}
InitTilingData();
// init tools
tools_.toolParams_.seqSize = tilingData_->baseParams.seqSize;
tools_.toolParams_.cmpRatio = tilingData_->baseParams.cmpRatio;
tools_.Init(startPos, seqUsed, cuSeqlens);
// 剔除尾部的无效batch
for (; constInfo.batchSize > 0; --constInfo.batchSize) {
uint32_t bSeqUsed = tools_.GetSeqLength(constInfo.batchSize - 1);
if (bSeqUsed > 0) {
break;
}
}
// 所有batch的有效序列都为0时, 直接退出
if (constInfo.batchSize == 0) {
return;
}
// 0. 计算最后一个Tc块的起始位置
constInfo.bIdxOfLastTc = constInfo.batchSize - 1;
// 1. 计算head_dim的切分大小, 构建ConstInfo的其他信息
SetBaseSize(); // 设置基本块大小
CalcSplitCoreInfo();
// 2. 计算循环次数
loopTimes = GetLoopTimes();
// 3. 初始化workspace
InitWorkspace(workspace);
// 4. 初始化block层
if ASCEND_IS_AIC {
#if __CCE_AICORE__ == 310
blockCube_.InitParams(constInfo, tools_);
#else
blockCube_.InitParams(constInfo, tools_);
#endif
blockCube_.Init(x, wKv, wGate, stateCache, ape, normWeight, ropeSin, ropeCos,
stateBlockTable, cuSeqlens, seqUsed, startPos, cmpKvOut);
blockCube_.InitBuffers(pipe_);
#if __CCE_AICORE__ == 310
blockCube_.InitGlobalBuffers(mm1KvResGm, mm1ScoreResGm);
#else
blockCube_.InitGlobalBuffers(mm1KvResGm, mm1ScoreResGm);
#endif
} else {
blockVec_.InitParams(constInfo, tools_);
blockVec_.Init(x, wKv, wGate, stateCache, ape, normWeight, ropeSin, ropeCos, stateBlockTable,
cuSeqlens, seqUsed, startPos, cmpKvOut);
blockVec_.InitBuffers(pipe_);
#if __CCE_AICORE__ == 310
blockVec_.InitVec1GlobalTensor(Vec1InputKvGm, Vec1InputScoreGm, vec1KvCacheGm, vec1ScoreCacheGm, vec1ResGm, vec2InputGm);
#else
blockVec_.InitVec1GlobalTensor(Vec1InputKvGm, Vec1InputScoreGm, vec1KvCacheGm, vec1ScoreCacheGm, vec1ResGm, vec2InputGm);
#endif
}
}
template <typename COMP>
__aicore__ inline void CompressorKernelPerf<COMP>::InitTilingData() {
constInfo.cmpRatio = tilingData_->baseParams.cmpRatio;
constInfo.batchSize = tilingData_->baseParams.batchSize;
constInfo.mBaseSize = tilingData_->innerSplitParams.mBaseSize;
constInfo.headDim = tilingData_->baseParams.headDim;
constInfo.hSize = tilingData_->baseParams.hiddenSize;
constInfo.sSize = tilingData_->baseParams.seqSize;
constInfo.ropeHeadDim = tilingData_->baseParams.ropeHeadDim;
constInfo.normEps = tilingData_->baseParams.normEps;
constInfo.reciprocalD = tilingData_->baseParams.reciprocalD;
constInfo.usedCoreNum = tilingData_->baseParams.usedCoreNum;
constInfo.blockNum = tilingData_->pageAttentionParams.blockNum;
constInfo.blockSize = tilingData_->pageAttentionParams.blockSize;
constInfo.maxBlockNumPerBatch = tilingData_->pageAttentionParams.maxBlockNumPerBatch;
constInfo.stateCacheStrideDim0 = tilingData_->baseParams.stateCacheStrideDim0;
constInfo.nSize = tilingData_->baseParams.nSize;
constInfo.vec1TailCacheSize = tilingData_->workspaceParams.vec1TailCacheSize;
constInfo.dbWorkspaceRatio = tilingData_->workspaceParams.dbWorkspaceRatio;
}
template <typename COMP>
__aicore__ inline void CompressorKernelPerf<COMP>::SetBaseSize()
{
uint32_t mSize = 0;
uint32_t minMBaseSize = 0;
bool sameSeqUsed = true;
uint32_t firstBatchSeqUsed = tools_.GetSeqLength(0);
for (uint32_t i = 0; i < constInfo.batchSize; i++) {
uint32_t bSeqUsed = tools_.GetSeqLength(i);
uint32_t bStartPos = tools_.GetStartPos(i);
// 获取m大小
mSize += bSeqUsed;
// 获取是否等长
if (sameSeqUsed && (bSeqUsed != firstBatchSeqUsed)) {
sameSeqUsed = false;
}
// 获取m轴最小切分大小
if (minMBaseSize != constInfo.cmpRatio) {
uint32_t startCmpIdx = bStartPos / constInfo.cmpRatio;
uint32_t endCmpIdx = (bStartPos + bSeqUsed) / constInfo.cmpRatio;
if (startCmpIdx == endCmpIdx) {
if (bSeqUsed > minMBaseSize) {
minMBaseSize = bSeqUsed;
}
} else if (startCmpIdx + 1 == endCmpIdx) {
uint32_t startCmpValidSeqCnt = constInfo.cmpRatio - (bStartPos % constInfo.cmpRatio);
uint32_t endCmpValidSeqCnt = (bStartPos + bSeqUsed) % constInfo.cmpRatio;
if (startCmpValidSeqCnt > minMBaseSize) {
minMBaseSize = startCmpValidSeqCnt;
}
if (endCmpValidSeqCnt > minMBaseSize) {
minMBaseSize = endCmpValidSeqCnt;
}
} else {
minMBaseSize = constInfo.cmpRatio;
}
}
}
uint32_t aiCoreNum = constInfo.usedCoreNum;
constInfo.dBaseSize = 64;
uint32_t dBaseBlockNum = constInfo.headDim / constInfo.dBaseSize;
if (sameSeqUsed && mSize <= (constInfo.mBaseSize * (aiCoreNum / dBaseBlockNum))) {
if constexpr (COMP::coff == COFF::OVERLAP) {
if (constInfo.headDim == 128) {
dBaseBlockNum = 8;
} else if (constInfo.headDim == 512) {
dBaseBlockNum = 16;
}
} else {
if (constInfo.headDim == 128) {
dBaseBlockNum = 8;
} else if (constInfo.headDim == 512) {
dBaseBlockNum = 16;
}
}
// 核数足够时, 修改才生效
if (aiCoreNum >= dBaseBlockNum) {
constInfo.dBaseSize = constInfo.headDim / dBaseBlockNum;
// 开启全核
uint32_t coreGroupNum = aiCoreNum / dBaseBlockNum;
uint32_t newMBaseSize = (constInfo.batchSize + coreGroupNum - 1) / coreGroupNum * firstBatchSeqUsed;
if (newMBaseSize > minMBaseSize && newMBaseSize < constInfo.mBaseSize) {
constInfo.mBaseSize = newMBaseSize;
}
}
}
}
template <typename COMP>
__aicore__ inline void CompressorKernelPerf<COMP>::SkipInvalidBatch(BatchInfo &batchInfo)
{
for (; batchInfo.bIdx < constInfo.batchSize; ++batchInfo.bIdx) {
batchInfo.seqCnt = tools_.GetSeqLength(batchInfo.bIdx);
if (batchInfo.seqCnt > 0) {
break;
}
}
batchInfo.remSeqCnt = batchInfo.seqCnt;
if (tools_.isExistSeqUsed_) {
batchInfo.seqUsedCnt = tools_.GetSeqUsed(batchInfo.bIdx);
} else {
batchInfo.seqUsedCnt = batchInfo.seqCnt;
}
if (batchInfo.bIdx < constInfo.batchSize) {
batchInfo.bStartPos = tools_.GetStartPos(batchInfo.bIdx);
batchInfo.sIdx = 0;
batchInfo.headHolderSeq = batchInfo.bStartPos & (constInfo.cmpRatio - 1);
batchInfo.tcNum = (batchInfo.bStartPos + batchInfo.seqCnt + constInfo.cmpRatio - 1) / constInfo.cmpRatio - batchInfo.bStartPos / constInfo.cmpRatio;
batchInfo.compressedTcNum = (batchInfo.bStartPos + batchInfo.seqUsedCnt) / constInfo.cmpRatio - batchInfo.bStartPos / constInfo.cmpRatio;
}
}
template <typename COMP>
__aicore__ inline void CompressorKernelPerf<COMP>::UpdateCurGroup(BasicBlockInfo &basicBlockInfo,
BatchInfo batchInfo, uint32_t &curGroupQuota, uint32_t curDealSeq)
{
// 更新当前组的信息
if (curGroupQuota == 0 && !isFirstUpdateCurGroup) {
return;
}
isFirstUpdateCurGroup = false;
basicBlockInfo.bIdx = batchInfo.bIdx;
uint32_t curGroupDealSeq = curGroupQuota < curDealSeq ? curGroupQuota : curDealSeq;
basicBlockInfo.sIdx = batchInfo.sIdx + curGroupDealSeq;
basicBlockInfo.dealSeqCnt += curGroupDealSeq;
curGroupQuota -= curGroupDealSeq;
// 结尾需要跳batch,需要考虑在当前组起始为末尾,或者当前组起始大于整个M轴
if ((curGroupQuota == 0 || basicBlockInfo.bIdx == constInfo.batchSize - 1) && basicBlockInfo.sIdx == batchInfo.seqCnt) {
basicBlockInfo.sIdx = 0;
for (basicBlockInfo.bIdx++; basicBlockInfo.bIdx < constInfo.batchSize; ++basicBlockInfo.bIdx) {
uint32_t seqCnt = tools_.GetSeqLength(basicBlockInfo.bIdx);
if (seqCnt > 0) {
break;
}
}
}
}
template <typename COMP>
__aicore__ inline BasicBlockInfo CompressorKernelPerf<COMP>::SkipOneLoop(BatchInfo &batchInfo)
{
BasicBlockInfo basicBlockInfo{};
isFirstUpdateCurGroup = true;
uint32_t curGroupQuota = constInfo.mBaseSize * constInfo.curGroupIdx; // m轴当前组起始
bool curGroupStartFlag = false;
uint32_t quota = constInfo.coreGroupNum * constInfo.mBaseSize;
for (; batchInfo.bIdx < constInfo.batchSize;) {
uint32_t curDealSeq = 0;
uint32_t curDealTcNum = 0;
uint32_t curDealCompressedTcNum = 0;
// 无法处理完当前整个batch
if (quota < batchInfo.remSeqCnt) {
// 向下对齐r,
if (quota > constInfo.cmpRatio - batchInfo.headHolderSeq) {
uint32_t delta = (batchInfo.bStartPos + batchInfo.sIdx + quota) & (constInfo.cmpRatio - 1); // 超出对齐的部分
curDealSeq = quota - delta;
quota -= curDealSeq;
curDealTcNum = (curDealSeq + constInfo.cmpRatio - 1) / constInfo.cmpRatio;
curDealCompressedTcNum = min(curDealTcNum, batchInfo.compressedTcNum);
// 更新当前组所需信息
UpdateCurGroup(basicBlockInfo, batchInfo, curGroupQuota, curDealSeq);
// 更新batch信息
batchInfo.remSeqCnt = batchInfo.remSeqCnt - curDealSeq;
batchInfo.sIdx = batchInfo.sIdx + curDealSeq;
batchInfo.compressedTcNum -= curDealCompressedTcNum;
batchInfo.tcNum -= curDealTcNum;
// 更新loop信息
basicBlockInfo.dealTcNum += curDealTcNum;
basicBlockInfo.compressedTcNum += curDealCompressedTcNum;
}
break;
} else {
// 处理整个batch
quota -= batchInfo.remSeqCnt;
curDealSeq = batchInfo.remSeqCnt;
curDealTcNum = batchInfo.tcNum;
// 更新当前组所需信息
UpdateCurGroup(basicBlockInfo, batchInfo, curGroupQuota, curDealSeq);
// 更新batch和loop信息
batchInfo.remSeqCnt = 0;
basicBlockInfo.dealTcNum += batchInfo.tcNum;
basicBlockInfo.compressedTcNum += batchInfo.compressedTcNum;
batchInfo.bIdx++;
SkipInvalidBatch(batchInfo);
}
}
uint32_t totalDataSize = constInfo.coreGroupNum * constInfo.mBaseSize - quota;
// 2. 当前组的起始偏移
uint32_t currentGroupStart = constInfo.curGroupIdx * constInfo.mBaseSize;
// 3. 安全判断
if (currentGroupStart >= totalDataSize) {
// 超出尾块
basicBlockInfo.dealSeqCnt = 0;
} else {
// 还在有效范围内,计算剩余量
uint32_t remaining = totalDataSize - currentGroupStart;
basicBlockInfo.dealSeqCnt = (remaining < constInfo.mBaseSize) ? remaining : constInfo.mBaseSize;
}
return basicBlockInfo;
}
template <typename COMP>
__aicore__ inline uint32_t CompressorKernelPerf<COMP>::GetLoopTimes()
{
// 计算主循环次数
uint32_t loopTimes = 0;
BatchInfo batchInfo{};
SkipInvalidBatch(batchInfo);
for (;batchInfo.bIdx < constInfo.batchSize; ++loopTimes) {
SkipOneLoop(batchInfo);
}
return loopTimes;
}
template <typename COMP>
__aicore__ inline void CompressorKernelPerf<COMP>::CalcSplitCoreInfo()
{
// D方向的基本块数量
constInfo.dBasicBlockNum = constInfo.headDim / constInfo.dBaseSize;
// 核的组数
constInfo.coreGroupNum = constInfo.usedCoreNum / constInfo.dBasicBlockNum;
// 每个核处理的d方向的索引
constInfo.dIdx = (constInfo.aiCoreIdx % constInfo.dBasicBlockNum) * constInfo.dBaseSize;
// 当前组id
constInfo.curGroupIdx = constInfo.aiCoreIdx / constInfo.dBasicBlockNum;
constInfo.mm1ResSize = constInfo.mBaseSize * constInfo.headDim * constInfo.coreGroupNum;
uint32_t coff = (uint32_t)COMP::coff;
constInfo.mm1KvResSize = constInfo.mBaseSize * constInfo.headDim * coff;
constInfo.mm1ScoreResSize = constInfo.mBaseSize * constInfo.headDim * coff;
constInfo.vec1ResSize = constInfo.mBaseSize * constInfo.headDim * constInfo.nSize;
constInfo.dbSize = constInfo.coreGroupNum * constInfo.mm1KvResSize;
}
template <typename COMP>
__aicore__ inline void CompressorKernelPerf<COMP>::InitWorkspace(__gm__ uint8_t *workspace) {
uint64_t offset = 0;
uint64_t mm1KvResStartOffset = offset;
// mm1KvResGm
mm1KvResGm.SetGlobalBuffer(
(__gm__ MM1_OUT_T *)(workspace + offset +
constInfo.curGroupIdx * constInfo.mm1KvResSize * sizeof(MM1_OUT_T)));
offset += constInfo.dbWorkspaceRatio * constInfo.coreGroupNum * constInfo.mm1KvResSize * sizeof(MM1_OUT_T);
uint64_t mm1ScoreResStartOffset = offset;
// mm1ScoreResGm
mm1ScoreResGm.SetGlobalBuffer(
(__gm__ MM1_OUT_T *)(workspace + offset +
constInfo.curGroupIdx * constInfo.mm1ScoreResSize * sizeof(MM1_OUT_T)));
offset += constInfo.dbWorkspaceRatio * constInfo.coreGroupNum * constInfo.mm1ScoreResSize * sizeof(MM1_OUT_T);
Vec1InputKvGm.SetGlobalBuffer(
(__gm__ MM1_OUT_T *)(workspace + mm1KvResStartOffset));
Vec1InputScoreGm.SetGlobalBuffer(
(__gm__ MM1_OUT_T *)(workspace + mm1ScoreResStartOffset));
vec1KvCacheGm.SetGlobalBuffer((__gm__ MM1_OUT_T *)(workspace + offset));
offset += constInfo.dbWorkspaceRatio * constInfo.vec1TailCacheSize * sizeof(MM1_OUT_T);
vec1ScoreCacheGm.SetGlobalBuffer((__gm__ MM1_OUT_T *)(workspace + offset));
offset += constInfo.dbWorkspaceRatio * constInfo.vec1TailCacheSize * sizeof(MM1_OUT_T);
uint64_t beforeVecOffset = offset;
// vec1Res
vec1ResGm.SetGlobalBuffer(
(__gm__ VEC1_OUT_T *)(workspace + offset));
offset += constInfo.dbWorkspaceRatio * constInfo.coreGroupNum * constInfo.vec1ResSize * sizeof(VEC1_OUT_T);
// vec2Input
vec2InputGm.SetGlobalBuffer(
(__gm__ VEC1_OUT_T *)(workspace + beforeVecOffset));
}
template <typename COMP>
__aicore__ inline void CompressorKernelPerf<COMP>::ComputeMm1(const RunInfo &info, bool isNeedExcute) {
CrossCoreWaitFlag<SYNC_MODE2, PIPE_FIX>(SYNC_V1_C1_FLAG + info.cubeDbIdx);
if (isNeedExcute) {
blockCube_.ComputeMm1(info);
}
CrossCoreSetFlag<SYNC_MODE0, PIPE_FIX>(SYNC_C1_FLAG);
CrossCoreWaitFlag<SYNC_MODE0, PIPE_FIX>(SYNC_C1_FLAG);
CrossCoreSetFlag<SYNC_MODE2, PIPE_FIX>(SYNC_C1_V1_FLAG + info.cubeDbIdx);
}
template <typename COMP>
__aicore__ inline void CompressorKernelPerf<COMP>::ComputeVec1(const Vec1RunInfo &info) {
CrossCoreWaitFlag<SYNC_MODE2, PIPE_MTE2>(SYNC_C1_V1_FLAG + info.c1v1DbIdx);
CrossCoreWaitFlag<SYNC_MODE0, PIPE_MTE2>(SYNC_V1_FLAG2 + info.c1v1DbIdx);
blockVec_.ComputeVec1(info);
CrossCoreSetFlag<SYNC_MODE0, PIPE_MTE2>(SYNC_V1_FLAG);
CrossCoreWaitFlag<SYNC_MODE0, PIPE_MTE2>(SYNC_V1_FLAG);
CrossCoreSetFlag<SYNC_MODE2, PIPE_MTE2>(SYNC_V1_C1_FLAG + info.c1v1DbIdx);
CrossCoreSetFlag<SYNC_MODE0, PIPE_MTE3>(SYNC_V1_FLAG2 + (info.c1v1DbIdx + 1) % constInfo.dbWorkspaceRatio);
}
template <typename COMP>
__aicore__ inline void CompressorKernelPerf<COMP>::ComputeVec2(const Vec2RunInfo &info) {
blockVec_.ComputeVec2(info);
}
template <typename COMP>
__aicore__ inline void CompressorKernelPerf<COMP>::AllocEventID()
{
if ASCEND_IS_AIC {
blockCube_.AllocEventID(pipe_);
} else {
blockVec_.AllocEventID();
for (int i = 0; i < constInfo.dbWorkspaceRatio; ++i) {
CrossCoreSetFlag<SYNC_MODE2, PIPE_MTE2>(SYNC_V1_C1_FLAG + i);
}
CrossCoreSetFlag<SYNC_MODE0, PIPE_MTE3>(SYNC_V1_FLAG2);
}
}
template <typename COMP>
__aicore__ inline void CompressorKernelPerf<COMP>::FreeEventID()
{
if ASCEND_IS_AIC {
for (int i = 0; i < constInfo.dbWorkspaceRatio; ++i) {
CrossCoreWaitFlag<SYNC_MODE2, PIPE_FIX>(SYNC_V1_C1_FLAG + i);
}
blockCube_.FreeEventID(pipe_);
} else {
CrossCoreWaitFlag<SYNC_MODE0, PIPE_MTE2>(SYNC_V1_FLAG2 + loopTimes % constInfo.dbWorkspaceRatio);
blockVec_.FreeEventID();
}
}
template <typename COMP>
__aicore__ inline bool CompressorKernelPerf<COMP>::IsNeedExcuteC1(RunInfo info)
{
// B超出范围则cube不执行
return info.bStart < constInfo.batchSize;
}
template <typename COMP>
__aicore__ inline void CompressorKernelPerf<COMP>::CalcC1V1Params(RunInfo &info, Vec1RunInfo &vec1Info, BatchInfo &batchInfo, uint32_t loopIdx)
{
vec1Info.bStart = batchInfo.bIdx;
vec1Info.sStart = batchInfo.sIdx;
vec1Info.resetResFlag = (loopIdx & (constInfo.nSize - 1)) == 0;
vec1Info.c1v1DbIdx = (vec1Loop++ & (constInfo.dbWorkspaceRatio - 1));
vec1Info.v1v2DbIdx = (vec2Loop & (constInfo.dbWorkspaceRatio - 1));
BasicBlockInfo basicBlockInfo = SkipOneLoop(batchInfo);
info.cubeDbIdx = (cubeLoop++ & (constInfo.dbWorkspaceRatio - 1));
info.dealSeqCnt = basicBlockInfo.dealSeqCnt;
info.dealTcNum = basicBlockInfo.dealTcNum;
info.bStart = basicBlockInfo.bIdx;
info.sStart = basicBlockInfo.sIdx;
vec1Info.dealTcNum = basicBlockInfo.dealTcNum;
vec1Info.dealScSize = basicBlockInfo.compressedTcNum;
allCompressedTcNum_ += basicBlockInfo.compressedTcNum;
}
template <typename COMP>
__aicore__ inline bool CompressorKernelPerf<COMP>::IsNeedExcuteV2(Vec2RunInfo &vec2Info)
{
return (vec2Info.dealScSize > 0);
}
template <typename COMP>
__aicore__ inline bool CompressorKernelPerf<COMP>::IsNeedSyncAll(uint32_t curBasicBlockIdx)
{
if (allCompressedTcNum_ == 0) {
return false;
}
uint32_t cnt = curBasicBlockIdx + 1;
if ((cnt == loopTimes) || (cnt % constInfo.nSize == 0)) {
return true;
}
return false;
}
template <typename COMP>
__aicore__ inline void CompressorKernelPerf<COMP>::UpdateVec2Info(
Vec2RunInfo &vec2Info, uint32_t curBasicBlockIdx, const Vec1RunInfo &info)
{
// nSize轮起始先重置v2Info信息
if (curBasicBlockIdx % constInfo.nSize == 0) {
vec2Info.v2DbIdx = (vec2Loop & (constInfo.dbWorkspaceRatio - 1));
vec2Info.bStart = info.bStart;
vec2Info.sStart = info.sStart;
// 将sStart转成bCompressedId
uint32_t startPos = tools_.GetStartPos(info.bStart);
if (tools_.isExistSeqUsed_) {
uint32_t seqUsed = tools_.GetSeqUsed(info.bStart);
if (vec2Info.sStart >= seqUsed) {
vec2Info.bStart++;
vec2Info.sStart = 0;
}
}
vec2Info.bCompressedId = (startPos + vec2Info.sStart) / constInfo.cmpRatio - startPos / constInfo.cmpRatio;
vec2Info.dealScSize = 0;
} else if ((curBasicBlockIdx + 1) % constInfo.nSize == 0) {
vec2Loop++;
}
vec2Info.dealScSize += info.dealScSize;
vec2Info.compressedId += info.dealScSize;
}
template <typename COMP>
__aicore__ inline void CompressorKernelPerf<COMP>::Process()
{
// 所有batch的有效序列都为0时, 直接退出
if (constInfo.batchSize == 0) {
return;
}
AllocEventID();
BatchInfo batchInfo{};
RunInfo extraInfo[1];
Vec1RunInfo vec1Info{};
Vec2RunInfo vec2Info{};
SkipInvalidBatch(batchInfo);
for (uint32_t i = 0; i < loopTimes; ++i) {
RunInfo &extraInfo0 = extraInfo[0];
CalcC1V1Params(extraInfo0, vec1Info, batchInfo, i);
bool isNeedExcuteC1 = IsNeedExcuteC1(extraInfo0);
if ASCEND_IS_AIC {
ComputeMm1(extraInfo0, isNeedExcuteC1);
} else {
ComputeVec1(vec1Info);
UpdateVec2Info(vec2Info, i, vec1Info);
if (IsNeedSyncAll(i)) {
SyncAll();
if (IsNeedExcuteV2(vec2Info)) {
ComputeVec2(vec2Info);
}
}
}
}
FreeEventID();
}
} // namespace Compressor
#endif // COMPRESSOR_KERNEL_PERF_H

View File

@@ -0,0 +1,56 @@
/**
 * Copyright (c) 2026 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 COMPRESSOR_template_tiling_key.h
* \brief
*/
#ifndef COMPRESSOR_TEMPLATE_TILING_KEY_H
#define COMPRESSOR_TEMPLATE_TILING_KEY_H
#include "ascendc/host_api/tiling/template_argument.h"
#define ASCENDC_TPL_1_BW 1 // 每个参数占用1个bit位
#define ASCENDC_TPL_2_BW 2 // 每个参数占用2个bit位
#define ASCENDC_TPL_4_BW 4 // 每个参数占用4个bit位
// 可表示的tilingkey范围为64bit,注意不可超过限制
ASCENDC_TPL_ARGS_DECL(compressor, // 算子唯一标识,与opType保持一致
// 可能需要切分之后的headdim
// bit:0 LAYOUT 0:BSH 1:TH
ASCENDC_TPL_UINT_DECL(X_LAYOUT, ASCENDC_TPL_1_BW, ASCENDC_TPL_UI_LIST, 0, 1),
// bit:1-4 x的dtype 0:BF16 1:FP16
ASCENDC_TPL_UINT_DECL(X_DTYPE, ASCENDC_TPL_4_BW, ASCENDC_TPL_UI_LIST, 0, 1),
// bit:5-6 coff 1:无需overlap 2:需要overlap
ASCENDC_TPL_UINT_DECL(COFF, ASCENDC_TPL_2_BW, ASCENDC_TPL_UI_LIST, 1, 2),
// bit:7-8 rotary_mode 1:half 2:interleave
ASCENDC_TPL_UINT_DECL(ROTARY_MODE, ASCENDC_TPL_2_BW, ASCENDC_TPL_UI_LIST, 1, 2),
// bit:9-10 cache_mode 1:CONTINUOUS 2:cycle
ASCENDC_TPL_UINT_DECL(CACHE_MODE, ASCENDC_TPL_2_BW, ASCENDC_TPL_UI_LIST, 1, 2),
// bit:11-12 template_id 0:empty_tensor 1:normal 2:full load
ASCENDC_TPL_UINT_DECL(TEMPLATE_ID, ASCENDC_TPL_2_BW, ASCENDC_TPL_UI_LIST, 0, 1, 2),
// bit:13 rope dtype 0:same as x 1:fp32
ASCENDC_TPL_UINT_DECL(ROPE_DTYPE, ASCENDC_TPL_1_BW, ASCENDC_TPL_UI_LIST, 0, 1),
);
ASCENDC_TPL_SEL(
ASCENDC_TPL_ARGS_SEL(ASCENDC_TPL_UINT_SEL(X_LAYOUT, ASCENDC_TPL_UI_LIST, 0, 1),
ASCENDC_TPL_UINT_SEL(X_DTYPE, ASCENDC_TPL_UI_LIST, 0, 1),
ASCENDC_TPL_UINT_SEL(COFF, ASCENDC_TPL_UI_LIST, 1, 2),
ASCENDC_TPL_UINT_SEL(ROTARY_MODE, ASCENDC_TPL_UI_LIST, 1, 2),
ASCENDC_TPL_UINT_SEL(CACHE_MODE, ASCENDC_TPL_UI_LIST, 1, 2),
ASCENDC_TPL_UINT_SEL(TEMPLATE_ID, ASCENDC_TPL_UI_LIST, 0, 1, 2),
ASCENDC_TPL_UINT_SEL(ROPE_DTYPE, ASCENDC_TPL_UI_LIST, 0, 1),
ASCENDC_TPL_TILING_STRUCT_SEL(optiling::CompressorTilingData)),
);
#endif // COMPRESSOR_TEMPLATE_TILING_KEY_H

View File

@@ -0,0 +1,69 @@
/**
 * Copyright (c) 2026 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 COMPRESSOR_tiling_datay.h
* \brief
*/
#ifndef COMPRESSOR_TILING_DATA_H
#define COMPRESSOR_TILING_DATA_H
#include <cstdint>
#include "kernel_tiling/kernel_tiling.h"
const uint32_t CMP_MAX_AIC_CORE_NUM = 26; // 25 + 1 保证数组8字节对齐
namespace optiling {
// 1. 基础参数结构体
struct CompressorBaseParams {
uint32_t batchSize = 0; // bastch size(批大小)
uint32_t seqSize = 0; // sequence size(kvs大小)
uint32_t hiddenSize = 0; // hidden size(隐藏层大小)
uint32_t tokenSize = 0; // token size = batchSize * seqSize(token总数:批大小x序列1长度)
uint32_t headDim = 0; // head size of kv
uint32_t ropeHeadDim = 64; // dim size per rope head 64(单个带RoPE头的维度)
uint32_t csSize = 0; // Compress sequence len
uint32_t cmpRatio = 4; // Compress ratio
uint32_t cgSize = 0; // Compress group size
float normEps = 1e-6; // RMSNorm eps
float reciprocalD = 0; // 1分之D
uint32_t usedCoreNum = 0; // 使用核数
uint32_t nSize = 0; // 控制v2积攒的轮数
uint64_t stateCacheStrideDim0 = 0; // stateCache第0维的stride
};
struct CompressorPageAttentionParams {
uint32_t blockNum = 0;
uint32_t blockSize = 1;
uint32_t maxBlockNumPerBatch = 1;
};
struct CompressorInnerSplitParams {
uint32_t mBaseSize;
uint32_t dBaseSize;
};
struct CompressorWorkspaceParams {
uint32_t mm1KvResSize;
uint32_t mm1ScoreResSize;
uint32_t vec1ResSize;
uint32_t vec1TailCacheSize;
uint32_t dbWorkspaceRatio = 1;
};
struct CompressorTilingData {
CompressorBaseParams baseParams;
CompressorPageAttentionParams pageAttentionParams;
CompressorInnerSplitParams innerSplitParams;
CompressorWorkspaceParams workspaceParams;
};
} // optiling
#endif // COMPRESSOR_TILING_DATA_H

View File

@@ -0,0 +1,761 @@
/**
 * Copyright (c) 2026 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 compressor_tools.h
* \brief 放算子都需要、与算子联系紧密、但是又不方便单独独立出来的公共工具
*/
#ifndef COMPRESSOR_TOOLS_H
#define COMPRESSOR_TOOLS_H
#include "compressor_comm.h"
using namespace AscendC;
namespace Compressor {
struct ToolsParams {
uint32_t seqSize = 0U;
uint32_t cmpRatio = 0U;
};
template <typename COMP>
class CompressorTools {
public:
__aicore__ inline CompressorTools()
{
}
__aicore__ inline void Init(__gm__ uint8_t *cuSeqlens, __gm__ uint8_t *seqUsed, __gm__ uint8_t *startPos);
__aicore__ inline uint32_t GetSeqUsed(uint32_t bIdx);
__aicore__ inline uint32_t GetStartPos(uint32_t bIdx);
__aicore__ inline uint32_t GetSeqLength(uint32_t bIdx);
__aicore__ inline uint32_t GetTIdxByBatch(uint32_t bIdx);
public:
ToolsParams toolParams_{};
bool isExistSeqUsed_ = false;
private:
bool isExistStartPos_ = false;
GlobalTensor<int32_t> cuSeqlensGm_;
GlobalTensor<int32_t> sequsedGm_;
GlobalTensor<int32_t> startPosGm_;
};
template <typename COMP>
__aicore__ inline void CompressorTools<COMP>::Init(__gm__ uint8_t *startPos, __gm__ uint8_t *seqUsed,
__gm__ uint8_t *cuSeqlens)
{
isExistStartPos_ = (startPos != nullptr);
if (isExistStartPos_) {
startPosGm_.SetGlobalBuffer((__gm__ int32_t *)startPos);
}
isExistSeqUsed_ = (seqUsed != nullptr);
if (isExistSeqUsed_) {
sequsedGm_.SetGlobalBuffer((__gm__ int32_t *)seqUsed);
}
if constexpr (COMP::xLayout == X_LAYOUT::TH) {
cuSeqlensGm_.SetGlobalBuffer((__gm__ int32_t *)cuSeqlens);
}
}
template <typename COMP>
__aicore__ inline uint32_t CompressorTools<COMP>::GetSeqUsed(uint32_t bIdx)
{
if (isExistSeqUsed_) {
return (uint32_t)sequsedGm_.GetValue(bIdx);
} else {
if constexpr (COMP::xLayout == X_LAYOUT::TH) {
return (uint32_t)(cuSeqlensGm_.GetValue(bIdx + 1) - cuSeqlensGm_.GetValue(bIdx));
} else {
return toolParams_.seqSize;
}
}
}
template <typename COMP>
__aicore__ inline uint32_t CompressorTools<COMP>::GetStartPos(uint32_t bIdx)
{
if (isExistStartPos_) {
return (uint32_t)startPosGm_.GetValue(bIdx);
} else {
return 0;
}
}
template <typename COMP>
__aicore__ inline uint32_t CompressorTools<COMP>::GetSeqLength(uint32_t bIdx)
{
if constexpr (COMP::xLayout == X_LAYOUT::TH) {
return cuSeqlensGm_.GetValue(bIdx + 1) - cuSeqlensGm_.GetValue(bIdx);
} else {
return toolParams_.seqSize;
}
}
template <typename COMP>
__aicore__ inline uint32_t CompressorTools<COMP>::GetTIdxByBatch(uint32_t bIdx)
{
if constexpr (COMP::xLayout == X_LAYOUT::TH) {
return (uint32_t)(cuSeqlensGm_.GetValue(bIdx));
} else {
return toolParams_.seqSize * bIdx;
}
}
// iterator
struct SliceInfo {
__aicore__ inline SliceInfo(){};
__aicore__ inline SliceInfo(uint32_t bIdx, uint32_t sIdx) : bIdx(bIdx), sIdx(sIdx){};
uint32_t bIdx = 0U;
uint32_t sIdx = 0U;
uint32_t bSeqUsed = 0U;
uint32_t bStartPos = 0U;
uint32_t headHolderSeqCnt = 0U;
uint32_t validSeqCnt = 0U;
uint32_t tailHolderSeqCnt = 0U;
uint32_t dealSeqCnt = 0;
uint32_t dealTcSize = 0U;
uint32_t compressTcSize = 0U;
};
template <typename COMP>
class CompressorSliceIterator {
public:
__aicore__ inline CompressorSliceIterator(CompressorTools<COMP> &tools) : tools_(tools)
{
}
__aicore__ inline void Reset(uint32_t bIdx, uint32_t sIdx);
__aicore__ inline void SetMaxBatchSize(uint32_t batch_size);
__aicore__ inline void SetMaxDealSeqCnt(uint32_t maxDealSeqCnt);
__aicore__ inline bool IsEnd();
__aicore__ inline void IteratorSlice();
__aicore__ inline SliceInfo &GetSlice();
__aicore__ inline SliceInfo &GetSliceByCmp();
bool isFirst_ = true;
SliceInfo sliceInfo_{};
private:
CompressorTools<COMP> &tools_;
// iterator
uint32_t maxDealSeqCnt_ = 0;
uint32_t batch_size_ = 0;
};
template <typename COMP>
__aicore__ inline void CompressorSliceIterator<COMP>::Reset(uint32_t bIdx, uint32_t sIdx)
{
sliceInfo_.bIdx = bIdx;
sliceInfo_.sIdx = sIdx;
isFirst_ = true;
}
template <typename COMP>
__aicore__ inline void CompressorSliceIterator<COMP>::SetMaxBatchSize(uint32_t batch_size)
{
this->batch_size_ = batch_size;
}
template <typename COMP>
__aicore__ inline void CompressorSliceIterator<COMP>::SetMaxDealSeqCnt(uint32_t maxDealSeqCnt)
{
this->maxDealSeqCnt_ = maxDealSeqCnt;
}
template <typename COMP>
__aicore__ inline bool CompressorSliceIterator<COMP>::IsEnd()
{
return (sliceInfo_.bIdx >= batch_size_) || (maxDealSeqCnt_ == 0);
}
template <typename COMP>
__aicore__ inline void CompressorSliceIterator<COMP>::IteratorSlice()
{
bool isUpdateBatchInfo = false;
if (!isFirst_) {
// 更新剩余未处理的行数
maxDealSeqCnt_ -= sliceInfo_.dealSeqCnt;
// 更新sIdx和bIdx、以及与bIdx相关的bStartPos和bSeqUsed
sliceInfo_.sIdx += sliceInfo_.validSeqCnt;
if (sliceInfo_.sIdx == sliceInfo_.bSeqUsed) {
sliceInfo_.sIdx = 0;
sliceInfo_.bIdx++;
isUpdateBatchInfo = true;
}
} else {
isUpdateBatchInfo = true;
isFirst_ = false;
}
// 更新与bIdx相关的bStartPos和bSeqUsed
if (isUpdateBatchInfo) {
// SkipInvalidBatch
while (sliceInfo_.bIdx < batch_size_) {
sliceInfo_.bSeqUsed = tools_.GetSeqUsed(sliceInfo_.bIdx);
if (sliceInfo_.bSeqUsed > 0) {
break;
}
sliceInfo_.bIdx++;
}
if (sliceInfo_.bIdx < batch_size_) {
sliceInfo_.bStartPos = tools_.GetStartPos(sliceInfo_.bIdx);
}
}
}
template <typename COMP>
__aicore__ inline SliceInfo &CompressorSliceIterator<COMP>::GetSliceByCmp()
{
uint32_t cmpRatio = tools_.toolParams_.cmpRatio;
if (isFirst_) {
sliceInfo_.bSeqUsed = tools_.GetSeqUsed(sliceInfo_.bIdx);
sliceInfo_.bStartPos = tools_.GetStartPos(sliceInfo_.bIdx);
isFirst_ = false;
}
// 计算头部占位行数、有效数据行数、尾部占位行数
sliceInfo_.headHolderSeqCnt = (sliceInfo_.bStartPos + sliceInfo_.sIdx) % cmpRatio;
sliceInfo_.validSeqCnt = sliceInfo_.bSeqUsed - sliceInfo_.sIdx;
if (sliceInfo_.headHolderSeqCnt + sliceInfo_.validSeqCnt > maxDealSeqCnt_) {
sliceInfo_.validSeqCnt = maxDealSeqCnt_ - sliceInfo_.headHolderSeqCnt;
}
sliceInfo_.tailHolderSeqCnt =
cmpRatio - (sliceInfo_.bStartPos + sliceInfo_.sIdx + sliceInfo_.validSeqCnt) % cmpRatio;
if (sliceInfo_.tailHolderSeqCnt == cmpRatio) {
sliceInfo_.tailHolderSeqCnt = 0;
}
// 头和尾处理,否则需要处理的seq等于cmpRatio
if (sliceInfo_.validSeqCnt < cmpRatio) {
sliceInfo_.dealSeqCnt = sliceInfo_.validSeqCnt;
if (sliceInfo_.sIdx == 0) {
sliceInfo_.dealSeqCnt = cmpRatio - sliceInfo_.headHolderSeqCnt;
}
} else {
sliceInfo_.dealSeqCnt = cmpRatio;
}
sliceInfo_.validSeqCnt = sliceInfo_.dealSeqCnt;
// 计算本次可以处理的Tc个数
sliceInfo_.dealTcSize = (sliceInfo_.dealSeqCnt + cmpRatio - 1) / cmpRatio;
// 因为是一个batch的数据, 只有最后一个压缩块才可能不需要压缩, 此时sliceInfo_.tailHolderSeqCnt > 0
sliceInfo_.compressTcSize = sliceInfo_.dealTcSize;
if (sliceInfo_.tailHolderSeqCnt > 0) {
sliceInfo_.compressTcSize = sliceInfo_.dealTcSize - 1; // 最后一个压缩块不满时,其不需要压缩
}
return sliceInfo_;
}
template <typename COMP>
__aicore__ inline SliceInfo &CompressorSliceIterator<COMP>::GetSlice()
{
uint32_t cmpRatio = tools_.toolParams_.cmpRatio;
if (isFirst_) {
sliceInfo_.bSeqUsed = tools_.GetSeqUsed(sliceInfo_.bIdx);
sliceInfo_.bStartPos = tools_.GetStartPos(sliceInfo_.bIdx);
isFirst_ = false;
}
// 计算头部占位行数、有效数据行数、尾部占位行数
sliceInfo_.headHolderSeqCnt = (sliceInfo_.bStartPos + sliceInfo_.sIdx) % cmpRatio;
sliceInfo_.validSeqCnt = sliceInfo_.bSeqUsed - sliceInfo_.sIdx;
if (sliceInfo_.headHolderSeqCnt + sliceInfo_.validSeqCnt > maxDealSeqCnt_) {
sliceInfo_.validSeqCnt = maxDealSeqCnt_ - sliceInfo_.headHolderSeqCnt;
}
sliceInfo_.tailHolderSeqCnt =
cmpRatio - (sliceInfo_.bStartPos + sliceInfo_.sIdx + sliceInfo_.validSeqCnt) % cmpRatio;
if (sliceInfo_.tailHolderSeqCnt == cmpRatio) {
sliceInfo_.tailHolderSeqCnt = 0;
}
sliceInfo_.dealSeqCnt = sliceInfo_.headHolderSeqCnt + sliceInfo_.validSeqCnt + sliceInfo_.tailHolderSeqCnt;
// 计算本次可以处理的Tc个数
sliceInfo_.dealTcSize = sliceInfo_.dealSeqCnt / cmpRatio;
// 因为是一个batch的数据, 只有最后一个压缩块才可能不需要压缩, 此时sliceInfo_.tailHolderSeqCnt > 0
sliceInfo_.compressTcSize = sliceInfo_.dealTcSize;
if (sliceInfo_.tailHolderSeqCnt > 0) {
sliceInfo_.compressTcSize = sliceInfo_.dealTcSize - 1; // 最后一个压缩块不满时,其不需要压缩
}
return sliceInfo_;
}
struct SplitCoreSliceInfo : public SliceInfo {
__aicore__ inline SplitCoreSliceInfo(){};
__aicore__ inline SplitCoreSliceInfo(uint32_t bIdx, uint32_t sIdx) : SliceInfo(bIdx, sIdx){};
uint32_t preFirstSeqCnt = 0U; // 左边每次迭代基本块的第一个seqCnt大小
};
template <typename COMP>
class CompressorSplitCoreSliceIterator {
public:
__aicore__ inline CompressorSplitCoreSliceIterator(CompressorTools<COMP> &tools) : tools_(tools)
{
}
__aicore__ inline void Reset(uint32_t bIdx, uint32_t sIdx);
__aicore__ inline void SetMaxBatchSize(uint32_t batch_size);
__aicore__ inline void SetMaxDealSeqCnt(uint32_t maxDealSeqCnt);
__aicore__ inline bool IsEnd();
__aicore__ inline void IteratorSlice();
__aicore__ inline SplitCoreSliceInfo &GetSlice();
__aicore__ inline SplitCoreSliceInfo &GetSliceByCmp();
__aicore__ inline uint32_t GetBIdx();
__aicore__ inline SplitCoreSliceInfo &GetLeftNextCmpSeqCnt();
__aicore__ inline SplitCoreSliceInfo &GetRightNextCmpSeqCnt();
bool isFirst_ = true;
bool isLeftFirstBath = false;
bool isMaxDealSeqCntFirst = false;
SplitCoreSliceInfo sliceInfo_{};
private:
CompressorTools<COMP> &tools_;
// iterator
uint32_t maxDealSeqCnt_ = 0;
uint32_t batch_size_ = 0;
};
template <typename COMP>
__aicore__ inline void CompressorSplitCoreSliceIterator<COMP>::Reset(uint32_t bIdx, uint32_t sIdx)
{
sliceInfo_.bIdx = bIdx;
sliceInfo_.sIdx = sIdx;
isFirst_ = true;
}
template <typename COMP>
__aicore__ inline void CompressorSplitCoreSliceIterator<COMP>::SetMaxBatchSize(uint32_t batch_size)
{
this->batch_size_ = batch_size;
isMaxDealSeqCntFirst = true;
}
template <typename COMP>
__aicore__ inline void CompressorSplitCoreSliceIterator<COMP>::SetMaxDealSeqCnt(uint32_t maxDealSeqCnt)
{
this->maxDealSeqCnt_ = maxDealSeqCnt;
}
template <typename COMP>
__aicore__ inline bool CompressorSplitCoreSliceIterator<COMP>::IsEnd()
{
return (sliceInfo_.bIdx >= batch_size_) || (maxDealSeqCnt_ == 0);
}
template <typename COMP>
__aicore__ inline uint32_t CompressorSplitCoreSliceIterator<COMP>::GetBIdx()
{
return sliceInfo_.bIdx;
}
template <typename COMP>
__aicore__ inline void CompressorSplitCoreSliceIterator<COMP>::IteratorSlice()
{
bool isUpdateBatchInfo = false;
if (isMaxDealSeqCntFirst) {
isMaxDealSeqCntFirst = false;
}
if (!isFirst_) {
// 更新剩余未处理的行数
maxDealSeqCnt_ -= sliceInfo_.dealSeqCnt;
// 更新sIdx和bIdx、以及与bIdx相关的bStartPos和bSeqUsed
sliceInfo_.sIdx += sliceInfo_.validSeqCnt;
if (sliceInfo_.sIdx == sliceInfo_.bSeqUsed) {
sliceInfo_.sIdx = 0;
// 左边最后一块跳到b=0 s=0处理
if (isLeftFirstBath) {
isLeftFirstBath = false;
} else {
sliceInfo_.bIdx++;
}
isUpdateBatchInfo = true;
}
} else {
isUpdateBatchInfo = true;
isFirst_ = false;
}
// 更新与bIdx相关的bStartPos和bSeqUsed
if (isUpdateBatchInfo) {
// SkipInvalidBatch
while (sliceInfo_.bIdx < batch_size_) {
sliceInfo_.bSeqUsed = tools_.GetSeqUsed(sliceInfo_.bIdx);
if (sliceInfo_.bSeqUsed > 0) {
break;
}
sliceInfo_.bIdx++;
}
if (sliceInfo_.bIdx < batch_size_) {
sliceInfo_.bStartPos = tools_.GetStartPos(sliceInfo_.bIdx);
}
}
}
template <typename COMP>
__aicore__ inline SplitCoreSliceInfo &CompressorSplitCoreSliceIterator<COMP>::GetLeftNextCmpSeqCnt()
{
uint32_t cmpRatio = tools_.toolParams_.cmpRatio;
if (isFirst_) {
// 左边 T轴首次减去T轴最后一块
sliceInfo_.bSeqUsed = tools_.GetSeqUsed(batch_size_ - 1);
sliceInfo_.bStartPos = tools_.GetStartPos(batch_size_ - 1);
// 处理最后一块是中间整块或者尾块的情况
uint32_t lastSeqCnt = (sliceInfo_.bStartPos + sliceInfo_.bSeqUsed) % cmpRatio == 0 ?
cmpRatio :
(sliceInfo_.bStartPos + sliceInfo_.bSeqUsed) % cmpRatio;
// 处理最后一块是头块的情况
if (sliceInfo_.bSeqUsed < cmpRatio) {
lastSeqCnt = sliceInfo_.bSeqUsed;
}
sliceInfo_.sIdx = sliceInfo_.bSeqUsed - lastSeqCnt;
isLeftFirstBath = true;
isFirst_ = false;
}
// 计算头部占位行数、有效数据行数、尾部占位行数
sliceInfo_.headHolderSeqCnt = (sliceInfo_.bStartPos + sliceInfo_.sIdx) % cmpRatio;
sliceInfo_.validSeqCnt = sliceInfo_.bSeqUsed - sliceInfo_.sIdx;
if (sliceInfo_.headHolderSeqCnt + sliceInfo_.validSeqCnt > maxDealSeqCnt_) {
sliceInfo_.validSeqCnt = maxDealSeqCnt_ - sliceInfo_.headHolderSeqCnt;
}
sliceInfo_.tailHolderSeqCnt =
cmpRatio - (sliceInfo_.bStartPos + sliceInfo_.sIdx + sliceInfo_.validSeqCnt) % cmpRatio;
if (sliceInfo_.tailHolderSeqCnt == cmpRatio) {
sliceInfo_.tailHolderSeqCnt = 0;
}
// 头和尾处理,否则需要处理的seq等于cmpRatio
if (sliceInfo_.validSeqCnt < cmpRatio) {
sliceInfo_.dealSeqCnt = sliceInfo_.validSeqCnt;
if (sliceInfo_.sIdx == 0) {
sliceInfo_.dealSeqCnt = cmpRatio - sliceInfo_.headHolderSeqCnt;
}
} else {
sliceInfo_.dealSeqCnt = cmpRatio;
}
sliceInfo_.validSeqCnt = sliceInfo_.dealSeqCnt;
// 计算本次可以处理的Tc个数
sliceInfo_.dealTcSize = (sliceInfo_.dealSeqCnt + cmpRatio - 1) / cmpRatio;
// 因为是一个batch的数据, 只有最后一个压缩块才可能不需要压缩, 此时sliceInfo_.tailHolderSeqCnt > 0
sliceInfo_.compressTcSize = sliceInfo_.dealTcSize;
if (sliceInfo_.tailHolderSeqCnt > 0) {
sliceInfo_.compressTcSize = sliceInfo_.dealTcSize - 1; // 最后一个压缩块不满时,其不需要压缩
}
// 记录左边第一个块
if (isMaxDealSeqCntFirst) {
sliceInfo_.preFirstSeqCnt = sliceInfo_.dealSeqCnt;
}
return sliceInfo_;
}
template <typename COMP>
__aicore__ inline SplitCoreSliceInfo &CompressorSplitCoreSliceIterator<COMP>::GetRightNextCmpSeqCnt()
{
uint32_t cmpRatio = tools_.toolParams_.cmpRatio;
if (isFirst_) {
sliceInfo_.bSeqUsed = tools_.GetSeqUsed(sliceInfo_.bIdx);
sliceInfo_.bStartPos = tools_.GetStartPos(sliceInfo_.bIdx);
isFirst_ = false;
}
// 计算头部占位行数、有效数据行数、尾部占位行数
sliceInfo_.headHolderSeqCnt = (sliceInfo_.bStartPos + sliceInfo_.sIdx) % cmpRatio;
sliceInfo_.validSeqCnt = sliceInfo_.bSeqUsed - sliceInfo_.sIdx;
if (sliceInfo_.headHolderSeqCnt + sliceInfo_.validSeqCnt > maxDealSeqCnt_) {
sliceInfo_.validSeqCnt = maxDealSeqCnt_ - sliceInfo_.headHolderSeqCnt;
}
sliceInfo_.tailHolderSeqCnt =
cmpRatio - (sliceInfo_.bStartPos + sliceInfo_.sIdx + sliceInfo_.validSeqCnt) % cmpRatio;
if (sliceInfo_.tailHolderSeqCnt == cmpRatio) {
sliceInfo_.tailHolderSeqCnt = 0;
}
// 头和尾处理,否则需要处理的seq等于cmpRatio
if (sliceInfo_.validSeqCnt < cmpRatio) {
sliceInfo_.dealSeqCnt = sliceInfo_.validSeqCnt;
if (sliceInfo_.sIdx == 0) {
sliceInfo_.dealSeqCnt = cmpRatio - sliceInfo_.headHolderSeqCnt;
}
} else {
sliceInfo_.dealSeqCnt = cmpRatio;
}
sliceInfo_.validSeqCnt = sliceInfo_.dealSeqCnt;
// 计算本次可以处理的Tc个数
sliceInfo_.dealTcSize = (sliceInfo_.dealSeqCnt + cmpRatio - 1) / cmpRatio;
// 因为是一个batch的数据, 只有最后一个压缩块才可能不需要压缩, 此时sliceInfo_.tailHolderSeqCnt > 0
sliceInfo_.compressTcSize = sliceInfo_.dealTcSize;
if (sliceInfo_.tailHolderSeqCnt > 0) {
sliceInfo_.compressTcSize = sliceInfo_.dealTcSize - 1; // 最后一个压缩块不满时,其不需要压缩
}
return sliceInfo_;
}
struct Vec1SliceInfo : public SliceInfo {
__aicore__ inline Vec1SliceInfo(){};
__aicore__ inline Vec1SliceInfo(uint32_t bIdx, uint32_t sIdx) : SliceInfo(bIdx, sIdx){};
__aicore__ inline Vec1SliceInfo(uint32_t bIdx, uint32_t sIdx, uint32_t dealedSeqCnt)
: SliceInfo(bIdx, sIdx), dealedSeqCnt(dealedSeqCnt){};
uint32_t dealedSeqCnt = 0U;
uint32_t dealedTcCnt = 0U;
uint32_t bSeqLength = 0U;
uint32_t compressoredScCnt = 0U;
bool isFirst = false;
bool isLast = false;
};
struct StatisticInfo {
__aicore__ inline StatisticInfo(){};
__aicore__ inline StatisticInfo(uint32_t actualTcCnt, uint32_t dealSeqCnt, uint32_t compressorScCnt)
: actualTcCnt(actualTcCnt), dealSeqCnt(dealSeqCnt), compressorScCnt(compressorScCnt){};
uint32_t actualTcCnt = 0U;
uint32_t dealSeqCnt = 0U;
uint32_t compressorScCnt = 0U;
};
template <typename COMP>
class CompressorVec1SliceIterator {
public:
__aicore__ inline CompressorVec1SliceIterator(CompressorTools<COMP> &tools) : tools_(tools)
{
}
__aicore__ inline void Reset(uint32_t bIdx, uint32_t sIdx);
__aicore__ inline void Reset(uint32_t bIdx, uint32_t sIdx, uint32_t dealedSeqCnt, uint32_t compressoredScCnt);
__aicore__ inline void SetMaxBatchSize(uint32_t batch_size);
__aicore__ inline void SetDealedSeqCnt(uint32_t dealedSeqCnt);
__aicore__ inline void SetDealedTcCnt(uint32_t dealedTcCnt);
__aicore__ inline void SetCompressoredScCnt(uint32_t compressoredScCnt);
__aicore__ inline void SetNeedDealTcSize(uint32_t needDealTcSize);
__aicore__ inline void SetNeedDealTcSize(uint32_t needDealTcSize, uint32_t canDealTcSize);
__aicore__ inline uint32_t GetNeedDealTcSize();
__aicore__ inline bool IsEnd();
template <bool IS_STATISTIC = false>
__aicore__ inline void IteratorSlice();
__aicore__ inline Vec1SliceInfo &GetSlice();
template <bool IS_STATISTIC = false>
__aicore__ inline StatisticInfo &FullIteratorSlice();
private:
CompressorTools<COMP> &tools_;
bool isFirst_ = true;
Vec1SliceInfo sliceInfo_{};
StatisticInfo statisticInfo_{};
uint32_t needDealTcSize_ = 0U;
uint32_t batch_size_ = 0U;
};
template <typename COMP>
__aicore__ inline void CompressorVec1SliceIterator<COMP>::Reset(uint32_t bIdx, uint32_t sIdx)
{
sliceInfo_.bIdx = bIdx;
sliceInfo_.sIdx = sIdx;
while (tools_.GetSeqLength(sliceInfo_.bIdx) == 0) {
sliceInfo_.bIdx++;
if (sliceInfo_.bIdx == batch_size_) {
sliceInfo_.bIdx = 0;
}
}
sliceInfo_.bSeqUsed = tools_.GetSeqUsed(sliceInfo_.bIdx);
sliceInfo_.bStartPos = tools_.GetStartPos(sliceInfo_.bIdx);
sliceInfo_.bSeqLength = tools_.GetSeqLength(sliceInfo_.bIdx);
isFirst_ = true;
}
template <typename COMP>
__aicore__ inline void CompressorVec1SliceIterator<COMP>::Reset(uint32_t bIdx, uint32_t sIdx, uint32_t dealedSeqCnt,
uint32_t compressoredScCnt)
{
Reset(bIdx, sIdx);
SetDealedSeqCnt(dealedSeqCnt);
SetCompressoredScCnt(compressoredScCnt);
}
template <typename COMP>
__aicore__ inline void CompressorVec1SliceIterator<COMP>::SetMaxBatchSize(uint32_t batch_size)
{
this->batch_size_ = batch_size;
}
template <typename COMP>
__aicore__ inline void CompressorVec1SliceIterator<COMP>::SetDealedSeqCnt(uint32_t dealedSeqCnt)
{
this->sliceInfo_.dealedSeqCnt = dealedSeqCnt;
}
template <typename COMP>
__aicore__ inline void CompressorVec1SliceIterator<COMP>::SetCompressoredScCnt(uint32_t compressoredScCnt)
{
this->sliceInfo_.compressoredScCnt = compressoredScCnt;
}
template <typename COMP>
__aicore__ inline void CompressorVec1SliceIterator<COMP>::SetDealedTcCnt(uint32_t dealedTcCnt)
{
this->sliceInfo_.dealedTcCnt = dealedTcCnt;
}
template <typename COMP>
__aicore__ inline void CompressorVec1SliceIterator<COMP>::SetNeedDealTcSize(uint32_t needDealTcSize)
{
this->needDealTcSize_ = needDealTcSize;
}
template <typename COMP>
template <bool IS_STATISTIC>
__aicore__ inline void CompressorVec1SliceIterator<COMP>::IteratorSlice()
{
uint32_t cmpRatio = tools_.toolParams_.cmpRatio;
if constexpr (IS_STATISTIC) {
statisticInfo_.actualTcCnt += sliceInfo_.dealTcSize;
statisticInfo_.compressorScCnt += sliceInfo_.compressTcSize;
}
needDealTcSize_ -= sliceInfo_.dealTcSize;
sliceInfo_.dealedSeqCnt += sliceInfo_.validSeqCnt;
sliceInfo_.compressoredScCnt += sliceInfo_.compressTcSize;
sliceInfo_.sIdx += sliceInfo_.validSeqCnt;
if (sliceInfo_.sIdx >= sliceInfo_.bSeqUsed) {
do {
uint32_t seqLength = tools_.GetSeqLength(sliceInfo_.bIdx);
if (sliceInfo_.bSeqUsed < seqLength) {
uint32_t nextAlignSIdx = Align(sliceInfo_.bStartPos + sliceInfo_.sIdx, cmpRatio) - sliceInfo_.bStartPos;
sliceInfo_.dealedSeqCnt += nextAlignSIdx - sliceInfo_.sIdx;
uint32_t tcGap = CeilDivT(static_cast<int32_t>(seqLength - nextAlignSIdx),
static_cast<int32_t>(cmpRatio));
if (sliceInfo_.bSeqUsed == 0 && nextAlignSIdx > sliceInfo_.sIdx) {
// 此时bseqused所在压缩块未被纳入计算
tcGap++;
}
sliceInfo_.sIdx = nextAlignSIdx;
if (needDealTcSize_ < tcGap) {
sliceInfo_.dealedSeqCnt += needDealTcSize_ * cmpRatio;
sliceInfo_.sIdx += needDealTcSize_ * cmpRatio;
needDealTcSize_ = 0;
break;
}
sliceInfo_.dealedSeqCnt += seqLength - sliceInfo_.sIdx;
needDealTcSize_ -= tcGap;
}
sliceInfo_.bIdx++;
if (sliceInfo_.bIdx == batch_size_) {
sliceInfo_.bIdx = 0;
}
sliceInfo_.sIdx = 0;
sliceInfo_.bSeqUsed = tools_.GetSeqUsed(sliceInfo_.bIdx);
} while (sliceInfo_.bSeqUsed == 0);
sliceInfo_.bSeqLength = tools_.GetSeqLength(sliceInfo_.bIdx);
sliceInfo_.bStartPos = tools_.GetStartPos(sliceInfo_.bIdx);
}
if (isFirst_) {
isFirst_ = false;
}
}
template <typename COMP>
__aicore__ inline uint32_t CompressorVec1SliceIterator<COMP>::GetNeedDealTcSize()
{
return needDealTcSize_;
}
template <typename COMP>
__aicore__ inline bool CompressorVec1SliceIterator<COMP>::IsEnd()
{
return (needDealTcSize_ == 0);
}
template <typename COMP>
__aicore__ inline Vec1SliceInfo &CompressorVec1SliceIterator<COMP>::GetSlice()
{
uint32_t cmpRatio = tools_.toolParams_.cmpRatio;
if (sliceInfo_.bSeqUsed < sliceInfo_.sIdx) {
sliceInfo_.headHolderSeqCnt = 0;
sliceInfo_.validSeqCnt = 0;
sliceInfo_.tailHolderSeqCnt = 0;
sliceInfo_.dealTcSize = 0;
sliceInfo_.compressTcSize = 0;
} else {
// 计算头部占位行数、有效数据行数、尾部占位行数
sliceInfo_.headHolderSeqCnt = (sliceInfo_.bStartPos + sliceInfo_.sIdx) % cmpRatio;
sliceInfo_.validSeqCnt = sliceInfo_.bSeqUsed - sliceInfo_.sIdx;
if (CeilDivT(sliceInfo_.headHolderSeqCnt + sliceInfo_.validSeqCnt, cmpRatio) > needDealTcSize_) {
sliceInfo_.validSeqCnt = needDealTcSize_ * cmpRatio - sliceInfo_.headHolderSeqCnt;
}
uint32_t globalTotalSeqCnt = sliceInfo_.bStartPos + sliceInfo_.sIdx + sliceInfo_.validSeqCnt;
sliceInfo_.tailHolderSeqCnt = Align(globalTotalSeqCnt, cmpRatio) - globalTotalSeqCnt;
// 计算本次可以处理的Tc个数
sliceInfo_.dealTcSize =
(sliceInfo_.headHolderSeqCnt + sliceInfo_.validSeqCnt + sliceInfo_.tailHolderSeqCnt) / cmpRatio;
sliceInfo_.compressTcSize =
(sliceInfo_.headHolderSeqCnt + min(sliceInfo_.validSeqCnt, sliceInfo_.bSeqUsed - sliceInfo_.sIdx)) /
cmpRatio;
}
sliceInfo_.isFirst = isFirst_;
sliceInfo_.isLast =
sliceInfo_.bSeqUsed > sliceInfo_.sIdx &&
CeilDivT(sliceInfo_.headHolderSeqCnt + sliceInfo_.bSeqUsed - sliceInfo_.sIdx, cmpRatio) >= needDealTcSize_;
return sliceInfo_;
}
template <typename COMP>
template <bool IS_STATISTIC>
__aicore__ inline StatisticInfo &CompressorVec1SliceIterator<COMP>::FullIteratorSlice()
{
if constexpr (IS_STATISTIC) {
statisticInfo_ = {0U, 0U, 0U};
Vec1SliceInfo tempSliceInfo = GetSlice();
while (!IsEnd()) {
GetSlice();
IteratorSlice<IS_STATISTIC>();
}
Vec1SliceInfo sliceInfo = GetSlice();
statisticInfo_.dealSeqCnt = sliceInfo.dealedSeqCnt - tempSliceInfo.dealedSeqCnt;
} else {
while (!IsEnd()) {
GetSlice();
IteratorSlice<IS_STATISTIC>();
}
}
return statisticInfo_;
}
} // namespace Compressor
#endif

View File

@@ -0,0 +1,347 @@
/**
 * Copyright (c) 2026 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 compressor_vector_comm.h
* \brief 存放各种vector的公共组件
*/
#ifndef COMPRESSOR_VECTOR_COMM_H
#define COMPRESSOR_VECTOR_COMM_H
#include "compressor_comm.h"
namespace Compressor {
struct MatRpeatParam {
uint32_t row;
uint32_t col;
uint32_t dtypeMask;
uint32_t loopTimes;
uint32_t colRemain;
uint8_t repeatStride;
};
struct RmsNormParam {
float reciprocal;
float epsilon;
uint32_t row;
uint32_t col;
};
/**
* @brief ColumnSum 对矩阵按列进行求和
* @param dstLocal 输出tensor [1, col],支持和shareTmpUb是同一块空间
* @param srcLocal 输入tensor [row, col]
* @param shareTmpUb 临时buffer 内部需要的空间为 [ceil(row / 2) * col * sizeof(float)]
* @param row 行数
* @param col 列数
*/
__aicore__ inline void ColumnSum(const LocalTensor<float> &dstLocal, const LocalTensor<float> &srcLocal,
const LocalTensor<float> &shareTmpUb, uint32_t row, uint32_t col)
{
// 行数为1时,直接将srcLocal复制到dstLocal
if (unlikely(row == 1)) {
DataCopy(dstLocal, srcLocal, row * col);
PipeBarrier<PIPE_V>();
return;
}
for (uint32_t mask = MAX_R << 1; mask > 1; mask >>= 1) {
if (row & mask) {
// 将输入对半求和后放进临时空间
Add(shareTmpUb, srcLocal, srcLocal[mask * col / 2], mask * col / 2); // 2:对矩阵按列做计算
PipeBarrier<PIPE_V>();
// 将余量加到前一半上
if (unlikely(row > mask)) {
if ((row - mask) > (mask >> 1)) {
Add(shareTmpUb, shareTmpUb, srcLocal[mask * col], mask * col / 2); // 2:对矩阵按列做计算
PipeBarrier<PIPE_V>();
Add(shareTmpUb, shareTmpUb, srcLocal[(mask + (mask >> 1)) * col], (row - mask - (mask >> 1)) * col);
PipeBarrier<PIPE_V>();
} else {
Add(shareTmpUb, shareTmpUb, srcLocal[mask * col], (row - mask) * col);
PipeBarrier<PIPE_V>();
}
}
// 每次将后一半行加到前一半上
for (uint32_t i = mask >> 2; i > 1; i >>= 1) {
Add(shareTmpUb, shareTmpUb, shareTmpUb[i * col], i * col);
PipeBarrier<PIPE_V>();
}
if (mask == 2) { // 2:最后一次矩阵运算处理
DataCopy(dstLocal, shareTmpUb, col);
} else {
Add(dstLocal, shareTmpUb, shareTmpUb[col], col);
}
PipeBarrier<PIPE_V>();
break;
}
}
}
/**
* @brief ColumnMax 对矩阵按列进行求最大值
* @param dstLocal 输出tensor [1, col],支持和shareTmpUb是同一块空间
* @param srcLocal 输入tensor [row, col]
* @param shareTmpUb 临时buffer 内部需要的空间为 [ceil(row / 2) * col * sizeof(float)]
* @param row 行数
* @param col 列数
*/
__aicore__ inline void ColumnMax(const LocalTensor<float> &dstLocal, const LocalTensor<float> &srcLocal,
const LocalTensor<float> &shareTmpUb, uint32_t row, uint32_t col)
{
// 行数为1时,直接将srcLocal复制到dstLocal
if (unlikely(row == 1)) {
DataCopy(dstLocal, srcLocal, row * col);
PipeBarrier<PIPE_V>();
return;
}
for (uint32_t mask = MAX_R << 1; mask > 1; mask >>= 1) {
if (row & mask) {
// 将输入对半求最大值后放进临时空间
Max(shareTmpUb, srcLocal, srcLocal[mask * col / 2], mask * col / 2); // 2:对矩阵按列做计算
PipeBarrier<PIPE_V>();
// 将余量和前一半求最大值后加到前一半上
if (unlikely(row > mask)) {
if ((row - mask) > (mask >> 1)) {
Max(shareTmpUb, shareTmpUb, srcLocal[mask * col], mask * col / 2); // 2:对矩阵按列做计算
PipeBarrier<PIPE_V>();
Max(shareTmpUb, shareTmpUb, srcLocal[(mask + (mask >> 1)) * col], (row - mask - (mask >> 1)) * col);
PipeBarrier<PIPE_V>();
} else {
Max(shareTmpUb, shareTmpUb, srcLocal[mask * col], (row - mask) * col);
PipeBarrier<PIPE_V>();
}
}
// 每次将后一半行和前一半最大值后加到前一半上
for (uint32_t i = mask >> 2; i > 1; i >>= 1) {
Max(shareTmpUb, shareTmpUb, shareTmpUb[i * col], i * col);
PipeBarrier<PIPE_V>();
}
if (mask == 2) { // 2:最后一次矩阵运算处理
DataCopy(dstLocal, shareTmpUb, col);
} else {
Max(dstLocal, shareTmpUb, shareTmpUb[col], col);
}
PipeBarrier<PIPE_V>();
break;
}
}
}
/**
* @brief MatSubVec 矩阵逐行减向量
* @param dstLocal 输出tensor [row, col]
* @param src0Local 输入tensor [row, col]
* @param src1Local 输入tensor [1, col]
* @param repeatParam 描述待处理数据的排布,包括
row 行数
col 列数
dtypeMask 一次迭代参与计算元素数
loopTimes 循环次数
colRemain 剩余列数
repeatStride 循环步长(内存中实际列长度)
*/
__aicore__ inline void MatSubVec(const LocalTensor<float> &dstLocal, const LocalTensor<float> &src0Local,
const LocalTensor<float> &src1Local, const MatRpeatParam &repeatParam)
{
for (uint32_t row = 0; row < repeatParam.row; row += REPEAT_MAX_NUM) {
uint32_t repeatRowTimes = Std::min(repeatParam.row - row, REPEAT_MAX_NUM);
uint32_t offset = 0;
for (uint32_t i = 0; i < repeatParam.loopTimes; i++) {
Sub(dstLocal[row * repeatParam.col + offset], src0Local[row * repeatParam.col + offset], src1Local[offset],
repeatParam.dtypeMask, repeatRowTimes,
{1, 1, 1, repeatParam.repeatStride, repeatParam.repeatStride, 0});
offset += repeatParam.dtypeMask;
}
if (repeatParam.colRemain > 0) {
Sub(dstLocal[row * repeatParam.col + offset], src0Local[row * repeatParam.col + offset], src1Local[offset],
repeatParam.colRemain, repeatRowTimes,
{1, 1, 1, repeatParam.repeatStride, repeatParam.repeatStride, 0});
}
}
}
/**
* @brief MatDivVec 矩阵逐行除以向量
* @param dstLocal 输出tensor [row, col]
* @param src0Local 输入tensor [row, col]
* @param src1Local 输入tensor [1, col]
* @param repeatParam 描述待处理数据的排布,包括
row 行数
col 列数
dtypeMask 一次迭代参与计算元素数
loopTimes 循环次数
colRemain 剩余列数
repeatStride 循环步长(内存中实际列长度)
*/
__aicore__ inline void MatDivVec(const LocalTensor<float> &dstLocal, const LocalTensor<float> &src0Local,
const LocalTensor<float> &src1Local, const MatRpeatParam &repeatParam)
{
for (uint32_t row = 0; row < repeatParam.row; row += REPEAT_MAX_NUM) {
uint32_t repeatRowTimes = Std::min(repeatParam.row - row, REPEAT_MAX_NUM);
uint32_t offset = 0;
for (uint32_t i = 0; i < repeatParam.loopTimes; i++) {
Div(dstLocal[row * repeatParam.col + offset], src0Local[row * repeatParam.col + offset], src1Local[offset],
repeatParam.dtypeMask, repeatRowTimes,
{1, 1, 1, repeatParam.repeatStride, repeatParam.repeatStride, 0});
offset += repeatParam.dtypeMask;
}
if (repeatParam.colRemain > 0) {
Div(dstLocal[row * repeatParam.col + offset], src0Local[row * repeatParam.col + offset], src1Local[offset],
repeatParam.colRemain, repeatRowTimes,
{1, 1, 1, repeatParam.repeatStride, repeatParam.repeatStride, 0});
}
}
}
/**
* @brief MatMulVec 矩阵逐行乘以向量
* @param dstLocal 输出tensor [row, col]
* @param src0Local 输入tensor [row, col]
* @param src1Local 输入tensor [1, col]
* @param repeatParam 描述待处理数据的排布,包括
row 行数
col 列数
dtypeMask 一次迭代参与计算元素数
loopTimes 循环次数
colRemain 剩余列数
repeatStride 循环步长(内存中实际列长度)
*/
__aicore__ inline void MatMulVec(const LocalTensor<float> &dstLocal, const LocalTensor<float> &src0Local,
const LocalTensor<float> &src1Local, const MatRpeatParam &repeatParam)
{
for (uint32_t row = 0; row < repeatParam.row; row += REPEAT_MAX_NUM) {
uint32_t repeatRowTimes = Std::min(repeatParam.row - row, REPEAT_MAX_NUM);
uint32_t offset = 0;
for (uint32_t i = 0; i < repeatParam.loopTimes; i++) {
Mul(dstLocal[row * repeatParam.col + offset], src0Local[row * repeatParam.col + offset], src1Local[offset],
repeatParam.dtypeMask, repeatRowTimes,
{1, 1, 1, repeatParam.repeatStride, repeatParam.repeatStride, 0});
offset += repeatParam.dtypeMask;
}
if (repeatParam.colRemain > 0) {
Mul(dstLocal[row * repeatParam.col + offset], src0Local[row * repeatParam.col + offset], src1Local[offset],
repeatParam.colRemain, repeatRowTimes,
{1, 1, 1, repeatParam.repeatStride, repeatParam.repeatStride, 0});
}
}
}
/**
* @brief RowSum 矩阵对每行求和
* @param dstLocal 输出tensor [1, row]
* @param srcLocal 输入tensor [row, col]
* @param shareTmpUb 临时buffer 内部需要的空间为 [row, col],支持和srcLocal是同一块空间
* @param repeatParam 描述待处理数据的排布,包括
row 行数
col 列数
dtypeMask 一次迭代参与计算元素数
loopTimes 循环次数
colRemain 剩余列数
repeatStride 循环步长(内存中实际列长度)
*/
__aicore__ inline void RowSum(const LocalTensor<float> &dstLocal, const LocalTensor<float> &srcLocal,
const LocalTensor<float> &shareTmpUb, const MatRpeatParam &repeatParam)
{
uint32_t blockCount = repeatParam.loopTimes;
if (blockCount > 0 && repeatParam.colRemain > 0) {
Add(shareTmpUb, srcLocal, srcLocal[blockCount * repeatParam.dtypeMask], repeatParam.colRemain,
repeatParam.row,
{1, 1, 1, repeatParam.repeatStride, repeatParam.repeatStride, repeatParam.repeatStride});
AscendC::PipeBarrier<PIPE_V>();
}
for (uint32_t loopCount = blockCount >> 1; loopCount > 0; loopCount = blockCount >> 1) {
blockCount = (blockCount + 1) >> 1;
for (uint32_t i = 0; i < loopCount; i++) {
Add(shareTmpUb[i * repeatParam.dtypeMask], srcLocal[i * repeatParam.dtypeMask],
srcLocal[(i + blockCount) * repeatParam.dtypeMask], repeatParam.dtypeMask, repeatParam.row,
{1, 1, 1, repeatParam.repeatStride, repeatParam.repeatStride, repeatParam.repeatStride});
}
AscendC::PipeBarrier<PIPE_V>();
}
WholeReduceSum(dstLocal, shareTmpUb,
(repeatParam.col < repeatParam.dtypeMask) ? repeatParam.col :
repeatParam.dtypeMask,
repeatParam.row, 1, 1, repeatParam.repeatStride);
}
/**
* @brief RowDivs 矩阵每行除以对应元素
* @param dstLocal 输出tensor [row, col]
* @param src0Local 输入tensor [row, col]
* @param src1Local 输入tensor [row, 1],需要扩展到一个datablock中(实际内存需要为[row, FP32_BLOCK_ELEMENT_NUM])
* @param repeatParam 描述待处理数据的排布,包括
row 行数
col 列数
dtypeMask 一次迭代参与计算元素数
loopTimes 循环次数
colRemain 剩余列数
repeatStride 循环步长(内存中实际列长度)
*/
__aicore__ inline void RowDivs(const LocalTensor<float> &dstLocal, const LocalTensor<float> &src0Local,
const LocalTensor<float> &src1Local, const MatRpeatParam &repeatParam)
{
for (uint32_t row = 0; row < repeatParam.row; row += REPEAT_MAX_NUM) {
uint32_t repeatRowTimes = Std::min(repeatParam.row - row, REPEAT_MAX_NUM);
uint32_t offset = 0;
for (uint32_t i = 0; i < repeatParam.loopTimes; i++) {
Div(dstLocal[row * repeatParam.col + offset], src0Local[row * repeatParam.col + offset], src1Local,
repeatParam.dtypeMask, repeatRowTimes,
{1, 1, 0, repeatParam.repeatStride, repeatParam.repeatStride, 1});
offset += repeatParam.dtypeMask;
}
if (repeatParam.colRemain > 0) {
Div(dstLocal[row * repeatParam.col + offset], src0Local[row * repeatParam.col + offset], src1Local,
repeatParam.colRemain, repeatRowTimes,
{1, 1, 0, repeatParam.repeatStride, repeatParam.repeatStride, 1});
}
}
}
/**
* @brief RowMuls 矩阵每行乘以相同元素
* @param dstLocal 输出tensor [row, col]
* @param src0Local 输入tensor [row, col]
* @param src1Local 输入tensor [row, 1],需要扩展到一个datablock中(实际内存需要为[row, FP32_BLOCK_ELEMENT_NUM])
* @param repeatParam 描述待处理数据的排布,包括
row 行数
col 列数
dtypeMask 一次迭代参与计算元素数
loopTimes 循环次数
colRemain 剩余列数
repeatStride 循环步长(内存中实际列长度)
*/
__aicore__ inline void RowMuls(const LocalTensor<float> &dstLocal, const LocalTensor<float> &src0Local,
const LocalTensor<float> &src1Local, const MatRpeatParam &repeatParam)
{
for (uint32_t row = 0; row < repeatParam.row; row += REPEAT_MAX_NUM) {
uint32_t repeatRowTimes = Std::min(repeatParam.row - row, REPEAT_MAX_NUM);
uint32_t offset = 0;
for (uint32_t i = 0; i < repeatParam.loopTimes; i++) {
Mul(dstLocal[row * repeatParam.col + offset], src0Local[row * repeatParam.col + offset], src1Local,
repeatParam.dtypeMask, repeatRowTimes,
{1, 1, 0, repeatParam.repeatStride, repeatParam.repeatStride, 1});
offset += repeatParam.dtypeMask;
}
if (repeatParam.colRemain > 0) {
Mul(dstLocal[row * repeatParam.col + offset], src0Local[row * repeatParam.col + offset], src1Local,
repeatParam.colRemain, repeatRowTimes,
{1, 1, 0, repeatParam.repeatStride, repeatParam.repeatStride, 1});
}
}
}
} // namespace Compressor
#endif // COMPRESSOR_VECTOR_COMM_H

View File

@@ -0,0 +1,87 @@
/**
 * Copyright (c) 2026 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 rms_norm.h
* \brief
*/
#ifndef RMS_NORM_H
#define RMS_NORM_H
#include "compressor_comm.h"
#include "compressor_vector_comm.h"
namespace Compressor {
/**
* @brief RmsNorm 对矩阵进行rmsnorm
* @param dstLocal 输出tensor [row, col],支持和srcLocal是同一块空间
* @param srcLocal 输入tensor [row, col]
* @param gammaLocal 系数gamma [1, col]
* @param shareTmpUb 临时buffer 内部需要的空间为 [(row * col + row) * sizeof(float)]
* @param rmsNormParams rms所需系数,包括
reciprocal rmsnorm系数reciprocal
epsilon rmsnorm系数epsilon
row 处理的行数
col 列数
*/
template <typename GammaType>
__aicore__ inline void RmsNorm(const LocalTensor<float> &dstLocal, const LocalTensor<float> &srcLocal,
const LocalTensor<GammaType> &gammaLocal, const LocalTensor<float> &shareTmpUb,
const RmsNormParam &rmsNormParams)
{
uint64_t cnt = rmsNormParams.row * rmsNormParams.col;
LocalTensor<float> temp1Local = shareTmpUb.ReinterpretCast<float>();
LocalTensor<float> temp2Local = temp1Local[cnt];
// temp1Local = srcLocal ^ 2
Mul(temp1Local, srcLocal, srcLocal, cnt);
PipeBarrier<PIPE_V>();
MatRpeatParam repeatParams = {
rmsNormParams.row, // row
rmsNormParams.col, // col
FP32_REPEAT_ELEMENT_NUM, // dtypeMask
rmsNormParams.col / FP32_REPEAT_ELEMENT_NUM, // loopTimes
rmsNormParams.col % FP32_REPEAT_ELEMENT_NUM, // colsRemain
static_cast<uint8_t>(rmsNormParams.col / FP32_BLOCK_ELEMENT_NUM), // repeatStride
};
// temp2Local[row] = Sum(temp1Local)
RowSum(temp2Local, temp1Local, temp1Local, repeatParams);
PipeBarrier<PIPE_V>();
// temp2Local[row] = temp2Local[row] * reciprocal(1/N)
Muls(temp2Local, temp2Local, rmsNormParams.reciprocal, rmsNormParams.row);
PipeBarrier<PIPE_V>();
// temp2Local[row] = temp2Local[row] + epsilon
Adds(temp2Local, temp2Local, rmsNormParams.epsilon, rmsNormParams.row);
PipeBarrier<PIPE_V>();
// temp2Local[row] = Sqrt(temp2Local[row])
Sqrt(temp2Local, temp2Local, rmsNormParams.row);
PipeBarrier<PIPE_V>();
// temp1Local[row, 8] = brc(temp2Local[row, 1])
Brcb(temp1Local, temp2Local, CeilDivT(rmsNormParams.row, BRCB_NUM), {1, 8});
PipeBarrier<PIPE_V>();
// dstLocal = srcLocal / temp1Local(sum)
RowDivs(dstLocal, srcLocal, temp1Local, repeatParams);
PipeBarrier<PIPE_V>();
// dstLocal = dstLocal * gammaLocal
MatMulVec(dstLocal, dstLocal, gammaLocal, repeatParams);
}
} // namespace Compressor
#endif // MLA_PROLOG_RMS_NORM_H

View File

@@ -0,0 +1,130 @@
/**
 * Copyright (c) 2026 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 rope.h
* \brief
*/
#ifndef ROPE_H
#define ROPE_H
#include "compressor_comm.h"
#include "compressor_vector_comm.h"
namespace Compressor {
/**
* @brief SetGatherSrcOffset 计算用于interleave模式的offset
* @param gatherOffsetLocal 输出tensor [count],数据类型需要为int64_t,使用时要转换
* @param count offset的元素个数,一般为列数
*/
template <typename T>
__aicore__ inline void SetGatherSrcOffset(const LocalTensor<int32_t> &gatherOffsetLocal, uint32_t count)
{
for (uint32_t i = 0; i < 8; i++) {
gatherOffsetLocal.SetValue(i, i ^ 1);
}
event_t eventId_S_V = static_cast<event_t>(GetTPipePtr()->FetchEventID(HardEvent::S_V));
SetFlag<HardEvent::S_V>(eventId_S_V);
WaitFlag<HardEvent::S_V>(eventId_S_V);
int32_t scalarValue = 8;
while (scalarValue < count) {
int32_t nextValue = scalarValue * 2;
PipeBarrier<PIPE_V>();
if (nextValue < count) {
Adds(gatherOffsetLocal[scalarValue], gatherOffsetLocal, scalarValue, scalarValue);
} else {
Adds(gatherOffsetLocal[scalarValue], gatherOffsetLocal, scalarValue, count - scalarValue);
break;
}
scalarValue = nextValue;
}
PipeBarrier<PIPE_V>();
Muls(gatherOffsetLocal, gatherOffsetLocal, static_cast<int32_t>(sizeof(T)), count);
}
/**
* @brief RotaryPosEmb 同时做row行的RotaryPosEmb,每一行的元素为col
* @param dstLocal 输出tensor [row, actualCol],支持和srcLocal是同一块空间
* @param srcLocal 输入tensor [row, actualCol]
* @param cosLocal cos系数tensor [row, col]
* @param sinLocal sin系数tensor [row, col]
* @param shareTmpUb 临时buffer 内部需要的空间为 [row * col * sizeof(float)]
* @param gatherOffsetcastLocal 用于interleave模式的offset,数据类型需要为uint64_t
* @param row 待处理的行数
* @param col 待处理的列数
* @param actualCol 实际列数
* @param baseAddr 计算基地址
*/
template <ROTARY_MODE MODE>
__aicore__ inline void RotaryPosEmb(const LocalTensor<float> &dstLocal, const LocalTensor<float> &srcLocal,
const LocalTensor<float> &cosLocal, const LocalTensor<float> &sinLocal,
const LocalTensor<float> &shareTmpUb,
const LocalTensor<uint32_t> &gatherOffsetcastLocal, uint32_t row, uint32_t col,
uint32_t actualCol, uint64_t baseAddr)
{
uint64_t cnt = row * col;
uint32_t half_col = col >> 1;
uint64_t rsvdCnt = 0;
LocalTensor<float> reArrLocal = shareTmpUb.ReinterpretCast<float>();
if constexpr (MODE == ROTARY_MODE::HALF) {
DataCopy(reArrLocal, srcLocal[baseAddr + half_col],
{static_cast<uint16_t>(row), static_cast<uint16_t>(CeilDivT(half_col, FP32_BLOCK_ELEMENT_NUM)),
static_cast<uint16_t>(CeilDivT(actualCol - half_col, FP32_BLOCK_ELEMENT_NUM)),
static_cast<uint16_t>(CeilDivT(half_col, FP32_BLOCK_ELEMENT_NUM))});
DataCopy(reArrLocal[half_col], srcLocal[baseAddr],
{static_cast<uint16_t>(row), static_cast<uint16_t>(CeilDivT(half_col, FP32_BLOCK_ELEMENT_NUM)),
static_cast<uint16_t>(CeilDivT(actualCol - half_col, FP32_BLOCK_ELEMENT_NUM)),
static_cast<uint16_t>(CeilDivT(half_col, FP32_BLOCK_ELEMENT_NUM))});
PipeBarrier<PIPE_V>();
Muls(reArrLocal, reArrLocal, float(-1), half_col, row,
{1, 1, static_cast<uint8_t>(CeilDivT(static_cast<uint32_t>(col), FP32_BLOCK_ELEMENT_NUM)),
static_cast<uint8_t>(CeilDivT(static_cast<uint32_t>(col), FP32_BLOCK_ELEMENT_NUM))});
} else if constexpr (MODE == ROTARY_MODE::INTERLEAVE) {
for (uint32_t i = 0; i < row; i++) {
Gather(reArrLocal[i * col], srcLocal[i * actualCol + baseAddr], gatherOffsetcastLocal, 0, col);
}
PipeBarrier<PIPE_V>();
uint32_t repeatTimes = cnt / FP32_REPEAT_ELEMENT_NUM;
uint32_t remainder = cnt % FP32_REPEAT_ELEMENT_NUM;
uint64_t fullMask = 0x5555555555555555;
uint64_t partialMask = 0x55;
SetVectorMask<float, MaskMode::NORMAL>(0, fullMask);
Muls<float, false>(reArrLocal, reArrLocal, float(-1), MASK_PLACEHOLDER, repeatTimes,
{1, 1, FP32_BLOCK_ELEMENT_NUM, FP32_BLOCK_ELEMENT_NUM});
if (unlikely(remainder > 0)) {
SetVectorMask<float, MaskMode::NORMAL>(0, partialMask);
Muls<float, false>(reArrLocal[repeatTimes * FP32_REPEAT_ELEMENT_NUM],
reArrLocal[repeatTimes * FP32_REPEAT_ELEMENT_NUM], float(-1), MASK_PLACEHOLDER,
remainder / FP32_BLOCK_ELEMENT_NUM, {1, 1, 1, 1});
}
ResetMask();
}
PipeBarrier<PIPE_V>();
BinaryRepeatParams computeParams{1,
1,
1,
static_cast<uint8_t>(CeilDivT(actualCol, FP32_BLOCK_ELEMENT_NUM)),
static_cast<uint8_t>(CeilDivT(actualCol, FP32_BLOCK_ELEMENT_NUM)),
static_cast<uint8_t>(CeilDivT(col, FP32_BLOCK_ELEMENT_NUM))};
Mul(dstLocal[baseAddr], srcLocal[baseAddr], cosLocal, col, row, computeParams);
Mul(reArrLocal, reArrLocal, sinLocal, cnt);
PipeBarrier<PIPE_V>();
Add(dstLocal[baseAddr], dstLocal[baseAddr], reArrLocal, col, row, computeParams);
}
}
#endif

View File

@@ -0,0 +1,52 @@
/**
 * Copyright (c) 2026 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 soft_max.h
* \brief
*/
#ifndef SOFT_MAX_H
#define SOFT_MAX_H
#include "compressor_comm.h"
#include "compressor_vector_comm.h"
namespace Compressor {
/**
* @brief ColumnSoftMax 对矩阵按列进行SoftMax
* @param dstLocal 输出tensor [row, col],支持和srcLocal是同一块空间
* @param srcLocal 输入tensor [row, col]
* @param shareTmpUb 临时buffer 内部需要的空间为 [floor(row / 2) * col * sizeof(float)]
* @param row 行数
* @param col 列数
*/
__aicore__ inline void ColumnSoftMax(const LocalTensor<float> &dstLocal, const LocalTensor<float> &srcLocal,
const LocalTensor<float> &shareTmpUb, uint32_t row, uint32_t col)
{
uint32_t dtypeMask = FP32_REPEAT_ELEMENT_NUM;
uint32_t dLoop = col / dtypeMask;
uint32_t dRemain = col % dtypeMask;
uint8_t repeatStride = col / FP32_BLOCK_ELEMENT_NUM;
ColumnMax(shareTmpUb, srcLocal, shareTmpUb, row, col);
PipeBarrier<PIPE_V>();
MatSubVec(dstLocal, srcLocal, shareTmpUb, {row, col, dtypeMask, dLoop, dRemain, repeatStride});
PipeBarrier<PIPE_V>();
Exp(dstLocal, dstLocal, row * col);
PipeBarrier<PIPE_V>();
ColumnSum(shareTmpUb, dstLocal, shareTmpUb, row, col);
PipeBarrier<PIPE_V>();
MatDivVec(dstLocal, dstLocal, shareTmpUb, {row, col, dtypeMask, dLoop, dRemain, repeatStride});
}
} // namespace Compressor
#endif