* 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 all_gather_matmul_tiling_base.cpp
* \brief
*/
#include <queue>
#include <dlfcn.h>
#include <fcntl.h>
#include <cstdio>
#include <cstdlib>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <cmath>
#include <cstdint>
#include "mc2_hcom_topo_info.h"
#include "mc2_log.h"
#include "graph/utils/type_utils.h"
#include "register/op_def_registry.h"
#include "tiling/mc2_tiling_utils.h"
#include "util/math_util.h"
#include "all_gather_formulaic_tiling.h"
#include "arch35/all_gather_fit_balance_tiling.h"
#include "all_gather_matmul_tiling_base.h"
#include "../../op_kernel/all_gather_matmul_v2_apt_tiling_key.h"
using namespace AscendC;
using namespace ge;
using namespace Mc2Tiling;
namespace optiling
{
const std::set<int> SUPPORT_RANK_SIZE{2, 4, 8, 16, 32, 64};
constexpr uint64_t BLOCK_SIZE_INDEX = 6;
static const std::initializer_list<ge::DataType> FP8_DTYPE_SUPPORT_LIST = {
ge::DataType::DT_FLOAT8_E4M3FN, ge::DataType::DT_FLOAT8_E5M2, ge::DataType::DT_HIFLOAT8};
static bool CheckSupportDtype(const ge::DataType x1DataType, const std::initializer_list<ge::DataType> &supportTypes)
{
return std::find(supportTypes.begin(), supportTypes.end(), x1DataType) != supportTypes.end();
}
bool AllGatherMatmulTilingBase::CheckInputParaEmptyPointer()
{
const gert::StorageShape* x1Shape = context_->GetInputShape(INPUT_X1);
const gert::StorageShape* x2Shape = context_->GetInputShape(INPUT_X2);
OP_TILING_CHECK((x1Shape == nullptr) || (x2Shape == nullptr),
VECTOR_INNER_ERR_REPORT_TILING(opName_, "the shape is invalid"), return false);
auto x1TensorDesc = context_->GetInputDesc(INPUT_X1);
auto x2TensorDesc = context_->GetInputDesc(INPUT_X2);
auto scaleShape = context_->GetOptionalInputShape(SCALE);
auto yTensorDesc = context_->GetOutputDesc(OUTPUT_Y);
auto amaxOutShape = context_->GetOutputShape(OUTPUT_AMAX);
OP_TILING_CHECK((x1TensorDesc == nullptr) || (x2TensorDesc == nullptr) || (yTensorDesc == nullptr),
VECTOR_INNER_ERR_REPORT_TILING(opName_, "the tensor is invalid"), return false);
OP_TILING_CHECK((scaleShape != nullptr),
VECTOR_INNER_ERR_REPORT_TILING(opName_, "the quantscale tensor should be nullptr"), return false);
if (amaxOutShape != nullptr) {
OP_LOGI(opName_, "amaxOutShapeDim0 is %lu", amaxOutShape->GetStorageShape().GetDim(0));
}
OP_TILING_CHECK((amaxOutShape != nullptr) && (amaxOutShape->GetStorageShape().GetDim(0) != 0),
VECTOR_INNER_ERR_REPORT_TILING(opName_, "the amaxOut tensor should be nullptr or empty tensor, but amaxOut is %lu",
amaxOutShape->GetStorageShape().GetDim(0)), return false);
auto attrs = context_->GetAttrs();
OP_TILING_CHECK((attrs == nullptr), VECTOR_INNER_ERR_REPORT_TILING(opName_, "failed to get attrs"), return false);
auto outputShape = context_->GetOutputShape(OUTPUT_Y);
OP_TILING_CHECK((outputShape == nullptr), VECTOR_INNER_ERR_REPORT_TILING(opName_, "the outputShape is nullptr"),
return false);
return true;
}
bool AllGatherMatmulTilingBase::CheckGroupSize()
{
ge::DataType aType = context_->GetInputDesc(INPUT_X1)->GetDataType();
ge::DataType bType = context_->GetInputDesc(INPUT_X2)->GetDataType();
auto attrsPtr = context_->GetAttrs();
auto groupSizePtr = attrsPtr->GetAttrPointer<uint64_t>(GROUPSIZE_INDEX);
if (((aType == ge::DT_BF16) && (bType == ge::DT_BF16)) || ((aType == ge::DT_FLOAT16) && (bType == ge::DT_FLOAT16))) {
if (groupSizePtr != nullptr){
OP_TILING_CHECK((*groupSizePtr != 0),
CUBE_INNER_ERR_REPORT(opName_, "when the datatype of x1 and x2 are fp16 or bf16,"
"groupSizePtr should be nullptr or 0."),
return false);
}
}
return true;
}
bool AllGatherMatmulTilingBase::CheckInputScale()
{
ge::DataType aType = context_->GetInputDesc(INPUT_X1)->GetDataType();
ge::DataType bType = context_->GetInputDesc(INPUT_X2)->GetDataType();
auto scale1Shape = context_->GetOptionalInputShape(SCALE_INV1);
auto scale2Shape = context_->GetOptionalInputShape(SCALE_INV2);
auto scaleShape = context_->GetOptionalInputShape(SCALE);
if (((aType == ge::DT_BF16) && (bType == ge::DT_BF16)) || ((aType == ge::DT_FLOAT16) && (bType == ge::DT_FLOAT16))) {
OP_TILING_CHECK((scale1Shape != nullptr),
VECTOR_INNER_ERR_REPORT_TILING(opName_,
"when the datatype of x1 and x2 are fp16 or bf16, scale1 should be None"),
return false);
OP_TILING_CHECK((scale2Shape != nullptr),
VECTOR_INNER_ERR_REPORT_TILING(opName_,
"when the datatype of x1 and x2 are fp16 or bf16, scale2 should be None"),
return false);
}
OP_TILING_CHECK((scaleShape != nullptr),
VECTOR_INNER_ERR_REPORT_TILING(opName_, "the quantscale tensor should be nullptr"), return false);
return true;
}
bool AllGatherMatmulTilingBase::CheckInputParaArraySize()
{
const gert::StorageShape* x1Shape = context_->GetInputShape(INPUT_X1);
const gert::StorageShape* x2Shape = context_->GetInputShape(INPUT_X2);
uint64_t x1ShapeDimNum = x1Shape->GetStorageShape().GetDimNum();
uint64_t x2ShapeDimNum = x2Shape->GetStorageShape().GetDimNum();
OP_TILING_CHECK((x1ShapeDimNum != 2) || (x2ShapeDimNum != 2),
VECTOR_INNER_ERR_REPORT_TILING(opName_, "the dimNum is not 2"), return false);
int64_t x1Dim0 = x1Shape->GetStorageShape().GetDim(0);
int64_t x1Dim1 = x1Shape->GetStorageShape().GetDim(1);
int64_t x2Dim0 = x2Shape->GetStorageShape().GetDim(0);
int64_t x2Dim1 = x2Shape->GetStorageShape().GetDim(1);
if (CheckSupportDtype(context_->GetInputDesc(INPUT_X1)->GetDataType(), FP8_DTYPE_SUPPORT_LIST)) {
OP_TILING_CHECK(
(x1Dim0 == 0) || (x1Dim1 == 0) || (x2Dim0 == 0) || (x2Dim1 == 0),
VECTOR_INNER_ERR_REPORT_TILING(opName_, "the value is invalid. x1Dim0 %ld, x1Dim1 %ld, x2Dim0 %ld, x2Dim1 %ld",
x1Dim0, x1Dim1, x2Dim0, x2Dim1),
return false);
}
OP_TILING_CHECK(
(x1Dim1 < KVALUE_MIN) || (x1Dim1 >= KVALUE_MAX),
VECTOR_INNER_ERR_REPORT_TILING(opName_, "The k-axis should be in range[256, 65535), but it is: %ld.", x1Dim1),
return false);
return true;
}
bool AllGatherMatmulTilingBase::CheckInputAndOutputParaFormat()
{
auto x1TensorDesc = context_->GetInputDesc(INPUT_X1);
auto x2TensorDesc = context_->GetInputDesc(INPUT_X2);
auto yTensorDesc = context_->GetOutputDesc(OUTPUT_Y);
auto x1Format = x1TensorDesc->GetStorageFormat();
auto x2Format = x2TensorDesc->GetStorageFormat();
auto yFormat = yTensorDesc->GetStorageFormat();
OP_TILING_CHECK(x1Format != yFormat,
VECTOR_INNER_ERR_REPORT_TILING(opName_, "output format is not same as x1 format"), return false);
OP_TILING_CHECK(
!mc2tiling::CheckSuppportedFormat(x1Format) || !mc2tiling::CheckSuppportedFormat(x2Format),
VECTOR_INNER_ERR_REPORT_TILING(opName_, "a shape Format, b shape Format only support ND, the format is %s",
TypeUtils::FormatToSerialString(x1Format).c_str()),
return false);
return true;
}
bool AllGatherMatmulTilingBase::CheckGatherOutPara()
{
auto attrs = context_->GetAttrs();
auto isGatherout = attrs->GetAttrPointer<bool>(IS_GATHER_OUT);
auto gatherIndex = attrs->GetAttrPointer<int64_t>(GATHER_IDX);
auto gatherOutShape = context_->GetOutputShape(GATHER_OUT);
const gert::StorageShape* x1Shape = context_->GetInputShape(INPUT_X1);
int64_t x1Dim0 = x1Shape->GetStorageShape().GetDim(0);
int64_t x1Dim1 = x1Shape->GetStorageShape().GetDim(1);
int64_t mValue = x1Dim0 * static_cast<int64_t>(rankSize_);
if ((*isGatherout) && (gatherOutShape != nullptr)) {
OP_TILING_CHECK((*gatherIndex != 0),
VECTOR_INNER_ERR_REPORT_TILING(opName_, "gather_index should be 0 in nowadays,"
"the actual value is %d\n", *gatherIndex),
return false);
int64_t gatherOutDim0 = gatherOutShape->GetStorageShape().GetDim(0);
OP_TILING_CHECK((gatherOutDim0 != mValue),
VECTOR_INNER_ERR_REPORT_TILING(opName_, "m-axis should be %ld, but gatherout is %ld\n", mValue,
gatherOutDim0),
return false);
int64_t gatherOutDim1 = gatherOutShape->GetStorageShape().GetDim(1);
OP_TILING_CHECK(
(x1Dim1 != gatherOutDim1),
VECTOR_INNER_ERR_REPORT_TILING(opName_,
"The k-axis of x1 and gatherOut should be same,"
"but x1's k-axis is: %ld and gatherOut's k-axis is: %ld.", x1Dim1, gatherOutDim1),
return false);
}
return true;
}
bool AllGatherMatmulTilingBase::CheckOutputParaDim0()
{
auto outputShape = context_->GetOutputShape(OUTPUT_Y);
uint64_t outputDim0 = outputShape->GetStorageShape().GetDim(0);
const gert::StorageShape* x1Shape = context_->GetInputShape(INPUT_X1);
uint64_t x1Dim0 = x1Shape->GetStorageShape().GetDim(0);
uint64_t mValue = x1Dim0 * static_cast<uint64_t>(rankSize_);
OP_TILING_CHECK(
(outputDim0 != mValue),
VECTOR_INNER_ERR_REPORT_TILING(opName_, "m-axis should be %lu, but output is %lu \n", mValue, outputDim0),
return false);
return true;
}
bool AllGatherMatmulTilingBase::CheckBiasParaDim0()
{
const gert::StorageShape* matrix_bias = context_->GetOptionalInputShape(BIAS);
const gert::StorageShape* x1Shape = context_->GetInputShape(INPUT_X1);
const gert::StorageShape* x2Shape = context_->GetInputShape(INPUT_X2);
uint64_t x1Dim1 = x1Shape->GetStorageShape().GetDim(1);
uint64_t x2Dim0 = x2Shape->GetStorageShape().GetDim(0);
uint64_t x2Dim1 = x2Shape->GetStorageShape().GetDim(1);
uint64_t nValue = (x1Dim1 == x2Dim0) ? x2Dim1 : x2Dim0;
if (matrix_bias != nullptr) {
uint64_t biasDim0 = matrix_bias->GetStorageShape().GetDim(0);
OP_TILING_CHECK(
(biasDim0 != nValue),
VECTOR_INNER_ERR_REPORT_TILING(opName_, "bias n-axis should be %lu, but it's %lu\n", nValue, biasDim0),
return false);
}
return true;
}
bool AllGatherMatmulTilingBase::CheckParaInvaild()
{
if (!CheckInputParaEmptyPointer()) {
return false;
}
if (!CheckInputScale()) {
return false;
}
if (!CheckGroupSize()) {
return false;
}
if (!CheckInputParaArraySize()) {
return false;
}
if (!CheckInputAndOutputParaFormat()) {
return false;
}
if (!CheckGatherOutPara()) {
return false;
}
if (!CheckOutputParaDim0()) {
return false;
}
SetTilingArgsDim();
if (!CheckBiasParaDim0()) {
return false;
}
return true;
}
void AllGatherMatmulTilingBase::SetTilingArgsDim()
{
const gert::StorageShape* x1Shape = context_->GetInputShape(INPUT_X1);
const gert::StorageShape* x2Shape = context_->GetInputShape(INPUT_X2);
uint64_t x1Dim0 = x1Shape->GetStorageShape().GetDim(0);
uint64_t x1Dim1 = x1Shape->GetStorageShape().GetDim(1);
uint64_t x2Dim0 = x2Shape->GetStorageShape().GetDim(0);
uint64_t x2Dim1 = x2Shape->GetStorageShape().GetDim(1);
args_.orgMValue = x1Dim0;
args_.orgNValue = (x1Dim1 == x2Dim0) ? x2Dim1 : x2Dim0;
args_.orgKValue = x1Dim1;
args_.mValue = x1Dim0;
args_.nValue = (x1Dim1 == x2Dim0) ? x2Dim1 : x2Dim0;
args_.kValue = x1Dim1;
return;
}
void AllGatherMatmulTilingBase::SetTilingArgsDataType()
{
const gert::StorageShape* matrixBias = context_->GetOptionalInputShape(BIAS);
ge::DataType aType = context_->GetInputDesc(INPUT_X1)->GetDataType();
ge::DataType bType = context_->GetInputDesc(INPUT_X2)->GetDataType();
ge::DataType biasType;
bool isBias = true;
auto cType = aType;
if (matrixBias == nullptr) {
isBias = false;
biasType = cType;
} else {
biasType = context_->GetOptionalInputDesc(BIAS)->GetDataType();
}
args_.inputDtypeSize = mc2tiling::GetDataTypeSize(opName_, aType);
args_.outputDtypeSize = mc2tiling::GetDataTypeSize(opName_, cType);
args_.isBias = isBias;
args_.geAType = aType;
args_.geBType = bType;
args_.geCType = cType;
args_.geBiasType = biasType;
args_.aType = mc2tiling::ConvertGeTypeToMmType(opName_, aType);
args_.bType = mc2tiling::ConvertGeTypeToMmType(opName_, bType);
args_.cType = mc2tiling::ConvertGeTypeToMmType(opName_, cType);
args_.biasType = mc2tiling::ConvertGeTypeToMmType(opName_, biasType);
inputIsBf16Fp16_ = ((aType == ge::DT_BF16) || (aType == ge::DT_FLOAT16)) ? true : false;
return;
}
void AllGatherMatmulTilingBase::SetTilingArgsGatherStatus()
{
auto gatherOutShape = context_->GetOutputShape(GATHER_OUT);
args_.isStorageGather = true;
if (gatherOutShape != nullptr) {
int64_t mulGatherShape = 1;
for (uint32_t i = 0; i < gatherOutShape->GetStorageShape().GetDimNum(); i++) {
mulGatherShape = mulGatherShape * gatherOutShape->GetStorageShape().GetDim(i);
OP_LOGD("AllGatherMatmul", "gatherOutShape StorageShape=%ld, Dim=%u.",
gatherOutShape->GetStorageShape().GetDim(i), i);
}
if (mulGatherShape == 0) {
args_.isStorageGather = false;
}
} else {
args_.isStorageGather = false;
}
return;
}
bool AllGatherMatmulTilingBase::AnalyzeInputs()
{
if (!CheckParaInvaild()) {
return false;
}
args_.enablePad = false;
args_.enableSplitK = false;
SetTilingArgsDim();
SetTilingArgsDataType();
SetTilingArgsGatherStatus();
return true;
}
ge::graphStatus AllGatherMatmulTilingBase::AnalyzeShapeAttr()
{
opName_ = context_->GetNodeName();
OP_TILING_CHECK(((!AnalyzeAttrs()) || (!AnalyzeInputs()) || (!SetCommAlgo())),
VECTOR_INNER_ERR_REPORT_TILING(opName_, "fail to analyze context info"), return ge::GRAPH_FAILED);
commAlgorithm_ = static_cast<uint64_t>(args_.commAlg);
return ge::GRAPH_SUCCESS;
}
void AllGatherMatmulTilingBase::SetMC2AllGatherDataInfo(Mc2Tiling::RCSTiling& rcsCfg,
::TCubeTiling& mmTiling,
::TCubeTiling& tailTiling,
uint32_t debugMode)
{
auto columnNum = args_.orgKValue;
OP_LOGD(opName_, "Debug mode is %u, gather out flag is %d, K is %lu, N is %lu.", debugMode,
(rcsCfg.gatherLen == 0), args_.orgKValue, args_.orgNValue);
if ((debugMode == mc2tiling::MC2_DEBUG_ONLY_AICPU) && (rcsCfg.gatherLen != 0) &&
(args_.orgKValue > args_.orgNValue)) {
OP_LOGW("AllGatherMatmul",
"K [%lu] is greater than N [%lu], cut recvOff and sendCnt according to N under "
"debugMode 4 (i.e. communication only).",
args_.orgKValue, args_.orgNValue);
columnNum = args_.orgNValue;
}
}
* Due to communication constraints:
* 1. The maximum number of communication attempts is limited to 16
* 2. The data volume of a single communication shall not exceed 256MB;
* Thus, it is required to pre-intercept the x1 that still exceeds the limit after being evenly split into 16 parts
*/
ge::graphStatus AllGatherMatmulTilingBase::CheckHCCLSize()
{
uint64_t sizeOfSingleM = args_.kValue * sizeof(args_.geAType) * args_.rankDim;
OP_TILING_CHECK(sizeOfSingleM > mc2tiling::ALL_GATHER_HCCL_MEM_LIMIT,
OP_LOGE(opName_, "Unsupported x1 size. Even after splitting data x1 into (1, k), the size still exceeds 256MB."), return ge::GRAPH_FAILED);
uint64_t sizeOfSplitM = Ops::Base::CeilDiv(args_.mValue, mc2tiling::ALL_GATHER_HCCL_NUM_LIMIT) * sizeOfSingleM;
OP_TILING_CHECK(sizeOfSingleM > mc2tiling::ALL_GATHER_HCCL_MEM_LIMIT,
OP_LOGE(opName_, "Unsupported x1 size. Even after splitting data M into 16 parts (rounded up), the size still exceeds 256MB."), return ge::GRAPH_FAILED);
return ge::GRAPH_SUCCESS;
}
ge::graphStatus AllGatherMatmulTilingBase::AdjustHCCLLimit(Mc2Tiling::RCSTiling& rcfCfg, mc2tiling::Mc2QuantMode quantMmMode)
{
if (tileMValue_ * args_.kValue * sizeof(args_.geAType) * args_.rankDim <= mc2tiling::ALL_GATHER_HCCL_MEM_LIMIT) {
return ge::GRAPH_SUCCESS;
}
OPS_LOG_I(opName_, "The result of formulaic tiling result does not meet the hccl restriction,"
" current splitting: tileM [%ld], tileCnt [%ld], tailM [%ld], tailCnt [%ld]. start re-splitM.",
tileMValue_, rcfCfg.tileCnt, tailMValue_, rcfCfg.tailCnt);
OP_TILING_CHECK((quantMmMode == mc2tiling::Mc2QuantMode::PERBLOCK_MODE),
OP_LOGE(opName_, "Unsupported x1 size. Even after formulaic splitting, the size still exceeds 256MB."),
return ge::GRAPH_FAILED);
uint64_t minSplitPart = Ops::Base::CeilDiv(args_.mValue * args_.kValue * sizeof(args_.geAType) * args_.rankDim, mc2tiling::ALL_GATHER_HCCL_MEM_LIMIT);
tileMValue_ = Ops::Base::CeilDiv(args_.mValue, minSplitPart);
rcfCfg.tileCnt = Ops::Base::FloorDiv(args_.mValue, tileMValue_);
rcfCfg.tailM = args_.mValue - rcfCfg.tileCnt * tileMValue_;
tailMValue_ = rcfCfg.tailM;
if (tailMValue_ == 0) {
rcfCfg.tailCnt = 0;
} else {
rcfCfg.tailCnt = 1;
}
OPS_LOG_I(opName_, "Because the result of formulaic tiling result does not meet the hccl restriction,"
" the re-splitM result: tileM [%ld], tileCnt [%ld], tailM [%ld], tailCnt [%ld]. end re-splitM.",
tileMValue_, rcfCfg.tileCnt, tailMValue_, rcfCfg.tailCnt);
return ge::GRAPH_SUCCESS;
}
void AllGatherMatmulTilingBase::DoAllGatherTiling(Mc2Tiling::RCSTiling& rcsCfg,
::TCubeTiling& mmTiling,
::TCubeTiling& tailTiling,
uint32_t& debugMode, uint32_t& dataType)
{
auto debugMode_ = mc2tiling::Mc2TilingUtils::GetDebugMode();
debugMode = debugMode_;
SetMC2AllGatherDataInfo(rcsCfg, mmTiling, tailTiling, debugMode_);
dataType = (static_cast<uint32_t>(mc2tiling::ConvertGeTypeToHcclType(opName_, args_.geAType)));
storageA_ = GetStorageA(rcsCfg);
}
void AllGatherMatmulTilingBase::SetRcsTilingData(Mc2Tiling::RCSTiling& rcsCfg)
{
rcsCfg.rankDim = args_.rankDim;
rcsCfg.isTransposeA = args_.isATrans;
rcsCfg.isTransposeB = args_.isBTrans;
rcsCfg.commtype = (static_cast<uint32_t>(args_.cmdType));
OP_LOGD(opName_,
"AlGaterMatmul SetRcsTilingData, args_.orgMValue=%lu, args_.orgNValue=%lu, args_.orgKValue=%lu.",
args_.orgMValue, args_.orgNValue, args_.orgKValue);
rcsCfg.rankM = args_.orgMValue;
rcsCfg.rankN = args_.orgNValue;
rcsCfg.rankK = args_.orgKValue;
rcsCfg.aicCoreNum = args_.aicCoreNum;
rcsCfg.storageGather = 0;
if (args_.isStorageGather) {
rcsCfg.storageGather = 1;
}
if (args_.isBias && (args_.bType == matmul_tiling::DataType::DT_BFLOAT16)) {
biasLen_ = mc2tiling::AlignUp(args_.orgNValue, mc2tiling::SHAPE_ALIGN_SIZE) * sizeof(float);
}
rcsCfg.biasLen = biasLen_;
}
bool AllGatherMatmulTilingBase::SetCommAlgo()
{
args_.commAlg = mc2tiling::Mc2GetCommAlgo(rankSize_, args_.orgMValue, group_, context_);
if (args_.commAlg == mc2tiling::COMM_ALG_DEFAULT) {
OP_LOGE(opName_, "CommAlgo %u is not supported.", args_.commAlg);
return false;
}
return true;
}
uint32_t AllGatherMatmulTilingBase::AllGatherSplitM(mc2tiling::TilingArgs& args, uint32_t maxTileCnt = 64)
{
if (args.commTurn >= maxTileCnt) {
args.commTurn = maxTileCnt;
}
uint64_t tileLen = 1;
if (args.mValue > args.commTurn) {
tileLen = args.mValue / args.commTurn;
}
if (args.inputDtypeSize == 2) {
tileLen = mc2tiling::AlignUp<uint64_t>(tileLen, 64);
} else if (args.inputDtypeSize == 4) {
tileLen = mc2tiling::AlignUp<uint64_t>(tileLen, 32);
}
if (args.mValue > tileLen) {
return tileLen;
}
return args.mValue;
}
CutResult AllGatherMatmulTilingBase::GetTilingResult()
{
SocVersion inputSocVersion = (npuArch_ == NpuArch::DAV_3510) ? SocVersion::SOC950 : SocVersion::SOC910_B;
if (inputSocVersion == SocVersion::SOC950) {
AllGatherMMFitBalanceTiling tileFormulate(args_, KernelType::ALL_GATHER, TopoType::STANDARD_CARD);
return tileFormulate.GetTiling();
} else {
AllGatherPlusMMV2 tileFormulate(args_, args_.rankDim, KernelType::ALL_GATHER, SocVersion::SOC910_B);
tileFormulate.GetTiling();
return tileFormulate.tilingM_.cutRes;
}
}
void AllGatherMatmulTilingBase::DoSplitMTiling(Mc2Tiling::RCSTiling& rcfCfg)
{
if (args_.commAlg == mc2tiling::COMM_ALG_DOUBLE_RING) {
args_.mValue /= DOUBLE_RING_FACTOR;
drMValue_ = args_.mValue;
OP_LOGI(opName_, " args.mValue is set to be %lu under double ring communication algorithm.", args_.mValue);
}
if (args_.enableSplitK) {
OP_LOGI(opName_, "enabelSplik is True.");
rcfCfg.tileCnt = 1;
rcfCfg.tailCnt = 0;
rcfCfg.tailM = 0;
} else if (args_.commTurn != 0) {
OP_LOGI(opName_, "commTurn is %lu.", args_.commTurn);
uint64_t splite = AllGatherSplitM(args_);
auto tileCnt = args_.mValue / splite;
auto tileTail = args_.mValue % splite;
rcfCfg.tileCnt = tileCnt;
tileMValue_ = splite;
rcfCfg.tailCnt = 0;
rcfCfg.tailM = tileTail;
if (tileTail != 0) {
tailMValue_ = tileTail;
}
} else {
CutResult mCutAllgather = GetTilingResult();
rcfCfg.tileCnt = mCutAllgather.numLongTile;
tileMValue_ = mCutAllgather.longTileLen;
rcfCfg.tailCnt = 0;
rcfCfg.tailM = 0;
if (mCutAllgather.numShortTile > 0) {
rcfCfg.tailM = mCutAllgather.shortTileLen;
tailMValue_ = mCutAllgather.shortTileLen;
rcfCfg.tailCnt = mCutAllgather.numShortTile;
}
}
}
void AllGatherMatmulTilingBase::Reset()
{
tileMValue_ = 0UL;
tailMValue_ = 0UL;
rankSize_ = 0L;
outputIsFp8_ = false;
inputIsBf16Fp16_ = true;
commAlgorithm_ = 0U;
enableNd2Nz_ = true;
castBias_ = false;
biasLen_ = 0U;
storageA_ = 0U;
gatherIndex_ = 0U;
}
bool AllGatherMatmulTilingBase::AnalyzeAttrs()
{
auto attrs = context_->GetAttrs();
OP_TILING_CHECK((attrs == nullptr), VECTOR_INNER_ERR_REPORT_TILING(opName_, "failed to get attrs"), return false);
group_ = attrs->GetAttrPointer<char>(GROUP);
auto isTransA = attrs->GetAttrPointer<bool>(IS_TRANS_A);
auto isTransB = attrs->GetAttrPointer<bool>(IS_TRANS_B);
auto gatherIndexPtr = attrs->GetAttrPointer<int64_t>(GATHER_IDX);
auto commTurn = attrs->GetAttrPointer<int64_t>(COMM_TURN);
OP_TILING_CHECK(!mc2tiling::GetRankSize(opName_, group_, rankSize_), VECTOR_INNER_ERR_REPORT_TILING(opName_,
"GetRankSize failed."), return false);
OP_TILING_CHECK(
SUPPORT_RANK_SIZE.find(rankSize_) == SUPPORT_RANK_SIZE.end(),
VECTOR_INNER_ERR_REPORT_TILING(
opName_, "world_size should be 2 or 4 or 8 or 16 or 32 or 64, but the actual value is %ld.", rankSize_),
return false);
OP_TILING_CHECK(commTurn == nullptr, VECTOR_INNER_ERR_REPORT_TILING(opName_, "commTurn is nullptr!"),
return false);
OP_TILING_CHECK(
*commTurn != 0,
VECTOR_INNER_ERR_REPORT_TILING(opName_, "The expected value of commTurn is 0, but the actual value is %d.",
*commTurn), return false);
args_.isATrans = isTransA ? *isTransA : 0;
args_.isBTrans = isTransB ? *isTransB : 0;
args_.cmdType = mc2tiling::AicpuComType::HCCL_CMD_ALLGATHER;
args_.rankDim = static_cast<uint32_t>(rankSize_);
args_.commTurn = commTurn ? *commTurn : 0;
gatherIndex_ = gatherIndexPtr ? *gatherIndexPtr : 0;
OP_TILING_CHECK((args_.isATrans != 0),
VECTOR_INNER_ERR_REPORT_TILING(opName_, "the isTransA should be false, but real value is true"),
return false);
OP_TILING_CHECK(
(gatherIndex_ != 0),
VECTOR_INNER_ERR_REPORT_TILING(opName_, "the gatherIndex should be 0, but real value is %u", gatherIndex_),
return false);
auto blockSize = *context_->GetAttrs()->GetAttrPointer<int64_t>(BLOCK_SIZE_INDEX);
OP_TILING_CHECK(blockSize != 0, VECTOR_INNER_ERR_REPORT_TILING(opName_,
"blockSize should be 0, but the actual value is %u.", blockSize), return false);
OP_LOGD(opName_,
" group=%s, rankSize=%ld, is_trans_a=%u, is_trans_b=%d, gather_index=%u,"
" comm_turn=%lu",
group_, rankSize_, args_.isATrans, args_.isBTrans, gatherIndex_, args_.commTurn);
return true;
}
ge::graphStatus AllGatherMatmulTilingBase::GetPlatformInfo()
{
auto platformInfo = context_->GetPlatformInfo();
OP_TILING_CHECK(platformInfo == nullptr, VECTOR_INNER_ERR_REPORT_TILING(opName_, "fail to get platform info"),
return ge::GRAPH_FAILED);
auto ascendcPlatform = platform_ascendc::PlatformAscendC(platformInfo);
npuArch_ = ascendcPlatform.GetCurNpuArch();
libApiWorkSpaceSize_ = ascendcPlatform.GetLibApiWorkSpaceSize();
args_.aicCoreNum = ascendcPlatform.GetCoreNumAic();
return ge::GRAPH_SUCCESS;
};
ge::graphStatus AllGatherMatmulTilingBase::GetShapeAttrsInfo()
{
return AnalyzeShapeAttr();
};
ge::graphStatus AllGatherMatmulTilingBase::DoLibApiTiling()
{
return ge::GRAPH_SUCCESS;
}
uint64_t AllGatherMatmulTilingBase::GetStorageA(Mc2Tiling::RCSTiling& rcsCfg)
{
constexpr uint64_t alignAddrLen = 512;
uint32_t gatherIndex = rcsCfg.gatherIndex;
uint64_t nd2nzLen = 0;
uint64_t storageA = 0;
if (gatherIndex == 0U) {
uint64_t alignByte = 256 / args_.inputDtypeSize;
uint64_t kALign = ops::CeilAlign(static_cast<uint64_t>(rcsCfg.rankK), alignByte);
uint64_t nALign = ops::CeilAlign(static_cast<uint64_t>(rcsCfg.rankN), alignByte);
nd2nzLen = kALign * nALign * args_.inputDtypeSize;
} else {
auto alignM = rcsCfg.rankM + 16;
auto alignK = rcsCfg.rankK + 16;
nd2nzLen = mc2tiling::AlignUp(alignM * alignK * args_.inputDtypeSize, alignAddrLen);
}
if (args_.cmdType == mc2tiling::AicpuComType::HCCL_CMD_ALLGATHER) {
uint64_t gmcFloat = 0;
uint64_t gatherLen = 0;
if (args_.isStorageGather == false) {
if (gatherIndex == 0U) {
gatherLen =
mc2tiling::AlignUp(rcsCfg.rankM * rcsCfg.rankK * args_.inputDtypeSize, alignAddrLen);
} else {
gatherLen =
mc2tiling::AlignUp(rcsCfg.rankK * rcsCfg.rankN * args_.inputDtypeSize, alignAddrLen);
}
gatherLen *= rcsCfg.rankDim;
}
rcsCfg.nd2NzWorkLen = nd2nzLen;
rcsCfg.cToFloatLen = gmcFloat;
rcsCfg.gatherLen = gatherLen;
storageA = nd2nzLen + gmcFloat + gatherLen;
}
return storageA;
}
ge::graphStatus AllGatherMatmulTilingBase::GetWorkspaceSize()
{
size_t* workspaces = context_->GetWorkspaceSizes(1);
OP_TILING_CHECK(workspaces == nullptr, VECTOR_INNER_ERR_REPORT_TILING(opName_, "get workspace failed"),
return ge::GRAPH_FAILED);
workspaceSize_ = libApiWorkSpaceSize_ + storageA_ + biasLen_;
workspaces[0] = workspaceSize_;
OP_LOGD(opName_, "workspaces[0] size=%ld, biasLen=%d", workspaces[0], biasLen_);
return ge::GRAPH_SUCCESS;
}
uint64_t AllGatherMatmulTilingBase::GetTilingKey() const
{
uint8_t outputType = (outputIsFp8_) ? static_cast<uint8_t>(1) : static_cast<uint8_t>(0);
const uint64_t tilingKey = GET_TPL_TILING_KEY(
inputIsBf16Fp16_, args_.isBTrans, outputType, TPL_DEFAULT_MODE, SCALE_TYPE_NOT_IS_MX);
OP_LOGD(opName_, "AllGatherMatmulV2, inputIsBf16Fp16_, args_.isBTrans, outputType: [%d,%d,%u]", \
inputIsBf16Fp16_, args_.isBTrans, outputType);
OP_LOGD(opName_, "tilingKey=%lu", tilingKey);
return tilingKey;
}
}