* Copyright (c) 2025 Huawei Technologies Co., Ltd.
* This program is free software, you can redistribute it and/or modify it under the terms and conditions of
* CANN Open Software License Agreement Version 2.0 (the "License").
* Please refer to the License for details. You may not use this file except in compliance with the License.
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
* See LICENSE in the root of the software repository for the full text of the License.
*/
* \file scatter_list_rsbse.h
* \brief
*/
#ifndef SCATTER_LIST_RSBSE_H_
#define SCATTER_LIST_RSBSE_H_
#include "kernel_operator.h"
#include "scatter_list_base.h"
namespace ScatterList {
using namespace AscendC;
template <typename T1, typename T2>
class ScatterListRSBSE : public ScatterListBase<T1>
{
public:
__aicore__ inline ScatterListRSBSE(){};
__aicore__ inline void Init(
GM_ADDR var, GM_ADDR indice, GM_ADDR updates, GM_ADDR mask, GM_ADDR varOut, GM_ADDR workspace,
const ScatterListTilingData* tilingData);
__aicore__ inline void Process();
private:
__aicore__ inline void CopyIn();
__aicore__ inline void CopyOutEqLen(const int64_t& eachCoreBatchNum);
__aicore__ inline void CopyOutNotEqLen(const int64_t& eachCoreBatchNum);
constexpr static uint32_t bufferNum = 1;
private:
TPipe pipe;
TQue<QuePosition::VECIN, 1> indiceInQueue;
TQue<QuePosition::VECIN, 1> maskInQueue;
TQue<QuePosition::VECIN, bufferNum> updatesInQueue;
GlobalTensor<T1> varGm;
GlobalTensor<T1> updatesGm;
GlobalTensor<T2> indiceGm;
GlobalTensor<uint8_t> maskGm;
GM_ADDR varPtr = nullptr;
bool maskIsNull = false;
int64_t blockIndex = 0;
int64_t preCoreBatchIdx = 0;
int64_t curCoreBatchIdx = 0;
int64_t dim0Idx = 0;
int64_t dim1Idx = 0;
int64_t dim2OffsetIdx = 0;
int64_t dim2UpdateLen = 0;
int64_t dstGmOffset = 0;
int64_t srcGmOffset = 0;
ScatterListTilingData m_tilingData;
};
template <typename T1, typename T2>
__aicore__ inline void ScatterListRSBSE<T1, T2>::Init(
GM_ADDR var, GM_ADDR indice, GM_ADDR updates, GM_ADDR mask, GM_ADDR varOut, GM_ADDR workspace,
const ScatterListTilingData* tilingData)
{
blockIndex = GetBlockIdx();
this->ParseTilingData(tilingData, m_tilingData);
varPtr = var;
indiceGm.SetGlobalBuffer((__gm__ T2*)indice);
updatesGm.SetGlobalBuffer((__gm__ T1*)updates);
preCoreBatchIdx = blockIndex * m_tilingData.preCoreBatchNum;
pipe.InitBuffer(indiceInQueue, 1, m_tilingData.indiceUbSize);
pipe.InitBuffer(updatesInQueue, bufferNum, m_tilingData.updatesUbSize);
if (mask == nullptr) {
maskIsNull = true;
} else {
maskGm.SetGlobalBuffer((__gm__ uint8_t*)mask);
pipe.InitBuffer(maskInQueue, 1, m_tilingData.maskUbSize);
}
}
template <typename T1, typename T2>
__aicore__ inline void ScatterListRSBSE<T1, T2>::Process()
{
if (blockIndex >= m_tilingData.useCoreNum) {
return;
}
if (blockIndex == m_tilingData.useCoreNum - 1) {
if (m_tilingData.indiceDims != 1) {
CopyIn();
CopyOutNotEqLen(m_tilingData.lastCoreBatchNum);
} else {
CopyIn();
CopyOutEqLen(m_tilingData.lastCoreBatchNum);
}
} else {
if (m_tilingData.indiceDims == 1) {
CopyIn();
CopyOutEqLen(m_tilingData.preCoreBatchNum);
} else {
CopyIn();
CopyOutNotEqLen(m_tilingData.preCoreBatchNum);
}
}
}
template <typename T1, typename T2>
__aicore__ inline void ScatterListRSBSE<T1, T2>::CopyIn()
{
LocalTensor<T1> updatesUb = updatesInQueue.AllocTensor<T1>();
DataCopy(updatesUb, updatesGm[preCoreBatchIdx * m_tilingData.srcBatchStride], m_tilingData.updatesCount);
updatesInQueue.EnQue(updatesUb);
LocalTensor<T2> indiceUb = indiceInQueue.AllocTensor<T2>();
DataCopy(indiceUb, indiceGm, m_tilingData.indiceCount);
indiceInQueue.EnQue(indiceUb);
if (!maskIsNull) {
LocalTensor<uint8_t> maskUb = maskInQueue.AllocTensor<uint8_t>();
DataCopy(maskUb, maskGm, m_tilingData.maskCount);
maskInQueue.EnQue(maskUb);
}
}
template <typename T1, typename T2>
__aicore__ inline void ScatterListRSBSE<T1, T2>::CopyOutEqLen(const int64_t& eachCoreBatchNum)
{
LocalTensor<T1> updatesUb = updatesInQueue.DeQue<T1>();
LocalTensor<T2> indiceUb = indiceInQueue.DeQue<T2>();
LocalTensor<uint8_t> maskUb;
if (!maskIsNull) {
maskUb = maskInQueue.DeQue<uint8_t>();
}
this->Mte2ToS();
this->Mte2ToMte3();
for (int64_t eachCoreBatchIdx = 0; eachCoreBatchIdx < eachCoreBatchNum; eachCoreBatchIdx++) {
curCoreBatchIdx = preCoreBatchIdx + eachCoreBatchIdx;
dim0Idx = curCoreBatchIdx / m_tilingData.dim1Count;
if (maskIsNull || maskUb.GetValue(dim0Idx) == 1) {
varGm.SetGlobalBuffer(this->GetTensorAddr(varPtr, dim0Idx));
dim1Idx = curCoreBatchIdx % m_tilingData.dim1Count;
dim2OffsetIdx = indiceUb.GetValue(dim0Idx);
dstGmOffset = dim1Idx * m_tilingData.dstBatchStride + dim2OffsetIdx * m_tilingData.dim3Count;
srcGmOffset = eachCoreBatchIdx * m_tilingData.srcBatchStride;
DataCopy(varGm[dstGmOffset], updatesUb[srcGmOffset], m_tilingData.srcBatchStride);
}
}
indiceInQueue.FreeTensor(indiceUb);
updatesInQueue.FreeTensor(updatesUb);
if (!maskIsNull) {
maskInQueue.FreeTensor(maskUb);
}
}
template <typename T1, typename T2>
__aicore__ inline void ScatterListRSBSE<T1, T2>::CopyOutNotEqLen(const int64_t& eachCoreBatchNum)
{
LocalTensor<T1> updatesUb = updatesInQueue.DeQue<T1>();
LocalTensor<T2> indiceUb = indiceInQueue.DeQue<T2>();
LocalTensor<uint8_t> maskUb;
if (!maskIsNull) {
maskUb = maskInQueue.DeQue<uint8_t>();
}
this->Mte2ToS();
this->Mte2ToMte3();
for (int64_t eachCoreBatchIdx = 0; eachCoreBatchIdx < eachCoreBatchNum; eachCoreBatchIdx++) {
curCoreBatchIdx = preCoreBatchIdx + eachCoreBatchIdx;
dim0Idx = curCoreBatchIdx / m_tilingData.dim1Count;
if (maskIsNull || maskUb.GetValue(dim0Idx) == 1) {
varGm.SetGlobalBuffer(this->GetTensorAddr(varPtr, dim0Idx));
dim1Idx = curCoreBatchIdx % m_tilingData.dim1Count;
dim2OffsetIdx = indiceUb.GetValue(dim0Idx * 2);
dim2UpdateLen = indiceUb.GetValue(dim0Idx * 2 + 1);
dstGmOffset = dim1Idx * m_tilingData.dstBatchStride + dim2OffsetIdx * m_tilingData.dim3Count;
srcGmOffset = eachCoreBatchIdx * m_tilingData.srcBatchStride;
DataCopy(varGm[dstGmOffset], updatesUb[srcGmOffset], dim2UpdateLen * m_tilingData.dim3Count);
}
}
indiceInQueue.FreeTensor(indiceUb);
updatesInQueue.FreeTensor(updatesUb);
if (!maskIsNull) {
maskInQueue.FreeTensor(maskUb);
}
}
}
#endif