* 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 config_manager.cpp
* \brief
*/
#include "config_manager.h"
#include <map>
#include <fstream>
#include <cstdlib>
#include <string>
#include <sstream>
#include <shared_mutex>
#include <limits.h>
#include "tilefwk/pypto_fwk_log.h"
#include "interface/utils/common.h"
#include "interface/utils/file_utils.h"
#include "tilefwk/comm_group_recorder.h"
#include <unistd.h>
namespace npu::tile_fwk {
const std::string tilefwkConfigEnvName = "TILEFWK_CONFIG_PATH";
static PassConfigs InternalGetPassConfigs(const nlohmann::json& root, const GlobalPassConfigs* globalConfigs);
static GlobalPassConfigs InternalGetGlobalConfigs(const nlohmann::json& globalCfg);
static const nlohmann::json* GetJsonNode(const nlohmann::json& root, const std::vector<std::string>& keys)
{
auto* curr = &root;
for (auto&& key : keys) {
if (auto it = curr->find(key); it != curr->end()) {
curr = &*it;
} else {
return nullptr;
}
}
return curr;
}
static const nlohmann::json* GetJsonChild(const nlohmann::json& root, const std::string& key)
{
return GetJsonNode(root, {key});
}
ConfigManager::ConfigManager() { Initialize(); }
ConfigManager& ConfigManager::Instance()
{
static ConfigManager instance;
return instance;
}
const nlohmann::json* ConfigManager::GetJsonNode(const nlohmann::json& root, const std::vector<std::string>& keys)
{
return ::npu::tile_fwk::GetJsonNode(root, keys);
}
Status ConfigManager::Initialize()
{
std::string jsonFilePath = GetEnvVar(tilefwkConfigEnvName);
if (jsonFilePath.empty()) {
jsonFilePath = RealPath(GetCurrentSharedLibPath() + "/configs/tile_fwk_config.json");
}
config::SetRunDataOption(KEY_PTO_CONFIG_FILE, jsonFilePath);
config::SetRunDataOption(KEY_RUNTYPE, "npu");
FE_LOGI("Start to parse op_json_file %s", jsonFilePath.c_str());
if (!ReadJsonFile(jsonFilePath, json_)) {
FE_LOGE(FeError::INVALID_FILE, "ReadJsonFile failed.");
return FAILED;
}
#ifdef SRCPATH
constexpr const char* SRC_PATH = SRCPATH;
std::string genJsonPath = std::string(SRC_PATH) + "/framework/src/cost_model/simulation/scripts/";
if (IsPathExist(genJsonPath)) {
auto files = GetFiles(genJsonPath, "json");
if (!files.empty()) {
for (const auto& file : files) {
std::ifstream genJsonFile(genJsonPath + file);
nlohmann::json jsonConfig = nlohmann::json::parse(genJsonFile);
genJsonFile.close();
if (jsonConfig.contains("global_configs")) {
const auto& genGlobal = jsonConfig["global_configs"];
if (genGlobal.contains("platform_configs") && !genGlobal["platform_configs"].empty()) {
json_["global"]["platform"].update(genGlobal["platform_configs"]);
}
if (genGlobal.contains("simulation_configs") && !genGlobal["simulation_configs"].empty()) {
json_["global"]["simulation"].update(genGlobal["simulation_configs"]);
}
}
}
}
}
#endif
originJson_ = json_;
if (auto* node = GetJsonNode(json_, {"global", "pass"})) {
globalPassConfigs_ = InternalGetGlobalConfigs(*node);
}
return SUCCESS;
}
void ConfigManager::RefreshGlobalPassCfg()
{
if (auto* node = GetJsonNode(json_, {"global", "pass"})) {
globalPassConfigs_ = InternalGetGlobalConfigs(*node);
}
}
static std::string GetHostName() {
char host[HOST_NAME_MAX] = {0};
if (gethostname(host, sizeof(host)) == 0) {
return std::string(host);
}
return "unknown-host";
}
static std::string CreateLogTopFolder()
{
auto now = std::chrono::high_resolution_clock::now();
auto time = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
auto us = std::chrono::duration_cast<std::chrono::microseconds>(now.time_since_epoch()).count() % 1000000;
std::stringstream timestamp;
timestamp << std::put_time(std::localtime(&time), "%Y%m%d_%H%M%S");
constexpr int NUM_SIX = 6;
timestamp << "_" << std::setw(NUM_SIX) << std::setfill('0') << us;
std::string folderPath = config::OutputBaseDir();
bool ret = CreateDir(folderPath);
CHECK(FeError::BAD_FD, ret) << "Failed to create dir: " << folderPath << ", ensure its parent dir exists.";
folderPath = folderPath + "/output_" + timestamp.str() + "_" + std::to_string(getpid()) + "_" + GetHostName();
ret = CreateDir(folderPath);
FE_ASSERT(FeError::BAD_FD, ret) << "Failed to create dir: " << folderPath << ", ensure its parent dir exists.";
config::SetRunDataOption(KEY_COMPUTE_GRAPH_PATH, RealPath(folderPath));
return folderPath;
}
const std::string& ConfigManager::LogTopFolder()
{
if (globalConfigs_.logTopFolder.empty()) {
globalConfigs_.logTopFolder = CreateLogTopFolder();
}
return globalConfigs_.logTopFolder;
}
const std::string& ConfigManager::LogTensorGraphFolder()
{
if (globalConfigs_.logTensorGraphFolder.empty()) {
globalConfigs_.logTensorGraphFolder = LogTopFolder() + "/TensorGraph";
CreateDir(globalConfigs_.logTensorGraphFolder);
}
return globalConfigs_.logTensorGraphFolder;
}
const std::string& ConfigManager::LogFile()
{
if (globalConfigs_.logFile.empty()) {
globalConfigs_.logFile = LogTopFolder() + "/run.log";
}
return globalConfigs_.logFile;
}
void ConfigManager::ResetLog(const std::string& path)
{
std::string newLogFile;
if (path.empty()) {
globalConfigs_.logTopFolder = CreateLogTopFolder();
newLogFile = globalConfigs_.logTopFolder + "/run.log";
} else {
newLogFile = path + "/run.log";
}
globalConfigs_.logFile = std::move(newLogFile);
}
PassConfigs ConfigManager::GetPassConfigs(const std::string& strategy, const std::string& identifier) const
{
auto* node = GetJsonNode(json_, {"global", "pass_strategies", strategy, identifier});
if (!node) {
return globalPassConfigs_.defaultPassConfigs;
}
return InternalGetPassConfigs(*node, &globalPassConfigs_);
}
void ConfigManager::PassConfigsDebugInfo(const std::string& strategy, const std::vector<std::string>& identifiers) const
{
auto* node = GetJsonNode(json_, {"global", "pass_strategies", strategy});
if (!node) {
FE_LOGI(
"[ConfigManager] Missing custom pass strategy < %s > configs. %s", strategy.c_str(),
"You may add your own custom strategy configs in 'tile_fwk_config.json'.");
return;
}
size_t maxLength = 0;
for (auto&& identifier : identifiers) {
maxLength = std::max(maxLength, identifier.size());
}
FE_LOGI("[ConfigManager] Strategy < %s > is found. Custom pass strategy will be used.", strategy.c_str());
for (auto&& identifier : identifiers) {
std::string spaces(maxLength - identifier.size(), ' ');
if (node->find(identifier) != node->end()) {
FE_LOGI("[ConfigManager] Pass instance %s<%s> configs loaded.", spaces.c_str(), identifier.c_str());
} else {
FE_LOGI(
"[ConfigManager] Pass instance %s<%s> configs for pass strategy <%s> is missing. \
You may add your own custom strategy configs in 'tile_fwk_config.json'.",
spaces.c_str(), identifier.c_str(), strategy.c_str());
}
}
}
static std::map<std::string, std::function<void(PassConfigs&, const nlohmann::json&)>> g_assignPassConfigFns = {
{KEY_PRINT_GRAPH, [](PassConfigs& configs, const nlohmann::json& node) { configs.printGraph = node.get<bool>(); }},
{KEY_PRINT_PROGRAM,
[](PassConfigs& configs, const nlohmann::json& node) { configs.printProgram = node.get<bool>(); }},
{KEY_DUMP_GRAPH, [](PassConfigs& configs, const nlohmann::json& node) { configs.dumpGraph = node.get<bool>(); }},
{KEY_DUMP_PASS_TIME_COST,
[](PassConfigs& configs, const nlohmann::json& node) { configs.dumpPassTimeCost = node.get<bool>(); }},
{KEY_PRE_CHECK, [](PassConfigs& configs, const nlohmann::json& node) { configs.preCheck = node.get<bool>(); }},
{KEY_POST_CHECK, [](PassConfigs& configs, const nlohmann::json& node) { configs.postCheck = node.get<bool>(); }},
{KEY_EXPECTED_VALUE_CHECK,
[](PassConfigs& configs, const nlohmann::json& node) { configs.expectedValueCheck = node.get<bool>(); }},
{KEY_DISABLE_PASS,
[](PassConfigs& configs, const nlohmann::json& node) { configs.disablePass = node.get<bool>(); }},
{KEY_HEALTH_CHECK,
[](PassConfigs& configs, const nlohmann::json& node) { configs.healthCheck = node.get<bool>(); }},
{KEY_RESUME_PARH,
[](PassConfigs& configs, const nlohmann::json& node) { configs.resumePath = node.get<std::string>(); }},
};
static PassConfigs InternalGetPassConfigs(const nlohmann::json& root, const GlobalPassConfigs* globalConfigs)
{
PassConfigs configs;
if (globalConfigs != nullptr) {
if (!globalConfigs->enablePassConfigs) {
return {};
}
configs = globalConfigs->defaultPassConfigs;
}
for (auto&& [key, assignFn] : g_assignPassConfigFns) {
if (auto* node = GetJsonChild(root, key)) {
assignFn(configs, *node);
}
}
return configs;
}
static std::map<std::string, std::function<void(GlobalPassConfigs&, const nlohmann::json&)>> g_assignGlobalConfigFns = {
{"enable_pass_configs",
[](GlobalPassConfigs& configs, const nlohmann::json& node) { configs.enablePassConfigs = node.get<bool>(); }},
{"default_pass_configs",
[](GlobalPassConfigs& configs, const nlohmann::json& node) {
configs.defaultPassConfigs = InternalGetPassConfigs(node, nullptr);
}},
};
static GlobalPassConfigs InternalGetGlobalConfigs(const nlohmann::json& globalCfg)
{
GlobalPassConfigs configs;
for (auto&& [key, assignFn] : g_assignGlobalConfigFns) {
if (auto* node = GetJsonChild(globalCfg, key)) {
assignFn(configs, *node);
}
}
return configs;
}
struct RunDataDir {
std::string path;
std::string dName;
std::string montage() { return path + "/" + dName; }
bool empty() { return (path.empty() || dName.empty()); }
void Reset()
{
path.clear();
dName.clear();
}
};
struct ConfigStorage {
ConfigStorage() { Init(); }
void Init()
{
auto res = ConfigManager::Instance().GetPrintOptions();
if (res != nullptr && res->is_object()) {
printOption.edgeItems = res->value("edgeitems", printOption.edgeItems);
printOption.precision = res->value("precision", printOption.precision);
printOption.threshold = res->value("threshold", printOption.threshold);
printOption.linewidth = res->value("linewidth", printOption.linewidth);
}
Reset();
}
void Reset()
{
funcType = FunctionType::DYNAMIC;
semanticLabel = nullptr;
rundataDir.Reset();
}
FunctionType funcType;
std::shared_ptr<SemanticLabel> semanticLabel;
RunDataDir rundataDir;
PrintOptions printOption;
};
namespace config {
static ConfigStorage g_config;
std::shared_mutex g_rwlock;
void Reset()
{
g_config.Reset();
ConfigManagerNg::CurrentScope()->Clear();
}
void SetBuildStatic(bool isStatic)
{
g_config.funcType = isStatic ? FunctionType::STATIC : FunctionType::DYNAMIC;
FE_LOGD("Set functionType[%s] successfully.", (isStatic ? "STATIC" : "DYNAMIC"));
}
FunctionType GetFunctionType() { return g_config.funcType; }
void SetSemanticLabel(const std::string& label, const char* filename, int lineno)
{
g_config.semanticLabel = std::make_shared<SemanticLabel>(label, filename, lineno);
FE_LOGD("Set semanticLabel[%s] successfully.", label.c_str());
}
void SetSemanticLabel(std::shared_ptr<SemanticLabel> label) { g_config.semanticLabel = label; }
std::shared_ptr<SemanticLabel> GetSemanticLabel() { return g_config.semanticLabel; }
constexpr int LIMIT_DIR_NUM_BEFORE_CREATE = 127;
constexpr const char* PREFIX_RUNDATA = "rundata_";
constexpr const char* ENV_VAR_PYPTO_HOME = "PYPTO_HOME";
constexpr const char* ENV_VAR_HOME = "HOME";
void CreateRunDataDir()
{
std::string envStr = GetEnvVar(ENV_VAR_PYPTO_HOME);
std::string dir = envStr.empty() ? (GetEnvVar(ENV_VAR_HOME) + "/.pypto") : envStr;
g_config.rundataDir.path = dir + "/run";
RemoveOldestDirs(g_config.rundataDir.path, PREFIX_RUNDATA, LIMIT_DIR_NUM_BEFORE_CREATE);
auto time = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
std::stringstream timestamp;
timestamp << std::put_time(std::localtime(&time), "%Y%m%d%H%M%S");
g_config.rundataDir.dName = PREFIX_RUNDATA + timestamp.str();
bool res = CreateMultiLevelDir(g_config.rundataDir.montage());
FE_ASSERT(FeError::BAD_FD, res) << "Failed to create directory: " << g_config.rundataDir.montage();
}
void SetRunDataOption(const std::string& key, const std::string& value)
{
static nlohmann::json j;
std::shared_lock lock(g_rwlock);
j[key] = value;
auto dumpValue = j.dump(2);
if (g_config.rundataDir.empty()) {
CreateRunDataDir();
}
auto filename = g_config.rundataDir.montage() + "/rundata.json";
SaveFileSafe(filename, reinterpret_cast<uint8_t*>(dumpValue.data()), dumpValue.size());
}
void SetPrintOptions(int edgeItems, int precision, int threshold, int linewidth)
{
g_config.printOption.edgeItems = edgeItems;
g_config.printOption.precision = precision;
g_config.printOption.threshold = threshold;
g_config.printOption.linewidth = linewidth;
FE_LOGD("Set print option [%d %d %d %d] successfully.", edgeItems, precision, threshold, linewidth);
}
PrintOptions& GetPrintOptions() { return g_config.printOption; }
const std::string& OutputBaseDir()
{
static std::string baseDir;
static std::once_flag flag;
std::call_once(flag, []() {
const char* tileFwkDir = std::getenv("TILE_FWK_OUTPUT_DIR");
if (tileFwkDir != nullptr && strlen(tileFwkDir) > 0) {
FE_LOGD("Get env TILE_FWK_OUTPUT_DIR[%s] successfully.", tileFwkDir);
baseDir = tileFwkDir;
} else {
const char* ascendWorkPath = std::getenv("ASCEND_WORK_PATH");
if (ascendWorkPath != nullptr && strlen(ascendWorkPath) > 0) {
baseDir = std::string(ascendWorkPath) + "/pypto";
} else {
baseDir = "output";
}
}
});
return baseDir;
}
std::string GetEmitPath(const std::string& name)
{
std::string dirPath;
if (ConfigManager::Instance().GetCodeGenConfig(KEY_FIXED_OUTPUT_PATH, false)) {
std::string rootDir;
const char* ascendWorkPath = std::getenv("ASCEND_WORK_PATH");
if (ascendWorkPath != nullptr && strlen(ascendWorkPath) > 0) {
rootDir = std::string(ascendWorkPath) + "/pypto";
}
std::vector<std::string> groupNames = Distributed::CommGroupRecorder::GetInstance().Output();
if (groupNames.size() == 0) {
dirPath = rootDir.empty() ? name : (rootDir + "/" + name);
} else {
const char* rankId = std::getenv("TILE_FWK_DEVICE_ID");
if (rootDir.empty()) {
dirPath = std::string(rankId) + "/" + name;
} else {
dirPath = rootDir + "/" + std::string(rankId) + "/" + name;
}
}
} else {
dirPath = LogTopFolder() + "/" + name;
}
return dirPath;
}
}
}