* This file is part of the MindStudio project.
* Copyright (c) 2025 Huawei Technologies Co.,Ltd.
*
* MindStudio is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
*
* http://license.coscl.org.cn/MulanPSL2
*
* 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 FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
* -------------------------------------------------------------------------
*/
#include "json_manager.h"
#include <fstream>
#include "client_parser.h"
#include "securec.h"
namespace Utility
{
JsonManager& JsonManager::GetInstance()
{
static JsonManager jsonManager{};
return jsonManager;
}
bool JsonManager::SaveToFile(const std::string& configOutputDir)
{
if (!FileCreateManager::GetInstance(configOutputDir).CreateConfigFile(&fp_, MemScope::CONFIG_FILE, jsonFilePath_))
{
return false;
}
std::ofstream ofs(jsonFilePath_);
if (!ofs.is_open())
{
std::cout << "[msmemscope] Error: Failed to save json file: " << jsonFilePath_ << std::endl;
return false;
}
else
{
try
{
ofs << jsonConfig_.dump(JSON_INDENT);
}
catch (const std::exception& e)
{
std::cout << "[msmemscope] Error: Exception during dump: " << e.what() << std::endl;
ofs.close();
return false;
}
}
ofs.close();
return true;
}
bool JsonManager::LoadFromFile(std::string filePath)
{
std::ifstream ifs(filePath);
if (!ifs.is_open())
{
std::cout << "[msmemscope] Error: Failed to open json file: " << filePath << std::endl;
return false;
}
else
{
ifs >> jsonConfig_;
ifs.close();
}
return true;
}
bool JsonManager::CheckKeyIsValid(const std::string& key, nlohmann::json& current)
{
std::vector<std::string> parts;
Split(key, std::back_inserter(parts), ".");
if (parts.empty())
{
std::cout << "[msmemscope] Error: Empty key path provided!" << std::endl;
return false;
}
for (auto& part : parts)
{
if (!current.contains(part))
{
std::cout << "[msmemscope] Error: Key path: " << part << "keyword not exist!" << std::endl;
return false;
}
current = current[part];
}
return true;
}
void JsonManager::GetStringValue(const std::string& key, std::string& value)
{
nlohmann::json current = jsonConfig_;
if (!CheckKeyIsValid(key, current))
{
return;
}
try
{
value = current.get<std::string>();
}
catch (const std::exception& e)
{
std::cout << "[msmemscope] Error: Exception while reading nested key " << key << ": " << e.what() << std::endl;
return;
}
}
void JsonManager::GetCharListValue(const std::string& key, char* buffer, size_t bufferSize)
{
if (!buffer || bufferSize == 0)
{
std::cout << "[msmemscope] Error: Invalid buffer or buffer size!" << std::endl;
return;
}
std::string str;
GetStringValue(key, str);
if (str.empty())
{
buffer[0] = '\0';
return;
}
if (strncpy_s(buffer, bufferSize, str.c_str(), bufferSize - 1) != EOK)
{
std::cout << "[msmemscope] Error: strncpy_s FAILED" << std::endl;
return;
}
}
void JsonManager::GetUint8Value(const std::string& key, uint8_t& value)
{
nlohmann::json current = jsonConfig_;
if (!CheckKeyIsValid(key, current))
{
return;
}
try
{
value = current.get<uint8_t>();
}
catch (const std::exception& e)
{
std::cout << "[msmemscope] Error: Exception while reading nested key " << key << ": " << e.what() << std::endl;
return;
}
}
void JsonManager::GetUint32Value(const std::string& key, uint32_t& value)
{
nlohmann::json current = jsonConfig_;
if (!CheckKeyIsValid(key, current))
{
return;
}
try
{
value = current.get<uint32_t>();
}
catch (const std::exception& e)
{
std::cout << "[msmemscope] Error: Exception while reading nested key " << key << ": " << e.what() << std::endl;
return;
}
}
void JsonManager::GetBoolValue(const std::string& key, bool& value)
{
nlohmann::json current = jsonConfig_;
if (!CheckKeyIsValid(key, current))
{
return;
}
try
{
value = current.get<bool>();
}
catch (const std::exception& e)
{
std::cout << "[msmemscope] Error: Exception while reading nested key " << key << ": " << e.what() << std::endl;
return;
}
}
void JsonManager::GetVectorIntValue(const std::string& key, std::vector<int>& value)
{
nlohmann::json current = jsonConfig_;
if (!CheckKeyIsValid(key, current))
{
return;
}
try
{
value = current.get<std::vector<int>>();
}
catch (const std::exception& e)
{
std::cout << "[msmemscope] Error: Exception while reading nested key " << key << ": " << e.what() << std::endl;
return;
}
}
void JsonManager::GetUint32ListsValue(const std::string& key, uint32_t* lists, size_t length)
{
if (!lists || length == 0)
{
std::cout << "[msmemscope] Error: Invalid lists or lists size!" << std::endl;
return;
}
std::vector<int> valueLists;
GetVectorIntValue(key, valueLists);
if (valueLists.empty())
{
return;
}
std::copy(valueLists.begin(), valueLists.begin() + std::min(length, valueLists.size()), lists);
}
JsonConfig& JsonConfig::GetInstance()
{
static JsonConfig jsonConfig;
return jsonConfig;
}
bool JsonConfig::EnsureConfigPathConsistency(const std::string& configOutputDir)
{
const char* envPath = std::getenv(MSMEMSCOPE_CONFIG_ENV);
std::string currentEnvPath = envPath ? std::string(envPath) : "";
auto& fileManager = FileCreateManager::GetInstance(configOutputDir);
std::string actualConfigPath = fileManager.GetProjectDir() + '/' + MemScope::CONFIG_FILE + ".json";
bool needUpdate = false;
if (currentEnvPath.empty() || currentEnvPath != actualConfigPath)
{
needUpdate = true;
}
if (needUpdate)
{
if (setenv(MSMEMSCOPE_CONFIG_ENV, actualConfigPath.c_str(), 1) != 0)
{
std::cout << "[msmemscope] Error: Failed to set MSMEMSCOPE_CONFIG_ENV to " << actualConfigPath << std::endl;
return false;
}
}
return true;
}
void JsonConfig::SaveConfigToJson(const MemScope::Config& config)
{
Utility::JsonManager::GetInstance().SetValue("enableCStack", config.enableCStack);
Utility::JsonManager::GetInstance().SetValue("enablePyStack", config.enablePyStack);
Utility::JsonManager::GetInstance().SetValue("enableCompare", config.enableCompare);
Utility::JsonManager::GetInstance().SetValue("cStackDepth", config.cStackDepth);
Utility::JsonManager::GetInstance().SetValue("pyStackDepth", config.pyStackDepth);
Utility::JsonManager::GetInstance().SetValue("levelType", config.levelType);
Utility::JsonManager::GetInstance().SetValue("eventType", config.eventType);
Utility::JsonManager::GetInstance().SetValue("analysisType", config.analysisType);
Utility::JsonManager::GetInstance().SetValue("collectMode", config.collectMode);
Utility::JsonManager::GetInstance().SetValue("outputDir", config.outputDir);
Utility::JsonManager::GetInstance().SetValue("dataFormat", config.dataFormat);
Utility::JsonManager::GetInstance().SetValue("collectAllNpu", config.collectAllNpu);
Utility::JsonManager::GetInstance().SetValue("collectCpu", config.collectCpu);
Utility::JsonManager::GetInstance().SetValue("npuSlots", config.npuSlots);
Utility::JsonManager::GetInstance().SetValue("logLevel", config.logLevel);
Utility::JsonManager::GetInstance().SetValue("isEffective", config.isEffective);
std::vector<uint32_t> stepIdList{config.stepList.stepIdList,
config.stepList.stepIdList + MemScope::SELECTED_STEP_MAX_NUM};
Utility::JsonManager::GetInstance().SetNestedValue("SelectedStepList.stepIdList", stepIdList);
Utility::JsonManager::GetInstance().SetNestedValue("SelectedStepList.stepCount", config.stepList.stepCount);
Utility::JsonManager::GetInstance().SetNestedValue("watchConfig.isWatched", config.watchConfig.isWatched);
Utility::JsonManager::GetInstance().SetNestedValue("watchConfig.fullContent", config.watchConfig.fullContent);
Utility::JsonManager::GetInstance().SetNestedValue("watchConfig.start", config.watchConfig.start);
Utility::JsonManager::GetInstance().SetNestedValue("watchConfig.end", config.watchConfig.end);
Utility::JsonManager::GetInstance().SetNestedValue("watchConfig.outputId", config.watchConfig.outputId);
if (!EnsureConfigPathConsistency(config.outputDir))
{
std::cout << "[msmemscope] Error: Failed to ensure config path consistency." << std::endl;
return;
}
if (!Utility::JsonManager::GetInstance().SaveToFile(config.outputDir))
{
std::cout << "[msmemscope] Error: Save Json config to file failed!" << std::endl;
return;
}
}
bool JsonConfig::ReadJsonConfig(MemScope::Config& config)
{
const char* path = std::getenv(MSMEMSCOPE_CONFIG_ENV);
if (!path)
{
return false;
}
if (!Utility::JsonManager::GetInstance().LoadFromFile(path))
{
std::cout << "[msmemscope] Error: Failed to load json config file: " << path << std::endl;
return false;
}
Utility::JsonManager::GetInstance().GetCharListValue("outputDir", config.outputDir, sizeof(config.outputDir));
Utility::JsonManager::GetInstance().GetUint8Value("analysisType", config.analysisType);
Utility::JsonManager::GetInstance().GetUint8Value("collectMode", config.collectMode);
Utility::JsonManager::GetInstance().GetUint8Value("dataFormat", config.dataFormat);
Utility::JsonManager::GetInstance().GetUint8Value("eventType", config.eventType);
Utility::JsonManager::GetInstance().GetUint8Value("levelType", config.levelType);
Utility::JsonManager::GetInstance().GetUint8Value("logLevel", config.logLevel);
Utility::JsonManager::GetInstance().GetUint32Value("cStackDepth", config.cStackDepth);
Utility::JsonManager::GetInstance().GetUint32Value("pyStackDepth", config.pyStackDepth);
Utility::JsonManager::GetInstance().GetUint32Value("npuSlots", config.npuSlots);
Utility::JsonManager::GetInstance().GetBoolValue("collectAllNpu", config.collectAllNpu);
Utility::JsonManager::GetInstance().GetBoolValue("collectCpu", config.collectCpu);
Utility::JsonManager::GetInstance().GetBoolValue("enableCStack", config.enableCStack);
Utility::JsonManager::GetInstance().GetBoolValue("enablePyStack", config.enablePyStack);
Utility::JsonManager::GetInstance().GetBoolValue("enableCompare", config.enableCompare);
Utility::JsonManager::GetInstance().GetBoolValue("isEffective", config.isEffective);
Utility::JsonManager::GetInstance().GetUint32ListsValue("SelectedStepList.stepIdList", config.stepList.stepIdList,
sizeof(config.stepList.stepIdList));
Utility::JsonManager::GetInstance().GetUint8Value("SelectedStepList.stepCount", config.stepList.stepCount);
Utility::JsonManager::GetInstance().GetBoolValue("watchConfig.isWatched", config.watchConfig.isWatched);
Utility::JsonManager::GetInstance().GetBoolValue("watchConfig.fullContent", config.watchConfig.fullContent);
Utility::JsonManager::GetInstance().GetUint32Value("watchConfig.outputId", config.watchConfig.outputId);
Utility::JsonManager::GetInstance().GetCharListValue("watchConfig.start", config.watchConfig.start,
sizeof(config.watchConfig.start));
Utility::JsonManager::GetInstance().GetCharListValue("watchConfig.end", config.watchConfig.end,
sizeof(config.watchConfig.end));
return true;
}
}