* 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 "graph/opsproto_manager.h"
#include <cstdlib>
#include <functional>
#include "framework/common/debug/ge_log.h"
#include "graph/types.h"
#include "graph/def_types.h"
#include "graph/operator_factory_impl.h"
#include "mmpa/mmpa_api.h"
#include "graph_metadef/common/plugin/plugin_manager.h"
#include "graph/operator_factory_impl.h"
namespace af {
OpsProtoManager *OpsProtoManager::Instance() {
static OpsProtoManager instance;
return &instance;
}
bool OpsProtoManager::Initialize(const std::map<std::string, std::string> &options) {
const std::lock_guard<std::mutex> lock(mutex_);
if (is_init_) {
GELOGI("OpsProtoManager is already initialized.");
return true;
}
const std::map<std::string, std::string>::const_iterator iter = options.find("ge.opsProtoLibPath");
if (iter == options.end()) {
GELOGW("[Initialize][CheckOption] Option \"ge.opsProtoLibPath\" not set");
return false;
}
pluginPath_ = iter->second;
LoadBuiltinOpsPluginSo(pluginPath_);
is_init_ = true;
return true;
}
void OpsProtoManager::Finalize() {
const std::lock_guard<std::mutex> lock(mutex_);
if (!is_init_) {
GELOGI("OpsProtoManager is not initialized.");
return;
}
for (const auto handle : handles_) {
if (handle != nullptr) {
if (mmDlclose(handle) != 0) {
const char_t *error = mmDlerror();
error = (error == nullptr) ? "" : error;
GELOGW("[Finalize][CloseHandle] close handle unsuccessfully, reason:%s", error);
continue;
}
GELOGI("close opsprotomanager handler success");
} else {
GELOGW("[Finalize][CheckHandle] handler is null");
}
}
is_init_ = false;
}
OpsProtoManager::~OpsProtoManager() {
OperatorFactoryImpl::ReleaseRegInfo();
Finalize();
}
static std::vector<std::string> SplitStr(const std::string &str, const char_t delim) {
std::vector<std::string> elems;
if (str.empty()) {
elems.emplace_back("");
return elems;
}
std::stringstream str_stream(str);
std::string item;
while (getline(str_stream, item, delim)) {
elems.push_back(item);
}
const auto str_size = str.size();
if ((str_size > 0UL) && (str[str_size - 1UL] == delim)) {
elems.emplace_back("");
}
return elems;
}
static void GetOpsProtoSoFileList(const std::string &path, std::vector<std::string> &file_list) {
const std::vector<std::string> v_path = SplitStr(path, ':');
std::string os_type;
std::string cpu_type;
PluginManager::GetCurEnvPackageOsAndCpuType(os_type, cpu_type);
for (size_t i = 0UL; i < v_path.size(); ++i) {
const std::string new_path = v_path[i] + "lib/" + os_type + "/" + cpu_type + "/";
char_t resolved_path[MMPA_MAX_PATH] = {};
const INT32 result = mmRealPath(new_path.c_str(), &(resolved_path[0U]), MMPA_MAX_PATH);
if (result == EN_OK) {
std::vector<std::string> file_list_unfiltered;
PluginManager::GetFileListWithSuffix(new_path, ".so", file_list_unfiltered);
std::for_each(file_list_unfiltered.begin(), file_list_unfiltered.end(), [&file_list](const std::string &file) {
if (!PluginManager::IsEndWith(file, "rt2.0.so") && !PluginManager::IsEndWith(file, "rt.so")) {
file_list.emplace_back(file);
}
});
} else {
GELOGW("[FindSo][Check] Get path with os&cpu type [%s] unsuccessfully, reason:%s", new_path.c_str(), strerror(errno));
PluginManager::GetFileListWithSuffix(v_path[i], ".so", file_list);
}
}
}
void OpsProtoManager::LoadOpsProtoPluginSo(const std::string &path) {
if (path.empty()) {
REPORT_INNER_ERR_MSG("E18888", "filePath is empty. please check your text file.");
GELOGE(GRAPH_FAILED, "[Check][Param] filePath is empty. please check your text file.");
return;
}
GELOGW("[LoadSo][Check] Shared library will not be checked. Please make sure that the source of shared library is "
"trusted.");
OperatorFactoryImpl::SetRegisterOverridable(true);
void *const handle = mmDlopen(path.c_str(), static_cast<int32_t>(static_cast<uint32_t>(MMPA_RTLD_NOW) |
static_cast<uint32_t>(MMPA_RTLD_GLOBAL)));
OperatorFactoryImpl::SetRegisterOverridable(false);
if (handle == nullptr) {
const char_t *error = mmDlerror();
error = (error == nullptr) ? "" : error;
GELOGW("[LoadSo][Open] OpsProtoManager dlopen unsuccessfully, plugin name:%s. Message(%s).", path.c_str(), error);
return;
}
GELOGI("OpsProtoManager plugin load %s successfully.", path.c_str());
handles_.push_back(handle);
}
void OpsProtoManager::LoadBuiltinOpsPluginSo(const std::string &path_list) {
if (path_list.empty()) {
REPORT_INNER_ERR_MSG("E18888", "filePath is empty. please check your text file.");
GELOGE(GRAPH_FAILED, "[Check][Param] filePath is empty. please check your text file.");
return;
}
std::vector<std::string> file_list;
GetOpsProtoSoFileList(path_list, file_list);
if (file_list.empty()) {
GELOGW("[LoadSo][Check] OpsProtoManager can not find any plugin file in pluginPath: %s \n", path_list.c_str());
return;
}
GELOGW("[LoadSo][Check] Shared library will not be checked. Please make sure that the source of shared library is "
"trusted.");
for (const auto &elem : file_list) {
LoadOpsProtoPluginSo(elem);
}
}
}