* 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 "engines/manager/engine_manager/dnnengine_manager.h"
#include <cstdio>
#include <map>
#include "framework/common/debug/log.h"
#include "common/plugin/ge_make_unique_util.h"
#include "base/err_msg.h"
#include "framework/common/debug/ge_log.h"
#include "analyzer/analyzer.h"
#include "graph/ge_context.h"
#include "graph/utils/graph_utils.h"
#include "graph/utils/node_utils.h"
#include "graph/utils/op_type_utils.h"
#include "api/gelib/gelib.h"
#include "base/err_msg.h"
namespace {
const char *const kSchedulerUnits = "schedule_units";
const char *const kId = "id";
const char *const kName = "name";
const char *const kExAttrs = "ex_attrs";
const char *const kIndependent = "independent";
const char *const kSkipAssignStream = "skip_assign_stream";
const char *const kCalEngines = "cal_engines";
const char *const kAttach = "attach";
const char *const kVectorCore = "VectorCore";
const char *const kVectorEngine = "VectorEngine";
const char *const kAIcoreEngine = "AIcoreEngine";
const char *const kHostCpuEngineName = "DNN_VM_HOST_CPU";
const char *const kHostCpuOpKernelLibName = "DNN_VM_HOST_CPU_OP_STORE";
const char *const kNoSupportReason = "Dynamic shape is not supported on this chip!";
const std::map<std::string, std::string> kAcceleratorToEngineName = {
{"AiCore", "AIcoreEngine"},
{"AiVector", "VectorEngine"},
{"Dsa", "DSAEngine"},
{"Dvpp", "DNN_VM_DVPP"},
{"AiCpuAscend", "DNN_VM_AICPU_ASCEND"},
{"AiCpu", "DNN_VM_AICPU"},
{"HostCpu", "DNN_VM_HOST_CPU"},
{"Hccl", "DNN_HCCL"},
{"FftsPlus", "ffts_plus"}};
}
namespace ge {
namespace {
const char *const kGetDNNEngineObjs = "GetDNNEngineObjs";
const char *const kInvalidCompositeEngineName = "InvalidCompositeEngineName";
constexpr uint32_t kMaxRecursiveDepth = 25U;
bool ExecOnHostCpu(const OpDescPtr &op_desc) {
if (!ge::GetContext().GetHostExecFlag()) {
return false;
}
const std::string type = op_desc->GetType();
bool is_not_cpu_op = OpTypeUtils::IsDataNode(type) || (type == ge::CONSTANT) || (type == ge::CONSTANTOP) ||
OpTypeUtils::IsVarLikeNode(type) || (type == ge::FILECONSTANT) || (type == ge::NETOUTPUT) ||
(type == ge::PARTITIONEDCALL);
return (!is_not_cpu_op);
}
}
DNNEngineManager::DNNEngineManager() : init_flag_(false) {}
DNNEngineManager::~DNNEngineManager() {
engines_attrs_map_.clear();
schedulers_.clear();
engines_map_.clear();
atomic_2_composite_.clear();
checksupport_cost_.clear();
}
DNNEngineManager &DNNEngineManager::GetInstance() {
static DNNEngineManager instance;
return instance;
}
Status DNNEngineManager::Initialize(const std::map<std::string, std::string> &options) {
if (init_flag_) {
GELOGW("DNNEngineManager has been initialized.");
return SUCCESS;
}
std::string so_path = "plugin/nnengine/";
std::string path = GetModelPath();
path.append(so_path);
std::string so_api_func = kGetDNNEngineObjs;
std::vector<std::string> so_func{so_api_func};
Status status = plugin_mgr_.Load(path, so_func);
if (status != SUCCESS) {
GELOGE(status, "[Load][EngineSo]Failed, lib path %s", path.c_str());
REPORT_INNER_ERR_MSG("E19999", "Load engine so failed, lib path %s", path.c_str());
return status;
}
status = plugin_mgr_.InvokeAll<std::map<std::string, DNNEnginePtr> &>(so_api_func, engines_map_);
if (status != SUCCESS) {
GELOGE(status, "[Get][DNNEngineObjs]Failed, so_api_func %s", so_api_func.c_str());
REPORT_INNER_ERR_MSG("E19999", "Get DNNEngineObjs failed, so_api_func %s", so_api_func.c_str());
return status;
}
GELOGI("The number of DNNEngineObjs is %zu.", engines_map_.size());
for (auto iter = engines_map_.cbegin(); iter != engines_map_.cend(); ++iter) {
if (iter->second == nullptr) {
GELOGI("Engine: %s point to nullptr", (iter->first).c_str());
continue;
}
GELOGI("DNNEngine name: %s.", (iter->first).c_str());
const uint64_t start = ge::GetCurrentTimestamp();
status = iter->second->Initialize(options);
const uint64_t end = ge::GetCurrentTimestamp();
GEEVENT("[GEPERFTRACE] The time cost of DNNEngineManager::Initialize[%s] is [%lu] micro seconds.",
(iter->first).c_str(), (end - start));
if (status != SUCCESS) {
GELOGE(status, "[Init][Engine]Failed, engine %s", (iter->first).c_str());
REPORT_INNER_ERR_MSG("E19999", "Initialize engine %s failed", (iter->first).c_str());
return status;
}
DNNEngineAttribute attrs;
iter->second->GetAttributes(attrs);
if (attrs.runtime_type == RuntimeType::DEVICE) {
if ((attrs.mem_type.size()) != 1 ||
((attrs.mem_type.size() > 1) && (attrs.mem_type[0] != GE_ENGINE_ATTR_MEM_TYPE_HBM))) {
GELOGE(GE_ENG_MEMTYPE_ERROR, "[Check][Param]Engine %s in aicore, but the memory type is "
"not HBM, mem_type_size %zu", (iter->first).c_str(), attrs.mem_type.size());
REPORT_INNER_ERR_MSG("E19999", "Engine %s in aicore, but the memory type is not HBM, mem_type_size %zu",
(iter->first).c_str(), attrs.mem_type.size());
return GE_ENG_MEMTYPE_ERROR;
}
}
}
status = ParserJsonFile();
if (status != SUCCESS) {
GELOGE(status, "[Parse][JsonFile]Failed");
return status;
}
status = CheckJsonFile();
if (status != SUCCESS) {
GELOGE(status, "[Check][JsonFile]Failed");
return status;
}
init_flag_ = true;
return SUCCESS;
}
Status DNNEngineManager::Finalize() {
if (!init_flag_) {
GELOGW("DNNEngineManager has been finalized.");
return SUCCESS;
}
for (auto iter = engines_map_.cbegin(); iter != engines_map_.cend(); ++iter) {
if (iter->second != nullptr) {
GELOGI("DNNEngine name: %s.", (iter->first).c_str());
Status status = iter->second->Finalize();
if (status != SUCCESS) {
GELOGE(status, "[Finalize][Engine]Failed, engine %s", (iter->first).c_str());
REPORT_INNER_ERR_MSG("E19999", "Finalize engine %s failed", (iter->first).c_str());
return status;
}
}
}
init_flag_ = false;
engines_map_.clear();
atomic_2_composite_.clear();
engines_attrs_map_.clear();
schedulers_.clear();
std::lock_guard<std::mutex> lock(mutex_);
checksupport_cost_.clear();
return SUCCESS;
}
std::shared_ptr<ge::DNNEngine> DNNEngineManager::GetEngine(const std::string &name) const {
auto iter = engines_map_.find(name);
if (iter != engines_map_.end()) {
return iter->second;
}
GELOGW("Failed to get engine object by engine name. %s.", name.c_str());
return nullptr;
}
bool DNNEngineManager::IsEngineRegistered(const std::string &name) {
std::map<std::string, DNNEnginePtr>::const_iterator iter = engines_map_.find(name);
if (iter != engines_map_.cend()) {
return true;
}
GELOGW("Engine:[%s] is not registered", name.c_str());
return false;
}
void DNNEngineManager::InitPerformanceStatistic() {
std::lock_guard<std::mutex> lock(mutex_);
checksupport_cost_.clear();
}
void DNNEngineManager::LogCheckSupportCost() const {
std::lock_guard<std::mutex> lock(mutex_);
for (auto &it : checksupport_cost_) {
GEEVENT("The time cost of %s::CheckSupported is [%lu] micro seconds.", it.first.c_str(), it.second);
}
}
void DNNEngineManager::GetOpInfos(std::vector<OpInfo> &op_infos, const OpDescPtr &op_desc,
bool &is_op_specified_engine) const {
std::string engine_name;
std::string kernel_name;
bool has_engine_attr = AttrUtils::GetStr(op_desc, ATTR_NAME_OP_SPECIFIED_ENGINE_NAME, engine_name) &&
!engine_name.empty();
bool has_kernel_attr = AttrUtils::GetStr(op_desc, ATTR_NAME_OP_SPECIFIED_KERNEL_LIB_NAME, kernel_name) &&
!kernel_name.empty();
is_op_specified_engine = has_engine_attr && has_kernel_attr;
if (is_op_specified_engine) {
OpInfo temp_op_info{engine_name, kernel_name, 0, false, false, false, "", ""};
GELOGD("GetDNNEngineName:get op specified engine:%s and kernel:%s", engine_name.c_str(), kernel_name.c_str());
op_infos.emplace_back(std::move(temp_op_info));
} else {
std::lock_guard<std::mutex> lock(mutex_);
op_infos = OpsKernelManager::GetInstance().GetOpsKernelInfo(op_desc->GetType());
}
}
void DNNEngineManager::GetExcludeEngines(std::set<std::string> &exclude_engines) {
std::string ge_core_type;
const auto ret = ge::GetContext().GetOption(ge::CORE_TYPE, ge_core_type);
const std::string &exclude_core_Type = (ge_core_type == kVectorCore) ? kAIcoreEngine : kVectorEngine;
if (ret == GRAPH_SUCCESS) {
GELOGI("option [%s] is set to [%s], engine type will exclude %s",
CORE_TYPE.c_str(), ge_core_type.c_str(), exclude_core_Type.c_str());
}
const auto &graph_option = GetThreadLocalContext().GetAllGraphOptions();
const auto it = graph_option.find(EXCLUDE_ENGINES);
if (it != graph_option.end()) {
GetExcludeEngines(it->second, exclude_engines);
}
exclude_engines.insert(exclude_core_Type);
}
void DNNEngineManager::GetExcludeEngines(const std::string &option, std::set<std::string> &engine_names) {
std::ostringstream oss;
auto accelerators = StringUtils::Split(option, '|');
for (size_t i = 0U; i < accelerators.size(); ++i) {
const auto &after_trim = StringUtils::Trim(accelerators[i]);
if (after_trim.empty()) {
continue;
}
const auto iter = kAcceleratorToEngineName.find(after_trim);
if (iter != kAcceleratorToEngineName.end()) {
engine_names.insert(iter->second);
oss << iter->second << ",";
} else {
GELOGW("can not get engine name. please check value of option %s. option value[%s], failed engine[%s] ",
EXCLUDE_ENGINES.c_str(), option.c_str(), after_trim.c_str());
}
}
GELOGI("graph option %s is [%s], engine name is [%s]",
EXCLUDE_ENGINES.c_str(), option.c_str(), oss.str().c_str());
}
void DNNEngineManager::UpdateOpDescWithOpInfo(const OpDescPtr &op_desc, const OpInfo &op_info) {
if (!op_info.opKernelLib.empty()) {
op_desc->SetOpKernelLibName(op_info.opKernelLib);
}
if (ExecOnHostCpu(op_desc)) {
return;
}
if (op_info.flagAsync) {
GELOGD("Set aicpu blocking op:%s attribute(is_blocking_op):true", op_desc->GetName().c_str());
(void)AttrUtils::SetBool(op_desc, ATTR_NAME_IS_BLOCKING_OP, true);
}
(void) AttrUtils::SetStr(op_desc, ATTR_NAME_ENGINE_NAME_FOR_LX, op_info.engine);
(void) AttrUtils::SetStr(op_desc, ATTR_NAME_KKERNEL_LIB_NAME_FOR_LX, op_info.opKernelLib);
}
void DNNEngineManager::UpdateOpDescsWithOpInfos(const std::map<NodePtr, OpInfo> &nodes_op_infos) {
for (const auto &it : nodes_op_infos) {
const auto &op_desc = it.first->GetOpDesc();
const auto &op_info = it.second;
UpdateOpDescWithOpInfo(op_desc, op_info);
}
}
std::string DNNEngineManager::GetDNNEngineName(const ge::NodePtr &node_ptr) {
std::set<std::string> exclude_engines;
GetExcludeEngines(exclude_engines);
OpInfo matched_op_info;
const auto &engine = GetDNNEngineName(node_ptr, exclude_engines, matched_op_info);
if (!engine.empty()) {
UpdateOpDescWithOpInfo(node_ptr->GetOpDesc(), matched_op_info);
}
return engine;
}
std::string DNNEngineManager::GetDNNEngineName(const ge::NodePtr &node_ptr,
const std::set<std::string> &exclude_engines,
OpInfo &matched_op_info) {
GE_IF_BOOL_EXEC(node_ptr == nullptr, GELOGE(GE_CLI_GE_NOT_INITIALIZED, "DNNEngineManager: node_ptr is nullptr");
return "");
auto op_desc = node_ptr->GetOpDesc();
GE_IF_BOOL_EXEC(op_desc == nullptr, GELOGE(GE_CLI_GE_NOT_INITIALIZED, "DNNEngineManager: op_desc is nullptr");
return "");
std::vector<OpInfo> op_infos;
bool is_op_specified_engine = false;
GetOpInfos(op_infos, op_desc, is_op_specified_engine);
if (op_infos.empty()) {
GELOGI("DNNEngineManager: Can not get op info by op type %s", op_desc->GetType().c_str());
return "";
}
GE_IF_BOOL_EXEC(ExecOnHostCpu(op_desc), return GetHostCpuEngineName(op_infos, op_desc, matched_op_info));
std::map<std::string, std::string> unsupported_reasons;
for (const auto &it : op_infos) {
if ((exclude_engines.find(it.engine) != exclude_engines.end()) && (!is_op_specified_engine)) {
continue;
}
const auto &kernel_name = it.opKernelLib;
auto kernel_info_store = OpsKernelManager::GetInstance().GetOpsKernelInfoStore(kernel_name);
if (kernel_info_store == nullptr) {
GELOGW("DNNEngineManager:Can not find any supported ops kernel info store by kernel_name %s, op type is %s, "
"op name is %s", kernel_name.c_str(), op_desc->GetType().c_str(), op_desc->GetName().c_str());
return "";
}
std::string unsupported_reason;
uint64_t start_time = GetCurrentTimestamp();
CheckSupportFlag flag = CheckSupportFlag::kDefault;
bool check_support_res = true;
try {
check_support_res = kernel_info_store->CheckSupported(node_ptr, unsupported_reason, flag);
} catch (std::runtime_error &e) {
std::ostringstream oss;
oss << "got an exception, op type[" << op_desc->GetType() << "],ops kernel[" << kernel_name << "], reason["
<< e.what() << "]";
GELOGE(GE_GRAPH_ASSIGN_ENGINE_FAILED, "%s", oss.str().c_str());
unsupported_reasons.emplace(kernel_name, oss.str());
break;
}
if (check_support_res) {
{
std::lock_guard<std::mutex> lock(mutex_);
checksupport_cost_[kernel_name] += GetCurrentTimestamp() - start_time;
}
op_desc->SetOpEngineName(it.engine);
matched_op_info = it;
GELOGD("DNNEngineManager:Set kernel_lib %s, atomic engine %s, to node %s", kernel_name.c_str(), it.engine.c_str(),
op_desc->GetName().c_str());
return it.engine;
} else {
if (flag == CheckSupportFlag::kNotSupportDynamicShape) {
REPORT_PREDEFINED_ERR_MSG(
"EZ3002", std::vector<const char *>({"optype", "opskernel", "reason"}),
std::vector<const char *>({op_desc->GetType().c_str(), kernel_name.c_str(), kNoSupportReason}));
GELOGE(GE_GRAPH_ASSIGN_ENGINE_FAILED, "[Check][OpSupported]Op type %s of kernel %s is unsupported, reason: %s",
op_desc->GetType().c_str(), kernel_name.c_str(), kNoSupportReason);
return "";
}
{
std::lock_guard<std::mutex> lock(mutex_);
checksupport_cost_[kernel_name] += GetCurrentTimestamp() - start_time;
}
unsupported_reasons.emplace(kernel_name, unsupported_reason);
GELOGI("DNNEngineManager: op does not support, kernel_name is %s, op type is %s, op name is %s",
kernel_name.c_str(), op_desc->GetType().c_str(), op_desc->GetName().c_str());
if (!op_desc->HasAttr("_is_ge_op")) {
REPORT_PREDEFINED_ERR_MSG("W11001", std::vector<const char *>({"opname"}),
std::vector<const char *>({op_desc->GetName().c_str()}));
}
}
}
std::string reason;
for (const auto &it : unsupported_reasons) {
reason += it.first + ":" + it.second + ";";
REPORT_PREDEFINED_ERR_MSG(
"EZ3002", std::vector<const char *>({"optype", "opskernel", "reason"}),
std::vector<const char *>({op_desc->GetType().c_str(), it.first.c_str(), it.second.c_str()}));
GELOGE(GE_GRAPH_ASSIGN_ENGINE_FAILED,
"[Check][OpSupported]Op type %s of ops kernel %s "
"is unsupported, reason : %s",
op_desc->GetType().c_str(), it.first.c_str(), it.second.c_str());
}
auto root_graph = ge::GraphUtils::FindRootGraph(node_ptr->GetOwnerComputeGraph());
if (root_graph != nullptr) {
analyzer::DataInfo analyze_info{root_graph->GetSessionID(), root_graph->GetGraphID(),
analyzer::CHECKSUPPORT, node_ptr, reason};
(void)Analyzer::GetInstance()->DoAnalyze(analyze_info);
}
REPORT_PREDEFINED_ERR_MSG(
"EZ3003", std::vector<const char *>({"opname", "optype"}),
std::vector<const char *>({op_desc->GetName().c_str(), op_desc->GetType().c_str()}));
GELOGE(GE_GRAPH_ASSIGN_ENGINE_FAILED, "[Get][DNNEngineName]Can't find any supported ops kernel "
"and engine of %s, type is %s",
op_desc->GetName().c_str(), op_desc->GetType().c_str());
return "";
}
std::string DNNEngineManager::GetCompositeEngineName(const ge::NodePtr &node_ptr, uint32_t recursive_depth) {
const auto &op_desc = node_ptr->GetOpDesc();
GE_IF_BOOL_EXEC(op_desc == nullptr, GELOGE(GE_CLI_GE_NOT_INITIALIZED, "DNNEngineManager: op_desc is nullptr");
return "");
if (recursive_depth > kMaxRecursiveDepth) {
REPORT_INNER_ERR_MSG("E19999", "Get CompositeEngineName will be terminated because too many nesting levels(%u) of "
"subgraphs, last node is %s", recursive_depth, op_desc->GetName().c_str());
GELOGE(PARAM_INVALID,
"[Check][Param] Get CompositeEngineName will be terminated because too many nesting levels(%u) of subgraphs, "
"last node is %s", recursive_depth, op_desc->GetName().c_str());
return "";
}
if (OpsKernelManager::GetInstance().GetCompositeEngines().empty() ||
OpsKernelManager::GetInstance().GetCompositeEngineKernelLibNames().empty()) {
return "";
}
std::string composite_engine_name;
(void)AttrUtils::GetStr(op_desc, ATTR_NAME_COMPOSITE_ENGINE_NAME, composite_engine_name);
std::string composite_engine_kernel_lib_name;
(void)AttrUtils::GetStr(op_desc, ATTR_NAME_COMPOSITE_ENGINE_KERNEL_LIB_NAME, composite_engine_kernel_lib_name);
if (!composite_engine_name.empty() && !composite_engine_kernel_lib_name.empty()) {
return composite_engine_name;
}
bool recursive_mode = (op_desc->GetType() == PARTITIONEDCALL)
? (op_desc->HasAttr(ATTR_NAME_FFTS_SUB_GRAPH) || op_desc->HasAttr(ATTR_NAME_FFTS_PLUS_SUB_GRAPH))
: !op_desc->GetSubgraphInstanceNames().empty();
GELOGD("Node: %s, Recursive mode: %d", op_desc->GetName().c_str(), static_cast<int32_t>(recursive_mode));
return recursive_mode ? GetCompositeEngine(node_ptr, recursive_depth) : GetCompositeEngine(node_ptr);
}
std::string DNNEngineManager::GetCompositeEngine(const NodePtr &node) {
std::string composite_engine_name;
if (IsNoTask(node)) {
bool in_diff_flag = false;
std::string in_composite_engine_name = kInvalidCompositeEngineName;
for (const auto &in_node : node->GetInAllNodes()) {
std::string tmp_composite_engine_name;
(void)AttrUtils::GetStr(in_node->GetOpDesc(), ATTR_NAME_COMPOSITE_ENGINE_NAME, tmp_composite_engine_name);
if (in_composite_engine_name == kInvalidCompositeEngineName) {
in_composite_engine_name = tmp_composite_engine_name;
} else if (in_composite_engine_name != tmp_composite_engine_name) {
in_diff_flag = true;
break;
}
}
if (!in_diff_flag &&
(in_composite_engine_name != kInvalidCompositeEngineName) &&
!in_composite_engine_name.empty()) {
composite_engine_name = in_composite_engine_name;
}
}
const auto &op_desc = node->GetOpDesc();
if (composite_engine_name.empty()) {
auto atomic_engine_name = op_desc->GetOpEngineName().empty() ? GetDNNEngineName(node) : op_desc->GetOpEngineName();
composite_engine_name = (op_desc->GetType() == NETOUTPUT) ? "" : GetCompositeEngineName(atomic_engine_name);
}
const auto &composite_engine_kernel_lib_name = GetCompositeEngineKernelLibName(composite_engine_name);
if (composite_engine_name.empty() || composite_engine_kernel_lib_name.empty()) {
(void)op_desc->DelAttr(ATTR_NAME_COMPOSITE_ENGINE_NAME);
(void)op_desc->DelAttr(ATTR_NAME_COMPOSITE_ENGINE_KERNEL_LIB_NAME);
} else {
GELOGI("Assign composite engine %s, kernel lib name %s for node %s.", composite_engine_name.c_str(),
composite_engine_kernel_lib_name.c_str(), op_desc->GetName().c_str());
(void)AttrUtils::SetStr(op_desc, ATTR_NAME_COMPOSITE_ENGINE_NAME, composite_engine_name);
(void)AttrUtils::SetStr(op_desc, ATTR_NAME_COMPOSITE_ENGINE_KERNEL_LIB_NAME, composite_engine_kernel_lib_name);
}
return composite_engine_name;
}
std::string DNNEngineManager::GetCompositeEngine(const NodePtr &func_node, uint32_t recursive_depth) {
const auto &op_desc = func_node->GetOpDesc();
bool graph_diff_composite_engine_flag = false;
std::string graph_composite_engine_name = kInvalidCompositeEngineName;
std::vector<ComputeGraphPtr> subgraphs;
if (NodeUtils::GetDirectSubgraphs(func_node, subgraphs) != GRAPH_SUCCESS) {
REPORT_INNER_ERR_MSG("E19999", "Get subgraphs of node %s failed", op_desc->GetName().c_str());
GELOGE(FAILED, "[Check][Param] Get subgraphs of node %s failed", op_desc->GetName().c_str());
return "";
}
for (const auto &subgraph : subgraphs) {
std::string cur_graph_composite_engine_name = GetCompositeEngine(subgraph, recursive_depth);
if (graph_composite_engine_name == kInvalidCompositeEngineName) {
graph_composite_engine_name = cur_graph_composite_engine_name;
} else if (graph_composite_engine_name != cur_graph_composite_engine_name) {
graph_diff_composite_engine_flag = true;
break;
}
}
std::string composite_engine_name;
std::string composite_engine_kernel_lib_name = GetCompositeEngineKernelLibName(graph_composite_engine_name);
if (!graph_diff_composite_engine_flag &&
(graph_composite_engine_name != kInvalidCompositeEngineName) &&
!graph_composite_engine_name.empty() &&
!composite_engine_kernel_lib_name.empty()) {
composite_engine_name = graph_composite_engine_name;
GELOGI("Assign composite engine %s, kernel lib name %s for node %s.", composite_engine_name.c_str(),
composite_engine_kernel_lib_name.c_str(), op_desc->GetName().c_str());
(void)AttrUtils::SetStr(op_desc, ATTR_NAME_COMPOSITE_ENGINE_NAME, composite_engine_name);
(void)AttrUtils::SetStr(op_desc, ATTR_NAME_COMPOSITE_ENGINE_KERNEL_LIB_NAME, composite_engine_kernel_lib_name);
} else {
(void)op_desc->DelAttr(ATTR_NAME_COMPOSITE_ENGINE_NAME);
(void)op_desc->DelAttr(ATTR_NAME_COMPOSITE_ENGINE_KERNEL_LIB_NAME);
}
return composite_engine_name;
}
std::string DNNEngineManager::GetCompositeEngine(const ComputeGraphPtr &subgraph, uint32_t recursive_depth) {
std::string graph_composite_engine_name;
(void)AttrUtils::GetStr(subgraph, ATTR_NAME_COMPOSITE_ENGINE_NAME, graph_composite_engine_name);
if (!graph_composite_engine_name.empty()) {
return graph_composite_engine_name;
}
bool node_diff_composite_engine_flag = false;
std::string node_composite_engine_name = kInvalidCompositeEngineName;
uint32_t assigned_node_num = 0;
for (const auto &cur_node : subgraph->GetDirectNode()) {
if (IsNoTask(cur_node) || cur_node->GetType() == NETOUTPUT) {
continue;
}
assigned_node_num++;
std::string cur_node_composite_engine_name = GetCompositeEngineName(cur_node, recursive_depth + 1);
if (node_composite_engine_name == kInvalidCompositeEngineName) {
node_composite_engine_name = cur_node_composite_engine_name;
} else if (node_composite_engine_name != cur_node_composite_engine_name) {
node_diff_composite_engine_flag = true;
break;
}
}
if (assigned_node_num == 0) {
GELOGD("all nodes in subgraph %s belongs to ge_local engine", subgraph->GetName().c_str());
return "";
}
if (!node_diff_composite_engine_flag &&
(node_composite_engine_name != kInvalidCompositeEngineName) &&
!node_composite_engine_name.empty()) {
GELOGI("Assign composite engine %s for subgraph %s.", node_composite_engine_name.c_str(), subgraph->GetName().c_str());
(void)AttrUtils::SetStr(subgraph, ATTR_NAME_COMPOSITE_ENGINE_NAME, node_composite_engine_name);
graph_composite_engine_name = node_composite_engine_name;
} else {
(void)subgraph->DelAttr(ATTR_NAME_COMPOSITE_ENGINE_NAME);
}
return graph_composite_engine_name;
}
std::string DNNEngineManager::GetCompositeEngineName(const std::string &atomic_engine_name) {
if (atomic_2_composite_.empty()) {
InitAtomicCompositeMapping();
}
const std::map<std::string, std::string>::const_iterator &iter = atomic_2_composite_.find(atomic_engine_name);
if (iter == atomic_2_composite_.cend()) {
GELOGW("Composite engine which contains atomic engine %s is not registered", atomic_engine_name.c_str());
return "";
}
return iter->second;
}
std::string DNNEngineManager::GetCompositeEngineKernelLibName(const std::string &composite_engine_name) const {
const auto &composite_engine_2_kernel_lib_name = OpsKernelManager::GetInstance().GetCompositeEngineKernelLibNames();
const auto &iter = composite_engine_2_kernel_lib_name.find(composite_engine_name);
if (iter == composite_engine_2_kernel_lib_name.end()) {
GELOGW("Kernel lib name of composite engine %s is not registered", composite_engine_name.c_str());
return "";
}
return iter->second;
}
std::string DNNEngineManager::GetHostCpuEngineName(const std::vector<OpInfo> &op_infos,
const OpDescPtr &op_desc,
OpInfo &matched_op_info) const {
for (const auto &it : op_infos) {
if ((it.engine == kHostCpuEngineName) && (it.opKernelLib == kHostCpuOpKernelLibName)) {
op_desc->SetOpEngineName(kHostCpuEngineName);
matched_op_info.opKernelLib = kHostCpuOpKernelLibName;
GELOGI("DNNEngineManager: Set OpKernelLibName %s and OpEngineName %s to %s",
kHostCpuOpKernelLibName, kHostCpuEngineName, op_desc->GetName().c_str());
return kHostCpuEngineName;
}
}
GELOGE(FAILED, "[Get][HostCpuEngineName]Failed, HostCpuEngine not support [%s, %s]",
op_desc->GetName().c_str(), op_desc->GetType().c_str());
REPORT_INNER_ERR_MSG("E19999", "Get HostCpuEngineName failed, HostCpuEngine not support [%s, %s]",
op_desc->GetName().c_str(), op_desc->GetType().c_str());
return "";
}
const std::map<std::string, SchedulerConf> &DNNEngineManager::GetSchedulers() const { return schedulers_; }
Status DNNEngineManager::ParserJsonFile() {
GELOGI("Begin to parse json file");
std::string json_file_path = "plugin/nnengine/ge_config/engine_conf.json";
std::string path = GetModelPath();
path.append(json_file_path);
nlohmann::json scheduler_json_file;
Status status = ReadJsonFile(path, &scheduler_json_file);
if (status != SUCCESS) {
GELOGE(FAILED, "[Read][JsonFile]Failed, file %s", path.c_str());
return FAILED;
}
if (scheduler_json_file.is_null()) {
GELOGW("Json file is null");
return SUCCESS;
}
try {
nlohmann::json scheduler_utils_json = scheduler_json_file[kSchedulerUnits];
if (scheduler_utils_json.is_null()) {
GELOGE(FAILED, "[Check[Param]Find scheduler units failed, the message is null, file %s", path.c_str());
REPORT_INNER_ERR_MSG("E19999", "Find scheduler units failed, the message is null, file %s", path.c_str());
return FAILED;
}
if (!scheduler_utils_json.is_array()) {
GELOGE(FAILED, "[Check][Param]The message of kSchedulerUnits is not array and "
"the file path is %s", path.c_str());
REPORT_INNER_ERR_MSG("E19999", "The message of kSchedulerUnits is not array and "
"the file path is %s", path.c_str());
return FAILED;
}
auto size = scheduler_json_file[kSchedulerUnits].size();
for (size_t i = 0; i < size; i++) {
SchedulerConf scheduler_conf;
std::map<std::string, EngineConfPtr> engine_conf_map;
nlohmann::json engines_json_map = scheduler_utils_json[i][kCalEngines];
if (engines_json_map.is_null()) {
GELOGE(FAILED, "[Check][Param]The message of cal_engines is null, file %s", path.c_str());
REPORT_INNER_ERR_MSG("E19999", "The message of cal_engines is null, file %s", path.c_str());
return FAILED;
}
std::string scheduler_id_temp = scheduler_utils_json[i][kId];
if (!scheduler_id_temp.empty()) {
scheduler_conf.id = scheduler_id_temp;
} else {
GELOGE(FAILED, "[Check][Param]Scheduler ID is null, file %s", path.c_str());
REPORT_INNER_ERR_MSG("E19999", "Scheduler ID is null, file %s", path.c_str());
return FAILED;
}
status = ParserEngineMessage(engines_json_map, scheduler_id_temp, engine_conf_map);
if (status != SUCCESS) {
GELOGE(FAILED, "[Parse][EngineMessage]Failed, scheduler_id_temp %s", scheduler_id_temp.c_str());
REPORT_INNER_ERR_MSG("E19999", "Parse engine message failed, scheduler_id_temp %s",
scheduler_id_temp.c_str());
return FAILED;
}
scheduler_conf.name = scheduler_utils_json[i][kName];
scheduler_conf.ex_attrs = scheduler_utils_json[i][kExAttrs];
scheduler_conf.cal_engines = engine_conf_map;
std::map<std::string, SchedulerConf>::const_iterator it = schedulers_.find(scheduler_id_temp);
if (it != schedulers_.cend()) {
GELOGW("[Check][Param]There are the same scheduler ts %s in the json file",
scheduler_id_temp.c_str());
continue;
}
schedulers_.emplace(scheduler_id_temp, scheduler_conf);
}
} catch (const nlohmann::detail::type_error &e) {
GELOGE(FAILED, "[Parse][JsonFile]Failed, file %s, reason %s", path.c_str(), e.what());
REPORT_PREDEFINED_ERR_MSG("E10032", std::vector<const char *>({"file_name", "reason"}),
std::vector<const char *>({path.c_str(), e.what()}));
return FAILED;
}
GELOGI("Parser json file SUCCESS");
return SUCCESS;
}
Status DNNEngineManager::ParserEngineMessage(const json engines_json, const std::string &scheduler_mark,
std::map<std::string, EngineConfPtr> &engines) const {
GELOGI("Begin to parser engine massage");
if (engines_json.is_null()) {
GELOGE(FAILED, "[Check][Param]The message of cal_engines is null");
REPORT_INNER_ERR_MSG("E19999", "The message of cal_engines is null");
return FAILED;
}
try {
if (engines_json.is_array()) {
for (size_t i = 0; i < engines_json.size(); i++) {
nlohmann::json engines_elems = engines_json[i];
EngineConfPtr engine_conf_ptr = MakeShared<EngineConf>();
if (engine_conf_ptr == nullptr) {
return FAILED;
}
std::string engine_id = engines_elems[kId];
if (!engine_id.empty()) {
engine_conf_ptr->id = engine_id;
} else {
GELOGE(FAILED, "[Check][Param]Engine ID is null");
REPORT_INNER_ERR_MSG("E19999", "Engine ID is null");
return FAILED;
}
if (engines_elems.find(kName) != engines_elems.end()) {
engine_conf_ptr->name = engines_elems[kName];
} else {
GELOGW("The engine %s name is null", engine_id.c_str());
}
if (engines_elems.find(kIndependent) != engines_elems.end()) {
engine_conf_ptr->independent = engines_elems[kIndependent];
}
if (engines_elems.find(kAttach) != engines_elems.end()) {
engine_conf_ptr->attach = engines_elems[kAttach];
}
if (engines_elems.find(kSkipAssignStream) != engines_elems.end()) {
engine_conf_ptr->skip_assign_stream = engines_elems[kSkipAssignStream];
}
engine_conf_ptr->scheduler_id = scheduler_mark;
std::map<std::string, EngineConfPtr>::const_iterator it = engines.find(engine_id);
if (it != engines.cend()) {
GELOGE(FAILED, "[Check][Param]There are the same engine %s message in the json file",
engine_id.c_str());
REPORT_INNER_ERR_MSG("E19999", "There are the same engine %s message in the json file",
engine_id.c_str());
return FAILED;
}
engines.emplace(engine_id, engine_conf_ptr);
}
} else {
GELOGE(FAILED, "[Check][Param]The message of cal_engines is not array in the json file");
REPORT_INNER_ERR_MSG("E19999", "The message of cal_engines is not array in the json file");
return FAILED;
}
} catch (const json::exception &e) {
GELOGE(FAILED, "[Construct][JsonContent]Failed, reason %s", e.what());
REPORT_PREDEFINED_ERR_MSG("E10059", std::vector<const char *>({"stage", "reason"}),
std::vector<const char *>({"Parse engine config JSON", e.what()}));
return FAILED;
}
GELOGI("Parser engine massage success");
return SUCCESS;
}
Status DNNEngineManager::ReadJsonFile(const std::string &file_path, JsonHandle handle) {
GELOGD("Begin to read json file");
if (file_path.empty()) {
GELOGE(FAILED, "[Check][Param]Json path is empty");
REPORT_PREDEFINED_ERR_MSG("E13000", std::vector<const char *>({"path", "errmsg"}),
std::vector<const char *>({file_path.c_str(), "the json file path is not configured"}));
return FAILED;
}
nlohmann::json *json_file = reinterpret_cast<nlohmann::json *>(handle);
if (json_file == nullptr) {
GELOGE(FAILED, "[Check][Param]Json file is nullptr");
REPORT_INNER_ERR_MSG("E19999", "Json file is nullptr");
return FAILED;
}
const char *file = file_path.data();
if ((mmAccess2(file, M_F_OK)) != EN_OK) {
if (engines_map_.size() != 0) {
GELOGE(FAILED, "[Check][Param]The json file %s does not exist, err %s",
file_path.c_str(), strerror(errno));
REPORT_PREDEFINED_ERR_MSG("E10410", std::vector<const char *>({"cfgpath"}),
std::vector<const char *>({file_path.c_str()}));
return FAILED;
} else {
GELOGW("The json file %s is not needed.", file_path.c_str());
return SUCCESS;
}
}
std::ifstream ifs(file_path);
if (!ifs.is_open()) {
GELOGE(FAILED, "[Open][JsonFile]Failed, file %s", file_path.c_str());
REPORT_PREDEFINED_ERR_MSG("E13001", std::vector<const char *>({"file", "errmsg"}),
std::vector<const char *>({file_path.c_str(), "failed to open the file"}));
return FAILED;
}
try {
ifs >> *json_file;
} catch (const json::exception &e) {
GELOGE(FAILED, "[Read][JsonFile]Failed, reason %s", e.what());
REPORT_PREDEFINED_ERR_MSG("E10032", std::vector<const char *>({"file_name", "reason"}),
std::vector<const char *>({file_path.c_str(), e.what()}));
ifs.close();
return FAILED;
}
ifs.close();
GELOGD("Read json file success");
return SUCCESS;
}
Status DNNEngineManager::CheckJsonFile() const {
GELOGD("Begin to check json file");
for (auto &it : engines_map_) {
std::string engine_name = it.first;
int32_t count = 0;
for (auto &iter : schedulers_) {
auto engine_map = iter.second.cal_engines;
std::map<std::string, EngineConfPtr>::const_iterator iter_engine_name = engine_map.find(engine_name);
if (iter_engine_name != engine_map.cend()) {
count++;
}
}
if (count == 0) {
GELOGE(FAILED, "[Check][JsonFile]The engine message %s is not found in the json file",
engine_name.c_str());
REPORT_INNER_ERR_MSG("E19999", "The engine message %s is not found in the json file",
engine_name.c_str());
return FAILED;
}
if (count > 1) {
GELOGE(FAILED, "[Check][JsonFile]The same engine message %s exists in the json file",
engine_name.c_str());
REPORT_INNER_ERR_MSG("E19999", "The same engine message %s exists in the json file",
engine_name.c_str());
return FAILED;
}
}
GELOGD("Check json file success");
return SUCCESS;
}
void DNNEngineManager::InitAtomicCompositeMapping() {
for (const auto &item : OpsKernelManager::GetInstance().GetCompositeEngines()) {
const auto &composite_engine = GetEngine(item.first);
if ((composite_engine == nullptr) || composite_engine->IsAtomic()) {
GELOGW("Composite engine %s is not registered", item.first.c_str());
}
for (const auto &atomic_engine_name : item.second) {
const auto &atomic_engine = GetEngine(atomic_engine_name);
if ((atomic_engine == nullptr) || !atomic_engine->IsAtomic()) {
GELOGW("Atomic engine %s is not registered", atomic_engine_name.c_str());
continue;
}
std::map<std::string, std::string>::const_iterator iter = atomic_2_composite_.find(atomic_engine_name);
if (iter != atomic_2_composite_.cend()) {
GELOGW("Atomic engine %s has been contained in composite engine %s, and will be overwritten by engine %s",
atomic_engine_name.c_str(), iter->second.c_str(), item.first.c_str());
}
atomic_2_composite_[atomic_engine_name] = item.first;
}
}
}
bool DNNEngineManager::IsNoTask(const NodePtr &node) {
const auto &op_desc = node->GetOpDesc();
if (op_desc->HasAttr(ATTR_NAME_NOTASK)) {
return true;
}
return IsStreamAssignSkip(node) && op_desc->GetSubgraphInstanceNames().empty();
}
bool DNNEngineManager::IsStreamAssignSkip(const NodePtr &node) {
const auto &op_desc = node->GetOpDesc();
const auto &engine_name = op_desc->GetOpEngineName().empty() ? GetDNNEngineName(node) : op_desc->GetOpEngineName();
return IsStreamAssignSkip(engine_name);
}
bool DNNEngineManager::IsStreamAssignSkip(const std::string &engine_name) {
for (const auto &scheduler : schedulers_) {
const auto &iter = scheduler.second.cal_engines.find(engine_name);
if (iter == scheduler.second.cal_engines.end()) {
GELOGW("No engine found within name %s", engine_name.c_str());
continue;
}
if (iter->second == nullptr) {
GELOGW("engine configuration of engine %s is null", engine_name.c_str());
continue;
}
return iter->second->skip_assign_stream;
}
return false;
}
}