* -------------------------------------------------------------------------
* 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 <algorithm>
#include <climits>
#include "ProjectParserFactory.h"
#include "ProjectParserBin.h"
#include "ProjectParserJson.h"
#include "ProjectParserDb.h"
#include "ProjectParserDbNPUMonitor.h"
#include "ProjectParserMemScope.h"
#include "ProjectParserMemSnapshot.h"
#include "ParserIE.h"
#include "DataBaseManager.h"
#include "ClusterFileParser.h"
#include "TraceTime.h"
#include "MemoryParse.h"
#include "FullDbParser.h"
#include "ProjectExplorerManager.h"
#include "MetaDataCacheManager.h"
#include "ServitizationOpenApi.h"
#include "ParserStatusManager.h"
#include "SystemMemoryDatabaseDef.h"
#include "ProjectAnalyze.h"
#include "TrackInfoManager.h"
#include "ExpertHotspotManager.h"
#include "JsonFileParserManager.h"
#include "RLMstxConfigManager.h"
#include "RenderEngine.h"
#include "TrackInfoManager.h"
#include "JsonParseMemPool.h"
#include "MemScopeParser.h"
#include "MemSnapshotParser.h"
#include "ProjectParserTriton.h"
#include "ProjectParserFtrace.h"
namespace Dic::Module {
using namespace Dic;
using namespace Dic::Server;
using namespace Dic::Module::Timeline;
using namespace Dic::Module::Global;
std::mutex ParserFactory::mutex;
std::pair<std::string, ParserType> ParserFactory::GetImportType(const std::string &path) {
const std::string filename = FileUtil::GetFileName(path);
std::string error;
if (!ProjectParserTriton().GetParseFileByImportFile(path, error).empty()) {
return std::make_pair(path, ParserType::TRITON_MEMORY);
}
if (!FileUtil::IsFolder(path) && ProjectParserMemScope::IsMemScopeDbFile(filename)) {
return std::make_pair(path, ParserType::DB_MEMSCOPE);
}
if (!FileUtil::IsFolder(path) && ProjectParserMemSnapshot::IsSnapshotPickleFile(filename)) {
return std::make_pair(path, ParserType::PKL_MEM_SNAPSHOT);
}
if (!FileUtil::IsFolder(path) && std::regex_match(filename, std::regex(npumonitorDBReg))) {
return std::make_pair(path, ParserType::DB_NPUMONITOR);
}
if (!FileUtil::IsFolder(path) && std::regex_match(filename, std::regex(ftraceDbReg))) {
return std::make_pair(path, ParserType::DB_FTRACE);
}
if (StringUtil::EndWith(path, computeBinSuffix)) {
return std::make_pair(path, ParserType::BIN);
}
if (!FileUtil::IsFolder(path) && ProjectParserJson::IsACLGraphDebugJSON(path)) {
return std::make_pair(path, ParserType::ACLGRPAH_DEBUG_JSON);
}
if (FileUtil::FindIfDbTypeByRegex(path, std::regex(traceViewReg), std::regex(DB_REG))) {
return std::make_pair(path, ParserType::DB);
}
if (ProjectParserJson::ExistJsonFormatFile(path) || ClusterFileParser::CheckIsCluster(path)) {
return std::make_pair(path, ParserType::JSON);
}
if (FileUtil::FindIfDbTypeByRegex(path, std::regex(traceViewReg), std::regex(npumonitorDBReg))) {
return std::make_pair(path, ParserType::DB_NPUMONITOR);
}
return std::make_pair(path, ParserType::OTHER);
}
std::shared_ptr<ProjectParserBase> ParserFactory::GetProjectParser(ParserType allocType) {
std::shared_ptr<ProjectParserBase> alloc;
switch (allocType) {
case ParserType::DB:
alloc = std::make_shared<ProjectParserDb>();
break;
case ParserType::BIN:
alloc = std::make_shared<ProjectParserBin>();
break;
case ParserType::ACLGRPAH_DEBUG_JSON:
alloc = std::make_shared<ProjectParserJson>(JsonFileParserManager::GetACLGraphDebugParser());
break;
case ParserType::JSON:
alloc = std::make_shared<ProjectParserJson>(JsonFileParserManager::GetTraceFileParser());
break;
case ParserType::IE:
alloc = std::make_shared<ParserIE>();
break;
case ParserType::DB_NPUMONITOR:
alloc = std::make_shared<ProjectParserDbNPUMonitor>();
break;
case ParserType::DB_MEMSCOPE:
alloc = std::make_shared<ProjectParserMemScope>();
break;
case ParserType::PKL_MEM_SNAPSHOT:
alloc = std::make_shared<ProjectParserMemSnapshot>();
break;
case ParserType::TRITON_MEMORY:
alloc = std::make_shared<ProjectParserTriton>();
break;
case ParserType::DB_FTRACE:
alloc = std::make_shared<ProjectParserFtrace>();
break;
default:
alloc = std::make_shared<ProjectParserBase>();
break;
}
return alloc;
}
void ParserFactory::Reset() {
std::lock_guard<std::mutex> lock(mutex);
std::shared_ptr<IE::ServitizationOpenApi> openApi = std::make_shared<IE::ServitizationOpenApi>();
openApi->Reset();
JsonFileParserManager::Instance().ResetAll();
Summary::KernelParse::Instance().Reset();
Memory::MemoryParse::Instance().Reset();
FullDb::FullDbParser::Instance().Reset();
MetaDataCacheManager::Instance().Clear();
MemScopeParser::Instance().Reset();
MemSnapshotParser::Instance().Reset();
}
void ProjectParserBase::SetBaseActionOfResponse(ImportActionResponse &response, const std::string &rankId,
const std::string &fileId, const std::string &cardPath, std::vector<std::string> dataPath, int64_t projectType) {
auto rankList = TrackInfoManager::Instance().GetRankListByFileId(fileId, rankId);
Action action;
if (!rankList.empty()) {
action.cluster = rankList[0].cluster;
}
action.cardName = rankId;
action.rankId = rankId;
action.result = true;
action.fileId = fileId;
action.dataPathList = dataPath;
action.cardPath = "Directory: " + cardPath;
action.projectType = projectType;
response.body.result.emplace_back(action);
}
void ProjectParserBase::ParseClusterEndProcess(std::string result, bool isShowCluster, const std::string &clusterId) {
ServerLog::Info("Parse Cluster File end, send event");
auto event = std::make_unique<ParseClusterCompletedEvent>();
event->moduleName = MODULE_TIMELINE;
event->result = true;
event->body.parseResult = std::move(result);
event->body.isShowCluster = isShowCluster;
event->body.clusterPath = clusterId;
SendEvent(std::move(event));
}
void ProjectParserBase::ParseEndCallBack(
const std::string &rankId, const std::string &fileId, bool result, const std::string &message) {
ServerLog::Info("Parse end, fileId:", rankId, ", result:", result);
if (result) {
SendParseSuccessEvent(rankId, fileId);
} else {
SendParseFailEvent(rankId, fileId, message);
}
}
void ProjectParserBase::ParseProgressCallBack(
const std::string &fileId, uint64_t parsedSize, uint64_t totalSize, int progress) {
auto event = std::make_unique<ParseProgressEvent>();
event->moduleName = MODULE_TIMELINE;
event->result = true;
event->body.fileId = fileId;
event->body.parsedSize = parsedSize;
event->body.totalSize = totalSize;
event->body.progress = progress;
SendEvent(std::move(event));
}
void ProjectParserBase::SendParseSuccessEvent(const std::string &rankId, const std::string &fileId) {
auto event = std::make_unique<ParseSuccessEvent>();
event->moduleName = MODULE_TIMELINE;
event->result = true;
event->body.unit.type = "card";
event->body.unit.metadata.cardId = rankId;
uint64_t min = UINT64_MAX;
uint64_t max = 0;
auto database = DataBaseManager::Instance().GetTraceDatabaseByFileId(fileId);
if (database == nullptr) {
ServerLog::Error("Failed to get connection. fileId:", fileId);
return;
}
event->body.unit.metadata.cardAlias = database->QueryCardAlias();
if (!database->QueryExtremumTimestamp(min, max)) {
return;
}
if (min == max && max == 0) {
event->body.startTimeUpdated = false;
} else {
event->body.startTimeUpdated = true;
TraceTime::Instance().UpdateTime(min, max);
TraceTime::Instance().UpdateCardTimeDuration(rankId, min, max);
}
event->body.maxTimeStamp = TraceTime::Instance().GetDuration();
event->body.startTime = TraceTime::Instance().GetStartTime();
event->body.offset = TraceTime::Instance().GetOffsetByFileId(rankId);
event->body.fileId = fileId;
event->body.isFullDb = Timeline::DataBaseManager::Instance().GetDataType(fileId) == DataType::DB;
std::vector<std::string> taskNameList = RL::RLMstxConfigManager::Instance().GetMstxTaskNameList();
auto mstxSliceList = FullDb::RenderEngine::Instance()->QueryMstxRLDetail(
rankId, Timeline::DataBaseManager::Instance().GetDataType(fileId), taskNameList);
event->body.isRl = !mstxSliceList.empty();
event->body.rankList = TrackInfoManager::Instance().GetRankListByFileId(fileId, rankId);
SearchMetaData(rankId, fileId, event->body.unit.children);
SearchGroupedAscendHardwareThreads(fileId, event->body.unit, event->body.threadGroupList);
SendEvent(std::move(event));
}
void ProjectParserBase::SendParseFailEvent(
const std::string &rankId, const std::string &fileId, const std::string &message) {
auto event = std::make_unique<ParseFailEvent>();
event->moduleName = MODULE_TIMELINE;
event->result = true;
event->body.rankId = rankId;
event->body.error = message;
event->body.dbPath = fileId;
SendEvent(std::move(event));
}
bool ProjectParserBase::IsNeedReset(const ImportActionRequest &request) {
if (request.params.projectAction == ProjectActionEnum::TRANSFER_PROJECT) {
return true;
}
std::string curProjectName = request.projectName;
if (request.params.isConflict || (!curProjectName.empty() && curProjectName != request.params.projectName)) {
return true;
}
return false;
}
void ProjectParserBase::SearchGroupedAscendHardwareThreads(
const std::string &fileId, const Unit &unit, std::vector<ThreadGroup> &groupedThreads) {
const auto database = DataBaseManager::Instance().GetTraceDatabaseByFileId(fileId);
if (database == nullptr) {
ServerLog::Error("Failed to get connection. fileId:", fileId);
return;
}
database->QueryGroupedAscendHardwareThreadsByModelId(groupedThreads);
uint8_t updatedGroupNum = 0;
for (const auto &item : unit.children) {
if (updatedGroupNum >= groupedThreads.size()) {
break;
}
std::unordered_set<std::string> threadIdSet;
threadIdSet.reserve(item->children.size());
for (const auto &threadPtr : item->children) {
threadIdSet.insert(threadPtr->metaData.threadId);
}
for (auto &groupedThread : groupedThreads) {
if (!groupedThread.processId.empty()) {
continue;
}
const bool matched = std::any_of(groupedThread.threadIds.begin(), groupedThread.threadIds.end(),
[&](const std::string &id) { return threadIdSet.find(id) != threadIdSet.end(); });
if (matched) {
groupedThread.processId = item->metaData.processId;
groupedThread.cardId = unit.metadata.cardId;
updatedGroupNum++;
break;
}
}
}
}
void ProjectParserBase::SearchMetaData(
const std::string &rankId, const std::string &fileId, std::vector<std::unique_ptr<UnitTrack>> &metaData) {
auto database = DataBaseManager::Instance().GetTraceDatabaseByFileId(fileId);
if (database == nullptr) {
ServerLog::Error("Failed to get connection. fileId:", fileId);
return;
}
database->QueryUnitsMetadata(rankId, metaData);
ProcessMetadata(metaData);
}
void ProjectParserBase::ProcessMetadata(std::vector<std::unique_ptr<UnitTrack>> &metaData) {
for (const auto &item : metaData) {
for (const auto &thread : item->children) {
if (thread->metaData.groupNameValue.empty()) {
continue;
}
thread->metaData.groupNameValue = StringUtil::FixGbkMojibakeStr(thread->metaData.groupNameValue);
thread->metaData.threadName = StringUtil::FixGbkMojibakeStr(thread->metaData.threadName);
std::vector<std::string> groupNameSplit = StringUtil::Split(thread->metaData.groupNameValue, " ");
std::string realGroupName = groupNameSplit.size() > 1 ? groupNameSplit[0] : thread->metaData.groupNameValue;
auto groupInfoOpt = MetaDataCacheManager::Instance().GetParallelGroupInfo(realGroupName);
if (!groupInfoOpt.has_value()) {
continue;
}
std::string groupName = StringUtil::FixGbkMojibakeStr(groupInfoOpt.value().groupName);
thread->metaData.threadName = groupName + ":" + thread->metaData.threadName;
thread->metaData.rankList = groupInfoOpt.value().globalRanks;
}
}
}
std::string ProjectParserBase::GetRankIdFromPath(const std::string &filePath, const std::string &importPath) {
std::string fileId = FileUtil::GetRankIdFromFile(filePath);
int i = 1;
std::string result = fileId;
std::string parentDir = FileUtil::GetParentPath(filePath);
std::string name = FileUtil::GetFileName(filePath);
while (DataBaseManager::Instance().HasRankId(DatabaseType::TRACE, result)) {
auto database = DataBaseManager::Instance().GetTraceDatabaseByRankId(result);
if (database == nullptr) {
continue;
}
std::string dir = FileUtil::GetParentPath(database->GetDbPath());
if (RegexUtil::RegexMatch(name, R"(^msprof_slice_[0-9_]+\.json$)") && parentDir == dir) {
return result;
}
result = fileId + "_" + std::to_string(++i);
}
std::string dbPath = FileUtil::GetDbPath(filePath);
if (dbPath.length() >= FileUtil::GetFilePathLengthLimit()) {
const std::string message = dbPath + " length exceed " + std::to_string(FileUtil::GetFilePathLengthLimit());
SendParseFailEvent("", dbPath, message);
}
dataPathToDbMap[importPath].push_back(dbPath);
return result;
}
std::string ProjectParserBase::GetDbPath(const std::string &filePath, const int index) {
std::string path(filePath);
std::string suffix = DB_FILE_SUFFIX;
if (index != 1) {
suffix = "_" + std::to_string(index) + suffix;
}
auto pos = path.find_last_of('.');
if (pos != std::string::npos) {
path.replace(pos, path.size() - pos, suffix);
} else {
path.append(suffix);
}
return path;
}
bool ProjectParserBase::ParseHeatMapToCluster(const std::vector<std::shared_ptr<ParseFileInfo>> &clusterInfos) {
bool res = false;
for (const auto &cluster : clusterInfos) {
std::vector<std::string> rankIdList;
for (const auto &child : cluster->subParseFile) {
rankIdList.push_back(child->rankId);
}
std::string errorMsg;
bool tempRes =
Summary::ExpertHotspotManager::UpdateHeatMapFromProfiling(errorMsg, cluster->parseFilePath, rankIdList);
if (!tempRes) {
ServerLog::Warn(errorMsg, " cluster path:", cluster->parseFilePath);
}
res = res | tempRes;
}
return res;
}
void ProjectParserBase::ParsePostProcess(const std::vector<std::shared_ptr<ParseFileInfo>> &clusterInfos) {
ParserStatusManager::Instance().WaitStartParse();
for (const auto &cluster : clusterInfos) {
for (const auto &child : cluster->subParseFile) {
TrackInfoManager::Instance().UpdateClusterDbToFileIdMap(cluster->parseFilePath, child->fileId);
}
}
SendAllParseSuccess();
auto event = std::make_unique<ParseHeatmapCompletedEvent>();
if (!clusterInfos.empty()) {
std::string errorMsg;
bool res = ParseHeatMapToCluster(clusterInfos);
event->body.parseResult = res;
event->result = true;
} else {
event->result = false;
event->body.parseResult = false;
event->body.errorMsg = "No cluster data exists.";
}
event->moduleName = MODULE_TIMELINE;
SendEvent(std::move(event));
}
void ProjectParserBase::SendAllParseSuccess() {
ParserStatusManager::Instance().WaitStartParse();
std::string notFinishTask = "";
const int maxSleepTimeMs = 2000;
int sleepTime = 200;
while (!ParserStatusManager::Instance().IsAllFinished(notFinishTask)) {
#ifdef INSIGHT_DEBUG
ServerLog::Info("NotFinishTask is: ", notFinishTask);
#endif
sleepTime = std::min(sleepTime * 2, maxSleepTimeMs);
std::this_thread::sleep_for(std::chrono::milliseconds(sleepTime));
}
ServerLog::Info("Send all parse finished");
auto event = std::make_unique<AllSuccessEvent>();
event->moduleName = MODULE_MEMORY;
event->result = true;
event->body.isAllPageParsed = true;
for (const auto &item : TraceTime::Instance().ComputeCardMinTimeInfo()) {
CardOffset cardOffset = {item.first, item.second};
event->body.cardOffsets.emplace_back(cardOffset);
}
event->body.minTime = TraceTime::Instance().GetStartTime();
Dic::Module::JsonParseMemPool::Instance().Clear();
SendEvent(std::move(event));
}
void ProjectParserBase::SaveDbPath(
const std::string &curProjectName, std::map<std::string, std::vector<std::string>> &dataPathToDbMap) {
Global::ProjectExplorerManager::Instance().UpdateProjectDbPath(curProjectName, dataPathToDbMap);
}
* 校验前端是否展示集群标签
*
* @param action 导入动作(切换项目、导入文件)
* @param curType 当前文件的类型
* @param projectName 项目名
* @return 是否要打开集群标签
*/
bool ProjectParserBase::CheckIsOpenClusterTag(
ProjectActionEnum action, ProjectTypeEnum curType, const std::string &projectName) {
if (curType == ProjectTypeEnum::TEXT_CLUSTER || curType == ProjectTypeEnum::DB_CLUSTER) {
return true;
}
if (action != ProjectActionEnum::ADD_FILE) {
return false;
}
std::vector<Global::ProjectExplorerInfo> projectInfo =
Global::ProjectExplorerManager::Instance().QueryProjectExplorer(projectName, {});
ProjectTypeEnum projectType = Global::ProjectExplorerManager::GetProjectType(projectInfo);
return (projectType == ProjectTypeEnum::TEXT_CLUSTER || projectType == ProjectTypeEnum::DB_CLUSTER);
}
void ProjectParserBase::BuildProjectExploreInfo(
ProjectExplorerInfo &projectInfo, const std::vector<std::string> &parsedFiles) {
auto parseInfo = std::make_shared<ParseFileInfo>();
parseInfo->type = ParseFileType::PROJECT;
parseInfo->parseFilePath = projectInfo.fileName;
parseInfo->subId = projectInfo.fileName;
parseInfo->curDirName = FileUtil::GetFileName(projectInfo.fileName);
parseInfo->projectType = projectInfo.projectType;
projectInfo.projectFileTree.emplace_back(parseInfo);
projectInfo.fileInfoMap.emplace(parseInfo->subId, parseInfo);
}
bool ProjectParserBase::IsParsedFile(const std::string &file) { return false; }
std::vector<std::string> ProjectParserBase::GetParentFileList(const std::string &prefix, const std::string &filePath) {
std::vector<std::string> res;
if (prefix == filePath) {
return res;
}
std::string curPath = FileUtil::GetParentPath(filePath);
while (!curPath.empty() && curPath != prefix) {
res.emplace_back(curPath);
curPath = FileUtil::GetParentPath(curPath);
}
return res;
}
std::tuple<std::string, std::string> ProjectParserBase::GetClusterInfo(const std::vector<std::string> &folders) {
if (folders.empty()) {
return {"", ""};
}
return {folders.back(), folders.back()};
}
std::vector<std::string> ProjectParserBase::SearchDeviceInfo(const std::string &searchPath) {
static std::regex profRegex("^PROF_");
static std::regex deviceRegex("^device_([0-9]+)$");
std::string profDir;
for (const auto &folder : FileUtil::GetSubDirs(searchPath)) {
std::string folderName = FileUtil::GetFileName(folder);
if (std::regex_search(folderName, profRegex)) {
profDir = folder;
break;
}
}
std::smatch match;
std::vector<std::string> res;
auto subDir = profDir.empty() ? FileUtil::GetSubDirs(searchPath)
: FileUtil::GetSubDirs(FileUtil::SplicePath(searchPath, profDir));
for (const auto &dir : subDir) {
std::string fileName = dir;
if (!std::regex_search(fileName, match, deviceRegex)) {
continue;
}
if (match.size() > 1) {
res.emplace_back(match[1].str());
}
}
std::sort(res.begin(), res.end());
return res;
}
void ProjectParserBase::AddRankDeviceParseFileInfo(ProjectExplorerInfo &info, std::shared_ptr<ParseFileInfo> rankInfo) {
auto deviceIdsGetFromDir = ProjectParserBase::SearchDeviceInfo(FileUtil::GetParentPath(rankInfo->parseFilePath));
auto deviceIdsFromFile = ProjectParserBase::ParseDeviceInfo(info, rankInfo->parseFilePath);
if (deviceIdsGetFromDir.size() < 2 || deviceIdsFromFile.size() < 2) {
if (!deviceIdsFromFile.empty()) {
rankInfo->deviceId = deviceIdsFromFile[0];
} else if (!deviceIdsGetFromDir.empty()) {
rankInfo->deviceId = deviceIdsGetFromDir.back();
} else {
rankInfo->deviceId = rankInfo->rankId;
}
info.AddSubParseFileInfo(rankInfo);
return;
}
std::vector<std::string> deviceId = deviceIdsFromFile;
std::for_each(deviceId.begin(), deviceId.end(), [&info, &rankInfo](const std::string &deviceId) {
auto deviceInfo = std::make_shared<ParseFileInfo>();
deviceInfo->subId = FileUtil::SplicePath(rankInfo->subId, deviceId);
deviceInfo->parseFilePath = rankInfo->parseFilePath;
deviceInfo->type = ParseFileType::DEVICE_CHIP;
deviceInfo->rankId = deviceId;
deviceInfo->fileId = rankInfo->fileId;
deviceInfo->clusterId = rankInfo->clusterId;
deviceInfo->deviceId = deviceId;
deviceInfo->projectType = info.projectType;
info.AddSubParseFileInfo(deviceInfo);
});
}
bool ProjectParserBase::IsMindFormsRankData(const std::vector<std::string> &parentFolders) {
if (parentFolders.empty()) {
return false;
}
return RegexUtil::RegexSearch(FileUtil::GetFileName(parentFolders.back()), "^rank_[0-9]+$").has_value();
}
void ProjectParserBase::SendUnitFinishNotify(
const std::string &fileId, bool res, const std::string &unitName, const std::string &error) {
auto event = std::make_unique<ParseUnitCompletedEvent>();
event->body.parseResult = res;
event->body.unitName = unitName;
event->body.errorMsg = error;
event->body.dbId = fileId;
event->moduleName = MODULE_TIMELINE;
event->result = true;
SendEvent(std::move(event));
}
std::vector<std::string> ProjectParserBase::ParseDeviceInfo(
Dic::Module::Global::ProjectExplorerInfo &info, const std::string &searchPath) {
if (info.projectType == static_cast<int64_t>(ProjectTypeEnum::DB_CLUSTER) ||
info.projectType == static_cast<int64_t>(ProjectTypeEnum::DB)) {
std::vector<std::string> dbFiles = FileUtil::FindFilesWithFilter(searchPath, std::regex{"analysis.db"});
if (dbFiles.empty()) {
return {};
}
std::set<std::string> deviceIds = ProjectParserBase::ParseDeviceIdSetFromDb(dbFiles[0]);
return std::vector<std::string>(deviceIds.begin(), deviceIds.end());
}
std::vector<std::string> stepTraceTimeCsvFiles =
FileUtil::FindFirstFileByRegex(searchPath, std::regex("^step_trace_time.csv$"));
if (stepTraceTimeCsvFiles.empty()) {
return {};
}
std::string stepTraceTimeCsvFile = stepTraceTimeCsvFiles[0];
auto deviceIdSet = ProjectParserBase::ParseDeviceIdSetFromCsv(stepTraceTimeCsvFile);
return std::vector<std::string>(deviceIdSet.begin(), deviceIdSet.end());
}
std::set<std::string> ProjectParserBase::ParseDeviceIdSetFromCsv(const std::string &filePath) {
auto file = OpenReadFileSafely(filePath);
if (!file.is_open()) {
ServerLog::Error("Failed to open step_trace_time.csv.");
return {};
}
std::string line;
uint64_t index = std::numeric_limits<uint64_t>::max();
getline(file, line);
auto headerRow = StringUtil::StringSplit(line);
auto it = std::find(headerRow.begin(), headerRow.end(), DEVICE_ID);
if (it == headerRow.end()) {
ServerLog::Info("No DeviceId col in step_trace_time.csv.");
return {};
}
index = static_cast<uint64_t>(std::distance(headerRow.begin(), it));
std::set<std::string> deviceIds;
while (getline(file, line)) {
auto dataRow = StringUtil::StringSplit(line);
if (dataRow.size() <= index) {
continue;
}
if (!dataRow[index].empty()) {
deviceIds.insert(dataRow[index]);
}
}
return deviceIds;
}
std::set<std::string> ProjectParserBase::ParseDeviceIdSetFromDb(const std::string &dbPath) {
std::recursive_mutex mutex;
auto database = std::make_shared<DbTraceDataBase>(mutex);
std::set<std::string> deviceId;
try {
database->OpenDb(dbPath, false);
database->QueryDeviceIdInStepTraceTime(deviceId);
} catch (std::exception &e) {
ServerLog::Error("Failed to query deviceId from StepTraceTimeTable.");
return deviceId;
}
return deviceId;
}
void ProjectParserBase::MergeFileTree(std::vector<std::shared_ptr<ParseFileInfo>> &rootTree,
const std::vector<std::shared_ptr<ParseFileInfo>> &childrenTree) {
if (rootTree.empty()) {
rootTree = childrenTree;
return;
}
if (childrenTree.empty()) {
return;
}
if (rootTree[0]->subId == childrenTree[0]->subId) {
rootTree[0]->subParseFile.insert(rootTree[0]->subParseFile.begin(), childrenTree[0]->subParseFile.begin(),
childrenTree[0]->subParseFile.end());
} else {
rootTree.insert(rootTree.end(), childrenTree.begin(), childrenTree.end());
}
}
void ProjectParserBase::SendImportActionRes(std::unique_ptr<ImportActionResponse> responsePtr) {
std::sort(responsePtr->body.result.begin(), responsePtr->body.result.end(), [](const Action &a, const Action &b) {
if (a.cardName.size() != b.cardName.size()) {
return a.cardName.size() < b.cardName.size();
}
return a.cardName < b.cardName;
});
SendResponse(std::move(responsePtr), true);
}
ProjectAnalyzeRegister<ProjectParserBase> pReg(ParserType::OTHER);
}