* Copyright (c) 2026 Huawei Technologies Co., Ltd.
* This program is free software, you can redistribute it and/or modify it under
* the terms and conditions of CANN Open Software License Agreement Version 2.0
* (the "License"). Please refer to the License for details. You may not use
* this file except in compliance with the License. THIS SOFTWARE IS PROVIDED ON
* AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS
* FOR A PARTICULAR PURPOSE. See LICENSE in the root of the software repository
* for the full text of the License.
*/
#include "api_impl_kernel_func.hpp"
#include <cstring>
#include <new>
#include <sstream>
#include <string>
#include "api_impl_creator.hpp"
#include "base_david.hpp"
#include "context.hpp"
#include "device.hpp"
#include "error_message_manage.hpp"
#include "kernel.hpp"
#include "kernel_utils.hpp"
#include "program.hpp"
#include "runtime.hpp"
namespace cce {
namespace runtime {
bool IsImplKernelFuncSupported() { return true; }
ApiKernelFunc* CreateImplKernelFuncAndGet()
{
ApiKernelFunc* const apiImplKernelFunc = new (std::nothrow) ApiImplKernelFunc();
if (apiImplKernelFunc == nullptr) {
RT_LOG_OUTER_MSG_IMPL(ErrorCode::EE1013, sizeof(ApiImplKernelFunc), "new");
RT_LOG(RT_LOG_ERROR, "create ApiImplKernelFunc failed.");
return nullptr;
}
RT_LOG(RT_LOG_INFO, "ApiImplKernelFunc:Runtime_alloc_size %zu", sizeof(ApiImplKernelFunc));
return apiImplKernelFunc;
}
void DestroyImplKernelFunc(ApiKernelFunc*& apiImplKernelFunc)
{
delete apiImplKernelFunc;
apiImplKernelFunc = nullptr;
}
static bool CheckVectorKernel(const Kernel* const kernel)
{
if (kernel->GetKernelAttrType() == RT_KERNEL_ATTR_TYPE_VECTOR) {
return true;
}
if (kernel->GetMixType() == MIX_AIV) {
return true;
}
return false;
}
rtError_t ApiImplKernelFunc::FuncGetAddr(const Kernel* const funcHandle, void** const aicAddr, void** const aivAddr)
{
NULL_PTR_RETURN_MSG_OUTER_WITH_FUNC_DESC(
funcHandle, RT_ERROR_INVALID_VALUE, "Obtaining the execution address of a specified kernel on the device");
NULL_PTR_RETURN_MSG_OUTER_WITH_FUNC_DESC(
aicAddr, RT_ERROR_INVALID_VALUE, "Obtaining the execution address of a specified kernel on the device");
NULL_PTR_RETURN_MSG_OUTER_WITH_FUNC_DESC(
aivAddr, RT_ERROR_INVALID_VALUE, "Obtaining the execution address of a specified kernel on the device");
COND_RETURN_AND_MSG_OUTER(
funcHandle->GetKernelRegisterType() != RT_KERNEL_REG_TYPE_NON_CPU, RT_ERROR_INVALID_VALUE, ErrorCode::EE1017,
"Obtaining the execution address of a specified kernel on the device", "funcHandle",
"The funcHandle obtained after registering the AI CPU operator is not supported");
Runtime::Instance()->CallApiBegin(RT_PROF_API_FUNC_GET_ADDR);
uint64_t funcAddr1 = 0ULL;
uint64_t funcAddr2 = 0ULL;
const rtError_t error = funcHandle->GetFunctionDevAddr(funcAddr1, funcAddr2);
if (error != RT_ERROR_NONE) {
*aicAddr = nullptr;
*aivAddr = nullptr;
} else if ((funcAddr1 != 0ULL) && (funcAddr2 == 0ULL) && CheckVectorKernel(funcHandle)) {
*aivAddr = RtValueToPtr<void*>(funcAddr1);
*aicAddr = RtValueToPtr<void*>(funcAddr2);
} else {
*aicAddr = RtValueToPtr<void*>(funcAddr1);
*aivAddr = RtValueToPtr<void*>(funcAddr2);
}
Runtime::Instance()->CallApiEnd(error);
ERROR_RETURN(error, "Get func addr by function handle failed.");
return error;
}
rtError_t ApiImplKernelFunc::FuncGetName(const Kernel* const kernel, const uint32_t maxLen, char_t* const name)
{
NULL_PTR_RETURN_MSG_OUTER_WITH_FUNC_DESC(kernel, RT_ERROR_INVALID_VALUE, "Obtaining the kernel function name");
NULL_PTR_RETURN_MSG_OUTER_WITH_FUNC_DESC(name, RT_ERROR_INVALID_VALUE, "Obtaining the kernel function name");
COND_RETURN_AND_MSG_OUTER_WITH_PARAM_AND_FUNC_DESC(
maxLen < (kernel->Name_().length() + 1U), RT_ERROR_INVALID_VALUE, "Obtaining the kernel function name", maxLen,
RtFmtMsg("greater than or equal to %zu", kernel->Name_().length() + 1U));
const errno_t error =
memcpy_s(name, static_cast<size_t>(maxLen), kernel->Name_().c_str(), kernel->Name_().length() + 1U);
if (error != EOK) {
std::stringstream ss;
ss << std::hex << "name=0x" << RtPtrToValue(name) << ", kernelName=0x" << RtPtrToValue(kernel->Name_().c_str())
<< std::dec << ", maxLen=" << maxLen << ", actualLen=" << kernel->Name_().length() + 1U << ".";
RT_LOG_OUTER_MSG_IMPL(
ErrorCode::EE1020, "Obtaining the kernel function name", "memcpy_s", std::to_string(error).c_str(),
strerror(error), ss.str().c_str());
const rtError_t ret = RT_ERROR_SEC_HANDLE;
ERROR_RETURN(ret, "get func name failed");
}
return RT_ERROR_NONE;
}
rtError_t ApiImplKernelFunc::FunctionGetAttribute(rtFuncHandle funcHandle, rtFuncAttribute attrType, int64_t* attrValue)
{
NULL_PTR_RETURN_MSG_OUTER_WITH_FUNC_DESC(
funcHandle, RT_ERROR_INVALID_VALUE, "Obtaining kernel function attributes");
NULL_PTR_RETURN_MSG_OUTER_WITH_FUNC_DESC(attrValue, RT_ERROR_INVALID_VALUE, "Obtaining kernel function attributes");
COND_RETURN_AND_MSG_OUTER_WITH_PARAM_NAME_AND_FUNC_DESC(
((static_cast<uint32_t>(attrType) < RT_FUNCTION_ATTR_KERNEL_TYPE) ||
(static_cast<uint32_t>(attrType) >= RT_FUNCTION_ATTR_MAX)),
RT_ERROR_INVALID_VALUE, "Obtaining kernel function attributes",
(attrType == RT_FUNCTION_ATTR_MAX) ? "FUNCTION_ATTR_MAX(4)" :
RtFmtMsg("UNKNOWN(%d)", static_cast<int32_t>(attrType)),
"attrType",
RtFmtMsg(
"[%d, %d)", static_cast<int32_t>(RT_FUNCTION_ATTR_KERNEL_TYPE),
static_cast<int32_t>(RT_FUNCTION_ATTR_MAX)));
if (attrType == RT_FUNCTION_ATTR_KERNEL_RATIO) {
const Runtime* const rtInstance = Runtime::Instance();
NULL_PTR_RETURN_MSG(rtInstance, RT_ERROR_INSTANCE_NULL);
const rtChipType_t chipType = rtInstance->GetChipType();
COND_RETURN_WARN(
!IS_SUPPORT_CHIP_FEATURE(chipType, RtOptionalFeatureType::RT_FEATURE_MODEL_ACL_GRAPH),
ACL_ERROR_RT_FEATURE_NOT_SUPPORT, "chip type(%d) does not support rtFunctionGetAttribute api, return.",
static_cast<int32_t>(chipType));
const Kernel* const kernel = RtPtrToPtr<Kernel*>(funcHandle);
COND_RETURN_AND_MSG_OUTER(
kernel->GetKernelRegisterType() != RT_KERNEL_REG_TYPE_NON_CPU, RT_ERROR_INVALID_VALUE, ErrorCode::EE1017,
"Obtaining kernel function attributes", "funcHandle",
"The funcHandle obtained after registering the AI CPU operator is not supported");
}
const Kernel* const kernel = RtPtrToPtr<Kernel*>(funcHandle);
switch (attrType) {
case RT_FUNCTION_ATTR_KERNEL_TYPE: {
*attrValue = static_cast<int64_t>(kernel->GetKernelAttrType());
COND_RETURN_ERROR_MSG_INNER(
*attrValue == static_cast<int64_t>(RT_KERNEL_ATTR_TYPE_INVALID), RT_ERROR_INVALID_VALUE,
"Invalid kernel type.");
break;
}
case RT_FUNCTION_ATTR_KERNEL_RATIO: {
const uint32_t taskRatio = kernel->GetTaskRation();
const uint32_t mixType = kernel->GetMixType();
uint16_t ratio[2];
ComputeRatio(ratio, mixType, taskRatio);
uint16_t* ratioArr = RtPtrToPtr<uint16_t*>(attrValue);
ratioArr[1] = ratio[0];
ratioArr[0] = ratio[1];
RT_LOG(RT_LOG_DEBUG, "mixType=%u, ratio[0]=%u, ratio[1]=%u.", mixType, ratio[0], ratio[1]);
break;
}
case RT_FUNCTION_ATTR_KERNEL_SCHED_MODE: {
*attrValue = static_cast<int64_t>(kernel->GetSchedMode());
break;
}
default: {
if (attrType == RT_FUNCTION_ATTR_MAX) {
RT_LOG(RT_LOG_WARNING, "Invalid attrType=FUNCTION_ATTR_MAX(4)");
} else {
RT_LOG(RT_LOG_WARNING, "Invalid attrType=UNKNOWN(%d)", static_cast<int32_t>(attrType));
}
break;
}
}
return RT_ERROR_NONE;
}
rtError_t ApiImplKernelFunc::FuncGetSize(const Kernel* const funcHandle, size_t* const aicSize, size_t* const aivSize)
{
NULL_PTR_RETURN_MSG_OUTER_WITH_FUNC_DESC(
funcHandle, RT_ERROR_INVALID_VALUE, "Obtaining the size of the kernel function code segment");
NULL_PTR_RETURN_MSG_OUTER_WITH_FUNC_DESC(
aicSize, RT_ERROR_INVALID_VALUE, "Obtaining the size of the kernel function code segment");
NULL_PTR_RETURN_MSG_OUTER_WITH_FUNC_DESC(
aivSize, RT_ERROR_INVALID_VALUE, "Obtaining the size of the kernel function code segment");
COND_RETURN_AND_MSG_OUTER(
funcHandle->GetKernelRegisterType() != RT_KERNEL_REG_TYPE_NON_CPU, RT_ERROR_INVALID_VALUE, ErrorCode::EE1017,
"Obtaining the size of the kernel function code segment", "funcHandle",
"The funcHandle obtained after registering the AI CPU operator is not supported");
uint32_t funcSize1 = 0U;
uint32_t funcSize2 = 0U;
funcHandle->GetKernelLength(funcSize1, funcSize2);
if ((funcSize1 != 0U) && (funcSize2 == 0U) && (CheckVectorKernel(funcHandle))) {
*aivSize = RtValueToPtr<size_t>(funcSize1);
*aicSize = RtValueToPtr<size_t>(funcSize2);
} else {
*aicSize = RtValueToPtr<size_t>(funcSize1);
*aivSize = RtValueToPtr<size_t>(funcSize2);
}
return RT_ERROR_NONE;
}
rtError_t ApiImplKernelFunc::FunctionGetBinary(const Kernel* const funcHandle, Program** const binHandle)
{
NULL_PTR_RETURN_MSG_OUTER_WITH_FUNC_DESC(
funcHandle, RT_ERROR_INVALID_VALUE, "Obtaining the binary handle of an operator");
NULL_PTR_RETURN_MSG_OUTER_WITH_FUNC_DESC(
binHandle, RT_ERROR_INVALID_VALUE, "Obtaining the binary handle of an operator");
Program* const prog = funcHandle->Program_();
*binHandle = prog;
return RT_ERROR_NONE;
}
rtError_t ApiImplKernelFunc::FunctionGetParamCount(const Kernel* funcHandle, size_t* paramCount)
{
COND_RETURN_WARN(
funcHandle->GetKernelRegisterType() == RT_KERNEL_REG_TYPE_CPU, RT_ERROR_FEATURE_NOT_SUPPORT,
"AI CPU kernels are not supported.");
COND_RETURN_AND_MSG_OUTER(
!funcHandle->HasParamSummary(), RT_ERROR_INVALID_VALUE, ErrorCode::EE1017,
"Obtaining the number of parameters from the kernel function handle", "funcHandle",
"Kernel does not have parameter information");
*paramCount = static_cast<size_t>(funcHandle->GetParamCount());
return RT_ERROR_NONE;
}
rtError_t ApiImplKernelFunc::FunctionGetParamInfo(
const Kernel* funcHandle, size_t paramIndex, size_t* paramOffset, size_t* paramSize)
{
COND_RETURN_WARN(
funcHandle->GetKernelRegisterType() == RT_KERNEL_REG_TYPE_CPU, RT_ERROR_FEATURE_NOT_SUPPORT,
"AI CPU kernels are not supported.");
COND_RETURN_AND_MSG_OUTER(
!funcHandle->HasParamSummary(), RT_ERROR_INVALID_VALUE, ErrorCode::EE1017,
"Obtaining parameter information from the kernel function handle", "funcHandle",
"Kernel does not have parameter information");
if (paramIndex >= funcHandle->GetParamCount()) {
RT_LOG_OUTER_MSG_WITH_FUNC_DESC(
ErrorCode::EE1003, "Obtaining parameter information from the kernel function handle", paramIndex,
"paramIndex", RtFmtMsg("[0, %u)", funcHandle->GetParamCount()));
return RT_ERROR_INVALID_VALUE;
}
uint32_t offset = 0U;
uint32_t size = 0U;
const rtError_t error = funcHandle->GetParamInfo(static_cast<uint32_t>(paramIndex), &offset, &size);
ERROR_RETURN(error, "GetParamInfo failed, paramIndex=%zu.", paramIndex);
if (paramOffset != nullptr) {
*paramOffset = static_cast<size_t>(offset);
}
if (paramSize != nullptr) {
*paramSize = static_cast<size_t>(size);
}
return RT_ERROR_NONE;
}
rtError_t ApiImplKernelFunc::FunctionGetAvailDynUbufPerBlock(
Kernel* funcHandle, uint32_t flags, size_t* dynamicUbufSize)
{
NULL_PTR_RETURN_MSG_OUTER_WITH_FUNC_DESC(
funcHandle, RT_ERROR_INVALID_VALUE,
"Querying the maximum size of the dynamic UB buffer that can be set for a kernel function");
NULL_PTR_RETURN_MSG_OUTER_WITH_FUNC_DESC(
dynamicUbufSize, RT_ERROR_INVALID_VALUE,
"Querying the maximum size of the dynamic UB buffer that can be set for a kernel function");
COND_RETURN_AND_MSG_OUTER_WITH_PARAM_AND_FUNC_DESC(
(flags != 0U), RT_ERROR_INVALID_VALUE,
"Querying the maximum size of the dynamic UB buffer that can be set for a kernel function", flags, "0");
NULL_PTR_RETURN_MSG(funcHandle->Program_(), RT_ERROR_PROGRAM_NULL);
const uint32_t kernelVfType = funcHandle->KernelVfType_();
const bool simtFlag = (kernelVfType == static_cast<uint32_t>(AivTypeFlag::AIV_TYPE_SIMT_VF_ONLY)) ||
(kernelVfType == static_cast<uint32_t>(AivTypeFlag::AIV_TYPE_SIMD_SIMT_MIX_VF));
if (!simtFlag) {
*dynamicUbufSize = 0U;
return RT_ERROR_NONE;
}
COND_RETURN_ERROR_MSG_INNER(
funcHandle->ShareMemSize_() > RT_SIMT_REMAIN_UB_SIZE, RT_ERROR_INVALID_VALUE,
"Compiler alloc ub size %u exceeds the maximum simt ub limit %u.", funcHandle->ShareMemSize_(),
RT_SIMT_REMAIN_UB_SIZE);
*dynamicUbufSize = static_cast<size_t>(RT_SIMT_REMAIN_UB_SIZE - funcHandle->ShareMemSize_());
return RT_ERROR_NONE;
}
rtError_t ApiImplKernelFunc::GetFunctionBySymbol(const void* symbol, Kernel** const funcHandle)
{
NULL_PTR_RETURN_MSG_OUTER_WITH_FUNC_DESC(
symbol, RT_ERROR_INVALID_VALUE, "Obtaining the kernel function handle based on the function symbol name");
NULL_PTR_RETURN_MSG_OUTER_WITH_FUNC_DESC(
funcHandle, RT_ERROR_INVALID_VALUE, "Obtaining the kernel function handle based on the function symbol name");
const Kernel* kernelTmp = nullptr;
Context* const curCtx = Runtime::Instance()->CurrentContext(true, DEFAULT_DEVICE_ID);
CHECK_CONTEXT_VALID_WITH_RETURN(curCtx, RT_ERROR_CONTEXT_NULL);
Device* device = curCtx->Device_();
NULL_PTR_RETURN_MSG(device, RT_ERROR_DEVICE_NULL);
Runtime* const rtInstance = Runtime::Instance();
kernelTmp = rtInstance->funcSymbolTable_.Lookup(symbol);
if (kernelTmp == nullptr) {
return RT_ERROR_INVALID_DEVICE_FUNCTION;
}
const Program* const prog = kernelTmp->Program_();
Program* const progTmp = const_cast<Program*>(prog);
rtError_t ret = progTmp->CopySoAndNameToCurrentDevice();
ERROR_RETURN(ret, "copy program failed retCode=%#x.", ret);
*funcHandle = const_cast<Kernel*>(kernelTmp);
return RT_ERROR_NONE;
}
}
}