* 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.
*/
#include "aicpu_bin_handler.h"
#include "mmpa/mmpa_api.h"
#include "common/checker.h"
#include "graph/ge_error_codes.h"
#include "graph_metadef/graph/utils/file_utils.h"
#include "graph/load/model_manager/model_manager.h"
#include "framework/common/debug/log.h"
#include "runtime/dev.h"
#include "runtime/context.h"
using namespace ge;
namespace gert {
namespace {
constexpr size_t kSocVersionLen = 128U;
constexpr int32_t kCpuKernelModeJson = 0;
constexpr int32_t kCpuKernelModeData = 2;
const std::string kAicpuBuiltInCustKernelFile = "/built-in/op_impl/aicpu/kernel/";
}
bool OpJsonBinHandler::is_support_ = true;
std::once_flag OpJsonBinHandler::init_flag_;
bool OpJsonBinHandler::IsSupportBinHandle()
{
std::call_once(init_flag_,
[]() {
char soc_version[kSocVersionLen] = {0};
if (rtGetSocVersion(soc_version, kSocVersionLen) != ge::GRAPH_SUCCESS) {
GELOGE(ge::FAILED, "Get soc version failed.");
return;
}
if (strncmp(soc_version, "Ascend910_96", (sizeof("Ascend910_96") - 1UL)) == 0) {
is_support_ = false;
}
GELOGI("Init bin handle support status, val=%u, socVersion=%s", static_cast<uint32_t>(is_support_), soc_version);
}
);
return is_support_;
}
ge::graphStatus OpJsonBinHandler::LoadBinary(const std::string &json_path) {
std::unique_lock lock(bin_mutex_);
if (bin_handle_ != nullptr) {
GELOGI("Load binary from json success, no need to load again. json_path=%s", json_path.c_str());
return ge::GRAPH_SUCCESS;
}
if (json_path.empty()) {
GELOGE(ge::FAILED, "Load binary failed by json path is empty.");
return ge::FAILED;
}
aclrtBinaryLoadOption bin_option = {};
bin_option.type = ACL_RT_BINARY_LOAD_OPT_CPU_KERNEL_MODE;
bin_option.value.cpuKernelMode = kCpuKernelModeJson;
aclrtBinaryLoadOptions load_bin_cfg = {&bin_option, 1U};
GE_ASSERT_SUCCESS(aclrtBinaryLoadFromFile(json_path.c_str(), &load_bin_cfg, &bin_handle_));
GE_ASSERT_NOTNULL(bin_handle_);
GELOGI("Load json binary success for %s.", json_path.c_str());
return ge::GRAPH_SUCCESS;
}
ge::graphStatus OpDataBinHandler::LoadBinary(const std::string &so_name, const ge::OpKernelBinPtr &kernel_bin)
{
std::unique_lock lock(bin_mutex_);
if (bin_handle_ != nullptr) {
GELOGI("Load binary from data success, no need to load again. so=%s", so_name.c_str());
return ge::GRAPH_SUCCESS;
}
if (kernel_bin == nullptr) {
GELOGE(ge::FAILED, "Load custom aicpu binary failed by nullptr. so=%s", so_name.c_str());
return ge::FAILED;
}
if (so_name.empty()) {
GELOGE(ge::FAILED, "Load custom aicpu binary failed by so name is empty.");
return ge::FAILED;
}
aclrtBinaryLoadOption bin_option = {};
bin_option.type = ACL_RT_BINARY_LOAD_OPT_CPU_KERNEL_MODE;
bin_option.value.cpuKernelMode = kCpuKernelModeData;
const aclrtBinaryLoadOptions load_bin_cfg = {&bin_option, 1U};
GE_ASSERT_SUCCESS(aclrtBinaryLoadFromData(kernel_bin->GetBinData(), kernel_bin->GetBinDataSize(),
&load_bin_cfg, &bin_handle_));
GE_ASSERT_NOTNULL(bin_handle_);
GELOGI("Load data binary success for %s.", so_name.c_str());
return ge::GRAPH_SUCCESS;
}
TfJsonBinHandler &TfJsonBinHandler::Instance() {
static TfJsonBinHandler inst;
return inst;
}
AicpuJsonBinHandler &AicpuJsonBinHandler::Instance() {
static AicpuJsonBinHandler inst;
return inst;
}
CustBinHandlerManager &CustBinHandlerManager::Instance()
{
static CustBinHandlerManager inst;
return inst;
}
ge::graphStatus CustBinHandlerManager::LoadAndGetBinHandle(const std::string &so_name,
const ge::OpKernelBinPtr &kernel_bin, rtBinHandle &handle) {
handle = nullptr;
if ((so_name.empty()) || (kernel_bin == nullptr)) {
GELOGE(ge::FAILED, "Load bin failed by so name is empty or bin is nullptr, so_name=%s", so_name.c_str());
return ge::FAILED;
}
rtContext_t current_ctx = nullptr;
GE_CHK_RT_RET(aclrtGetCurrentContext(¤t_ctx));
const uintptr_t resource_id = reinterpret_cast<uintptr_t>(current_ctx);
const std::lock_guard<std::recursive_mutex> lk(mutex_);
const auto &so_bin_maps = bin_manager_.find(resource_id);
if (so_bin_maps == bin_manager_.end()) {
OpDataBinHandlerPtr bin_handler = std::make_shared<OpDataBinHandler>();
GE_ASSERT_NOTNULL(bin_handler);
GE_ASSERT_SUCCESS(bin_handler->LoadBinary(so_name, kernel_bin));
bin_manager_.emplace(resource_id, std::unordered_map<std::string, OpDataBinHandlerPtr>{{so_name, bin_handler}});
handle = bin_handler->GetBinHandle();
GELOGI("Add resource and bin handle success, resource_id=%lu, so=%s, size=%lu",
resource_id, so_name.c_str(), bin_manager_.size());
return ge::GRAPH_SUCCESS;
}
const auto &iter = so_bin_maps->second.find(so_name);
if (iter == so_bin_maps->second.end()) {
OpDataBinHandlerPtr bin_handler = std::make_shared<OpDataBinHandler>();
GE_ASSERT_NOTNULL(bin_handler);
GE_ASSERT_SUCCESS(bin_handler->LoadBinary(so_name, kernel_bin));
so_bin_maps->second.emplace(so_name, bin_handler);
handle = bin_handler->GetBinHandle();
GELOGI("Add bin handle for so %s success, resource_id=%lu, size=%lu",
so_name.c_str(), resource_id, so_bin_maps->second.size());
return ge::GRAPH_SUCCESS;
}
GELOGI("Bin handle for so %s already exists, will not repeat load. resource_id=%lu",
so_name.c_str(), resource_id);
handle = iter->second->GetBinHandle();
return ge::GRAPH_SUCCESS;
}
ge::graphStatus CustBinHandlerManager::GetBinHandle(const std::string &so_name, rtBinHandle &handle) {
handle = nullptr;
if (so_name.empty()) {
GELOGE(ge::FAILED, "Get bin handle failed by empty so name, so_name=%s", so_name.c_str());
return ge::FAILED;
}
rtContext_t current_ctx = nullptr;
GE_CHK_RT_RET(aclrtGetCurrentContext(¤t_ctx));
const uintptr_t resource_id = reinterpret_cast<uintptr_t>(current_ctx);
const std::lock_guard<std::recursive_mutex> lk(mutex_);
const auto &so_bin_maps = bin_manager_.find(resource_id);
if (so_bin_maps == bin_manager_.end()) {
ge::OpKernelBinPtr kernel_bin = GetKernelBin(so_name);
GE_ASSERT_NOTNULL(kernel_bin);
(void)LoadAndGetBinHandle(so_name, kernel_bin, handle);
GELOGI("Bin handle is not found in resource id, but reading so succeeds, resource_id=%lu, so=%s, size=%lu",
resource_id, so_name.c_str(), bin_manager_.size());
return ge::SUCCESS;
}
const auto &iter = so_bin_maps->second.find(so_name);
if (iter == so_bin_maps->second.end()) {
ge::OpKernelBinPtr kernel_bin = GetKernelBin(so_name);
GE_ASSERT_NOTNULL(kernel_bin);
(void)LoadAndGetBinHandle(so_name, kernel_bin, handle);
GELOGI("Bin handle in current resource id, but read so success, resource_id=%lu, so=%s, size=%lu",
resource_id, so_name.c_str(), so_bin_maps->second.size());
return ge::GRAPH_SUCCESS;
}
GELOGI("Get bin handle success, resource_id=%lu, so=%s", resource_id, so_name.c_str());
handle = iter->second->GetBinHandle();
return ge::GRAPH_SUCCESS;
}
ge::OpKernelBinPtr CustBinHandlerManager::GetKernelBin(const std::string &so_name) {
const auto &iter = kernel_manager_.find(so_name);
if (iter == kernel_manager_.end()) {
ge::OpKernelBinPtr kernel_bin = nullptr;
(void)GetCustAicpuBinFromFile(so_name, kernel_bin);
if (kernel_bin == nullptr) {
GELOGI("Get cust aicpu bin from model, so=%s", so_name.c_str());
(void)ModelManager::GetInstance().GetCustAicpuSo(so_name, kernel_bin);
return kernel_bin;
}
kernel_manager_.emplace(so_name, kernel_bin);
return kernel_bin;
}
return iter->second;
}
bool CustBinHandlerManager::GetCustAicpuBinFromFile(const std::string &so_name, ge::OpKernelBinPtr &kernel_bin) {
const std::string folder_path = GetCustSoFolderPath();
if (folder_path.empty()) {
GELOGI("The folder path is empty, will not read");
return true;
}
const std::string file_path = folder_path + so_name;
const std::string real_path = ge::RealPath(file_path.c_str());
if (real_path.empty()) {
GELOGI("The file[%s] does not exist and will not be read.", file_path.c_str());
return true;
}
uint32_t len = 0U;
std::unique_ptr<char_t[]> bin_data = ge::GetBinDataFromFile(real_path, len);
if (bin_data == nullptr) {
GELOGE(ge::FAILED, "Read cust so[%s] failed", file_path.c_str());
return false;
}
std::vector<char_t> buffer(bin_data.get(), bin_data.get()+len);
kernel_bin = std::make_shared<ge::OpKernelBin>(so_name, std::move(buffer));
if (kernel_bin == nullptr) {
GELOGE(ge::FAILED, "Malloc memory for cust so failed, so=%s, len=%u", file_path.c_str(), len);
return false;
}
GELOGI("Read so[%s] success, len is %u", so_name.c_str(), len);
return true;
}
std::string CustBinHandlerManager::GetCustSoFolderPath() const {
std::string dir_path;
const char *path_env = nullptr;
MM_SYS_GET_ENV(MM_ENV_ASCEND_OPP_PATH, path_env);
if (path_env != nullptr) {
dir_path = path_env;
if (dir_path[dir_path.size() - 1UL] != '/') {
dir_path += "/";
}
dir_path += kAicpuBuiltInCustKernelFile;
}
GELOGI("Get cust so path is %s", dir_path.c_str());
return dir_path;
}
}