* 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 "event_trace_manager.h"
#include "bit_field.h"
#include "client_parser.h"
#include "cpython.h"
#include "dump.h"
#include "event_report.h"
#include "json_manager.h"
namespace MemScope
{
const std::unordered_map<std::string, std::function<void(const std::string &, Config &, bool &)>> parserConfigTable = {
{"call_stack", ParseCallstack}, {"level", ParseDataLevel}, {"events", ParseEventTraceType},
{"device", ParseDevice}, {"data_format", ParseDataFormat}, {"output", ParseOutputPath},
{"analysis", ParseAnalysis}, {"watch", ParseWatchConfig},
};
const std::vector<std::string> configPolicyTable = {
"output",
"data_format",
"watch",
};
ConfigManager::ConfigManager() { InitConfig(); }
void ConfigManager::InitConfig()
{
Config config;
if (firstConfig && Utility::JsonConfig::GetInstance().ReadJsonConfig(config))
{
firstConfig = false;
config_ = config;
}
else
{
ClientParser parser;
parser.InitialConfig(config);
SetConfigImpl(config);
}
}
void ConfigManager::GetConfigAfterInit(Config &config)
{
ClientParser parser;
parser.InitialConfig(config);
config.collectMode = static_cast<uint8_t>(CollectMode::DEFERRED);
config.isEffective = config_.isEffective;
config.dataFormat = config_.dataFormat;
config.watchConfig = config_.watchConfig;
if (strncpy_s(config.outputDir, sizeof(config.outputDir), config_.outputDir, sizeof(config.outputDir) - 1) != EOK)
{
std::cout << "[msmemscope] Error: strncpy dirpath FAILED" << std::endl;
return;
}
config.outputDir[sizeof(config.outputDir) - 1] = '\0';
}
void ConfigManager::InitStartConfig()
{
EventTraceManager::Instance().SetTraceStatus(EventTraceStatus::IN_TRACING);
Utility::JsonConfig::GetInstance().SaveConfigToJson(config_);
}
const Config &ConfigManager::GetConfig()
{
std::lock_guard<std::mutex> lock(mutex_);
return config_;
}
void ConfigManager::SetConfigImpl(const Config &config)
{
{
std::lock_guard<std::mutex> lock(mutex_);
config_ = config;
SetEventDefaultConfig(config_);
SetAnalysisDefaultConfig(config_);
}
}
void ConfigManager::SetConfig(const Config &config)
{
SetConfigImpl(config);
SetEffectiveConfig(config_);
Utility::SetLogLevel(static_cast<LogLv>(config_.logLevel));
Utility::JsonConfig::GetInstance().SaveConfigToJson(config_);
EventTraceManager::Instance().HandleWithATenCollect();
EventTraceManager::Instance().HandleWithDecompose();
}
bool ConfigManager::SetConfig(const std::unordered_map<std::string, std::string> &pythonConfig)
{
Config config;
GetConfigAfterInit(config);
for (auto &p : pythonConfig)
{
const std::string &key = p.first;
const std::string &value = p.second;
auto itr = parserConfigTable.find(key);
if (itr == parserConfigTable.end())
{
return false;
}
auto policyItr = std::find(configPolicyTable.begin(), configPolicyTable.end(), key);
if (policyItr != configPolicyTable.end() && config.isEffective)
{
std::cout << "[msmemscope] Warn: Config:\"output\",\"data_format\",\"watch\" cannot be set twice."
<< std::endl;
continue;
}
bool parseFail = false;
itr->second(value, config, parseFail);
if (parseFail)
{
return false;
}
}
SetConfigImpl(config);
SetEffectiveConfig(config_);
Utility::SetLogLevel(static_cast<LogLv>(config_.logLevel));
Utility::JsonConfig::GetInstance().SaveConfigToJson(config_);
EventTraceManager::Instance().HandleWithATenCollect();
EventTraceManager::Instance().HandleWithDecompose();
EventTraceManager::Instance().InitJudgeFuncTable();
EventReport::Instance(MemScopeCommType::SHARED_MEMORY).UpdateAnalysisType();
return true;
}
bool IsNeedTraceOp() { return BitPresent(GetConfig().levelType, static_cast<size_t>(LevelType::LEVEL_OP)); }
bool IsNeedTraceKernel() { return BitPresent(GetConfig().levelType, static_cast<size_t>(LevelType::LEVEL_KERNEL)); }
bool IsNeedTraceAccess() { return BitPresent(GetConfig().eventType, static_cast<size_t>(EventType::ACCESS_EVENT)); }
bool IsNeedTraceLaunch() { return BitPresent(GetConfig().eventType, static_cast<size_t>(EventType::LAUNCH_EVENT)); }
bool IsNeedTraceAlloc() { return BitPresent(GetConfig().eventType, static_cast<size_t>(EventType::ALLOC_EVENT)); }
bool IsNeedTraceFree() { return BitPresent(GetConfig().eventType, static_cast<size_t>(EventType::FREE_EVENT)); }
bool IsNeedTraceKernelLaunch() { return IsNeedTraceKernel() && IsNeedTraceLaunch(); }
bool IsNeedTraceOpLaunch() { return IsNeedTraceOp() && IsNeedTraceLaunch(); }
bool IsNeedTraceMemory() { return IsNeedTraceAlloc() && IsNeedTraceFree(); }
void EventTraceManager::InitJudgeFuncTable()
{
judgeFuncTable_ = {
{EventBaseType::KERNEL_LAUNCH, []() { return IsNeedTraceKernelLaunch(); }},
{EventBaseType::MALLOC, []() { return IsNeedTraceMemory(); }},
{EventBaseType::FREE, []() { return IsNeedTraceMemory(); }},
{EventBaseType::OP_LAUNCH, []() { return IsNeedTraceOpLaunch(); }},
{EventBaseType::ACCESS, []() { return IsNeedTraceAccess(); }},
};
};
bool EventTraceManager::IsNeedTrace(EventBaseType type)
{
if (status_ != EventTraceStatus::IN_TRACING)
{
return false;
}
if (destroyed_.load())
{
return false;
}
auto itr = judgeFuncTable_.find(type);
if (itr == judgeFuncTable_.end())
{
return true;
}
return itr->second();
}
bool EventTraceManager::IsTracingEnabled()
{
if (status_ != EventTraceStatus::IN_TRACING)
{
return false;
}
return true;
}
void EventTraceManager::InitTraceStatus()
{
auto status = (GetConfig().collectMode == static_cast<uint8_t>(CollectMode::IMMEDIATE)) && GetConfig().isEffective
? EventTraceStatus::IN_TRACING
: EventTraceStatus::NOT_IN_TRACING;
status_ = status;
return;
}
void EventTraceManager::SetTraceStatus(const EventTraceStatus status)
{
if (status == EventTraceStatus::IN_TRACING)
{
std::cout << "[msmemscope] Info: Start tracing.\n";
}
else if (status == EventTraceStatus::NOT_IN_TRACING)
{
std::cout << "[msmemscope] Info: Stop tracing.\n";
}
if (!EventReport::Instance(MemScopeCommType::SHARED_MEMORY).ReportTraceStatus(status))
{
std::cout << "[msmemscope] Error: Report trace status failed.\n";
}
std::lock_guard<std::mutex> lock(mutex_);
status_ = status;
HandleWithATenCollect();
HandleWithDecompose();
return;
}
void EventTraceManager::HandleWithATenCollect()
{
if ((status_ == EventTraceStatus::IN_TRACING) && IsNeedTraceOp() && aclInit_)
{
Utility::MemScopePythonCall("msmemscope.aten_collection", "enable_aten_collector");
return;
}
Utility::MemScopePythonCall("msmemscope.aten_collection", "disable_aten_collector");
return;
}
void EventTraceManager::HandleWithDecompose()
{
if ((status_ == EventTraceStatus::IN_TRACING) &&
BitPresent(GetConfig().analysisType, static_cast<size_t>(AnalysisType::DECOMPOSE_ANALYSIS)) && aclInit_)
{
Utility::MemScopePythonCall("msmemscope.optimizer_step_hook", "enable_optimizer_step_hook");
return;
}
Utility::MemScopePythonCall("msmemscope.optimizer_step_hook", "disable_optimizer_step_hook");
return;
}
void EventTraceManager::SetAclInitStatus(bool isInit)
{
aclInit_ = isInit;
HandleWithATenCollect();
HandleWithDecompose();
}
void EventTraceManager::CleanUpEventTraceManager()
{
Config config = Config{};
Dump::GetInstance(config).WritePublicEventToFile();
Dump::GetInstance(config).FflushEventToFile();
}
}