* 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 ring_attention_update_tiling_arch35.cpp
* \brief
*/
#include <iostream>
#include "platform/platform_info.h"
#include "log/log.h"
#include "register/op_impl_registry.h"
#include "tiling/platform/platform_ascendc.h"
#include "util/math_util.h"
#include "util/shape_util.h"
#include "ring_attention_update_tiling.h"
#include "ring_attention_update_tiling_arch35.h"
namespace optiling {
using namespace Ops::Base;
constexpr uint32_t REGBASE_KEY = 100;
constexpr uint32_t SOFTMAX_TND_KEY = 10;
constexpr uint32_t TND_KEY = 20;
constexpr uint32_t DTYPE_KEY_FP16 = 0;
constexpr uint32_t DTYPE_KEY_BF16 = 1;
constexpr uint32_t DTYPE_KEY_FP32 = 2;
constexpr uint32_t SIZE_B32 = 4;
constexpr uint32_t SIZE_B16 = 2;
constexpr uint32_t BLOCK_SIZE = 32;
constexpr uint32_t REPEAT_NUM_B32 = 256 / 4;
constexpr size_t CONST_ZERO = 0;
constexpr size_t CONST_ONE = 1;
constexpr size_t CONST_TWO = 2;
constexpr size_t CONST_THREE = 3;
constexpr size_t CONST_FOUR = 4;
constexpr size_t SOFTMAX_TAIL = 8;
constexpr uint64_t BUFFER_NUM_IN_QUE = 2;
template <typename T>
inline T AlignUp(T num, T rnd) {
return rnd == 0 ? 0 : (num + rnd - 1) / rnd * rnd;
}
template <typename T>
inline T AlignDown(T num, T rnd) {
return rnd == 0 ? 0 : num / rnd * rnd;
}
template <typename T>
inline T CeilDiv(T num, T div) {
return div == 0 ? 0 : (num + div - 1) / div;
}
static ge::graphStatus SafeDivisionCheck(int64_t inputNum) {
if (inputNum == 0) {
return ge::GRAPH_FAILED;
} else {
return ge::GRAPH_SUCCESS;
}
}
static ge::graphStatus RingAttentionUpdateRegbaseCheckDtype(const gert::TilingContext* context) {
auto prevAttnTensor = context->GetInputDesc(0);
OP_CHECK_NULL_WITH_CONTEXT(context, prevAttnTensor);
ge::DataType prevAttnDtype = prevAttnTensor->GetDataType();
if (prevAttnDtype != ge::DT_FLOAT16 && prevAttnDtype != ge::DT_BF16 && prevAttnDtype != ge::DT_FLOAT) {
std::string prevAttnDtypeStr = ToString(prevAttnDtype);
OP_LOGE_FOR_INVALID_DTYPE(context->GetNodeName(), "prev_attn_out",
prevAttnDtypeStr.c_str(), "FLOAT, FLOAT16 or BF16");
return ge::GRAPH_FAILED;
}
auto prevSoftmaxMaxTensor = context->GetInputDesc(1);
OP_CHECK_NULL_WITH_CONTEXT(context, prevSoftmaxMaxTensor);
ge::DataType prevSoftmaxMaxDtype = prevSoftmaxMaxTensor->GetDataType();
if (prevSoftmaxMaxDtype != ge::DT_FLOAT) {
std::string prevSoftmaxMaxDtypeStr = ToString(prevSoftmaxMaxDtype);
OP_LOGE_FOR_INVALID_DTYPE(context->GetNodeName(), "prev_softmax_max",
prevSoftmaxMaxDtypeStr.c_str(), "FLOAT");
return ge::GRAPH_FAILED;
}
auto prevSoftmaxSumTensor = context->GetInputDesc(2);
OP_CHECK_NULL_WITH_CONTEXT(context, prevSoftmaxSumTensor);
ge::DataType prevSoftmaxSumDtype = prevSoftmaxSumTensor->GetDataType();
if (prevSoftmaxSumDtype != ge::DT_FLOAT) {
std::string prevSoftmaxSumDtypeStr = ToString(prevSoftmaxSumDtype);
OP_LOGE_FOR_INVALID_DTYPE(context->GetNodeName(), "prev_softmax_sum",
prevSoftmaxSumDtypeStr.c_str(), "FLOAT");
return ge::GRAPH_FAILED;
}
auto curAttnTensor = context->GetInputDesc(3);
OP_CHECK_NULL_WITH_CONTEXT(context, curAttnTensor);
ge::DataType curAttnDtype = curAttnTensor->GetDataType();
if (curAttnDtype != ge::DT_FLOAT16 && curAttnDtype != ge::DT_BF16 && curAttnDtype != ge::DT_FLOAT) {
std::string curAttnDtypeStr = ToString(curAttnDtype);
OP_LOGE_FOR_INVALID_DTYPE(context->GetNodeName(), "cur_attn_out",
curAttnDtypeStr.c_str(), "FLOAT, FLOAT16 or BF16");
return ge::GRAPH_FAILED;
}
auto curSoftmaxMaxTensor = context->GetInputDesc(4);
OP_CHECK_NULL_WITH_CONTEXT(context, curSoftmaxMaxTensor);
ge::DataType curSoftmaxMaxDtype = curSoftmaxMaxTensor->GetDataType();
if (curSoftmaxMaxDtype != ge::DT_FLOAT) {
std::string curSoftmaxMaxDtypeStr = ToString(curSoftmaxMaxDtype);
OP_LOGE_FOR_INVALID_DTYPE(context->GetNodeName(), "cur_softmax_max",
curSoftmaxMaxDtypeStr.c_str(), "FLOAT");
return ge::GRAPH_FAILED;
}
auto curSoftmaxSumTensor = context->GetInputDesc(5);
OP_CHECK_NULL_WITH_CONTEXT(context, curSoftmaxSumTensor);
ge::DataType curSoftmaxSumDtype = curSoftmaxSumTensor->GetDataType();
if (curSoftmaxSumDtype != ge::DT_FLOAT) {
std::string curSoftmaxSumDtypeStr = ToString(curSoftmaxSumDtype);
OP_LOGE_FOR_INVALID_DTYPE(context->GetNodeName(), "cur_softmax_sum",
curSoftmaxSumDtypeStr.c_str(), "FLOAT");
return ge::GRAPH_FAILED;
}
if (prevAttnDtype != curAttnDtype) {
std::string dtypeMsg = ToString(prevAttnDtype) + " and " + ToString(curAttnDtype);
OP_LOGE_FOR_INVALID_DTYPES_WITH_REASON(context->GetNodeName(), "prev_attn_out and cur_attn_out",
dtypeMsg.c_str(), "The dtypes of input prev_attn_out and input cur_attn_out should be the same");
return ge::GRAPH_FAILED;
}
return ge::GRAPH_SUCCESS;
}
static ge::graphStatus RingAttentionUpdateRegbaseSBHCheckInputShape(const gert::TilingContext* context) {
auto prevAttnShapePtr = context->GetInputShape(0);
OP_CHECK_NULL_WITH_CONTEXT(context, prevAttnShapePtr);
gert::Shape prevAttnShape = prevAttnShapePtr->GetStorageShape();
if (prevAttnShape.GetDimNum() != CONST_THREE) {
std::string prevAttnDimNumStr = std::to_string(prevAttnShape.GetDimNum());
OP_LOGE_FOR_INVALID_SHAPEDIM(context->GetNodeName(), "prev_attn_out",
prevAttnDimNumStr.c_str(), "3D");
return ge::GRAPH_FAILED;
}
auto prevSoftmaxMaxShapePtr = context->GetInputShape(1);
OP_CHECK_NULL_WITH_CONTEXT(context, prevSoftmaxMaxShapePtr);
gert::Shape prevSoftmaxMaxShape = prevSoftmaxMaxShapePtr->GetStorageShape();
if (prevSoftmaxMaxShape.GetDimNum() != CONST_FOUR) {
std::string prevSoftmaxMaxDimNumStr = std::to_string(prevSoftmaxMaxShape.GetDimNum());
OP_LOGE_FOR_INVALID_SHAPEDIM(context->GetNodeName(), "prev_softmax_max",
prevSoftmaxMaxDimNumStr.c_str(), "4D");
return ge::GRAPH_FAILED;
}
if (prevSoftmaxMaxShape.GetDim(CONST_THREE) != SOFTMAX_TAIL) {
std::string reasonMsg = "The last dimension of prev_softmax_max should be " + std::to_string(SOFTMAX_TAIL);
std::string prevSoftmaxMaxShapeStr = ToString(prevSoftmaxMaxShape);
OP_LOGE_FOR_INVALID_SHAPE_WITH_REASON(context->GetNodeName(), "prev_softmax_max",
prevSoftmaxMaxShapeStr.c_str(), reasonMsg.c_str());
return ge::GRAPH_FAILED;
}
auto prevSoftmaxSumShapePtr = context->GetInputShape(2);
OP_CHECK_NULL_WITH_CONTEXT(context, prevSoftmaxSumShapePtr);
gert::Shape prevSoftmaxSumShape = prevSoftmaxSumShapePtr->GetStorageShape();
if (prevSoftmaxSumShape.GetDimNum() != CONST_FOUR) {
std::string prevSoftmaxSumDimNumStr = std::to_string(prevSoftmaxSumShape.GetDimNum());
OP_LOGE_FOR_INVALID_SHAPEDIM(context->GetNodeName(), "prev_softmax_sum",
prevSoftmaxSumDimNumStr.c_str(), "4D");
return ge::GRAPH_FAILED;
}
if (prevSoftmaxSumShape.GetDim(CONST_THREE) != SOFTMAX_TAIL) {
std::string reasonMsg = "The last dimension of prev_softmax_sum should be " + std::to_string(SOFTMAX_TAIL);
std::string prevSoftmaxSumShapeStr = ToString(prevSoftmaxSumShape);
OP_LOGE_FOR_INVALID_SHAPE_WITH_REASON(context->GetNodeName(), "prev_softmax_sum",
prevSoftmaxSumShapeStr.c_str(), reasonMsg.c_str());
return ge::GRAPH_FAILED;
}
auto curAttnShapePtr = context->GetInputShape(3);
OP_CHECK_NULL_WITH_CONTEXT(context, curAttnShapePtr);
gert::Shape curAttnShape = curAttnShapePtr->GetStorageShape();
if (curAttnShape.GetDimNum() != CONST_THREE) {
std::string curAttnDimNumStr = std::to_string(curAttnShape.GetDimNum());
OP_LOGE_FOR_INVALID_SHAPEDIM(context->GetNodeName(), "cur_attn_out",
curAttnDimNumStr.c_str(), "3D");
return ge::GRAPH_FAILED;
}
auto curSoftmaxMaxShapePtr = context->GetInputShape(4);
OP_CHECK_NULL_WITH_CONTEXT(context, curSoftmaxMaxShapePtr);
gert::Shape curSoftmaxMaxShape = curSoftmaxMaxShapePtr->GetStorageShape();
if (curSoftmaxMaxShape.GetDimNum() != CONST_FOUR) {
std::string curSoftmaxMaxDimNumStr = std::to_string(curSoftmaxMaxShape.GetDimNum());
OP_LOGE_FOR_INVALID_SHAPEDIM(context->GetNodeName(), "cur_softmax_max",
curSoftmaxMaxDimNumStr.c_str(), "4D");
return ge::GRAPH_FAILED;
}
if (curSoftmaxMaxShape.GetDim(CONST_THREE) != SOFTMAX_TAIL) {
std::string reasonMsg = "The last dimension of cur_softmax_max should be " + std::to_string(SOFTMAX_TAIL);
std::string curSoftmaxMaxShapeStr = ToString(curSoftmaxMaxShape);
OP_LOGE_FOR_INVALID_SHAPE_WITH_REASON(context->GetNodeName(), "cur_softmax_max",
curSoftmaxMaxShapeStr.c_str(), reasonMsg.c_str());
return ge::GRAPH_FAILED;
}
auto curSoftmaxSumShapePtr = context->GetInputShape(5);
OP_CHECK_NULL_WITH_CONTEXT(context, curSoftmaxSumShapePtr);
gert::Shape curSoftmaxSumShape = curSoftmaxSumShapePtr->GetStorageShape();
if (curSoftmaxSumShape.GetDimNum() != CONST_FOUR) {
std::string curSoftmaxSumDimNumStr = std::to_string(curSoftmaxSumShape.GetDimNum());
OP_LOGE_FOR_INVALID_SHAPEDIM(context->GetNodeName(), "cur_softmax_sum",
curSoftmaxSumDimNumStr.c_str(), "4D");
return ge::GRAPH_FAILED;
}
if (curSoftmaxSumShape.GetDim(CONST_THREE) != SOFTMAX_TAIL) {
std::string reasonMsg = "The last dimension of cur_softmax_sum should be " + std::to_string(SOFTMAX_TAIL);
std::string curSoftmaxSumShapeStr = ToString(curSoftmaxSumShape);
OP_LOGE_FOR_INVALID_SHAPE_WITH_REASON(context->GetNodeName(), "cur_softmax_sum",
curSoftmaxSumShapeStr.c_str(), reasonMsg.c_str());
return ge::GRAPH_FAILED;
}
return ge::GRAPH_SUCCESS;
}
static ge::graphStatus RingAttentionUpdateRegbaseSBHCheckShape(const gert::TilingContext* context) {
OP_CHECK_IF(RingAttentionUpdateRegbaseSBHCheckInputShape(context) != ge::GRAPH_SUCCESS,
OP_LOGE(context->GetNodeName(), "RingAttentionUpdateRegbaseSBHCheckInputShape failed, tiling failed"),
return ge::GRAPH_FAILED);
gert::Shape prevAttnShape = context->GetInputShape(0)->GetStorageShape();
gert::Shape prevSoftmaxMaxShape = context->GetInputShape(1)->GetStorageShape();
gert::Shape prevSoftmaxSumShape = context->GetInputShape(2)->GetStorageShape();
gert::Shape curAttnShape = context->GetInputShape(3)->GetStorageShape();
gert::Shape curSoftmaxMaxShape = context->GetInputShape(4)->GetStorageShape();
gert::Shape curSoftmaxSumShape = context->GetInputShape(5)->GetStorageShape();
if (prevAttnShape.GetDim(CONST_ZERO) != prevSoftmaxMaxShape.GetDim(CONST_TWO) ||
prevAttnShape.GetDim(CONST_ONE) != prevSoftmaxMaxShape.GetDim(CONST_ZERO)) {
std::string shapeMsg = ToString(prevAttnShape) + " and " + ToString(prevSoftmaxMaxShape);
std::string reasonMsg =
"The 0th dim of input prev_attn_out should be equal to the 2nd dim of input prev_softmax_max, "
"and the 1st dim of input prev_attn_out should be equal to the 0th dim of input prev_softmax_max";
OP_LOGE_FOR_INVALID_SHAPES_WITH_REASON(context->GetNodeName(), "prev_attn_out and prev_softmax_max",
shapeMsg.c_str(), reasonMsg.c_str());
return ge::GRAPH_FAILED;
}
if (prevSoftmaxMaxShape.GetDim(CONST_ZERO) != prevSoftmaxSumShape.GetDim(CONST_ZERO) ||
prevSoftmaxMaxShape.GetDim(CONST_ONE) != prevSoftmaxSumShape.GetDim(CONST_ONE) ||
prevSoftmaxMaxShape.GetDim(CONST_TWO) != prevSoftmaxSumShape.GetDim(CONST_TWO)) {
std::string shapeMsg = ToString(prevSoftmaxSumShape) + " and " + ToString(prevSoftmaxMaxShape);
std::string reasonMsg =
"The shape of input prev_softmax_sum should be the same as "
"the shape of input prev_softmax_max";
OP_LOGE_FOR_INVALID_SHAPES_WITH_REASON(context->GetNodeName(), "prev_softmax_sum and prev_softmax_max",
shapeMsg.c_str(), reasonMsg.c_str());
return ge::GRAPH_FAILED;
}
if (curAttnShape.GetDim(CONST_ZERO) != curSoftmaxMaxShape.GetDim(CONST_TWO) ||
curAttnShape.GetDim(CONST_ONE) != curSoftmaxMaxShape.GetDim(CONST_ZERO)) {
std::string shapeMsg = ToString(curAttnShape) + " and " + ToString(curSoftmaxMaxShape);
std::string reasonMsg =
"The 0th dim of input cur_attn_out should be equal to the 2nd dim of input cur_softmax_max, "
"and the 1st dim of input cur_attn_out should be equal to the 0th dim of input cur_softmax_max";
OP_LOGE_FOR_INVALID_SHAPES_WITH_REASON(context->GetNodeName(), "cur_attn_out and cur_softmax_max",
shapeMsg.c_str(), reasonMsg.c_str());
return ge::GRAPH_FAILED;
}
if (curSoftmaxMaxShape.GetDim(CONST_ZERO) != curSoftmaxSumShape.GetDim(CONST_ZERO) ||
curSoftmaxMaxShape.GetDim(CONST_ONE) != curSoftmaxSumShape.GetDim(CONST_ONE) ||
curSoftmaxMaxShape.GetDim(CONST_TWO) != curSoftmaxSumShape.GetDim(CONST_TWO)) {
std::string shapeMsg = ToString(curSoftmaxSumShape) + " and " + ToString(curSoftmaxMaxShape);
std::string reasonMsg =
"The first three dimensions of input cur_softmax_sum and cur_softmax_max should be the same";
OP_LOGE_FOR_INVALID_SHAPES_WITH_REASON(context->GetNodeName(), "cur_softmax_sum and cur_softmax_max",
shapeMsg.c_str(), reasonMsg.c_str());
return ge::GRAPH_FAILED;
}
if (prevSoftmaxMaxShape.GetDim(CONST_ZERO) != curSoftmaxMaxShape.GetDim(CONST_ZERO) ||
prevSoftmaxMaxShape.GetDim(CONST_ONE) != curSoftmaxMaxShape.GetDim(CONST_ONE) ||
prevSoftmaxMaxShape.GetDim(CONST_TWO) != curSoftmaxMaxShape.GetDim(CONST_TWO)) {
std::string shapeMsg = ToString(prevSoftmaxMaxShape) + " and " + ToString(curSoftmaxMaxShape);
std::string reasonMsg =
"The first three dimensions of input prev_softmax_max and cur_softmax_max should be the same";
OP_LOGE_FOR_INVALID_SHAPES_WITH_REASON(context->GetNodeName(), "prev_softmax_max and cur_softmax_max",
shapeMsg.c_str(), reasonMsg.c_str());
return ge::GRAPH_FAILED;
}
return ge::GRAPH_SUCCESS;
}
static ge::graphStatus RingAttentionUpdateRegbaseTNDCheckInputShape(const gert::TilingContext* context) {
auto prevAttnShapePtr = context->GetInputShape(0);
OP_CHECK_NULL_WITH_CONTEXT(context, prevAttnShapePtr);
gert::Shape prevAttnShape = prevAttnShapePtr->GetStorageShape();
if (prevAttnShape.GetDimNum() != CONST_THREE) {
std::string prevAttnDimNumStr = std::to_string(prevAttnShape.GetDimNum());
OP_LOGE_FOR_INVALID_SHAPEDIM(context->GetNodeName(), "prev_attn_out",
prevAttnDimNumStr.c_str(), "3D");
return ge::GRAPH_FAILED;
}
auto prevSoftmaxMaxShapePtr = context->GetInputShape(1);
OP_CHECK_NULL_WITH_CONTEXT(context, prevSoftmaxMaxShapePtr);
gert::Shape prevSoftmaxMaxShape = prevSoftmaxMaxShapePtr->GetStorageShape();
if (prevSoftmaxMaxShape.GetDimNum() != CONST_THREE) {
std::string prevSoftmaxMaxDimNumStr = std::to_string(prevSoftmaxMaxShape.GetDimNum());
OP_LOGE_FOR_INVALID_SHAPEDIM(context->GetNodeName(), "prev_softmax_max",
prevSoftmaxMaxDimNumStr.c_str(), "3D");
return ge::GRAPH_FAILED;
}
if (prevSoftmaxMaxShape.GetDim(CONST_TWO) != SOFTMAX_TAIL) {
std::string reasonMsg = "The last dimension of prev_softmax_max should be " + std::to_string(SOFTMAX_TAIL);
std::string prevSoftmaxMaxShapeStr = ToString(prevSoftmaxMaxShape);
OP_LOGE_FOR_INVALID_SHAPE_WITH_REASON(context->GetNodeName(), "prev_softmax_max",
prevSoftmaxMaxShapeStr.c_str(), reasonMsg.c_str());
return ge::GRAPH_FAILED;
}
auto prevSoftmaxSumShapePtr = context->GetInputShape(2);
OP_CHECK_NULL_WITH_CONTEXT(context, prevSoftmaxSumShapePtr);
gert::Shape prevSoftmaxSumShape = prevSoftmaxSumShapePtr->GetStorageShape();
if (prevSoftmaxSumShape.GetDimNum() != CONST_THREE) {
std::string prevSoftmaxSumDimNumStr = std::to_string(prevSoftmaxSumShape.GetDimNum());
OP_LOGE_FOR_INVALID_SHAPEDIM(context->GetNodeName(), "prev_softmax_sum",
prevSoftmaxSumDimNumStr.c_str(), "3D");
return ge::GRAPH_FAILED;
}
if (prevSoftmaxSumShape.GetDim(CONST_TWO) != SOFTMAX_TAIL) {
std::string reasonMsg = "The last dimension of prev_softmax_sum should be " + std::to_string(SOFTMAX_TAIL);
std::string prevSoftmaxSumShapeStr = ToString(prevSoftmaxSumShape);
OP_LOGE_FOR_INVALID_SHAPE_WITH_REASON(context->GetNodeName(), "prev_softmax_sum",
prevSoftmaxSumShapeStr.c_str(), reasonMsg.c_str());
return ge::GRAPH_FAILED;
}
auto curAttnShapePtr = context->GetInputShape(3);
OP_CHECK_NULL_WITH_CONTEXT(context, curAttnShapePtr);
gert::Shape curAttnShape = curAttnShapePtr->GetStorageShape();
if (curAttnShape.GetDimNum() != CONST_THREE) {
std::string curAttnDimNumStr = std::to_string(curAttnShape.GetDimNum());
OP_LOGE_FOR_INVALID_SHAPEDIM(context->GetNodeName(), "cur_attn_out",
curAttnDimNumStr.c_str(), "3D");
return ge::GRAPH_FAILED;
}
auto curSoftmaxMaxShapePtr = context->GetInputShape(4);
OP_CHECK_NULL_WITH_CONTEXT(context, curSoftmaxMaxShapePtr);
gert::Shape curSoftmaxMaxShape = curSoftmaxMaxShapePtr->GetStorageShape();
if (curSoftmaxMaxShape.GetDimNum() != CONST_THREE) {
std::string curSoftmaxMaxDimNumStr = std::to_string(curSoftmaxMaxShape.GetDimNum());
OP_LOGE_FOR_INVALID_SHAPEDIM(context->GetNodeName(), "cur_softmax_max",
curSoftmaxMaxDimNumStr.c_str(), "3D");
return ge::GRAPH_FAILED;
}
if (curSoftmaxMaxShape.GetDim(CONST_TWO) != SOFTMAX_TAIL) {
std::string reasonMsg = "The last dimension of cur_softmax_max should be " + std::to_string(SOFTMAX_TAIL);
std::string curSoftmaxMaxShapeStr = ToString(curSoftmaxMaxShape);
OP_LOGE_FOR_INVALID_SHAPE_WITH_REASON(context->GetNodeName(), "cur_softmax_max",
curSoftmaxMaxShapeStr.c_str(), reasonMsg.c_str());
return ge::GRAPH_FAILED;
}
auto curSoftmaxSumShapePtr = context->GetInputShape(5);
OP_CHECK_NULL_WITH_CONTEXT(context, curSoftmaxSumShapePtr);
gert::Shape curSoftmaxSumShape = curSoftmaxSumShapePtr->GetStorageShape();
if (curSoftmaxSumShape.GetDimNum() != CONST_THREE) {
std::string curSoftmaxSumDimNumStr = std::to_string(curSoftmaxSumShape.GetDimNum());
OP_LOGE_FOR_INVALID_SHAPEDIM(context->GetNodeName(), "cur_softmax_sum",
curSoftmaxSumDimNumStr.c_str(), "3D");
return ge::GRAPH_FAILED;
}
if (curSoftmaxSumShape.GetDim(CONST_TWO) != SOFTMAX_TAIL) {
std::string reasonMsg = "The last dimension of cur_softmax_sum should be " + std::to_string(SOFTMAX_TAIL);
std::string curSoftmaxSumShapeStr = ToString(curSoftmaxSumShape);
OP_LOGE_FOR_INVALID_SHAPE_WITH_REASON(context->GetNodeName(), "cur_softmax_sum",
curSoftmaxSumShapeStr.c_str(), reasonMsg.c_str());
return ge::GRAPH_FAILED;
}
return ge::GRAPH_SUCCESS;
}
static ge::graphStatus RingAttentionUpdateRegbaseTNDCheckShape(const gert::TilingContext* context) {
OP_CHECK_IF(RingAttentionUpdateRegbaseTNDCheckInputShape(context) != ge::GRAPH_SUCCESS,
OP_LOGE(context->GetNodeName(), "RingAttentionUpdateRegbaseTNDCheckInputShape failed, tiling failed"),
return ge::GRAPH_FAILED);
gert::Shape prevAttnShape = context->GetInputShape(0)->GetStorageShape();
gert::Shape prevSoftmaxMaxShape = context->GetInputShape(1)->GetStorageShape();
gert::Shape prevSoftmaxSumShape = context->GetInputShape(2)->GetStorageShape();
gert::Shape curAttnShape = context->GetInputShape(3)->GetStorageShape();
gert::Shape curSoftmaxMaxShape = context->GetInputShape(4)->GetStorageShape();
gert::Shape curSoftmaxSumShape = context->GetInputShape(5)->GetStorageShape();
if (prevAttnShape.GetDim(CONST_ZERO) != prevSoftmaxMaxShape.GetDim(CONST_ZERO) ||
prevAttnShape.GetDim(CONST_ONE) != prevSoftmaxMaxShape.GetDim(CONST_ONE)) {
std::string shapeMsg = ToString(prevAttnShape) + " and " + ToString(prevSoftmaxMaxShape);
std::string reasonMsg =
"The first two dimensions of input prev_attn_out and prev_softmax_max should be the same";
OP_LOGE_FOR_INVALID_SHAPES_WITH_REASON(context->GetNodeName(), "prev_attn_out and prev_softmax_max",
shapeMsg.c_str(), reasonMsg.c_str());
return ge::GRAPH_FAILED;
}
if (prevSoftmaxMaxShape.GetDim(CONST_ZERO) != prevSoftmaxSumShape.GetDim(CONST_ZERO) ||
prevSoftmaxMaxShape.GetDim(CONST_ONE) != prevSoftmaxSumShape.GetDim(CONST_ONE)) {
std::string shapeMsg = ToString(prevSoftmaxSumShape) + " and " + ToString(prevSoftmaxMaxShape);
std::string reasonMsg =
"The first two dimensions of input prev_softmax_sum and prev_softmax_max should be the same";
OP_LOGE_FOR_INVALID_SHAPES_WITH_REASON(context->GetNodeName(), "prev_softmax_sum and prev_softmax_max",
shapeMsg.c_str(), reasonMsg.c_str());
return ge::GRAPH_FAILED;
}
if (curAttnShape.GetDim(CONST_ZERO) != curSoftmaxMaxShape.GetDim(CONST_ZERO) ||
curAttnShape.GetDim(CONST_ONE) != curSoftmaxMaxShape.GetDim(CONST_ONE)) {
std::string shapeMsg = ToString(curAttnShape) + " and " + ToString(curSoftmaxMaxShape);
std::string reasonMsg =
"The first two dimensions of input cur_attn_out and cur_softmax_max should be the same";
OP_LOGE_FOR_INVALID_SHAPES_WITH_REASON(context->GetNodeName(), "cur_attn_out and cur_softmax_max",
shapeMsg.c_str(), reasonMsg.c_str());
return ge::GRAPH_FAILED;
}
if (curSoftmaxMaxShape.GetDim(CONST_ZERO) != curSoftmaxSumShape.GetDim(CONST_ZERO) ||
curSoftmaxMaxShape.GetDim(CONST_ONE) != curSoftmaxSumShape.GetDim(CONST_ONE)) {
std::string shapeMsg = ToString(curSoftmaxSumShape) + " and " + ToString(curSoftmaxMaxShape);
std::string reasonMsg =
"The first two dimensions of input cur_softmax_sum and cur_softmax_max should be the same";
OP_LOGE_FOR_INVALID_SHAPES_WITH_REASON(context->GetNodeName(), "cur_softmax_sum and cur_softmax_max",
shapeMsg.c_str(), reasonMsg.c_str());
return ge::GRAPH_FAILED;
}
if (prevSoftmaxMaxShape.GetDim(CONST_ZERO) != curSoftmaxMaxShape.GetDim(CONST_ZERO) ||
prevSoftmaxMaxShape.GetDim(CONST_ONE) != curSoftmaxMaxShape.GetDim(CONST_ONE)) {
std::string shapeMsg = ToString(prevSoftmaxMaxShape) + " and " + ToString(curSoftmaxMaxShape);
std::string reasonMsg =
"The first two dimensions of input prev_softmax_max and cur_softmax_max should be the same";
OP_LOGE_FOR_INVALID_SHAPES_WITH_REASON(context->GetNodeName(), "prev_softmax_max and cur_softmax_max",
shapeMsg.c_str(), reasonMsg.c_str());
return ge::GRAPH_FAILED;
}
return ge::GRAPH_SUCCESS;
}
static void RingAttentionUpdatePrintParamRegbaseSoftmaxTND(const gert::TilingContext* context, RingAttentionUpdateRegbaseSoftmaxTNDTilingData& tiling) {
OP_LOGD(context->GetNodeName(), "dimT = %ld", tiling.get_dimT());
OP_LOGD(context->GetNodeName(), "dimN = %ld", tiling.get_dimN());
OP_LOGD(context->GetNodeName(), "dimD = %ld", tiling.get_dimD());
OP_LOGD(context->GetNodeName(), "softmaxTailSize = %ld", tiling.get_softmaxTailSize());
OP_LOGD(context->GetNodeName(), "batchSize = %ld", tiling.get_batchSize());
OP_LOGD(context->GetNodeName(), "usedVectorCoreNum = %ld", tiling.get_usedVectorCoreNum());
OP_LOGD(context->GetNodeName(), "tnNumCoreEach = %ld", tiling.get_tnNumCoreEach());
OP_LOGD(context->GetNodeName(), "tnNumCoreTail = %ld", tiling.get_tnNumCoreTail());
OP_LOGD(context->GetNodeName(), "tnNumLoopEach = %ld", tiling.get_tnNumLoopEach());
OP_LOGD(context->GetNodeName(), "headDimLoopEach = %ld", tiling.get_headDimLoopEach());
}
static void RingAttentionUpdatePrintParamRegbaseTND(const gert::TilingContext* context, RingAttentionUpdateRegbaseTNDTilingData& tiling) {
OP_LOGD(context->GetNodeName(), "dimT = %ld", tiling.get_dimT());
OP_LOGD(context->GetNodeName(), "dimN = %ld", tiling.get_dimN());
OP_LOGD(context->GetNodeName(), "dimD = %ld", tiling.get_dimD());
OP_LOGD(context->GetNodeName(), "softmaxTailSize = %ld", tiling.get_softmaxTailSize());
OP_LOGD(context->GetNodeName(), "batchSize = %ld", tiling.get_batchSize());
OP_LOGD(context->GetNodeName(), "usedVectorCoreNum = %ld", tiling.get_usedVectorCoreNum());
OP_LOGD(context->GetNodeName(), "dimTCoreEach = %ld", tiling.get_dimTCoreEach());
OP_LOGD(context->GetNodeName(), "dimTCoreTail = %ld", tiling.get_dimTCoreTail());
OP_LOGD(context->GetNodeName(), "seqNumLoopEach = %ld", tiling.get_seqNumLoopEach());
OP_LOGD(context->GetNodeName(), "headNumLoopEach = %ld", tiling.get_headNumLoopEach());
OP_LOGD(context->GetNodeName(), "headDimLoopEach = %ld", tiling.get_headDimLoopEach());
}
static void RingAttentionUpdatePrintParamRegbaseSBH(const gert::TilingContext* context, RingAttentionUpdateRegbaseSBHTilingData& tiling) {
OP_LOGD(context->GetNodeName(), "dimB = %ld", tiling.get_dimB());
OP_LOGD(context->GetNodeName(), "dimS = %ld", tiling.get_dimS());
OP_LOGD(context->GetNodeName(), "dimN = %ld", tiling.get_dimN());
OP_LOGD(context->GetNodeName(), "dimD = %ld", tiling.get_dimD());
OP_LOGD(context->GetNodeName(), "softmaxTailSize = %ld", tiling.get_softmaxTailSize());
OP_LOGD(context->GetNodeName(), "usedVectorCoreNum = %ld", tiling.get_usedVectorCoreNum());
OP_LOGD(context->GetNodeName(), "coreNumGroup = %ld", tiling.get_coreNumGroup());
OP_LOGD(context->GetNodeName(), "bnNumGroup = %ld", tiling.get_bnNumGroup());
OP_LOGD(context->GetNodeName(), "seqNumCoreEach = %ld", tiling.get_seqNumCoreEach());
OP_LOGD(context->GetNodeName(), "seqNumCoreTail = %ld", tiling.get_seqNumCoreTail());
OP_LOGD(context->GetNodeName(), "seqNumLoopEach = %ld", tiling.get_seqNumLoopEach());
OP_LOGD(context->GetNodeName(), "headDimLoopEach = %ld", tiling.get_headDimLoopEach());
}
static int64_t GetInputDtypeSize(const gert::TilingContext* context) {
int64_t inputDtypeSize = 0;
auto attnTensor = context->GetInputDesc(0);
OP_CHECK_NULL_WITH_CONTEXT(context, attnTensor);
auto attnDtype = attnTensor->GetDataType();
if (attnDtype == ge::DT_FLOAT) {
inputDtypeSize = SIZE_B32;
} else if (attnDtype == ge::DT_FLOAT16 || attnDtype == ge::DT_BF16) {
inputDtypeSize = SIZE_B16;
} else {
std::string attnDtypeStr = ToString(attnDtype);
OP_LOGE_FOR_INVALID_DTYPE(context->GetNodeName(), "prev_attn_out",
attnDtypeStr.c_str(), "FLOAT, FLOAT16 or BF16");
}
OP_LOGD(context->GetNodeName(), "input data type size = %d", inputDtypeSize);
return inputDtypeSize;
}
static ge::graphStatus RingAttentionUpdateRegbaseSoftmaxTNDSplitCore(const gert::TilingContext* context, RingAttentionUpdateRegbaseSoftmaxTNDTilingData& tiling) {
int64_t dimT = tiling.get_dimT();
int64_t dimN = tiling.get_dimN();
const auto ascendcPlatform = platform_ascendc::PlatformAscendC(context->GetPlatformInfo());
auto maxCoreNum = ascendcPlatform.GetCoreNumAiv();
int64_t tnNumCoreEach = CeilDiv<int64_t>(dimT * dimN, maxCoreNum);
int64_t usedVectorCoreNum = CeilDiv<int64_t>(dimT * dimN, tnNumCoreEach);
int64_t tnNumCoreTail = dimT * dimN - tnNumCoreEach * (usedVectorCoreNum - 1);
tiling.set_tnNumCoreEach(tnNumCoreEach);
tiling.set_tnNumCoreTail(tnNumCoreTail);
tiling.set_usedVectorCoreNum(usedVectorCoreNum);
return ge::GRAPH_SUCCESS;
}
static ge::graphStatus RingAttentionUpdateRegbaseSoftmaxTNDSplitLoop(const gert::TilingContext* context, RingAttentionUpdateRegbaseSoftmaxTNDTilingData& tiling) {
uint64_t ubSize = 0;
const auto ascendcPlatform = platform_ascendc::PlatformAscendC(context->GetPlatformInfo());
ascendcPlatform.GetCoreMemSize(platform_ascendc::CoreMemType::UB, ubSize);
int64_t dimD = tiling.get_dimD();
int64_t softmaxTailSize = tiling.get_softmaxTailSize();
int64_t inputDtypeSize = GetInputDtypeSize(context);
OP_CHECK_IF(inputDtypeSize <= 0, OP_LOGE(context->GetNodeName(), "Dtype only support fp16, fp32, bf16 currently."), return ge::GRAPH_FAILED);
int64_t doubleBufferNum = 2;
int64_t softmaxQueueNum = 4 + 2;
int64_t softmaxBufferTempNum = 2;
int64_t attnQueueNum = 2 + 1;
int64_t softmaxEleSize = softmaxQueueNum * doubleBufferNum * SIZE_B32 + softmaxBufferTempNum * SIZE_B32;
int64_t attnEleSize = attnQueueNum * doubleBufferNum * inputDtypeSize;
OP_CHECK_IF(SafeDivisionCheck(softmaxTailSize) != ge::GRAPH_SUCCESS,
OP_LOGE(context->GetNodeName(), "Division by zero(softmaxTailSize) is not supported"),
return ge::GRAPH_FAILED);
int64_t tnNumLoopMin = REPEAT_NUM_B32 / softmaxTailSize;
int64_t softmaxSizeMin = tnNumLoopMin * softmaxTailSize * softmaxEleSize;
int64_t ubSizeRemain = ubSize - softmaxSizeMin;
int64_t headDimLoopAlign = REPEAT_NUM_B32;
int64_t headDimLoopMax = ubSizeRemain / (tnNumLoopMin * attnEleSize);
headDimLoopMax = headDimLoopMax / headDimLoopAlign * headDimLoopAlign;
int64_t tnNumLoopEach;
int64_t headDimLoopEach;
if (dimD < headDimLoopMax) {
headDimLoopEach = (dimD + headDimLoopAlign - 1) / headDimLoopAlign * headDimLoopAlign;
tnNumLoopEach = ubSize / (softmaxTailSize * softmaxEleSize + headDimLoopEach * attnEleSize);
} else {
headDimLoopEach = headDimLoopMax;
tnNumLoopEach = tnNumLoopMin;
}
tiling.set_tnNumLoopEach(tnNumLoopEach);
tiling.set_headDimLoopEach(headDimLoopEach);
return ge::GRAPH_SUCCESS;
}
static ge::graphStatus Tiling4RingAttentionUpdateRegbaseSoftmaxTND(const gert::TilingContext* context, RingAttentionUpdateRegbaseSoftmaxTNDTilingData& tiling) {
auto prevAttnOutShapePtr = context->GetInputShape(0);
OP_CHECK_NULL_WITH_CONTEXT(context, prevAttnOutShapePtr);
gert::Shape prevAttnOutShape = prevAttnOutShapePtr->GetStorageShape();
auto prevSoftmaxMaxShapePtr = context->GetInputShape(1);
OP_CHECK_NULL_WITH_CONTEXT(context, prevSoftmaxMaxShapePtr);
gert::Shape prevSoftmaxMaxShape = prevSoftmaxMaxShapePtr->GetStorageShape();
auto actualSeqQlenShapePtr = context->GetInputShape(6);
OP_CHECK_NULL_WITH_CONTEXT(context, actualSeqQlenShapePtr);
gert::Shape actualSeqQlenShape = actualSeqQlenShapePtr->GetStorageShape();
int64_t batchSize = actualSeqQlenShape.GetDim(0) - 1;
int64_t dimT = prevAttnOutShape.GetDim(0);
int64_t dimN = prevAttnOutShape.GetDim(1);
int64_t dimD = prevAttnOutShape.GetDim(2);
int64_t softmaxTailSize = prevSoftmaxMaxShape.GetDim(2);
if (batchSize <= 0) {
std::string actualSeqQlenShapeStr = ToString(actualSeqQlenShape);
OP_LOGE_FOR_INVALID_SHAPE_WITH_REASON(context->GetNodeName(), "actual_seq_qlen",
actualSeqQlenShapeStr.c_str(),
"The batch of input actual_seq_qlen should be greater than 1, "
"where batch refers to the 0th dim");
return ge::GRAPH_FAILED;
}
tiling.set_dimT(dimT);
tiling.set_dimN(dimN);
tiling.set_dimD(dimD);
tiling.set_softmaxTailSize(softmaxTailSize);
tiling.set_batchSize(batchSize);
OP_CHECK_IF(RingAttentionUpdateRegbaseSoftmaxTNDSplitCore(context, tiling) != ge::GRAPH_SUCCESS,
OP_LOGE(context->GetNodeName(), "RingAttentionUpdateRegbaseSoftmaxTNDSplitCore failed."),
return ge::GRAPH_FAILED);
OP_CHECK_IF(RingAttentionUpdateRegbaseSoftmaxTNDSplitLoop(context, tiling) != ge::GRAPH_SUCCESS,
OP_LOGE(context->GetNodeName(), "RingAttentionUpdateRegbaseSoftmaxTNDSplitLoop failed."),
return ge::GRAPH_FAILED);
return ge::GRAPH_SUCCESS;
}
static ge::graphStatus RingAttentionUpdateRegbaseTNDSplitCore(const gert::TilingContext* context, RingAttentionUpdateRegbaseTNDTilingData& tiling) {
int64_t dimT = tiling.get_dimT();
const auto ascendcPlatform = platform_ascendc::PlatformAscendC(context->GetPlatformInfo());
auto maxCoreNum = ascendcPlatform.GetCoreNumAiv();
int64_t dimTCoreEach = CeilDiv<int64_t>(dimT, maxCoreNum);
int64_t usedVectorCoreNum = CeilDiv<int64_t>(dimT, dimTCoreEach);
int64_t dimTCoreTail = dimT - dimTCoreEach * (usedVectorCoreNum - 1);
tiling.set_dimTCoreEach(dimTCoreEach);
tiling.set_dimTCoreTail(dimTCoreTail);
tiling.set_usedVectorCoreNum(usedVectorCoreNum);
return ge::GRAPH_SUCCESS;
}
static ge::graphStatus RingAttentionUpdateRegbaseTNDSplitLoop(const gert::TilingContext* context, RingAttentionUpdateRegbaseTNDTilingData& tiling) {
uint64_t ubSizeTotal = 0;
const auto ascendcPlatform = platform_ascendc::PlatformAscendC(context->GetPlatformInfo());
ascendcPlatform.GetCoreMemSize(platform_ascendc::CoreMemType::UB, ubSizeTotal);
int64_t dimN = tiling.get_dimN();
int64_t dimD = tiling.get_dimD();
int64_t softmaxTailSize = tiling.get_softmaxTailSize();
int64_t inputDtypeSize = GetInputDtypeSize(context);
OP_CHECK_IF(inputDtypeSize <= 0, OP_LOGE(context->GetNodeName(), "Dtype only support fp16, fp32, bf16 currently."), return ge::GRAPH_FAILED);
int64_t seqNumLoopEach = 1;
int64_t headNumLoopEach;
int64_t headDimLoopEach;
int64_t seqNumLoopMin = 1;
int64_t doubleBufferNum = 2;
int64_t softmaxQueueNum = 4 + 2;
int64_t softmaxBufferTempNum = 2 + 2;
int64_t attnQueueNum = 2 + 1;
int64_t softmaxEleSize = softmaxQueueNum * doubleBufferNum * SIZE_B32 + softmaxBufferTempNum * SIZE_B32;
int64_t attnEleSize = attnQueueNum * doubleBufferNum * inputDtypeSize;
int64_t headDimAlign = (dimD + REPEAT_NUM_B32 - 1) / REPEAT_NUM_B32 * REPEAT_NUM_B32;
int64_t ubSize = (int64_t)ubSizeTotal;
if (seqNumLoopMin * dimN * softmaxTailSize * softmaxEleSize + seqNumLoopMin * dimN * headDimAlign * attnEleSize < ubSize) {
OP_LOGD(context->GetNodeName(), "dimN & dimD is very small, UB can load multi Seq");
seqNumLoopEach = ubSize / (dimN * softmaxTailSize * softmaxEleSize + dimN * headDimAlign * attnEleSize);
headNumLoopEach = dimN;
headDimLoopEach = headDimAlign;
} else {
OP_LOGD(context->GetNodeName(), "dimN & dimD is big, UB can only load 1 Seq");
softmaxBufferTempNum = CONST_TWO;
softmaxEleSize = softmaxQueueNum * doubleBufferNum * SIZE_B32 + softmaxBufferTempNum * SIZE_B32;
seqNumLoopEach = 1;
int64_t headNumLoopMin = REPEAT_NUM_B32 / softmaxTailSize;
int64_t softmaxSizeMin = headNumLoopMin * softmaxTailSize * softmaxEleSize;
int64_t ubSizeRemain = ubSize - softmaxSizeMin;
int64_t headDimLoopMax = ubSizeRemain / (headNumLoopMin * attnEleSize);
headDimLoopMax = headDimLoopMax / REPEAT_NUM_B32 * REPEAT_NUM_B32;
if (dimD < headDimLoopMax) {
headDimLoopEach = (dimD + REPEAT_NUM_B32 - 1) / REPEAT_NUM_B32 * REPEAT_NUM_B32;
headNumLoopEach = ubSize / (softmaxTailSize * softmaxEleSize + headDimLoopEach * attnEleSize);
} else {
headDimLoopEach = headDimLoopMax;
headNumLoopEach = headNumLoopMin;
}
}
tiling.set_seqNumLoopEach(seqNumLoopEach);
tiling.set_headNumLoopEach(headNumLoopEach);
tiling.set_headDimLoopEach(headDimLoopEach);
return ge::GRAPH_SUCCESS;
}
static ge::graphStatus Tiling4RingAttentionUpdateRegbaseTND(const gert::TilingContext* context, RingAttentionUpdateRegbaseTNDTilingData& tiling) {
auto actualSeqQlenShapePtr = context->GetInputShape(6);
OP_CHECK_NULL_WITH_CONTEXT(context, actualSeqQlenShapePtr);
gert::Shape actualSeqQlenShape = actualSeqQlenShapePtr->GetStorageShape();
auto prevAttnOutShapePtr = context->GetInputShape(0);
OP_CHECK_NULL_WITH_CONTEXT(context, prevAttnOutShapePtr);
gert::Shape prevAttnOutShape = prevAttnOutShapePtr->GetStorageShape();
auto prevSoftmaxMaxShapePtr = context->GetInputShape(1);
OP_CHECK_NULL_WITH_CONTEXT(context, prevSoftmaxMaxShapePtr);
gert::Shape prevSoftmaxMaxShape = prevSoftmaxMaxShapePtr->GetStorageShape();
int64_t dimT = prevAttnOutShape.GetDim(0);
int64_t dimN = prevAttnOutShape.GetDim(1);
int64_t dimD = prevAttnOutShape.GetDim(2);
int64_t batchSize = actualSeqQlenShape.GetDim(0) - 1;
int64_t softmaxTailSize = prevSoftmaxMaxShape.GetDim(2);
if (batchSize <= 0) {
std::string actualSeqQlenShapeStr = ToString(actualSeqQlenShape);
OP_LOGE_FOR_INVALID_SHAPE_WITH_REASON(context->GetNodeName(), "actual_seq_qlen",
actualSeqQlenShapeStr.c_str(),
"The batch of input actual_seq_qlen should be greater than 1, "
"where batch refers to the 0th dim");
return ge::GRAPH_FAILED;
}
tiling.set_dimD(dimD);
tiling.set_dimN(dimN);
tiling.set_dimT(dimT);
tiling.set_softmaxTailSize(softmaxTailSize);
tiling.set_batchSize(batchSize);
OP_CHECK_IF(RingAttentionUpdateRegbaseTNDSplitCore(context, tiling) != ge::GRAPH_SUCCESS,
OP_LOGE(context->GetNodeName(), "RingAttentionUpdateRegbaseTNDSplitCore failed."),
return ge::GRAPH_FAILED);
OP_CHECK_IF(RingAttentionUpdateRegbaseTNDSplitLoop(context, tiling) != ge::GRAPH_SUCCESS,
OP_LOGE(context->GetNodeName(), "RingAttentionUpdateRegbaseTNDSplitLoop failed."),
return ge::GRAPH_FAILED);
return ge::GRAPH_SUCCESS;
}
static int64_t RingAttentionUpdateRegbaseGcd(int64_t inputNum0, int64_t inputNum1) {
if (inputNum1 == 0) {
return inputNum0;
} else {
return RingAttentionUpdateRegbaseGcd(inputNum1, inputNum0 % inputNum1);
}
}
static ge::graphStatus RingAttentionUpdateRegbaseSBHSplitCore(const gert::TilingContext* context, RingAttentionUpdateRegbaseSBHTilingData& tiling) {
const auto ascendcPlatform = platform_ascendc::PlatformAscendC(context->GetPlatformInfo());
auto maxCoreNum = ascendcPlatform.GetCoreNumAiv();
int64_t dimS = tiling.get_dimS();
int64_t dimB = tiling.get_dimB();
int64_t dimN = tiling.get_dimN();
int64_t bnNum = dimB * dimN;
int64_t groupNumTmpMax = 0;
int64_t maxCoreNumTmp = maxCoreNum;
for (int64_t core = maxCoreNum; core >= 1; core--) {
int64_t groupNumTmp = RingAttentionUpdateRegbaseGcd(bnNum, core);
if (groupNumTmp > groupNumTmpMax) {
groupNumTmpMax = groupNumTmp;
maxCoreNumTmp = core;
}
}
int64_t groupNum = groupNumTmpMax;
maxCoreNum = maxCoreNumTmp;
OP_LOGD(context->GetNodeName(), "groupNum = %ld", groupNum);
OP_CHECK_IF(SafeDivisionCheck(groupNum) != ge::GRAPH_SUCCESS,
OP_LOGE(context->GetNodeName(), "Division by zero(groupNum) is not supported"),
return ge::GRAPH_FAILED);
int64_t coreNumGroup = maxCoreNum / groupNum;
int64_t bnNumGroup = bnNum / groupNum;
int64_t seqNumCoreEach = CeilDiv<int64_t>(dimS, coreNumGroup);
coreNumGroup = CeilDiv<int64_t>(dimS, seqNumCoreEach);
int64_t seqNumCoreTail = dimS - (coreNumGroup - 1) * seqNumCoreEach;
int64_t usedVectorCoreNum = coreNumGroup * groupNum;
tiling.set_usedVectorCoreNum(usedVectorCoreNum);
tiling.set_coreNumGroup(coreNumGroup);
tiling.set_bnNumGroup(bnNumGroup);
tiling.set_seqNumCoreEach(seqNumCoreEach);
tiling.set_seqNumCoreTail(seqNumCoreTail);
return ge::GRAPH_SUCCESS;
}
static ge::graphStatus RingAttentionUpdateRegbaseSBHSplitLoop(const gert::TilingContext* context, RingAttentionUpdateRegbaseSBHTilingData& tiling) {
uint64_t maxUbSize;
const auto ascendcPlatform = platform_ascendc::PlatformAscendC(context->GetPlatformInfo());
ascendcPlatform.GetCoreMemSize(platform_ascendc::CoreMemType::UB, maxUbSize);
int64_t dimD = tiling.get_dimD();
int64_t softmaxTailSize = tiling.get_softmaxTailSize();
int64_t inputDtypeSize = GetInputDtypeSize(context);
OP_CHECK_IF(inputDtypeSize <= 0, OP_LOGE(context->GetNodeName(), "Dtype only support fp16, fp32, bf16 currently."), return ge::GRAPH_FAILED);
int64_t doubleBufferNum = 2;
int64_t softmaxQueueNum = 4 + 2;
int64_t softmaxBufferTempNum = 2;
int64_t attnQueueNum = 3;
int64_t softmaxEleSize = softmaxQueueNum * doubleBufferNum * SIZE_B32 + softmaxBufferTempNum * SIZE_B32;
int64_t attnEleSize = attnQueueNum * doubleBufferNum * inputDtypeSize;
int64_t seqNumLoopMin = REPEAT_NUM_B32 / softmaxTailSize;
int64_t softmaxSizeMin = seqNumLoopMin * softmaxTailSize * softmaxEleSize;
int64_t ubSizeRemain = maxUbSize - softmaxSizeMin;
OP_CHECK_IF(SafeDivisionCheck(seqNumLoopMin * attnEleSize) != ge::GRAPH_SUCCESS,
OP_LOGE(context->GetNodeName(), "Division by zero(seqNumLoopMin or attnEleSize) is not supported"),
return ge::GRAPH_FAILED);
int64_t headDimLoopMax = ubSizeRemain / (seqNumLoopMin * attnEleSize);
headDimLoopMax = headDimLoopMax / REPEAT_NUM_B32 * REPEAT_NUM_B32;
int64_t seqNumLoopEach;
int64_t headDimLoopEach;
if (dimD < headDimLoopMax) {
headDimLoopEach = (dimD + REPEAT_NUM_B32 - 1) / REPEAT_NUM_B32 * REPEAT_NUM_B32;
seqNumLoopEach = maxUbSize / (softmaxTailSize * softmaxEleSize + headDimLoopEach * attnEleSize);
} else {
headDimLoopEach = headDimLoopMax;
seqNumLoopEach = seqNumLoopMin;
}
tiling.set_seqNumLoopEach(seqNumLoopEach);
tiling.set_headDimLoopEach(headDimLoopEach);
return ge::GRAPH_SUCCESS;
}
static ge::graphStatus Tiling4RingAttentionUpdateRegbaseSBH(const gert::TilingContext* context, RingAttentionUpdateRegbaseSBHTilingData& tiling) {
auto prevAttnOutShapePtr = context->GetInputShape(0);
OP_CHECK_NULL_WITH_CONTEXT(context, prevAttnOutShapePtr);
gert::Shape prevAttnOutShape = prevAttnOutShapePtr->GetStorageShape();
auto prevSoftmaxMaxShapePtr = context->GetInputShape(1);
OP_CHECK_NULL_WITH_CONTEXT(context, prevSoftmaxMaxShapePtr);
gert::Shape prevSoftmaxMaxShape = prevSoftmaxMaxShapePtr->GetStorageShape();
int64_t dimB = prevSoftmaxMaxShape.GetDim(0);
int64_t dimN = prevSoftmaxMaxShape.GetDim(1);
int64_t dimS = prevSoftmaxMaxShape.GetDim(2);
int64_t dimH = prevAttnOutShape.GetDim(2);
if (SafeDivisionCheck(dimN) != ge::GRAPH_SUCCESS) {
std::string prevSoftmaxMaxShapeStr = ToString(prevSoftmaxMaxShape);
OP_LOGE_FOR_INVALID_SHAPE_WITH_REASON(context->GetNodeName(), "prev_softmax_max",
prevSoftmaxMaxShapeStr.c_str(),
"The N axis of input prev_softmax_max can not be 0, where N refers to the 1st dim of prev_softmax_max");
return ge::GRAPH_FAILED;
}
if (dimH % dimN != 0) {
std::string shapeMsg = ToString(prevAttnOutShape) + " and " + ToString(prevSoftmaxMaxShape);
std::string reasonMsg = "The H axis of input prev_attn_out must be divisible by the N axis of input prev_softmax_max, "
"where H refers to 2nd dim of prev_attn_out and N refers to the 1st dim of prev_softmax_max";
OP_LOGE_FOR_INVALID_SHAPES_WITH_REASON(context->GetNodeName(), "prev_attn_out and prev_softmax_max",
shapeMsg.c_str(), reasonMsg.c_str());
return ge::GRAPH_FAILED;
}
int64_t dimD = dimH / dimN;
int64_t softmaxTailSize = prevSoftmaxMaxShape.GetDim(3);
tiling.set_dimB(dimB);
tiling.set_dimS(dimS);
tiling.set_dimN(dimN);
tiling.set_dimD(dimD);
tiling.set_softmaxTailSize(softmaxTailSize);
OP_LOGD(context->GetNodeName(), "RingAttentionUpdateRegbaseSBHTiling RingAttentionUpdateRegbaseSBHSplitCore");
OP_CHECK_IF(RingAttentionUpdateRegbaseSBHSplitCore(context, tiling) != ge::GRAPH_SUCCESS,
OP_LOGE(context->GetNodeName(), "RingAttentionUpdateRegbaseSBHSplitCore failed."),
return ge::GRAPH_FAILED);
OP_CHECK_IF(RingAttentionUpdateRegbaseSBHSplitLoop(context, tiling) != ge::GRAPH_SUCCESS,
OP_LOGE(context->GetNodeName(), "RingAttentionUpdateRegbaseSBHSplitLoop failed."),
return ge::GRAPH_FAILED);
return ge::GRAPH_SUCCESS;
}
static int64_t GetTndSoftmaxLayout(gert::TilingContext* context) {
auto attrs = context->GetAttrs();
int64_t tndSoftmaxLayout = 0;
const char* inputSoftmaxLayout = attrs->GetAttrPointer<char>(1);
if (inputSoftmaxLayout == nullptr) {
tndSoftmaxLayout = 0;
} else {
std::string inputSoftmaxLayoutStr = inputSoftmaxLayout;
if (inputSoftmaxLayoutStr == "TND") {
tndSoftmaxLayout = 1;
} else if (inputSoftmaxLayoutStr == "" || inputSoftmaxLayoutStr == "SBH") {
tndSoftmaxLayout = 0;
} else {
tndSoftmaxLayout = -1;
}
}
return tndSoftmaxLayout;
}
static ge::graphStatus RingAttentionUpdateRegbaseSoftmaxTNDTiling(gert::TilingContext* context) {
RingAttentionUpdateRegbaseSoftmaxTNDTilingData tiling;
OP_CHECK_NULL_WITH_CONTEXT(context, context->GetRawTilingData());
OP_CHECK_NULL_WITH_CONTEXT(context, context->GetRawTilingData()->GetData());
OP_CHECK_IF(memset_s(context->GetRawTilingData()->GetData(), context->GetRawTilingData()->GetCapacity(), 0,
context->GetRawTilingData()->GetCapacity()) != EOK,
OP_LOGE(context->GetNodeName(), "Fail to clear softmaxTND tiling data"), return ge::GRAPH_FAILED);
OP_CHECK_IF(Tiling4RingAttentionUpdateRegbaseSoftmaxTND(context, tiling) != ge::GRAPH_SUCCESS,
OP_LOGE(context->GetNodeName(), "Tiling4RingAttentionUpdateRegbaseSoftmaxTND failed, tiling failed"),
return ge::GRAPH_FAILED);
RingAttentionUpdatePrintParamRegbaseSoftmaxTND(context, tiling);
tiling.SaveToBuffer(context->GetRawTilingData()->GetData(), context->GetRawTilingData()->GetCapacity());
context->GetRawTilingData()->SetDataSize(tiling.GetDataSize());
context->SetBlockDim(tiling.get_usedVectorCoreNum());
return ge::GRAPH_SUCCESS;
}
static ge::graphStatus RingAttentionUpdateRegbaseTNDTiling(gert::TilingContext* context) {
RingAttentionUpdateRegbaseTNDTilingData tiling;
OP_CHECK_NULL_WITH_CONTEXT(context, context->GetRawTilingData());
OP_CHECK_NULL_WITH_CONTEXT(context, context->GetRawTilingData()->GetData());
OP_CHECK_IF(memset_s(context->GetRawTilingData()->GetData(), context->GetRawTilingData()->GetCapacity(), 0,
context->GetRawTilingData()->GetCapacity()) != EOK,
OP_LOGE(context->GetNodeName(), "Fail to clear TND tiling data"), return ge::GRAPH_FAILED);
OP_CHECK_IF(Tiling4RingAttentionUpdateRegbaseTND(context, tiling) != ge::GRAPH_SUCCESS,
OP_LOGE(context->GetNodeName(), "Tiling4RingAttentionUpdateRegbaseTND failed, tiling failed"),
return ge::GRAPH_FAILED);
RingAttentionUpdatePrintParamRegbaseTND(context, tiling);
tiling.SaveToBuffer(context->GetRawTilingData()->GetData(), context->GetRawTilingData()->GetCapacity());
context->GetRawTilingData()->SetDataSize(tiling.GetDataSize());
context->SetBlockDim(tiling.get_usedVectorCoreNum());
return ge::GRAPH_SUCCESS;
}
static ge::graphStatus RingAttentionUpdateRegbaseSBHTiling(gert::TilingContext* context) {
RingAttentionUpdateRegbaseSBHTilingData tiling;
OP_CHECK_NULL_WITH_CONTEXT(context, context->GetRawTilingData());
OP_CHECK_NULL_WITH_CONTEXT(context, context->GetRawTilingData()->GetData());
OP_CHECK_IF(memset_s(context->GetRawTilingData()->GetData(), context->GetRawTilingData()->GetCapacity(), 0,
context->GetRawTilingData()->GetCapacity()) != EOK,
OP_LOGE(context->GetNodeName(), "Fail to clear SBH tiling data"), return ge::GRAPH_FAILED);
OP_CHECK_IF(Tiling4RingAttentionUpdateRegbaseSBH(context, tiling) != ge::GRAPH_SUCCESS,
OP_LOGE(context->GetNodeName(), "Tiling4RingAttentionUpdateRegbaseSBH failed, tiling failed"),
return ge::GRAPH_FAILED);
RingAttentionUpdatePrintParamRegbaseSBH(context, tiling);
tiling.SaveToBuffer(context->GetRawTilingData()->GetData(), context->GetRawTilingData()->GetCapacity());
context->GetRawTilingData()->SetDataSize(tiling.GetDataSize());
context->SetBlockDim(tiling.get_usedVectorCoreNum());
return ge::GRAPH_SUCCESS;
}
ge::graphStatus Tiling4RingAttentionUpdateRegbase(gert::TilingContext* context) {
OP_LOGD(context->GetNodeName(), "RingAttentionUpdateRegbaseCheckDtype start");
OP_CHECK_IF(RingAttentionUpdateRegbaseCheckDtype(context) != ge::GRAPH_SUCCESS,
OP_LOGE(context->GetNodeName(), "RingAttentionUpdateRegbaseCheckDtype failed."), return ge::GRAPH_FAILED);
auto attrs = context->GetAttrs();
OP_CHECK_NULL_WITH_CONTEXT(context, attrs);
const char* inputLayout = attrs->GetAttrPointer<char>(0);
OP_CHECK_IF(inputLayout == nullptr,
OP_LOGE(context->GetNodeName(), "Get required attr input_layout failed, tiling failed"), return ge::GRAPH_FAILED);
std::string inputLayoutStr = inputLayout;
int64_t tndSoftmaxLayout = GetTndSoftmaxLayout(context);
OP_CHECK_IF(tndSoftmaxLayout == -1,
OP_LOGE(context->GetNodeName(), "Get required attr input_softmax_layout failed, tiling failed"), return ge::GRAPH_FAILED);
uint32_t tilingKey = REGBASE_KEY;
if (inputLayoutStr == "TND") {
OP_LOGD(context->GetNodeName(), "Attr input_layout is TND.");
OP_CHECK_IF(RingAttentionUpdateRegbaseTNDCheckShape(context) != ge::GRAPH_SUCCESS,
OP_LOGE(context->GetNodeName(), "RingAttentionUpdateRegbaseTNDCheckShape failed."), return ge::GRAPH_FAILED);
if (tndSoftmaxLayout == 1) {
tilingKey += SOFTMAX_TND_KEY;
OP_CHECK_IF(RingAttentionUpdateRegbaseSoftmaxTNDTiling(context) != ge::GRAPH_SUCCESS,
OP_LOGE(context->GetNodeName(), "RingAttentionUpdateRegbaseSoftmaxTNDTiling failed."), return ge::GRAPH_FAILED);
} else {
tilingKey += TND_KEY;
OP_CHECK_IF(RingAttentionUpdateRegbaseTNDTiling(context) != ge::GRAPH_SUCCESS,
OP_LOGE(context->GetNodeName(), "RingAttentionUpdateRegbaseTNDTiling failed."), return ge::GRAPH_FAILED);
}
} else {
OP_LOGD(context->GetNodeName(), "Attr input_layout is SBH.");
OP_CHECK_IF(RingAttentionUpdateRegbaseSBHCheckShape(context) != ge::GRAPH_SUCCESS,
OP_LOGE(context->GetNodeName(), "RingAttentionUpdateRegbaseSBHCheckShape failed."), return ge::GRAPH_FAILED);
OP_CHECK_IF(RingAttentionUpdateRegbaseSBHTiling(context) != ge::GRAPH_SUCCESS,
OP_LOGE(context->GetNodeName(), "RingAttentionUpdateRegbaseSBHTiling failed."), return ge::GRAPH_FAILED);
}
const auto ascendcPlatform = platform_ascendc::PlatformAscendC(context->GetPlatformInfo());
uint32_t sysWorkspaceSize = ascendcPlatform.GetLibApiWorkSpaceSize();
size_t* currentWorkspace = context->GetWorkspaceSizes(1);
currentWorkspace[0] = sysWorkspaceSize;
context->SetTilingKey(tilingKey);
OP_LOGD(context->GetNodeName(), "RingAttentionUpdateRegbaseTiling tiling end");
return ge::GRAPH_SUCCESS;
}
}