* 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 stack_ball_query_tiling.cpp
* \brief
*/
#include "stack_ball_query_tiling.h"
#include <cstdint>
#include "log/log.h"
#include "platform/platform_infos_def.h"
#include "register/op_impl_registry.h"
#include "platform/platform_ascendc.h"
#include "util/math_util.h"
using namespace ge;
namespace optiling {
constexpr int32_t INDEX_INPUT_XYZ = 0;
constexpr int32_t INDEX_INPUT_CENTER_XYZ = 1;
constexpr int32_t INDEX_INPUT_XYZ_BATCH_CNT = 2;
constexpr int32_t INDEX_INPUT_CENTER_XYZ_BATCH_CNT = 3;
constexpr int32_t INDEX_OUTPUT_IDX = 0;
constexpr uint32_t WORKSPACE_16MB_SIZE = 16 * 1024 * 1024;
constexpr size_t MAX_RADIUS_IDX = 0;
constexpr size_t SAMPLE_NUM_IDX = 1;
constexpr int32_t FP32_MODE = 1;
constexpr int32_t FP16_MODE = 2;
constexpr int32_t FP32_INT64_MODE = 3;
constexpr int32_t FP16_INT64_MODE = 4;
static int32_t GetCeilInt(int32_t num1, int32_t num2)
{
if (num2 != 0) {
return (num1 + num2 - 1) / num2;
}
return 0;
}
static ge::graphStatus ValidateDtype(gert::TilingContext* context)
{
auto opName = context->GetNodeName();
auto xyzDesc = context->GetInputDesc(INDEX_INPUT_XYZ);
if (xyzDesc == nullptr) {
OP_LOGE_WITH_INVALID_INPUT(opName, "xyz");
return ge::GRAPH_FAILED;
}
auto xyzDtype = xyzDesc->GetDataType();
OP_CHECK_IF(xyzDtype != ge::DT_FLOAT16 && xyzDtype != ge::DT_FLOAT,
OP_LOGE_FOR_INVALID_DTYPE(opName, "xyz", std::to_string(static_cast<int32_t>(xyzDtype)).c_str(),
"float16/float32"),
return ge::GRAPH_FAILED);
auto centerXyzDesc = context->GetInputDesc(INDEX_INPUT_CENTER_XYZ);
if (centerXyzDesc == nullptr) {
OP_LOGE_WITH_INVALID_INPUT(opName, "center_xyz");
return ge::GRAPH_FAILED;
}
auto centerXyzDtype = centerXyzDesc->GetDataType();
OP_CHECK_IF(centerXyzDtype != xyzDtype,
OP_LOGE_FOR_INVALID_DTYPES_WITH_REASON(opName, "xyz and center_xyz",
(std::to_string(static_cast<int32_t>(xyzDtype)) + " vs " +
std::to_string(static_cast<int32_t>(centerXyzDtype)))
.c_str(),
"center_xyz dtype must equal xyz dtype"),
return ge::GRAPH_FAILED);
auto xyzBatchCntDesc = context->GetInputDesc(INDEX_INPUT_XYZ_BATCH_CNT);
if (xyzBatchCntDesc == nullptr) {
OP_LOGE_WITH_INVALID_INPUT(opName, "xyz_batch_cnt");
return ge::GRAPH_FAILED;
}
auto xyzBatchCntDtype = xyzBatchCntDesc->GetDataType();
OP_CHECK_IF(
xyzBatchCntDtype != ge::DT_INT32 && xyzBatchCntDtype != ge::DT_INT64,
OP_LOGE_FOR_INVALID_DTYPE(opName, "xyz_batch_cnt",
std::to_string(static_cast<int32_t>(xyzBatchCntDtype)).c_str(), "int32/int64"),
return ge::GRAPH_FAILED);
auto centerXyzBatchCntDesc = context->GetInputDesc(INDEX_INPUT_CENTER_XYZ_BATCH_CNT);
if (centerXyzBatchCntDesc == nullptr) {
OP_LOGE_WITH_INVALID_INPUT(opName, "center_xyz_batch_cnt");
return ge::GRAPH_FAILED;
}
auto centerXyzBatchCntDtype = centerXyzBatchCntDesc->GetDataType();
OP_CHECK_IF(
centerXyzBatchCntDtype != xyzBatchCntDtype,
OP_LOGE_FOR_INVALID_DTYPES_WITH_REASON(opName, "xyz_batch_cnt and center_xyz_batch_cnt",
(std::to_string(static_cast<int32_t>(xyzBatchCntDtype)) + " vs " +
std::to_string(static_cast<int32_t>(centerXyzBatchCntDtype)))
.c_str(),
"center_xyz_batch_cnt dtype must equal xyz_batch_cnt dtype"),
return ge::GRAPH_FAILED);
return ge::GRAPH_SUCCESS;
}
static ge::graphStatus ValidateShape(gert::TilingContext* context)
{
auto opName = context->GetNodeName();
auto xyzShape = context->GetInputShape(INDEX_INPUT_XYZ);
if (xyzShape == nullptr) {
OP_LOGE_WITH_INVALID_INPUT(opName, "xyz");
return ge::GRAPH_FAILED;
}
OP_CHECK_IF(xyzShape->GetStorageShape().GetDimNum() != 2,
OP_LOGE_FOR_INVALID_SHAPEDIM(
opName, "xyz", (std::to_string(xyzShape->GetStorageShape().GetDimNum()) + "D").c_str(), "2D"),
return ge::GRAPH_FAILED);
OP_CHECK_IF(xyzShape->GetStorageShape().GetDim(0) != 3,
OP_LOGE_FOR_INVALID_SHAPES_WITH_REASON(
opName, "xyz", ("xyz dim[0]=" + std::to_string(xyzShape->GetStorageShape().GetDim(0))).c_str(),
"xyz dim[0] must be 3 (x/y/z coordinates)"),
return ge::GRAPH_FAILED);
auto centerXyzShape = context->GetInputShape(INDEX_INPUT_CENTER_XYZ);
if (centerXyzShape == nullptr) {
OP_LOGE_WITH_INVALID_INPUT(opName, "center_xyz");
return ge::GRAPH_FAILED;
}
OP_CHECK_IF(
centerXyzShape->GetStorageShape().GetDimNum() != 2,
OP_LOGE_FOR_INVALID_SHAPEDIM(
opName, "center_xyz", (std::to_string(centerXyzShape->GetStorageShape().GetDimNum()) + "D").c_str(), "2D"),
return ge::GRAPH_FAILED);
OP_CHECK_IF(centerXyzShape->GetStorageShape().GetDim(1) != 3,
OP_LOGE_FOR_INVALID_SHAPES_WITH_REASON(
opName, "center_xyz",
("center_xyz dim[1]=" + std::to_string(centerXyzShape->GetStorageShape().GetDim(1))).c_str(),
"center_xyz dim[1] must be 3 (x/y/z coordinates)"),
return ge::GRAPH_FAILED);
auto xyzBatchCntShape = context->GetInputShape(INDEX_INPUT_XYZ_BATCH_CNT);
if (xyzBatchCntShape == nullptr) {
OP_LOGE_WITH_INVALID_INPUT(opName, "xyz_batch_cnt");
return ge::GRAPH_FAILED;
}
OP_CHECK_IF(xyzBatchCntShape->GetStorageShape().GetDimNum() != 1,
OP_LOGE_FOR_INVALID_SHAPEDIM(
opName, "xyz_batch_cnt",
(std::to_string(xyzBatchCntShape->GetStorageShape().GetDimNum()) + "D").c_str(), "1D"),
return ge::GRAPH_FAILED);
auto centerXyzBatchCntShape = context->GetInputShape(INDEX_INPUT_CENTER_XYZ_BATCH_CNT);
if (centerXyzBatchCntShape == nullptr) {
OP_LOGE_WITH_INVALID_INPUT(opName, "center_xyz_batch_cnt");
return ge::GRAPH_FAILED;
}
OP_CHECK_IF(centerXyzBatchCntShape->GetStorageShape().GetDimNum() != 1,
OP_LOGE_FOR_INVALID_SHAPEDIM(
opName, "center_xyz_batch_cnt",
(std::to_string(centerXyzBatchCntShape->GetStorageShape().GetDimNum()) + "D").c_str(), "1D"),
return ge::GRAPH_FAILED);
int64_t xyzBatchB = xyzBatchCntShape->GetStorageShape().GetDim(0);
int64_t centerXyzBatchB = centerXyzBatchCntShape->GetStorageShape().GetDim(0);
std::string batchMsg = "xyz_batch_cnt dim0=" + std::to_string(xyzBatchB) +
", center_xyz_batch_cnt dim0=" + std::to_string(centerXyzBatchB);
OP_CHECK_IF(
xyzBatchB != centerXyzBatchB,
OP_LOGE_FOR_INVALID_SHAPES_WITH_REASON(opName, "xyz_batch_cnt and center_xyz_batch_cnt", batchMsg.c_str(),
"xyz_batch_cnt dim0 must equal center_xyz_batch_cnt dim0"),
return ge::GRAPH_FAILED);
auto xyzDim0 = xyzShape->GetStorageShape().GetDim(0);
auto xyzDim1 = xyzShape->GetStorageShape().GetDim(1);
auto centerXyzDim0 = centerXyzShape->GetStorageShape().GetDim(0);
OP_CHECK_IF(xyzDim0 > INT32_MAX || xyzDim1 > INT32_MAX || centerXyzDim0 > INT32_MAX || xyzBatchB > INT32_MAX,
OP_LOGE_FOR_INVALID_SHAPESIZES_WITH_REASON(
opName, "xyz, center_xyz and xyz_batch_cnt",
("xyz=[" + std::to_string(xyzDim0) + ", " + std::to_string(xyzDim1) + "], center_xyz dim0=" +
std::to_string(centerXyzDim0) + ", xyz_batch_cnt dim0=" + std::to_string(xyzBatchB))
.c_str(),
"shape dimensions must not exceed INT32_MAX"),
return ge::GRAPH_FAILED);
const gert::RuntimeAttrs* attrs = context->GetAttrs();
if (attrs == nullptr) {
OP_LOGE_FOR_INVALID_ARGUMENT_WITH_REASON(opName, "attrs", "attribute container must not be null");
return ge::GRAPH_FAILED;
}
const int64_t* sampleNumPtr = attrs->GetAttrPointer<int64_t>(SAMPLE_NUM_IDX);
if (sampleNumPtr == nullptr) {
OP_LOGE_WITH_INVALID_INPUT(opName, "sample_num");
return ge::GRAPH_FAILED;
}
int64_t sampleNum = *sampleNumPtr;
int64_t totalIdxLength = centerXyzDim0 * sampleNum;
OP_CHECK_IF(totalIdxLength > INT32_MAX,
OP_LOGE_FOR_INVALID_VALUES_WITH_REASON(
opName, "center_xyz and sample_num",
("center_xyz dim0=" + std::to_string(centerXyzDim0) + ", sample_num=" + std::to_string(sampleNum) +
", center_xyz dim0 * sample_num=" + std::to_string(totalIdxLength))
.c_str(),
"center_xyz dim0 multiplied by sample_num must not exceed INT32_MAX"),
return ge::GRAPH_FAILED);
return ge::GRAPH_SUCCESS;
}
static ge::graphStatus ValidateAttrs(gert::TilingContext* context)
{
const gert::RuntimeAttrs* attrs = context->GetAttrs();
if (attrs == nullptr) {
OP_LOGE_FOR_INVALID_ARGUMENT_WITH_REASON(context->GetNodeName(), "attrs",
"attribute container must not be null");
return ge::GRAPH_FAILED;
}
const int64_t* sampleNumPtr = attrs->GetAttrPointer<int64_t>(SAMPLE_NUM_IDX);
if (sampleNumPtr == nullptr) {
OP_LOGE_WITH_INVALID_INPUT(context->GetNodeName(), "sample_num");
return ge::GRAPH_FAILED;
}
int64_t sampleNum = *sampleNumPtr;
OP_CHECK_IF(sampleNum <= 0,
OP_LOGE_FOR_INVALID_VALUE_WITH_REASON(context->GetNodeName(), "sample_num",
("sample_num=" + std::to_string(sampleNum)).c_str(),
"sample_num must be > 0"),
return ge::GRAPH_FAILED);
const float* maxRadiusPtr = attrs->GetAttrPointer<float>(MAX_RADIUS_IDX);
if (maxRadiusPtr == nullptr) {
OP_LOGE_WITH_INVALID_INPUT(context->GetNodeName(), "max_radius");
return ge::GRAPH_FAILED;
}
float maxRadius = *maxRadiusPtr;
OP_CHECK_IF(maxRadius <= 0.0f,
OP_LOGE_FOR_INVALID_VALUE_WITH_REASON(context->GetNodeName(), "max_radius",
("max_radius=" + std::to_string(maxRadius)).c_str(),
"max_radius must be > 0"),
return ge::GRAPH_FAILED);
return ge::GRAPH_SUCCESS;
}
static ge::graphStatus ValidateInputs(gert::TilingContext* context)
{
OP_CHECK_IF(ValidateDtype(context) != ge::GRAPH_SUCCESS, OP_LOGE_WITHOUT_REPORT(context, "ValidateDtype failed"),
return ge::GRAPH_FAILED);
OP_CHECK_IF(ValidateShape(context) != ge::GRAPH_SUCCESS, OP_LOGE_WITHOUT_REPORT(context, "ValidateShape failed"),
return ge::GRAPH_FAILED);
OP_CHECK_IF(ValidateAttrs(context) != ge::GRAPH_SUCCESS, OP_LOGE_WITHOUT_REPORT(context, "ValidateAttrs failed"),
return ge::GRAPH_FAILED);
return ge::GRAPH_SUCCESS;
}
class StackBallQueryTiling {
public:
explicit StackBallQueryTiling(gert::TilingContext* context) : tilingContext(context) {};
void Init() const;
ge::graphStatus RunKernelTiling();
void CalRunningInfo(gert::TilingContext* context, const uint64_t actCoreNum);
void TilingDataPrint() const;
private:
StackBallQueryTilingData tilingData;
gert::TilingContext* tilingContext = nullptr;
int32_t batchSize;
int32_t totalLengthCenterXyz;
int32_t totalLengthXyz;
int32_t totalIdxLength;
int32_t coreNum;
int32_t centerXyzPerCore;
int32_t tailCenterXyzPerCore;
float maxRadius;
int32_t sampleNum;
};
void StackBallQueryTiling::Init() const
{
OP_LOGD(tilingContext, "tiling initing.");
auto dataType = tilingContext->GetInputDesc(INDEX_INPUT_XYZ)->GetDataType();
auto cntDataType = tilingContext->GetInputDesc(INDEX_INPUT_XYZ_BATCH_CNT)->GetDataType();
tilingContext->SetTilingKey(FP32_MODE);
if (dataType == ge::DT_FLOAT) {
tilingContext->SetTilingKey(cntDataType == ge::DT_INT64 ? FP32_INT64_MODE : FP32_MODE);
OP_LOGD(tilingContext, "set tilingKey to FP32_MODE.");
} else if (dataType == ge::DT_FLOAT16) {
tilingContext->SetTilingKey(cntDataType == ge::DT_INT64 ? FP16_INT64_MODE : FP16_MODE);
OP_LOGD(tilingContext, "set tilingKey to FP16_MODE.");
}
OP_LOGD(tilingContext, "tiling inited.");
}
void StackBallQueryTiling::TilingDataPrint() const
{
OP_LOGD(tilingContext, "TilingDataPrint start.");
OP_LOGD(tilingContext, "batchSize is %d.", this->batchSize);
OP_LOGD(tilingContext, "totalLengthCenterXyz is %d.", this->totalLengthCenterXyz);
OP_LOGD(tilingContext, "totalLengthXyz is %d.", this->totalLengthXyz);
OP_LOGD(tilingContext, "totalIdxLength is %d.", this->totalIdxLength);
OP_LOGD(tilingContext, "coreNum is %d.", this->coreNum);
OP_LOGD(tilingContext, "centerXyzPerCore is %d.", this->centerXyzPerCore);
OP_LOGD(tilingContext, "tailCenterXyzPerCore is %d.", this->tailCenterXyzPerCore);
OP_LOGD(tilingContext, "sampleNum is %d.", this->sampleNum);
OP_LOGD(tilingContext, "maxRadius is %f.", this->maxRadius);
OP_LOGD(tilingContext, "TilingDataPrint end.");
}
void StackBallQueryTiling::CalRunningInfo(gert::TilingContext* context, const uint64_t actCoreNum)
{
const gert::RuntimeAttrs* attrs = context->GetAttrs();
const int64_t* sampleNumPtr = attrs->GetAttrPointer<int64_t>(SAMPLE_NUM_IDX);
this->sampleNum = static_cast<int32_t>(*sampleNumPtr);
const float* maxRadiusPtr = attrs->GetAttrPointer<float>(MAX_RADIUS_IDX);
this->maxRadius = *maxRadiusPtr;
auto runtimeCenterXyzShapePtr = context->GetInputShape(INDEX_INPUT_CENTER_XYZ);
const gert::Shape& centerXyzShape = runtimeCenterXyzShapePtr->GetStorageShape();
auto runtimeXyzShapePtr = context->GetInputShape(INDEX_INPUT_XYZ);
const gert::Shape& xyzShape = runtimeXyzShapePtr->GetStorageShape();
auto runtimeXyzBatchCntShapePtr = context->GetInputShape(INDEX_INPUT_XYZ_BATCH_CNT);
const gert::Shape& xyzBatchCntShape = runtimeXyzBatchCntShapePtr->GetStorageShape();
int64_t batchSizeInt64 = xyzBatchCntShape.GetDim(0);
int64_t totalLengthCenterXyzInt64 = centerXyzShape.GetDim(0);
int64_t totalLengthXyzInt64 = xyzShape.GetDim(1);
this->batchSize = static_cast<int32_t>(batchSizeInt64);
this->totalLengthCenterXyz = static_cast<int32_t>(totalLengthCenterXyzInt64);
this->totalLengthXyz = static_cast<int32_t>(totalLengthXyzInt64);
this->totalIdxLength = this->totalLengthCenterXyz * this->sampleNum;
if (static_cast<uint64_t>(this->totalLengthCenterXyz) <= actCoreNum) {
this->coreNum = totalLengthCenterXyz;
} else {
this->coreNum = static_cast<int32_t>(actCoreNum);
}
this->centerXyzPerCore = GetCeilInt(this->totalLengthCenterXyz, this->coreNum);
int32_t alignNum = 8;
if (GetCeilInt(alignNum, this->sampleNum) > this->centerXyzPerCore) {
this->centerXyzPerCore = GetCeilInt(alignNum, this->sampleNum);
}
this->tailCenterXyzPerCore = this->totalLengthCenterXyz % this->centerXyzPerCore;
if (this->tailCenterXyzPerCore == 0) {
this->coreNum = this->totalLengthCenterXyz / this->centerXyzPerCore;
} else {
this->coreNum = 1 + (this->totalLengthCenterXyz - this->tailCenterXyzPerCore) / this->centerXyzPerCore;
}
}
ge::graphStatus StackBallQueryTiling::RunKernelTiling()
{
OP_LOGD(tilingContext, "RunKernelTiling start.");
ge::graphStatus validateRet = ValidateInputs(tilingContext);
if (validateRet != ge::GRAPH_SUCCESS) {
return validateRet;
}
Init();
auto platformInfo = platform_ascendc::PlatformAscendC(tilingContext->GetPlatformInfo());
const uint64_t actCoreNum = platformInfo.GetCoreNumAiv();
CalRunningInfo(tilingContext, actCoreNum);
tilingData.set_batchSize(this->batchSize);
tilingData.set_totalLengthCenterXyz(this->totalLengthCenterXyz);
tilingData.set_totalLengthXyz(this->totalLengthXyz);
tilingData.set_totalIdxLength(this->totalIdxLength);
tilingData.set_coreNum(this->coreNum);
tilingData.set_centerXyzPerCore(this->centerXyzPerCore);
tilingData.set_tailCenterXyzPerCore(this->tailCenterXyzPerCore);
tilingData.set_maxRadius(this->maxRadius);
tilingData.set_sampleNum(this->sampleNum);
tilingContext->SetBlockDim(tilingData.get_coreNum());
tilingData.SaveToBuffer(tilingContext->GetRawTilingData()->GetData(),
tilingContext->GetRawTilingData()->GetCapacity());
tilingContext->GetRawTilingData()->SetDataSize(tilingData.GetDataSize());
TilingDataPrint();
size_t sysWorkspaceSize = WORKSPACE_16MB_SIZE;
size_t* currentWorkspace = tilingContext->GetWorkspaceSizes(1);
currentWorkspace[0] = sysWorkspaceSize;
OP_LOGD(tilingContext, "RunKernelTiling end.");
return ge::GRAPH_SUCCESS;
}
static ge::graphStatus TilingStackBallQuery(gert::TilingContext* context)
{
StackBallQueryTiling tilingObject(context);
return tilingObject.RunKernelTiling();
}
static ge::graphStatus TilingPrepare4StackBallQuery(gert::TilingParseContext* context)
{
OP_LOGD(context->GetNodeName(), "TilingPrepare4StackBallQuery enter.");
auto compileInfo = context->GetCompiledInfo<StackBallQueryCompileInfo>();
if (compileInfo == nullptr) {
OP_LOGE_FOR_INVALID_ARGUMENT_WITH_REASON(context->GetNodeName(), "compile_info",
"compile info must not be null");
return ge::GRAPH_FAILED;
}
auto platformInfo = context->GetPlatformInfo();
if (platformInfo == nullptr) {
OP_LOGE_FOR_INVALID_ARGUMENT_WITH_REASON(context->GetNodeName(), "platform_info",
"platform info must not be null");
return ge::GRAPH_FAILED;
}
auto ascendcPlatform = platform_ascendc::PlatformAscendC(platformInfo);
compileInfo->aicore_num = static_cast<uint32_t>(ascendcPlatform.GetCoreNumAiv());
OP_CHECK_IF(
(compileInfo->aicore_num <= 0),
OP_LOGE_FOR_INVALID_ARGUMENT_WITH_REASON(
context->GetNodeName(), "platform_info",
("AIV core number must be greater than 0, but got " + std::to_string(compileInfo->aicore_num)).c_str()),
return ge::GRAPH_FAILED);
uint64_t ubSizePlatForm;
ascendcPlatform.GetCoreMemSize(platform_ascendc::CoreMemType::UB, ubSizePlatForm);
compileInfo->ub_platform_byte_size = static_cast<int64_t>(ubSizePlatForm);
OP_CHECK_IF((compileInfo->ub_platform_byte_size <= 0),
OP_LOGE_FOR_INVALID_ARGUMENT_WITH_REASON(context->GetNodeName(), "platform_info",
("UB size must be greater than 0, but got " +
std::to_string(compileInfo->ub_platform_byte_size) + " bytes")
.c_str()),
return ge::GRAPH_FAILED);
return ge::GRAPH_SUCCESS;
}
IMPL_OP_OPTILING(StackBallQuery)
.Tiling(TilingStackBallQuery)
.TilingParse<StackBallQueryCompileInfo>(TilingPrepare4StackBallQuery);
}