* Copyright (c) 2025 Huawei Technologies Co., Ltd.
* This file is part of the MindStudio project.
*
* 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 "analysis/csrc/application/timeline/cann_assembler.h"
#include <algorithm>
#include <unordered_set>
#include "analysis/csrc/domain/entities/viewer_data/ai_task/include/api_data.h"
#include "analysis/csrc/domain/entities/viewer_data/ai_task/include/ascend_task_data.h"
#include "analysis/csrc/domain/services/environment/context.h"
#include "analysis/csrc/application/timeline/connection_id_pool.h"
namespace Analysis {
namespace Application {
using namespace Analysis::Domain::Environment;
using namespace Analysis::Viewer::Database;
using namespace Analysis::Infra;
using namespace Analysis::Utils;
namespace {
const uint32_t SORT_INDEX = 7;
const std::string CANN_ASSEMBLER = "CANN";
const std::string CANN_LABEL = "CPU";
const std::string PROCESS_API = "Api";
const std::unordered_map<uint16_t, std::string> LEVEL_MAP{
{MSPROF_REPORT_ACL_LEVEL, "AscendCL"},
{MSPROF_REPORT_RUNTIME_LEVEL, "Runtime"},
{MSPROF_REPORT_MODEL_LEVEL, "Model"},
{MSPROF_REPORT_NODE_LEVEL, "Node"},
{MSPROF_REPORT_HCCL_NODE_LEVEL, "Communication"}
};
}
CannAssembler::CannAssembler() : JsonAssembler(PROCESS_API, {{MSPROF_JSON_FILE, FileCategory::MSPROF}}) {}
void GenerateMetaData(std::vector<ApiData> &apiData, uint32_t pid, std::vector<std::shared_ptr<TraceEvent>> &res)
{
std::set<uint32_t> tidSet;
std::transform(apiData.begin(), apiData.end(), std::inserter(tidSet, tidSet.end()),
[](ApiData &data) { return data.threadId; });
std::shared_ptr<MetaDataNameEvent> processName;
MAKE_SHARED_RETURN_VOID(processName, MetaDataNameEvent, pid, DEFAULT_TID, META_DATA_PROCESS_NAME, CANN_ASSEMBLER);
std::shared_ptr<MetaDataLabelEvent> processLabel;
MAKE_SHARED_RETURN_VOID(processLabel, MetaDataLabelEvent, pid, DEFAULT_TID, META_DATA_PROCESS_LABEL, CANN_LABEL);
std::shared_ptr<MetaDataIndexEvent> processIndex;
MAKE_SHARED_RETURN_VOID(processIndex, MetaDataIndexEvent, pid, DEFAULT_TID, META_DATA_PROCESS_INDEX, SORT_INDEX);
res.push_back(processName);
res.push_back(processLabel);
res.push_back(processIndex);
for (const auto &id : tidSet) {
int tid = static_cast<int>(id);
std::string argName{"Thread " + std::to_string(tid)};
std::shared_ptr<MetaDataNameEvent> threadName;
MAKE_SHARED_RETURN_VOID(threadName, MetaDataNameEvent, pid, tid, META_DATA_THREAD_NAME, argName);
res.push_back(threadName);
std::shared_ptr<MetaDataIndexEvent> threadIndex;
MAKE_SHARED_RETURN_VOID(threadIndex, MetaDataIndexEvent, pid, tid, META_DATA_THREAD_INDEX, tid);
res.push_back(threadIndex);
}
}
std::string GetLevel(uint16_t level)
{
for (const auto &node : API_LEVEL_TABLE) {
if (node.second == level) {
return node.first;
}
}
return "";
}
std::string GetTraceName(uint16_t level, std::string &name)
{
auto it = LEVEL_MAP.find(level);
if (it != LEVEL_MAP.end()) {
return it->second + "@" + name;
}
return PROCESS_API + "@" + name;
}
std::unordered_set<uint64_t> GetMemcpyAsyncConnectionIds(DataInventory& dataInventory)
{
std::unordered_set<uint64_t> connectionIds;
auto taskData = dataInventory.GetPtr<std::vector<AscendTaskData>>();
if (taskData == nullptr) {
WARN("Can't get task data from dataInventory");
return connectionIds;
}
for (const auto& task: *taskData) {
if (task.hostType == MEMCPY_ASYNC) {
connectionIds.emplace(task.connectionId);
}
}
return connectionIds;
}
void GenerateApiTrace(std::vector<ApiData> &apiData, std::vector<std::shared_ptr<TraceEvent>> &res, uint32_t pid)
{
std::string levelStr;
std::string traceName;
double dur;
for (auto &data : apiData) {
levelStr = GetLevel(data.level);
traceName = GetTraceName(data.level, data.apiName);
dur = static_cast<double>(data.end - data.timestamp) / NS_TO_US;
std::shared_ptr<ApiTraceEvent> event;
MAKE_SHARED_RETURN_VOID(event, ApiTraceEvent, pid, data.threadId, dur,
DivideByPowersOfTenWithPrecision(data.timestamp), traceName, data.threadId,
data.connectionId, data.structType, levelStr, data.id, data.itemId);
res.push_back(event);
}
}
void GenerateConnectionTrace(std::vector<ApiData> &apiData, uint32_t pid, std::vector<std::shared_ptr<TraceEvent>> &res,
std::unordered_set<uint64_t> memcpyAsyncConnectionIds)
{
std::string connId;
std::string name;
for (auto &data : apiData) {
if (MSPROF_REPORT_NODE_LEVEL == data.level || RECORD_EVENT == data.id || WAIT_EVENT == data.id ||
memcpyAsyncConnectionIds.find(data.connectionId) != memcpyAsyncConnectionIds.end()) {
connId = ConnectionIdPool::GetConnectionId(data.connectionId, ConnectionCategory::GENERAL);
name = HOST_TO_DEVICE + connId;
std::shared_ptr<FlowEvent> start;
MAKE_SHARED_RETURN_VOID(start, FlowEvent, pid, data.threadId,
DivideByPowersOfTenWithPrecision(data.timestamp),
HOST_TO_DEVICE, connId, name, FLOW_START);
res.push_back(start);
}
}
}
uint8_t CannAssembler::AssembleData(DataInventory &dataInventory, JsonWriter &ostream, const std::string &profPath)
{
auto apiData = dataInventory.GetPtr<std::vector<ApiData>>();
if (apiData == nullptr) {
WARN("Can't get apiData from dataInventory");
return DATA_NOT_EXIST;
}
auto pid = Context::GetInstance().GetPidFromInfoJson(HOST_ID, profPath);
auto formatPid = JsonAssembler::GetFormatPid(pid, SORT_INDEX);
GenerateMetaData(*apiData, formatPid, res_);
GenerateApiTrace(*apiData, res_, formatPid);
auto memcpyAsyncConnectionIds = GetMemcpyAsyncConnectionIds(dataInventory);
GenerateConnectionTrace(*apiData, formatPid, res_, memcpyAsyncConnectionIds);
if (res_.empty()) {
ERROR("Can't Generate any CANN process data");
return ASSEMBLE_FAILED;
}
for (const auto &node : res_) {
node->DumpJson(ostream);
}
ostream << ",";
return ASSEMBLE_SUCCESS;
}
}
}