| @@ -203,6 +203,12 @@ const std::string TABLE_NAME_UB = "UB"; | |||
| 203 | 203 | ||
| 204 | const std::string PROCESSOR_NAME_BLOCK_DETAIL = "BLOCK_DETAIL"; | 204 | const std::string PROCESSOR_NAME_BLOCK_DETAIL = "BLOCK_DETAIL"; |
| 205 | const std::string PROCESSOR_NAME_PAGE_FAULT = "PAGE_FAULT"; | 205 | const std::string PROCESSOR_NAME_PAGE_FAULT = "PAGE_FAULT"; |
| 206 | +const std::string PROCESSOR_NAME_AICPU = "AICPU"; | ||
| 207 | +const std::string DB_NAME_AI_CPU = "ai_cpu.db"; | ||
| 208 | +const std::string TABLE_NAME_AI_CPU = "AiCpuData"; | ||
| 209 | +const std::string TABLE_NAME_AI_CPU_DP = "AiCpuDP"; | ||
| 210 | +const std::string DB_NAME_DATA_PREPROCESS = "data_preprocess.db"; | ||
| 211 | +const std::string TABLE_NAME_DATA_QUEUE = "DataQueue"; | ||
| 206 | 212 | ||
| 207 | const std::string PROCESSOR_NAME_DPU = "DPU"; | 213 | const std::string PROCESSOR_NAME_DPU = "DPU"; |
| 208 | const std::string TABLE_NAME_DPU_TASK = "DPU_TASK"; | 214 | const std::string TABLE_NAME_DPU_TASK = "DPU_TASK"; |
| @@ -0,0 +1,118 @@ | |||
| 1 | +/* ------------------------------------------------------------------------- | ||
| 2 | + * Copyright (c) 2026 Huawei Technologies Co., Ltd. | ||
| 3 | + * This file is part of the MindStudio project. | ||
| 4 | + * | ||
| 5 | + * MindStudio is licensed under Mulan PSL v2. | ||
| 6 | + * You can use this software according to the terms and conditions of the Mulan PSL v2. | ||
| 7 | + * You may obtain a copy of Mulan PSL v2 at: | ||
| 8 | + * | ||
| 9 | + * http://license.coscl.org.cn/MulanPSL2 | ||
| 10 | + * | ||
| 11 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, | ||
| 12 | + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, | ||
| 13 | + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. | ||
| 14 | + * See the Mulan PSL v2 for more details. | ||
| 15 | + * -------------------------------------------------------------------------*/ | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | + | ||
| 20 | + | ||
| 21 | + | ||
| 22 | + | ||
| 23 | + | ||
| 24 | + | ||
| 25 | + | ||
| 26 | + | ||
| 27 | +namespace Analysis | ||
| 28 | +{ | ||
| 29 | +namespace Application | ||
| 30 | +{ | ||
| 31 | +using namespace Analysis::Utils; | ||
| 32 | +using namespace Analysis::Domain; | ||
| 33 | + | ||
| 34 | +AicpuAssembler::AicpuAssembler(const std::string &name, const std::string &profPath) : SummaryAssembler(name, profPath) | ||
| 35 | +{ | ||
| 36 | +} | ||
| 37 | + | ||
| 38 | +uint8_t AicpuAssembler::AssembleData(DataInventory &dataInventory) | ||
| 39 | +{ | ||
| 40 | + auto aicpuData = dataInventory.GetPtr<std::vector<AicpuSummaryData>>(); | ||
| 41 | + auto dpData = dataInventory.GetPtr<std::vector<AicpuDpData>>(); | ||
| 42 | + auto miData = dataInventory.GetPtr<std::vector<AicpuMiData>>(); | ||
| 43 | + bool written = false; | ||
| 44 | + if (aicpuData != nullptr && WriteAicpuCsv(*aicpuData)) | ||
| 45 | + { | ||
| 46 | + written = true; | ||
| 47 | + } | ||
| 48 | + if (dpData != nullptr && WriteDpCsv(*dpData)) | ||
| 49 | + { | ||
| 50 | + written = true; | ||
| 51 | + } | ||
| 52 | + if (miData != nullptr && WriteMiCsv(*miData)) | ||
| 53 | + { | ||
| 54 | + written = true; | ||
| 55 | + } | ||
| 56 | + if (!written) | ||
| 57 | + { | ||
| 58 | + WARN("No data to export aicpu/dp/aicpu_mi summary"); | ||
| 59 | + return DATA_NOT_EXIST; | ||
| 60 | + } | ||
| 61 | + return ASSEMBLE_SUCCESS; | ||
| 62 | +} | ||
| 63 | + | ||
| 64 | +bool AicpuAssembler::WriteAicpuCsv(const std::vector<AicpuSummaryData> &data) | ||
| 65 | +{ | ||
| 66 | + if (data.empty()) | ||
| 67 | + { | ||
| 68 | + return false; | ||
| 69 | + } | ||
| 70 | + headers_ = {"Timestamp(us)", "Node", "Compute_time(us)", "Memcpy_time(us)", "Task_time(us)", | ||
| 71 | + "Dispatch_time(us)", "Total_time(us)", "Stream ID", "Task ID"}; | ||
| 72 | + res_.clear(); | ||
| 73 | + for (const auto &item : data) | ||
| 74 | + { | ||
| 75 | + res_.emplace_back(std::vector<std::string>{ | ||
| 76 | + DivideByPowersOfTenWithPrecision(item.timestampNs), item.nodeName, DoubleToStr(item.computeTimeUs), | ||
| 77 | + DoubleToStr(item.memcpyTimeUs), DoubleToStr(item.taskTimeUs), DoubleToStr(item.dispatchTimeUs), | ||
| 78 | + DoubleToStr(item.totalTimeUs), std::to_string(item.streamId), std::to_string(item.taskId)}); | ||
| 79 | + } | ||
| 80 | + WriteToFile(File::PathJoin({profPath_, Analysis::Common::OUTPUT_PATH, AICPU_NAME}), {}); | ||
| 81 | + return true; | ||
| 82 | +} | ||
| 83 | + | ||
| 84 | +bool AicpuAssembler::WriteDpCsv(const std::vector<AicpuDpData> &data) | ||
| 85 | +{ | ||
| 86 | + if (data.empty()) | ||
| 87 | + { | ||
| 88 | + return false; | ||
| 89 | + } | ||
| 90 | + headers_ = {"Timestamp(us)", "Action", "Source", "Cached Buffer Size"}; | ||
| 91 | + res_.clear(); | ||
| 92 | + for (const auto &item : data) | ||
| 93 | + { | ||
| 94 | + res_.emplace_back(std::vector<std::string>{DivideByPowersOfTenWithPrecision(item.timestamp), item.action, | ||
| 95 | + item.source, std::to_string(item.bufferSize)}); | ||
| 96 | + } | ||
| 97 | + WriteToFile(File::PathJoin({profPath_, Analysis::Common::OUTPUT_PATH, AICPU_DP_NAME}), {}); | ||
| 98 | + return true; | ||
| 99 | +} | ||
| 100 | + | ||
| 101 | +bool AicpuAssembler::WriteMiCsv(const std::vector<AicpuMiData> &data) | ||
| 102 | +{ | ||
| 103 | + if (data.empty()) | ||
| 104 | + { | ||
| 105 | + return false; | ||
| 106 | + } | ||
| 107 | + headers_ = {"Node Name", "Start Time(us)", "End Time(us)", "Queue Size"}; | ||
| 108 | + res_.clear(); | ||
| 109 | + for (const auto &item : data) | ||
| 110 | + { | ||
| 111 | + res_.emplace_back(std::vector<std::string>{item.nodeName, std::to_string(item.startTime), | ||
| 112 | + std::to_string(item.endTime), std::to_string(item.queueSize)}); | ||
| 113 | + } | ||
| 114 | + WriteToFile(File::PathJoin({profPath_, Analysis::Common::OUTPUT_PATH, AICPU_MI_NAME}), {}); | ||
| 115 | + return true; | ||
| 116 | +} | ||
| 117 | +} // namespace Application | ||
| 118 | +} // namespace Analysis | ||
| @@ -0,0 +1,42 @@ | |||
| 1 | +/* ------------------------------------------------------------------------- | ||
| 2 | + * Copyright (c) 2026 Huawei Technologies Co., Ltd. | ||
| 3 | + * This file is part of the MindStudio project. | ||
| 4 | + * | ||
| 5 | + * MindStudio is licensed under Mulan PSL v2. | ||
| 6 | + * You can use this software according to the terms and conditions of the Mulan PSL v2. | ||
| 7 | + * You may obtain a copy of Mulan PSL v2 at: | ||
| 8 | + * | ||
| 9 | + * http://license.coscl.org.cn/MulanPSL2 | ||
| 10 | + * | ||
| 11 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, | ||
| 12 | + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, | ||
| 13 | + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. | ||
| 14 | + * See the Mulan PSL v2 for more details. | ||
| 15 | + * -------------------------------------------------------------------------*/ | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | + | ||
| 20 | + | ||
| 21 | + | ||
| 22 | + | ||
| 23 | +namespace Analysis | ||
| 24 | +{ | ||
| 25 | +namespace Application | ||
| 26 | +{ | ||
| 27 | +class AicpuAssembler : public SummaryAssembler | ||
| 28 | +{ | ||
| 29 | + public: | ||
| 30 | + AicpuAssembler() = default; | ||
| 31 | + AicpuAssembler(const std::string &name, const std::string &profPath); | ||
| 32 | + | ||
| 33 | + private: | ||
| 34 | + uint8_t AssembleData(DataInventory &dataInventory) override; | ||
| 35 | + bool WriteAicpuCsv(const std::vector<Domain::AicpuSummaryData> &data); | ||
| 36 | + bool WriteDpCsv(const std::vector<Domain::AicpuDpData> &data); | ||
| 37 | + bool WriteMiCsv(const std::vector<Domain::AicpuMiData> &data); | ||
| 38 | +}; | ||
| 39 | +} // namespace Application | ||
| 40 | +} // namespace Analysis | ||
| 41 | + | ||
| 42 | + | ||
| @@ -40,6 +40,9 @@ const std::string STEP_TRACE_SUMMARY_NAME = "step_trace"; | |||
| 40 | const std::string COMM_STATISTIC_NAME = "communication_statistic"; | 40 | const std::string COMM_STATISTIC_NAME = "communication_statistic"; |
| 41 | const std::string OP_STATISTIC_NAME = "op_statistic"; | 41 | const std::string OP_STATISTIC_NAME = "op_statistic"; |
| 42 | const std::string PAGE_FAULT_NAME = "page_fault"; | 42 | const std::string PAGE_FAULT_NAME = "page_fault"; |
| 43 | +const std::string AICPU_NAME = "aicpu"; | ||
| 44 | +const std::string AICPU_DP_NAME = "dp"; | ||
| 45 | +const std::string AICPU_MI_NAME = "aicpu_mi"; | ||
| 43 | 46 | ||
| 44 | const std::string SUMMARY_SUFFIX = ".csv"; | 47 | const std::string SUMMARY_SUFFIX = ".csv"; |
| 45 | const std::string SLICE = "slice"; | 48 | const std::string SLICE = "slice"; |
| @@ -16,6 +16,9 @@ | |||
| 16 | 16 | ||
| 17 | 17 | ||
| 18 | 18 | ||
| 19 | + | ||
| 20 | + | ||
| 21 | + | ||
| 19 | 22 | ||
| 20 | 23 | ||
| 21 | 24 | ||
| @@ -53,6 +56,8 @@ std::unordered_map<std::string, AssemblerCreator> SummaryFactory::assemblerTable | |||
| 53 | { MAKE_SHARED0_NO_OPERATION(assembler, OpStatisticAssembler, PROCESSOR_NAME_OP_STATISTIC, profPath); }}, | 56 | { MAKE_SHARED0_NO_OPERATION(assembler, OpStatisticAssembler, PROCESSOR_NAME_OP_STATISTIC, profPath); }}, |
| 54 | {PROCESSOR_NAME_PAGE_FAULT, [](const std::string& profPath, std::shared_ptr<SummaryAssembler>& assembler) | 57 | {PROCESSOR_NAME_PAGE_FAULT, [](const std::string& profPath, std::shared_ptr<SummaryAssembler>& assembler) |
| 55 | { MAKE_SHARED0_NO_OPERATION(assembler, PageFaultAssembler, PROCESSOR_NAME_PAGE_FAULT, profPath); }}, | 58 | { MAKE_SHARED0_NO_OPERATION(assembler, PageFaultAssembler, PROCESSOR_NAME_PAGE_FAULT, profPath); }}, |
| 59 | + {PROCESSOR_NAME_AICPU, [](const std::string& profPath, std::shared_ptr<SummaryAssembler>& assembler) | ||
| 60 | + { MAKE_SHARED0_NO_OPERATION(assembler, AicpuAssembler, PROCESSOR_NAME_AICPU, profPath); }}, | ||
| 56 | }; | 61 | }; |
| 57 | 62 | ||
| 58 | std::shared_ptr<SummaryAssembler> SummaryFactory::GetAssemblerByName(const std::string& processName, | 63 | std::shared_ptr<SummaryAssembler> SummaryFactory::GetAssemblerByName(const std::string& processName, |
| @@ -30,11 +30,11 @@ namespace Application | |||
| 30 | { | 30 | { |
| 31 | namespace | 31 | namespace |
| 32 | { | 32 | { |
| 33 | -const std::vector<std::string> DATA_ASSEMBLE_LIST{PROCESSOR_OP_SUMMARY, PROCESSOR_NAME_COMM_STATISTIC, | 33 | +const std::vector<std::string> DATA_ASSEMBLE_LIST{ |
| 34 | - PROCESSOR_NAME_OP_STATISTIC, PROCESSOR_NAME_NPU_MEM, | 34 | + PROCESSOR_OP_SUMMARY, PROCESSOR_NAME_COMM_STATISTIC, PROCESSOR_NAME_OP_STATISTIC, |
| 35 | - PROCESSOR_NAME_NPU_MODULE_MEM, PROCESSOR_NAME_API, | 35 | + PROCESSOR_NAME_NPU_MEM, PROCESSOR_NAME_NPU_MODULE_MEM, PROCESSOR_NAME_API, |
| 36 | - PROCESSOR_NAME_FUSION_OP, PROCESSOR_TASK_TIME_SUMMARY, | 36 | + PROCESSOR_NAME_FUSION_OP, PROCESSOR_TASK_TIME_SUMMARY, PROCESSOR_NAME_STEP_TRACE, |
| 37 | - PROCESSOR_NAME_STEP_TRACE, PROCESSOR_NAME_PAGE_FAULT}; | 37 | + PROCESSOR_NAME_PAGE_FAULT, PROCESSOR_NAME_AICPU}; |
| 38 | 38 | ||
| 39 | const std::unordered_map<std::string, std::string> SUMMARY_DELIVERABLES{ | 39 | const std::unordered_map<std::string, std::string> SUMMARY_DELIVERABLES{ |
| 40 | {"op_summary", PROCESSOR_OP_SUMMARY}, | 40 | {"op_summary", PROCESSOR_OP_SUMMARY}, |
| @@ -47,6 +47,9 @@ const std::unordered_map<std::string, std::string> SUMMARY_DELIVERABLES{ | |||
| 47 | {"task_time", PROCESSOR_TASK_TIME_SUMMARY}, | 47 | {"task_time", PROCESSOR_TASK_TIME_SUMMARY}, |
| 48 | {"step_trace", PROCESSOR_NAME_STEP_TRACE}, | 48 | {"step_trace", PROCESSOR_NAME_STEP_TRACE}, |
| 49 | {"page_fault", PROCESSOR_NAME_PAGE_FAULT}, | 49 | {"page_fault", PROCESSOR_NAME_PAGE_FAULT}, |
| 50 | + {"aicpu", PROCESSOR_NAME_AICPU}, | ||
| 51 | + {"dp", PROCESSOR_NAME_AICPU}, | ||
| 52 | + {"aicpu_mi", PROCESSOR_NAME_AICPU}, | ||
| 50 | }; | 53 | }; |
| 51 | 54 | ||
| 52 | } // namespace | 55 | } // namespace |
| @@ -19,6 +19,7 @@ | |||
| 19 | 19 | ||
| 20 | 20 | ||
| 21 | 21 | ||
| 22 | + | ||
| 22 | 23 | ||
| 23 | 24 | ||
| 24 | 25 | ||
| @@ -69,6 +70,11 @@ REGISTER_SIMPLE_SUMMARY_NODE(PROCESSOR_NAME_NPU_MODULE_MEM, std::vector<NpuModul | |||
| 69 | REGISTER_SIMPLE_SUMMARY_NODE(PROCESSOR_NAME_API, std::vector<ApiData>, PROCESSOR_NAME_API); | 70 | REGISTER_SIMPLE_SUMMARY_NODE(PROCESSOR_NAME_API, std::vector<ApiData>, PROCESSOR_NAME_API); |
| 70 | REGISTER_SIMPLE_SUMMARY_NODE(PROCESSOR_NAME_STEP_TRACE, std::vector<TrainTraceData>, PROCESSOR_NAME_STEP_TRACE); | 71 | REGISTER_SIMPLE_SUMMARY_NODE(PROCESSOR_NAME_STEP_TRACE, std::vector<TrainTraceData>, PROCESSOR_NAME_STEP_TRACE); |
| 71 | REGISTER_SIMPLE_SUMMARY_NODE(PROCESSOR_NAME_PAGE_FAULT, std::vector<PageFaultData>, PROCESSOR_NAME_PAGE_FAULT); | 72 | REGISTER_SIMPLE_SUMMARY_NODE(PROCESSOR_NAME_PAGE_FAULT, std::vector<PageFaultData>, PROCESSOR_NAME_PAGE_FAULT); |
| 73 | +REGISTER_TOPO_NODE_SEQUENCE(typeid(void), TOPO_NODE(SUMMARY_GENERATION, PROCESSOR_NAME_AICPU), true, | ||
| 74 | + SummaryManager::CreateSummaryAssembler(PROCESSOR_NAME_AICPU), | ||
| 75 | + TOPO_DEPS(TOPO_NODE(DATA_PROCESSING, PROCESSOR_NAME_AICPU)), nullptr); | ||
| 76 | +REGISTER_TOPO_NODE_DEPENDENT_DATA(TOPO_NODE(SUMMARY_GENERATION, PROCESSOR_NAME_AICPU), std::vector<AicpuSummaryData>, | ||
| 77 | + std::vector<AicpuDpData>, std::vector<AicpuMiData>); | ||
| 72 | 78 | ||
| 73 | REGISTER_TOPO_NODE_SEQUENCE(typeid(void), TOPO_NODE(SUMMARY_GENERATION, PROCESSOR_NAME_FUSION_OP), true, | 79 | REGISTER_TOPO_NODE_SEQUENCE(typeid(void), TOPO_NODE(SUMMARY_GENERATION, PROCESSOR_NAME_FUSION_OP), true, |
| 74 | SummaryManager::CreateSummaryAssembler(PROCESSOR_NAME_FUSION_OP), | 80 | SummaryManager::CreateSummaryAssembler(PROCESSOR_NAME_FUSION_OP), |
| @@ -0,0 +1,329 @@ | |||
| 1 | +/* ------------------------------------------------------------------------- | ||
| 2 | + * Copyright (c) 2026 Huawei Technologies Co., Ltd. | ||
| 3 | + * This file is part of the MindStudio project. | ||
| 4 | + * | ||
| 5 | + * MindStudio is licensed under Mulan PSL v2. | ||
| 6 | + * You can use this software according to the terms and conditions of the Mulan PSL v2. | ||
| 7 | + * You may obtain a copy of Mulan PSL v2 at: | ||
| 8 | + * | ||
| 9 | + * http://license.coscl.org.cn/MulanPSL2 | ||
| 10 | + * | ||
| 11 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, | ||
| 12 | + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, | ||
| 13 | + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. | ||
| 14 | + * See the Mulan PSL v2 for more details. | ||
| 15 | + * -------------------------------------------------------------------------*/ | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | + | ||
| 20 | + | ||
| 21 | + | ||
| 22 | + | ||
| 23 | + | ||
| 24 | + | ||
| 25 | + | ||
| 26 | + | ||
| 27 | + | ||
| 28 | + | ||
| 29 | +namespace Analysis | ||
| 30 | +{ | ||
| 31 | +namespace Domain | ||
| 32 | +{ | ||
| 33 | +using namespace Analysis::Domain::Environment; | ||
| 34 | +using namespace Analysis::Utils; | ||
| 35 | +using namespace Analysis::Common; | ||
| 36 | + | ||
| 37 | +namespace | ||
| 38 | +{ | ||
| 39 | +using StreamTaskKey = std::tuple<uint16_t, uint32_t, uint32_t>; | ||
| 40 | +using GeKey = std::tuple<uint16_t, uint32_t, uint32_t, uint32_t>; | ||
| 41 | + | ||
| 42 | +// AiCpuData / AiCpuDP 落盘为 ns,对齐 Python aicpuViewer:CSV 为 us | ||
| 43 | +double NsToUs(double timeNs) { return timeNs / static_cast<double>(NS_TO_US); } | ||
| 44 | +} // namespace | ||
| 45 | + | ||
| 46 | +AicpuProcessor::AicpuProcessor(const std::string &profPath) : DataProcessor(profPath) {} | ||
| 47 | + | ||
| 48 | +bool AicpuProcessor::Process(DataInventory &dataInventory) | ||
| 49 | +{ | ||
| 50 | + bool flag = true; | ||
| 51 | + std::vector<AicpuSummaryData> summaryData; | ||
| 52 | + std::vector<AicpuDpData> dpData; | ||
| 53 | + std::vector<AicpuMiData> miData; | ||
| 54 | + auto deviceList = Utils::File::GetFilesWithPrefix(profPath_, DEVICE_PREFIX); | ||
| 55 | + for (const auto &devicePath : deviceList) | ||
| 56 | + { | ||
| 57 | + flag = ProcessSingleDevice(devicePath, summaryData, dpData, miData) && flag; | ||
| 58 | + } | ||
| 59 | + | ||
| 60 | + auto ascendTasks = dataInventory.GetPtr<std::vector<AscendTaskData>>(); | ||
| 61 | + auto taskInfos = dataInventory.GetPtr<std::vector<TaskInfoData>>(); | ||
| 62 | + auto version = Context::GetInstance().GetPlatformVersion(); | ||
| 63 | + const bool isChipV6 = Context::IsChipV6(version); | ||
| 64 | + if (!isChipV6 && ascendTasks != nullptr) | ||
| 65 | + { | ||
| 66 | + MatchBatchId(summaryData, *ascendTasks); | ||
| 67 | + } | ||
| 68 | + if (taskInfos != nullptr) | ||
| 69 | + { | ||
| 70 | + MatchNodeName(summaryData, *taskInfos, isChipV6); | ||
| 71 | + } | ||
| 72 | + std::stable_sort(summaryData.begin(), summaryData.end(), | ||
| 73 | + [](const AicpuSummaryData &lhs, const AicpuSummaryData &rhs) | ||
| 74 | + { return lhs.timestampNs < rhs.timestampNs; }); | ||
| 75 | + | ||
| 76 | + flag = SaveToDataInventory<AicpuSummaryData>(std::move(summaryData), dataInventory, PROCESSOR_NAME_AICPU) && flag; | ||
| 77 | + flag = SaveToDataInventory<AicpuDpData>(std::move(dpData), dataInventory, PROCESSOR_NAME_AICPU) && flag; | ||
| 78 | + flag = SaveToDataInventory<AicpuMiData>(std::move(miData), dataInventory, PROCESSOR_NAME_AICPU) && flag; | ||
| 79 | + return flag; | ||
| 80 | +} | ||
| 81 | + | ||
| 82 | +bool AicpuProcessor::ProcessSingleDevice(const std::string &devicePath, std::vector<AicpuSummaryData> &summaryData, | ||
| 83 | + std::vector<AicpuDpData> &dpData, std::vector<AicpuMiData> &miData) | ||
| 84 | +{ | ||
| 85 | + uint16_t deviceId = GetDeviceIdByDevicePath(devicePath); | ||
| 86 | + if (deviceId == INVALID_DEVICE_ID) | ||
| 87 | + { | ||
| 88 | + ERROR("the invalid deviceId cannot to be identified."); | ||
| 89 | + return false; | ||
| 90 | + } | ||
| 91 | + ProfTimeRecord timeRecord; | ||
| 92 | + if (!Context::GetInstance().GetProfTimeRecordInfo(timeRecord, profPath_, deviceId)) | ||
| 93 | + { | ||
| 94 | + ERROR("GetProfTimeRecordInfo failed, profPath is %.", profPath_); | ||
| 95 | + return false; | ||
| 96 | + } | ||
| 97 | + bool flag = LoadAiCpuData(devicePath, deviceId, timeRecord, summaryData); | ||
| 98 | + flag = LoadDpData(devicePath, timeRecord, dpData) && flag; | ||
| 99 | + flag = LoadMiData(devicePath, miData) && flag; | ||
| 100 | + return flag; | ||
| 101 | +} | ||
| 102 | + | ||
| 103 | +bool AicpuProcessor::LoadAiCpuData(const std::string &devicePath, uint16_t deviceId, const ProfTimeRecord &timeRecord, | ||
| 104 | + std::vector<AicpuSummaryData> &summaryData) | ||
| 105 | +{ | ||
| 106 | + DBInfo aicpuDB(DB_NAME_AI_CPU, TABLE_NAME_AI_CPU); | ||
| 107 | + std::string dbPath = Utils::File::PathJoin({devicePath, SQLITE, aicpuDB.dbName}); | ||
| 108 | + if (!aicpuDB.ConstructDBRunner(dbPath) || aicpuDB.dbRunner == nullptr) | ||
| 109 | + { | ||
| 110 | + ERROR("Create % connection failed.", dbPath); | ||
| 111 | + return false; | ||
| 112 | + } | ||
| 113 | + auto status = CheckPathAndTable(dbPath, aicpuDB, false); | ||
| 114 | + if (status != CHECK_SUCCESS) | ||
| 115 | + { | ||
| 116 | + return status != CHECK_FAILED; | ||
| 117 | + } | ||
| 118 | + OriAiCpuData oriData; | ||
| 119 | + std::string sql{ | ||
| 120 | + "SELECT stream_id, task_id, sys_start, sys_end, node_name, compute_time, memcpy_time, task_time, " | ||
| 121 | + "dispatch_time, total_time FROM " + | ||
| 122 | + aicpuDB.tableName + " ORDER BY sys_start"}; | ||
| 123 | + if (!aicpuDB.dbRunner->QueryData(sql, oriData)) | ||
| 124 | + { | ||
| 125 | + ERROR("Failed to obtain data from the % table.", aicpuDB.tableName); | ||
| 126 | + return false; | ||
| 127 | + } | ||
| 128 | + for (const auto &row : oriData) | ||
| 129 | + { | ||
| 130 | + AicpuSummaryData data; | ||
| 131 | + double sysStart = 0; | ||
| 132 | + double sysEnd = 0; | ||
| 133 | + double computeTime = 0; | ||
| 134 | + double memcpyTime = 0; | ||
| 135 | + double taskTime = 0; | ||
| 136 | + double dispatchTime = 0; | ||
| 137 | + double totalTime = 0; | ||
| 138 | + std::tie(data.streamId, data.taskId, sysStart, sysEnd, data.nodeName, computeTime, memcpyTime, taskTime, | ||
| 139 | + dispatchTime, totalTime) = row; | ||
| 140 | + data.deviceId = deviceId; | ||
| 141 | + HPFloat start{sysStart}; | ||
| 142 | + HPFloat end{sysEnd}; | ||
| 143 | + data.timestampNs = GetLocalTime(start, timeRecord).Uint64(); | ||
| 144 | + data.endNs = GetLocalTime(end, timeRecord).Uint64(); | ||
| 145 | + if (data.timestampNs < timeRecord.startTimeNs) | ||
| 146 | + { | ||
| 147 | + continue; | ||
| 148 | + } | ||
| 149 | + data.nodeName = data.nodeName.empty() ? NA : data.nodeName; | ||
| 150 | + data.computeTimeUs = NsToUs(computeTime); | ||
| 151 | + data.memcpyTimeUs = NsToUs(memcpyTime); | ||
| 152 | + data.taskTimeUs = NsToUs(taskTime); | ||
| 153 | + data.dispatchTimeUs = NsToUs(dispatchTime); | ||
| 154 | + data.totalTimeUs = NsToUs(totalTime); | ||
| 155 | + summaryData.push_back(data); | ||
| 156 | + } | ||
| 157 | + return true; | ||
| 158 | +} | ||
| 159 | + | ||
| 160 | +bool AicpuProcessor::LoadDpData(const std::string &devicePath, const ProfTimeRecord &timeRecord, | ||
| 161 | + std::vector<AicpuDpData> &dpData) | ||
| 162 | +{ | ||
| 163 | + DBInfo dpDB(DB_NAME_AI_CPU, TABLE_NAME_AI_CPU_DP); | ||
| 164 | + std::string dbPath = Utils::File::PathJoin({devicePath, SQLITE, dpDB.dbName}); | ||
| 165 | + if (!dpDB.ConstructDBRunner(dbPath) || dpDB.dbRunner == nullptr) | ||
| 166 | + { | ||
| 167 | + ERROR("Create % connection failed.", dbPath); | ||
| 168 | + return false; | ||
| 169 | + } | ||
| 170 | + auto status = CheckPathAndTable(dbPath, dpDB, false); | ||
| 171 | + if (status != CHECK_SUCCESS) | ||
| 172 | + { | ||
| 173 | + return status != CHECK_FAILED; | ||
| 174 | + } | ||
| 175 | + OriAiCpuDpData oriData; | ||
| 176 | + std::string sql{"SELECT timestamp, action, source, buffer_size FROM " + dpDB.tableName + " ORDER BY timestamp"}; | ||
| 177 | + if (!dpDB.dbRunner->QueryData(sql, oriData)) | ||
| 178 | + { | ||
| 179 | + ERROR("Failed to obtain data from the % table.", dpDB.tableName); | ||
| 180 | + return false; | ||
| 181 | + } | ||
| 182 | + for (const auto &row : oriData) | ||
| 183 | + { | ||
| 184 | + AicpuDpData data; | ||
| 185 | + double rawTimestamp = 0; | ||
| 186 | + std::tie(rawTimestamp, data.action, data.source, data.bufferSize) = row; | ||
| 187 | + HPFloat timestamp{rawTimestamp}; | ||
| 188 | + data.timestamp = GetLocalTime(timestamp, timeRecord).Uint64(); | ||
| 189 | + dpData.push_back(data); | ||
| 190 | + } | ||
| 191 | + return true; | ||
| 192 | +} | ||
| 193 | + | ||
| 194 | +bool AicpuProcessor::LoadMiData(const std::string &devicePath, std::vector<AicpuMiData> &miData) | ||
| 195 | +{ | ||
| 196 | + DBInfo miDB(DB_NAME_DATA_PREPROCESS, TABLE_NAME_DATA_QUEUE); | ||
| 197 | + std::string dbPath = Utils::File::PathJoin({devicePath, SQLITE, miDB.dbName}); | ||
| 198 | + if (!miDB.ConstructDBRunner(dbPath) || miDB.dbRunner == nullptr) | ||
| 199 | + { | ||
| 200 | + ERROR("Create % connection failed.", dbPath); | ||
| 201 | + return false; | ||
| 202 | + } | ||
| 203 | + auto status = CheckPathAndTable(dbPath, miDB, false); | ||
| 204 | + if (status != CHECK_SUCCESS) | ||
| 205 | + { | ||
| 206 | + return status != CHECK_FAILED; | ||
| 207 | + } | ||
| 208 | + OriAiCpuMiData oriData; | ||
| 209 | + std::string sql{"SELECT node_name, start_time, end_time, queue_size FROM " + miDB.tableName + | ||
| 210 | + " ORDER BY start_time"}; | ||
| 211 | + if (!miDB.dbRunner->QueryData(sql, oriData)) | ||
| 212 | + { | ||
| 213 | + ERROR("Failed to obtain data from the % table.", miDB.tableName); | ||
| 214 | + return false; | ||
| 215 | + } | ||
| 216 | + for (const auto &row : oriData) | ||
| 217 | + { | ||
| 218 | + AicpuMiData data; | ||
| 219 | + double startTime = 0; | ||
| 220 | + double endTime = 0; | ||
| 221 | + std::tie(data.nodeName, startTime, endTime, data.queueSize) = row; | ||
| 222 | + data.startTime = static_cast<uint64_t>(startTime); | ||
严重程度: 提示 问题: 原因: 这与 Python parity 一致(Python 怎么改:
本 PR 不必处理;建议在后续 PR 中校准 MI 时间字段单位(要么在 ![]() ![]() | |||
| 223 | + data.endTime = static_cast<uint64_t>(endTime); | ||
| 224 | + miData.push_back(data); | ||
| 225 | + } | ||
| 226 | + return true; | ||
| 227 | +} | ||
| 228 | + | ||
| 229 | +void AicpuProcessor::MatchBatchId(std::vector<AicpuSummaryData> &summaryData, | ||
| 230 | + const std::vector<AscendTaskData> &ascendTasks) | ||
| 231 | +{ | ||
| 232 | + std::map<StreamTaskKey, std::vector<const AscendTaskData *>> taskMap; | ||
| 233 | + for (const auto &task : ascendTasks) | ||
| 234 | + { | ||
| 235 | + if (task.hostType != KERNEL_AICPU_TASK_TYPE) | ||
| 236 | + { | ||
| 237 | + continue; | ||
| 238 | + } | ||
| 239 | + taskMap[{task.deviceId, task.streamId, task.taskId}].push_back(&task); | ||
| 240 | + } | ||
| 241 | + for (auto &entry : taskMap) | ||
| 242 | + { | ||
| 243 | + std::sort(entry.second.begin(), entry.second.end(), | ||
| 244 | + [](const AscendTaskData *lhs, const AscendTaskData *rhs) { return lhs->timestamp < rhs->timestamp; }); | ||
| 245 | + } | ||
| 246 | + | ||
| 247 | + std::map<StreamTaskKey, std::vector<AicpuSummaryData *>> aicpuMap; | ||
| 248 | + for (auto &item : summaryData) | ||
| 249 | + { | ||
| 250 | + aicpuMap[{item.deviceId, item.streamId, item.taskId}].push_back(&item); | ||
严重程度: 提示 问题: 原因: 当前单设备场景下安全(SQL 已排序,单设备同 (stream, task) 组合内顺序稳定);但若未来 怎么改:
建议对
![]() ![]() | |||
| 251 | + } | ||
| 252 | + for (auto &entry : aicpuMap) | ||
| 253 | + { | ||
| 254 | + std::sort(entry.second.begin(), entry.second.end(), | ||
| 255 | + [](const AicpuSummaryData *lhs, const AicpuSummaryData *rhs) { return lhs->endNs < rhs->endNs; }); | ||
| 256 | + } | ||
| 257 | + | ||
| 258 | + for (auto &entry : aicpuMap) | ||
| 259 | + { | ||
| 260 | + auto taskIt = taskMap.find(entry.first); | ||
| 261 | + if (taskIt == taskMap.end()) | ||
| 262 | + { | ||
| 263 | + continue; | ||
| 264 | + } | ||
| 265 | + auto &aicpuList = entry.second; | ||
| 266 | + auto &taskList = taskIt->second; | ||
| 267 | + size_t aicpuIndex = 0; | ||
| 268 | + size_t taskIndex = 0; | ||
| 269 | + while (aicpuIndex < aicpuList.size() && taskIndex < taskList.size()) | ||
| 270 | + { | ||
| 271 | + const uint64_t sysEndNs = aicpuList[aicpuIndex]->endNs; | ||
| 272 | + const auto *task = taskList[taskIndex]; | ||
| 273 | + if (task->timestamp <= sysEndNs && sysEndNs <= task->end) | ||
| 274 | + { | ||
| 275 | + aicpuList[aicpuIndex]->batchId = task->batchId; | ||
| 276 | + ++aicpuIndex; | ||
| 277 | + } | ||
| 278 | + else if (sysEndNs < task->timestamp) | ||
| 279 | + { | ||
| 280 | + ++aicpuIndex; | ||
| 281 | + } | ||
| 282 | + else | ||
| 283 | + { | ||
| 284 | + ++taskIndex; | ||
| 285 | + } | ||
| 286 | + } | ||
| 287 | + } | ||
| 288 | +} | ||
| 289 | + | ||
| 290 | +void AicpuProcessor::MatchNodeName(std::vector<AicpuSummaryData> &summaryData, | ||
| 291 | + const std::vector<TaskInfoData> &taskInfos, bool isChipV6) | ||
| 292 | +{ | ||
| 293 | + std::map<GeKey, std::string> geMap; | ||
| 294 | + std::map<StreamTaskKey, std::string> geMapV6; | ||
| 295 | + for (const auto &info : taskInfos) | ||
| 296 | + { | ||
| 297 | + if (!isChipV6 && info.taskType != AI_CPU) | ||
| 298 | + { | ||
| 299 | + continue; | ||
| 300 | + } | ||
| 301 | + if (isChipV6) | ||
| 302 | + { | ||
| 303 | + geMapV6.emplace(StreamTaskKey{info.deviceId, info.streamId, info.taskId}, info.opName); | ||
| 304 | + } | ||
| 305 | + else | ||
| 306 | + { | ||
| 307 | + geMap.emplace(GeKey{info.deviceId, info.streamId, info.taskId, info.batchId}, info.opName); | ||
| 308 | + } | ||
| 309 | + } | ||
| 310 | + for (auto &item : summaryData) | ||
| 311 | + { | ||
| 312 | + if (isChipV6) | ||
| 313 | + { | ||
| 314 | + auto it = geMapV6.find({item.deviceId, item.streamId, item.taskId}); | ||
| 315 | + if (it != geMapV6.end()) | ||
| 316 | + { | ||
| 317 | + item.nodeName = it->second; | ||
| 318 | + } | ||
| 319 | + continue; | ||
| 320 | + } | ||
| 321 | + auto it = geMap.find({item.deviceId, item.streamId, item.taskId, item.batchId}); | ||
严重程度: 提示 问题: 原因: C++ 写法更精确(避免多设备同 (stream, task, batch) 串扰),且 怎么改:
无需修改;如希望与 Python 完全对齐,可改 key 为 ![]() ![]() | |||
| 322 | + if (it != geMap.end()) | ||
| 323 | + { | ||
| 324 | + item.nodeName = it->second; | ||
| 325 | + } | ||
| 326 | + } | ||
| 327 | +} | ||
| 328 | +} // namespace Domain | ||
| 329 | +} // namespace Analysis | ||
| @@ -0,0 +1,62 @@ | |||
| 1 | +/* ------------------------------------------------------------------------- | ||
| 2 | + * Copyright (c) 2026 Huawei Technologies Co., Ltd. | ||
| 3 | + * This file is part of the MindStudio project. | ||
| 4 | + * | ||
| 5 | + * MindStudio is licensed under Mulan PSL v2. | ||
| 6 | + * You can use this software according to the terms and conditions of the Mulan PSL v2. | ||
| 7 | + * You may obtain a copy of Mulan PSL v2 at: | ||
| 8 | + * | ||
| 9 | + * http://license.coscl.org.cn/MulanPSL2 | ||
| 10 | + * | ||
| 11 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, | ||
| 12 | + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, | ||
| 13 | + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. | ||
| 14 | + * See the Mulan PSL v2 for more details. | ||
| 15 | + * -------------------------------------------------------------------------*/ | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | + | ||
| 20 | + | ||
| 21 | + | ||
| 22 | + | ||
| 23 | + | ||
| 24 | + | ||
| 25 | + | ||
| 26 | + | ||
| 27 | + | ||
| 28 | + | ||
| 29 | + | ||
| 30 | + | ||
| 31 | +namespace Analysis | ||
| 32 | +{ | ||
| 33 | +namespace Domain | ||
| 34 | +{ | ||
| 35 | +using OriAiCpuData = | ||
| 36 | + std::vector<std::tuple<uint32_t, uint32_t, double, double, std::string, double, double, double, double, double>>; | ||
| 37 | +using OriAiCpuDpData = std::vector<std::tuple<double, std::string, std::string, uint64_t>>; | ||
| 38 | +using OriAiCpuMiData = std::vector<std::tuple<std::string, double, double, uint64_t>>; | ||
| 39 | + | ||
| 40 | +class AicpuProcessor : public DataProcessor | ||
| 41 | +{ | ||
| 42 | + public: | ||
| 43 | + AicpuProcessor() = default; | ||
| 44 | + explicit AicpuProcessor(const std::string &profPath); | ||
| 45 | + | ||
| 46 | + private: | ||
| 47 | + bool Process(DataInventory &dataInventory) override; | ||
| 48 | + bool ProcessSingleDevice(const std::string &devicePath, std::vector<AicpuSummaryData> &summaryData, | ||
| 49 | + std::vector<AicpuDpData> &dpData, std::vector<AicpuMiData> &miData); | ||
| 50 | + bool LoadAiCpuData(const std::string &devicePath, uint16_t deviceId, const Utils::ProfTimeRecord &timeRecord, | ||
| 51 | + std::vector<AicpuSummaryData> &summaryData); | ||
| 52 | + bool LoadDpData(const std::string &devicePath, const Utils::ProfTimeRecord &timeRecord, | ||
| 53 | + std::vector<AicpuDpData> &dpData); | ||
| 54 | + bool LoadMiData(const std::string &devicePath, std::vector<AicpuMiData> &miData); | ||
| 55 | + void MatchBatchId(std::vector<AicpuSummaryData> &summaryData, const std::vector<AscendTaskData> &ascendTasks); | ||
| 56 | + void MatchNodeName(std::vector<AicpuSummaryData> &summaryData, const std::vector<TaskInfoData> &taskInfos, | ||
| 57 | + bool isChipV6); | ||
| 58 | +}; | ||
| 59 | +} // namespace Domain | ||
| 60 | +} // namespace Analysis | ||
| 61 | + | ||
| 62 | + | ||
| @@ -15,6 +15,7 @@ | |||
| 15 | * -------------------------------------------------------------------------*/ | 15 | * -------------------------------------------------------------------------*/ |
| 16 | 16 | ||
| 17 | 17 | ||
| 18 | + | ||
| 18 | 19 | ||
| 19 | 20 | ||
| 20 | 21 | ||
| @@ -110,6 +111,10 @@ REGISTER_PROCESSOR(PCIeProcessor, PROCESSOR_NAME_PCIE, TOPO_DEPS()); | |||
| 110 | REGISTER_PROCESSOR(SioProcessor, PROCESSOR_NAME_SIO, TOPO_DEPS()); | 111 | REGISTER_PROCESSOR(SioProcessor, PROCESSOR_NAME_SIO, TOPO_DEPS()); |
| 111 | REGISTER_PROCESSOR(SocBandwidthProcessor, PROCESSOR_NAME_SOC, TOPO_DEPS()); | 112 | REGISTER_PROCESSOR(SocBandwidthProcessor, PROCESSOR_NAME_SOC, TOPO_DEPS()); |
| 112 | REGISTER_PROCESSOR(PageFaultProcessor, PROCESSOR_NAME_PAGE_FAULT, TOPO_DEPS()); | 113 | REGISTER_PROCESSOR(PageFaultProcessor, PROCESSOR_NAME_PAGE_FAULT, TOPO_DEPS()); |
| 114 | +REGISTER_PROCESSOR_WITH_DATA(AicpuProcessor, PROCESSOR_NAME_AICPU, | ||
| 115 | + TOPO_DEPS(TOPO_NODE(DATA_PROCESSING, PROCESSOR_NAME_TASK), | ||
| 116 | + TOPO_NODE(DATA_PROCESSING, PROCESSOR_NAME_COMPUTE_TASK_INFO)), | ||
| 117 | + std::vector<AscendTaskData>, std::vector<TaskInfoData>); | ||
| 113 | REGISTER_PROCESSOR(NicTimelineProcessor, PROCESSOR_NAME_NIC_TIMELINE, TOPO_DEPS()); | 118 | REGISTER_PROCESSOR(NicTimelineProcessor, PROCESSOR_NAME_NIC_TIMELINE, TOPO_DEPS()); |
| 114 | REGISTER_PROCESSOR(RoCETimelineProcessor, PROCESSOR_NAME_ROCE_TIMELINE, TOPO_DEPS()); | 119 | REGISTER_PROCESSOR(RoCETimelineProcessor, PROCESSOR_NAME_ROCE_TIMELINE, TOPO_DEPS()); |
| 115 | REGISTER_PROCESSOR(NicProcessor, PROCESSOR_NAME_NIC, TOPO_DEPS()); | 120 | REGISTER_PROCESSOR(NicProcessor, PROCESSOR_NAME_NIC, TOPO_DEPS()); |
| @@ -0,0 +1,61 @@ | |||
| 1 | +/* ------------------------------------------------------------------------- | ||
| 2 | + * Copyright (c) 2026 Huawei Technologies Co., Ltd. | ||
| 3 | + * This file is part of the MindStudio project. | ||
| 4 | + * | ||
| 5 | + * MindStudio is licensed under Mulan PSL v2. | ||
| 6 | + * You can use this software according to the terms and conditions of the Mulan PSL v2. | ||
| 7 | + * You may obtain a copy of Mulan PSL v2 at: | ||
| 8 | + * | ||
| 9 | + * http://license.coscl.org.cn/MulanPSL2 | ||
| 10 | + * | ||
| 11 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, | ||
| 12 | + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, | ||
| 13 | + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. | ||
| 14 | + * See the Mulan PSL v2 for more details. | ||
| 15 | + * -------------------------------------------------------------------------*/ | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | + | ||
| 20 | + | ||
| 21 | + | ||
| 22 | + | ||
| 23 | +namespace Analysis | ||
| 24 | +{ | ||
| 25 | +namespace Domain | ||
| 26 | +{ | ||
| 27 | +struct AicpuSummaryData | ||
| 28 | +{ | ||
| 29 | + uint16_t deviceId = UINT16_MAX; | ||
| 30 | + uint64_t timestampNs = UINT64_MAX; | ||
| 31 | + uint64_t endNs = UINT64_MAX; | ||
| 32 | + std::string nodeName; | ||
| 33 | + double computeTimeUs = 0; | ||
| 34 | + double memcpyTimeUs = 0; | ||
| 35 | + double taskTimeUs = 0; | ||
| 36 | + double dispatchTimeUs = 0; | ||
| 37 | + double totalTimeUs = 0; | ||
| 38 | + uint32_t streamId = UINT32_MAX; | ||
| 39 | + uint32_t taskId = UINT32_MAX; | ||
| 40 | + uint32_t batchId = UINT32_MAX; | ||
| 41 | +}; | ||
| 42 | + | ||
| 43 | +struct AicpuDpData | ||
| 44 | +{ | ||
| 45 | + uint64_t timestamp = 0; | ||
| 46 | + std::string action; | ||
| 47 | + std::string source; | ||
| 48 | + uint64_t bufferSize = 0; | ||
| 49 | +}; | ||
| 50 | + | ||
| 51 | +struct AicpuMiData | ||
| 52 | +{ | ||
| 53 | + std::string nodeName; | ||
| 54 | + uint64_t startTime = 0; | ||
| 55 | + uint64_t endTime = 0; | ||
| 56 | + uint64_t queueSize = 0; | ||
| 57 | +}; | ||
| 58 | +} // namespace Domain | ||
| 59 | +} // namespace Analysis | ||
| 60 | + | ||
| 61 | + | ||
| @@ -19,6 +19,7 @@ | |||
| 19 | 19 | ||
| 20 | 20 | ||
| 21 | 21 | ||
| 22 | + | ||
| 22 | 23 | ||
| 23 | 24 | ||
| 24 | 25 | ||
| @@ -34,6 +35,7 @@ namespace Analysis | |||
| 34 | namespace Domain | 35 | namespace Domain |
| 35 | { | 36 | { |
| 36 | using namespace Utils; | 37 | using namespace Utils; |
| 38 | +using namespace Analysis::Application; | ||
| 37 | namespace | 39 | namespace |
| 38 | { | 40 | { |
| 39 | static const std::string MI_NAME = "GetNext_dequeue_wait"; | 41 | static const std::string MI_NAME = "GetNext_dequeue_wait"; |
| @@ -120,7 +122,7 @@ uint32_t AicpuPersistence::GenerateAndSaveNode(const std::string& deviceFilePath | |||
| 120 | total_time.Double()); | 122 | total_time.Double()); |
| 121 | } | 123 | } |
| 122 | 124 | ||
| 123 | - DBInfo dbInfo("ai_cpu.db", "AiCpuData"); | 125 | + DBInfo dbInfo(DB_NAME_AI_CPU, TABLE_NAME_AI_CPU); |
| 124 | MAKE_SHARED0_RETURN_VALUE(dbInfo.database, AicpuDB, ANALYSIS_ERROR); | 126 | MAKE_SHARED0_RETURN_VALUE(dbInfo.database, AicpuDB, ANALYSIS_ERROR); |
| 125 | std::string dbPath = Utils::File::PathJoin({deviceFilePath, SQLITE, dbInfo.dbName}); | 127 | std::string dbPath = Utils::File::PathJoin({deviceFilePath, SQLITE, dbInfo.dbName}); |
| 126 | INFO("Start to process %.", dbPath); | 128 | INFO("Start to process %.", dbPath); |
| @@ -151,7 +153,7 @@ uint32_t AicpuPersistence::GenerateAndSaveDp(const std::string& deviceFilePath) | |||
| 151 | data.emplace_back(timeStamp.Double(), std::string(dp.dp.action), std::string(dp.dp.source), dp.dp.size); | 153 | data.emplace_back(timeStamp.Double(), std::string(dp.dp.action), std::string(dp.dp.source), dp.dp.size); |
| 152 | } | 154 | } |
| 153 | 155 | ||
| 154 | - DBInfo dbInfo("ai_cpu.db", "AiCpuDP"); | 156 | + DBInfo dbInfo(DB_NAME_AI_CPU, TABLE_NAME_AI_CPU_DP); |
| 155 | MAKE_SHARED0_RETURN_VALUE(dbInfo.database, AicpuDB, ANALYSIS_ERROR); | 157 | MAKE_SHARED0_RETURN_VALUE(dbInfo.database, AicpuDB, ANALYSIS_ERROR); |
| 156 | std::string dbPath = Utils::File::PathJoin({deviceFilePath, SQLITE, dbInfo.dbName}); | 158 | std::string dbPath = Utils::File::PathJoin({deviceFilePath, SQLITE, dbInfo.dbName}); |
| 157 | INFO("Start to process %.", dbPath); | 159 | INFO("Start to process %.", dbPath); |
| @@ -213,7 +215,7 @@ uint32_t AicpuPersistence::GenerateAndSaveMi(const std::string& deviceFilePath) | |||
| 213 | mi.mi.runEndTime, mi.mi.runEndTime - mi.mi.runStartTime); | 215 | mi.mi.runEndTime, mi.mi.runEndTime - mi.mi.runStartTime); |
| 214 | } | 216 | } |
| 215 | 217 | ||
| 216 | - DBInfo dbInfo("data_preprocess.db", "DataQueue"); | 218 | + DBInfo dbInfo(DB_NAME_DATA_PREPROCESS, TABLE_NAME_DATA_QUEUE); |
| 217 | MAKE_SHARED0_RETURN_VALUE(dbInfo.database, DataPreprocessDB, ANALYSIS_ERROR); | 219 | MAKE_SHARED0_RETURN_VALUE(dbInfo.database, DataPreprocessDB, ANALYSIS_ERROR); |
| 218 | std::string dbPath = Utils::File::PathJoin({deviceFilePath, SQLITE, dbInfo.dbName}); | 220 | std::string dbPath = Utils::File::PathJoin({deviceFilePath, SQLITE, dbInfo.dbName}); |
| 219 | MAKE_SHARED_RETURN_VALUE(dbInfo.dbRunner, DBRunner, ANALYSIS_ERROR, dbPath); | 221 | MAKE_SHARED_RETURN_VALUE(dbInfo.dbRunner, DBRunner, ANALYSIS_ERROR, dbPath); |
| @@ -117,6 +117,8 @@ class ParseDpData: | |||
| 117 | with AiCpuModel(os.path.dirname(dp_path)) as model: | 117 | with AiCpuModel(os.path.dirname(dp_path)) as model: |
| 118 | data = model.get_all_data(DBNameConstant.TABLE_AI_CPU_DP) | 118 | data = model.get_all_data(DBNameConstant.TABLE_AI_CPU_DP) |
| 119 | # 表内 timestamp 为 ns(Python/C++ 落盘对齐),CSV 头为 Timestamp(us) | 119 | # 表内 timestamp 为 ns(Python/C++ 落盘对齐),CSV 头为 Timestamp(us) |
| 120 | + # 与 C++ LoadDpData 的 ORDER BY timestamp 对齐,保证 dp.csv 行序可重现 | ||
| 121 | + data.sort(key=lambda row: row[0]) | ||
| 120 | return [ | 122 | return [ |
| 121 | ( | 123 | ( |
| 122 | float(InfoConfReader().trans_into_local_time(float(row[0]))), | 124 | float(InfoConfReader().trans_into_local_time(float(row[0]))), |
| @@ -195,7 +195,9 @@ class ParseAiCpuData: | |||
| 195 | if not conn or not curs: | 195 | if not conn or not curs: |
| 196 | logging.warning("Can't connect %s", DBNameConstant.DB_CLUSTER_DATA_PREPROCESS) | 196 | logging.warning("Can't connect %s", DBNameConstant.DB_CLUSTER_DATA_PREPROCESS) |
| 197 | return [] | 197 | return [] |
| 198 | - sql = "select node_name, start_time, end_time, queue_size from {0}".format(DBNameConstant.TABLE_DATA_QUEUE) | 198 | + sql = "select node_name, start_time, end_time, queue_size from {0} order by start_time".format( |
| 199 | + DBNameConstant.TABLE_DATA_QUEUE | ||
| 200 | + ) | ||
| 199 | aicpu_mi_data = DBManager.fetch_all_data(conn.cursor(), sql) | 201 | aicpu_mi_data = DBManager.fetch_all_data(conn.cursor(), sql) |
| 200 | DBManager.destroy_db_connect(conn, curs) | 202 | DBManager.destroy_db_connect(conn, curs) |
| 201 | return aicpu_mi_data | 203 | return aicpu_mi_data |
| @@ -0,0 +1,279 @@ | |||
| 1 | +/* ------------------------------------------------------------------------- | ||
| 2 | + * Copyright (c) 2026 Huawei Technologies Co., Ltd. | ||
| 3 | + * This file is part of the MindStudio project. | ||
| 4 | + * | ||
| 5 | + * MindStudio is licensed under Mulan PSL v2. | ||
| 6 | + * You can use this software according to the terms and conditions of the Mulan PSL v2. | ||
| 7 | + * You may obtain a copy of Mulan PSL v2 at: | ||
| 8 | + * | ||
| 9 | + * http://license.coscl.org.cn/MulanPSL2 | ||
| 10 | + * | ||
| 11 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, | ||
| 12 | + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, | ||
| 13 | + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. | ||
| 14 | + * See the Mulan PSL v2 for more details. | ||
| 15 | + * -------------------------------------------------------------------------*/ | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | + | ||
| 20 | + | ||
| 21 | + | ||
| 22 | + | ||
| 23 | + | ||
| 24 | + | ||
| 25 | + | ||
| 26 | + | ||
| 27 | + | ||
| 28 | + | ||
| 29 | + | ||
| 30 | + | ||
| 31 | + | ||
| 32 | + | ||
| 33 | + | ||
| 34 | + | ||
| 35 | +using namespace Analysis::Application; | ||
| 36 | +using namespace Analysis::Domain; | ||
| 37 | +using namespace Analysis::Utils; | ||
| 38 | + | ||
| 39 | +namespace { | ||
| 40 | +const int DEPTH = 0; | ||
| 41 | +const std::string BASE_PATH = "./aicpu_assembler_utest"; | ||
| 42 | +const std::string PROF_PATH = File::PathJoin({BASE_PATH, "PROF_0"}); | ||
| 43 | +const std::string RESULT_PATH = File::PathJoin({PROF_PATH, Analysis::Common::OUTPUT_PATH}); | ||
| 44 | + | ||
| 45 | +const std::string AICPU_HEADER = | ||
| 46 | + "Timestamp(us),Node,Compute_time(us),Memcpy_time(us),Task_time(us),Dispatch_time(us),Total_time(us),Stream ID,Task " | ||
| 47 | + "ID"; | ||
| 48 | +const std::string DP_HEADER = "Timestamp(us),Action,Source,Cached Buffer Size"; | ||
| 49 | +const std::string MI_HEADER = "Node Name,Start Time(us),End Time(us),Queue Size"; | ||
| 50 | + | ||
| 51 | +std::string FindCsvByName(const std::string &name) | ||
| 52 | +{ | ||
| 53 | + const std::vector<std::string> files = File::GetOriginData(RESULT_PATH, {name}, {}); | ||
| 54 | + for (size_t i = 0; i < files.size(); ++i) { | ||
| 55 | + const std::string base = File::BaseName(files[i]); | ||
| 56 | + if (name == AICPU_NAME && base.find(AICPU_MI_NAME) == 0) { | ||
| 57 | + continue; | ||
| 58 | + } | ||
| 59 | + if (base.find(name) == 0) { | ||
| 60 | + return files[i]; | ||
| 61 | + } | ||
| 62 | + } | ||
| 63 | + return ""; | ||
| 64 | +} | ||
| 65 | + | ||
| 66 | +std::vector<std::string> ReadCsvLines(const std::string &filePath) | ||
| 67 | +{ | ||
| 68 | + FileReader reader(filePath); | ||
| 69 | + std::vector<std::string> lines; | ||
| 70 | + EXPECT_EQ(Analysis::ANALYSIS_OK, reader.ReadText(lines)); | ||
| 71 | + return lines; | ||
| 72 | +} | ||
| 73 | + | ||
| 74 | +template <typename T> | ||
| 75 | +void InjectVector(DataInventory &dataInventory, const std::vector<T> &data) | ||
| 76 | +{ | ||
| 77 | + std::shared_ptr<std::vector<T>> holder; | ||
| 78 | + MAKE_SHARED_NO_OPERATION(holder, std::vector<T>, data); | ||
| 79 | + dataInventory.Inject(holder); | ||
| 80 | +} | ||
| 81 | + | ||
| 82 | +std::vector<AicpuSummaryData> GenerateAicpuData() | ||
| 83 | +{ | ||
| 84 | + std::vector<AicpuSummaryData> res; | ||
| 85 | + AicpuSummaryData first; | ||
| 86 | + first.deviceId = 0; | ||
| 87 | + first.timestampNs = 1000000; | ||
| 88 | + first.nodeName = "Conv2D"; | ||
| 89 | + first.computeTimeUs = 1.5; | ||
| 90 | + first.memcpyTimeUs = 2.5; | ||
| 91 | + first.taskTimeUs = 500.0; | ||
| 92 | + first.dispatchTimeUs = 0.5; | ||
| 93 | + first.totalTimeUs = 10.5; | ||
| 94 | + first.streamId = 10; | ||
| 95 | + first.taskId = 20; | ||
| 96 | + res.push_back(first); | ||
| 97 | + | ||
| 98 | + AicpuSummaryData second; | ||
| 99 | + second.deviceId = 0; | ||
| 100 | + second.timestampNs = 2000000; | ||
| 101 | + second.nodeName = "N/A"; | ||
| 102 | + second.computeTimeUs = 3.0; | ||
| 103 | + second.memcpyTimeUs = 4.0; | ||
| 104 | + second.taskTimeUs = 8.0; | ||
| 105 | + second.dispatchTimeUs = 1.0; | ||
| 106 | + second.totalTimeUs = 20.0; | ||
| 107 | + second.streamId = 11; | ||
| 108 | + second.taskId = 30; | ||
| 109 | + res.push_back(second); | ||
| 110 | + return res; | ||
| 111 | +} | ||
| 112 | + | ||
| 113 | +std::vector<AicpuDpData> GenerateDpData() | ||
| 114 | +{ | ||
| 115 | + std::vector<AicpuDpData> res; | ||
| 116 | + AicpuDpData first; | ||
| 117 | + first.timestamp = 1000000; | ||
| 118 | + first.action = "enqueue"; | ||
| 119 | + first.source = "src0"; | ||
| 120 | + first.bufferSize = 128; | ||
| 121 | + res.push_back(first); | ||
| 122 | + | ||
| 123 | + AicpuDpData second; | ||
| 124 | + second.timestamp = 2500000; | ||
| 125 | + second.action = "dequeue"; | ||
| 126 | + second.source = "src1"; | ||
| 127 | + second.bufferSize = 256; | ||
| 128 | + res.push_back(second); | ||
| 129 | + return res; | ||
| 130 | +} | ||
| 131 | + | ||
| 132 | +std::vector<AicpuMiData> GenerateMiData() | ||
| 133 | +{ | ||
| 134 | + std::vector<AicpuMiData> res; | ||
| 135 | + AicpuMiData first; | ||
| 136 | + first.nodeName = "QueueA"; | ||
| 137 | + first.startTime = 100; | ||
| 138 | + first.endTime = 200; | ||
| 139 | + first.queueSize = 8; | ||
| 140 | + res.push_back(first); | ||
| 141 | + | ||
| 142 | + AicpuMiData second; | ||
| 143 | + second.nodeName = "QueueB"; | ||
| 144 | + second.startTime = 300; | ||
| 145 | + second.endTime = 400; | ||
| 146 | + second.queueSize = 16; | ||
| 147 | + res.push_back(second); | ||
| 148 | + return res; | ||
| 149 | +} | ||
| 150 | +} // namespace | ||
| 151 | + | ||
| 152 | +class AicpuAssemblerUTest : public testing::Test { | ||
| 153 | +protected: | ||
| 154 | + void SetUp() override | ||
| 155 | + { | ||
| 156 | + if (File::Check(BASE_PATH)) { | ||
| 157 | + File::RemoveDir(BASE_PATH, DEPTH); | ||
| 158 | + } | ||
| 159 | + EXPECT_TRUE(File::CreateDir(BASE_PATH)); | ||
| 160 | + EXPECT_TRUE(File::CreateDir(PROF_PATH)); | ||
| 161 | + EXPECT_TRUE(File::CreateDir(RESULT_PATH)); | ||
| 162 | + } | ||
| 163 | + | ||
| 164 | + void TearDown() override | ||
| 165 | + { | ||
| 166 | + EXPECT_TRUE(File::RemoveDir(BASE_PATH, DEPTH)); | ||
| 167 | + GlobalMockObject::verify(); | ||
| 168 | + } | ||
| 169 | +}; | ||
| 170 | + | ||
| 171 | +TEST_F(AicpuAssemblerUTest, ShouldReturnTrueWhenDataNotExist) | ||
| 172 | +{ | ||
| 173 | + AicpuAssembler assembler(PROCESSOR_NAME_AICPU, PROF_PATH); | ||
| 174 | + DataInventory dataInventory; | ||
| 175 | + EXPECT_TRUE(assembler.Run(dataInventory)); | ||
| 176 | + EXPECT_TRUE(FindCsvByName(AICPU_NAME).empty()); | ||
| 177 | + EXPECT_TRUE(FindCsvByName(AICPU_DP_NAME).empty()); | ||
| 178 | + EXPECT_TRUE(FindCsvByName(AICPU_MI_NAME).empty()); | ||
| 179 | +} | ||
| 180 | + | ||
| 181 | +TEST_F(AicpuAssemblerUTest, ShouldReturnTrueWhenEmptyVectorsInjected) | ||
| 182 | +{ | ||
| 183 | + DataInventory dataInventory; | ||
| 184 | + InjectVector(dataInventory, std::vector<AicpuSummaryData>()); | ||
| 185 | + InjectVector(dataInventory, std::vector<AicpuDpData>()); | ||
| 186 | + InjectVector(dataInventory, std::vector<AicpuMiData>()); | ||
| 187 | + | ||
| 188 | + AicpuAssembler assembler(PROCESSOR_NAME_AICPU, PROF_PATH); | ||
| 189 | + EXPECT_TRUE(assembler.Run(dataInventory)); | ||
| 190 | + EXPECT_TRUE(FindCsvByName(AICPU_NAME).empty()); | ||
| 191 | + EXPECT_TRUE(FindCsvByName(AICPU_DP_NAME).empty()); | ||
| 192 | + EXPECT_TRUE(FindCsvByName(AICPU_MI_NAME).empty()); | ||
| 193 | +} | ||
| 194 | + | ||
| 195 | +TEST_F(AicpuAssemblerUTest, ShouldWriteThreeCsvWhenAllDataExist) | ||
| 196 | +{ | ||
| 197 | + DataInventory dataInventory; | ||
| 198 | + InjectVector(dataInventory, GenerateAicpuData()); | ||
| 199 | + InjectVector(dataInventory, GenerateDpData()); | ||
| 200 | + InjectVector(dataInventory, GenerateMiData()); | ||
| 201 | + | ||
| 202 | + AicpuAssembler assembler(PROCESSOR_NAME_AICPU, PROF_PATH); | ||
| 203 | + EXPECT_TRUE(assembler.Run(dataInventory)); | ||
| 204 | + | ||
| 205 | + const std::string aicpuFile = FindCsvByName(AICPU_NAME); | ||
| 206 | + const std::string dpFile = FindCsvByName(AICPU_DP_NAME); | ||
| 207 | + const std::string miFile = FindCsvByName(AICPU_MI_NAME); | ||
| 208 | + ASSERT_FALSE(aicpuFile.empty()); | ||
| 209 | + ASSERT_FALSE(dpFile.empty()); | ||
| 210 | + ASSERT_FALSE(miFile.empty()); | ||
| 211 | + | ||
| 212 | + std::vector<std::string> aicpuLines = ReadCsvLines(aicpuFile); | ||
| 213 | + ASSERT_EQ(3ul, aicpuLines.size()); | ||
| 214 | + EXPECT_EQ(AICPU_HEADER, aicpuLines[0]); | ||
| 215 | + EXPECT_EQ("1000.000,Conv2D,1.5,2.5,500,0.5,10.5,10,20", aicpuLines[1]); | ||
| 216 | + EXPECT_EQ("2000.000,N/A,3,4,8,1,20,11,30", aicpuLines[2]); | ||
| 217 | + | ||
| 218 | + std::vector<std::string> dpLines = ReadCsvLines(dpFile); | ||
| 219 | + ASSERT_EQ(3ul, dpLines.size()); | ||
| 220 | + EXPECT_EQ(DP_HEADER, dpLines[0]); | ||
| 221 | + EXPECT_EQ("1000.000,enqueue,src0,128", dpLines[1]); | ||
| 222 | + EXPECT_EQ("2500.000,dequeue,src1,256", dpLines[2]); | ||
| 223 | + | ||
| 224 | + std::vector<std::string> miLines = ReadCsvLines(miFile); | ||
| 225 | + ASSERT_EQ(3ul, miLines.size()); | ||
| 226 | + EXPECT_EQ(MI_HEADER, miLines[0]); | ||
| 227 | + EXPECT_EQ("QueueA,100,200,8", miLines[1]); | ||
| 228 | + EXPECT_EQ("QueueB,300,400,16", miLines[2]); | ||
| 229 | +} | ||
| 230 | + | ||
| 231 | +TEST_F(AicpuAssemblerUTest, ShouldWriteAicpuOnly) | ||
| 232 | +{ | ||
| 233 | + DataInventory dataInventory; | ||
| 234 | + InjectVector(dataInventory, GenerateAicpuData()); | ||
| 235 | + | ||
| 236 | + AicpuAssembler assembler(PROCESSOR_NAME_AICPU, PROF_PATH); | ||
| 237 | + EXPECT_TRUE(assembler.Run(dataInventory)); | ||
| 238 | + EXPECT_FALSE(FindCsvByName(AICPU_NAME).empty()); | ||
| 239 | + EXPECT_TRUE(FindCsvByName(AICPU_DP_NAME).empty()); | ||
| 240 | + EXPECT_TRUE(FindCsvByName(AICPU_MI_NAME).empty()); | ||
| 241 | +} | ||
| 242 | + | ||
| 243 | +TEST_F(AicpuAssemblerUTest, ShouldWriteDpOnly) | ||
| 244 | +{ | ||
| 245 | + DataInventory dataInventory; | ||
| 246 | + InjectVector(dataInventory, GenerateDpData()); | ||
| 247 | + | ||
| 248 | + AicpuAssembler assembler(PROCESSOR_NAME_AICPU, PROF_PATH); | ||
| 249 | + EXPECT_TRUE(assembler.Run(dataInventory)); | ||
| 250 | + EXPECT_TRUE(FindCsvByName(AICPU_NAME).empty()); | ||
| 251 | + EXPECT_FALSE(FindCsvByName(AICPU_DP_NAME).empty()); | ||
| 252 | + EXPECT_TRUE(FindCsvByName(AICPU_MI_NAME).empty()); | ||
| 253 | +} | ||
| 254 | + | ||
| 255 | +TEST_F(AicpuAssemblerUTest, ShouldWriteMiOnly) | ||
| 256 | +{ | ||
| 257 | + DataInventory dataInventory; | ||
| 258 | + InjectVector(dataInventory, GenerateMiData()); | ||
| 259 | + | ||
| 260 | + AicpuAssembler assembler(PROCESSOR_NAME_AICPU, PROF_PATH); | ||
| 261 | + EXPECT_TRUE(assembler.Run(dataInventory)); | ||
| 262 | + EXPECT_TRUE(FindCsvByName(AICPU_NAME).empty()); | ||
| 263 | + EXPECT_TRUE(FindCsvByName(AICPU_DP_NAME).empty()); | ||
| 264 | + EXPECT_FALSE(FindCsvByName(AICPU_MI_NAME).empty()); | ||
| 265 | +} | ||
| 266 | + | ||
| 267 | +TEST_F(AicpuAssemblerUTest, ShouldGetAicpuAssemblerFromFactory) | ||
| 268 | +{ | ||
| 269 | + auto assembler = SummaryFactory::GetAssemblerByName(PROCESSOR_NAME_AICPU, PROF_PATH); | ||
| 270 | + EXPECT_NE(nullptr, assembler); | ||
| 271 | +} | ||
| 272 | + | ||
| 273 | +TEST_F(AicpuAssemblerUTest, ShouldMapThreeDeliverablesToOneAssembler) | ||
| 274 | +{ | ||
| 275 | + std::vector<std::string> assemblers; | ||
| 276 | + ASSERT_TRUE(SummaryManager::GetAssemblerList({"aicpu", "dp", "aicpu_mi", "aicpu"}, assemblers)); | ||
| 277 | + ASSERT_EQ(1ul, assemblers.size()); | ||
| 278 | + EXPECT_EQ(PROCESSOR_NAME_AICPU, assemblers[0]); | ||
| 279 | +} | ||
| @@ -66,7 +66,7 @@ TEST(SummaryManagerUTest, ShouldSelectAllDeliverablesWhenSelectionIsEmpty) | |||
| 66 | { | 66 | { |
| 67 | std::vector<TopoNodeId> roots; | 67 | std::vector<TopoNodeId> roots; |
| 68 | ASSERT_TRUE(SummaryManager::GetTopologyRoots({}, roots)); | 68 | ASSERT_TRUE(SummaryManager::GetTopologyRoots({}, roots)); |
| 69 | - EXPECT_EQ(roots.size(), 10UL); | 69 | + EXPECT_EQ(roots.size(), 11UL); |
| 70 | std::unordered_set<TopoNodeId, TopoNodeIdHash> uniqueRoots; | 70 | std::unordered_set<TopoNodeId, TopoNodeIdHash> uniqueRoots; |
| 71 | for (const auto& root : roots) | 71 | for (const auto& root : roots) |
| 72 | { | 72 | { |
| @@ -85,6 +85,19 @@ TEST(SummaryManagerUTest, ShouldSelectAndDeduplicateDeliverables) | |||
| 85 | EXPECT_EQ(assemblers[1], PROCESSOR_NAME_NPU_MEM); | 85 | EXPECT_EQ(assemblers[1], PROCESSOR_NAME_NPU_MEM); |
| 86 | } | 86 | } |
| 87 | 87 | ||
| 88 | +TEST(SummaryManagerUTest, ShouldDeduplicateAicpuFamilyDeliverables) | ||
| 89 | +{ | ||
| 90 | + std::vector<std::string> assemblers; | ||
| 91 | + ASSERT_TRUE(SummaryManager::GetAssemblerList({"aicpu", "dp", "aicpu_mi", "aicpu"}, assemblers)); | ||
| 92 | + ASSERT_EQ(assemblers.size(), 1UL); | ||
| 93 | + EXPECT_EQ(assemblers[0], PROCESSOR_NAME_AICPU); | ||
| 94 | + | ||
| 95 | + std::vector<TopoNodeId> roots; | ||
| 96 | + ASSERT_TRUE(SummaryManager::GetTopologyRoots({"dp", "aicpu_mi"}, roots)); | ||
| 97 | + ASSERT_EQ(roots.size(), 1UL); | ||
| 98 | + EXPECT_EQ(roots.front(), (TopoNodeId{TopoNodeStage::SUMMARY_GENERATION, PROCESSOR_NAME_AICPU})); | ||
| 99 | +} | ||
| 100 | + | ||
| 88 | TEST(SummaryManagerUTest, ShouldRejectUnknownDeliverable) | 101 | TEST(SummaryManagerUTest, ShouldRejectUnknownDeliverable) |
| 89 | { | 102 | { |
| 90 | std::vector<TopoNodeId> roots; | 103 | std::vector<TopoNodeId> roots; |
| @@ -0,0 +1,621 @@ | |||
| 1 | +/* ------------------------------------------------------------------------- | ||
| 2 | + * Copyright (c) 2026 Huawei Technologies Co., Ltd. | ||
| 3 | + * This file is part of the MindStudio project. | ||
| 4 | + * | ||
| 5 | + * MindStudio is licensed under Mulan PSL v2. | ||
| 6 | + * You can use this software according to the terms and conditions of the Mulan PSL v2. | ||
| 7 | + * You may obtain a copy of Mulan PSL v2 at: | ||
| 8 | + * | ||
| 9 | + * http://license.coscl.org.cn/MulanPSL2 | ||
| 10 | + * | ||
| 11 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, | ||
| 12 | + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, | ||
| 13 | + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. | ||
| 14 | + * See the Mulan PSL v2 for more details. | ||
| 15 | + * -------------------------------------------------------------------------*/ | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | + | ||
| 20 | + | ||
| 21 | + | ||
| 22 | + | ||
| 23 | + | ||
| 24 | + | ||
| 25 | + | ||
| 26 | + | ||
| 27 | + | ||
| 28 | + | ||
| 29 | + | ||
| 30 | + | ||
| 31 | + | ||
| 32 | + | ||
| 33 | + | ||
| 34 | + | ||
| 35 | + | ||
| 36 | + | ||
| 37 | + | ||
| 38 | + | ||
| 39 | + | ||
| 40 | +using namespace Analysis::Application; | ||
| 41 | +using namespace Analysis::Common; | ||
| 42 | +using namespace Analysis::Domain; | ||
| 43 | +using namespace Analysis::Domain::Environment; | ||
| 44 | +using namespace Analysis::Infra; | ||
| 45 | +using namespace Analysis::Utils; | ||
| 46 | + | ||
| 47 | +namespace { | ||
| 48 | +const int DEPTH = 0; | ||
| 49 | +const std::string BASE_PATH = "./aicpu_processor_utest"; | ||
| 50 | +const std::string PROF_PATH = File::PathJoin({BASE_PATH, "PROF_0"}); | ||
| 51 | + | ||
| 52 | +const TableColumns AICPU_TABLE_COLS = { | ||
| 53 | + {"stream_id", SQL_INTEGER_TYPE}, {"task_id", SQL_INTEGER_TYPE}, {"sys_start", SQL_NUMERIC_TYPE}, | ||
| 54 | + {"sys_end", SQL_NUMERIC_TYPE}, {"node_name", SQL_TEXT_TYPE}, {"compute_time", SQL_REAL_TYPE}, | ||
| 55 | + {"memcpy_time", SQL_REAL_TYPE}, {"task_time", SQL_REAL_TYPE}, {"dispatch_time", SQL_REAL_TYPE}, | ||
| 56 | + {"total_time", SQL_REAL_TYPE}, | ||
| 57 | +}; | ||
| 58 | + | ||
| 59 | +const TableColumns AICPU_DP_TABLE_COLS = { | ||
| 60 | + {"timestamp", SQL_NUMERIC_TYPE}, | ||
| 61 | + {"action", SQL_TEXT_TYPE}, | ||
| 62 | + {"source", SQL_TEXT_TYPE}, | ||
| 63 | + {"buffer_size", SQL_INTEGER_TYPE}, | ||
| 64 | +}; | ||
| 65 | + | ||
| 66 | +const TableColumns DATA_QUEUE_TABLE_COLS = { | ||
C 【review】【测试】DP 单测采用零 boot 偏移,结构性掩盖 wall-clock 偏移缺陷
![]() ![]() | |||
| 67 | + {"node_name", SQL_TEXT_TYPE}, {"queue_size", SQL_INTEGER_TYPE}, {"start_time", SQL_REAL_TYPE}, | ||
| 68 | + {"end_time", SQL_REAL_TYPE}, {"duration", SQL_REAL_TYPE}, | ||
| 69 | +}; | ||
| 70 | + | ||
| 71 | +using AiCpuInsert = OriAiCpuData; | ||
| 72 | +using DpInsert = OriAiCpuDpData; | ||
| 73 | +using MiInsert = std::vector<std::tuple<std::string, uint64_t, double, double, double>>; | ||
| 74 | + | ||
| 75 | +nlohmann::json BuildTimeRecord(const std::string &startUs, const std::string &baseNs, | ||
| 76 | + const std::string &platformVersion) | ||
| 77 | +{ | ||
| 78 | + return nlohmann::json{ | ||
| 79 | + {"startCollectionTimeBegin", startUs}, | ||
| 80 | + {"endCollectionTimeEnd", "999999999"}, | ||
| 81 | + {"startClockMonotonicRaw", baseNs}, | ||
| 82 | + {"platform_version", platformVersion}, | ||
| 83 | + }; | ||
| 84 | +} | ||
| 85 | + | ||
| 86 | +std::string DevicePath(uint16_t deviceId) | ||
| 87 | +{ | ||
| 88 | + return File::PathJoin({PROF_PATH, DEVICE_PREFIX + std::to_string(deviceId)}); | ||
| 89 | +} | ||
| 90 | + | ||
| 91 | +std::string SqlitePath(uint16_t deviceId) | ||
| 92 | +{ | ||
| 93 | + return File::PathJoin({DevicePath(deviceId), SQLITE}); | ||
| 94 | +} | ||
| 95 | + | ||
| 96 | +void CreateDeviceDir(uint16_t deviceId) | ||
| 97 | +{ | ||
| 98 | + EXPECT_TRUE(File::CreateDir(DevicePath(deviceId))); | ||
| 99 | + EXPECT_TRUE(File::CreateDir(SqlitePath(deviceId))); | ||
| 100 | +} | ||
| 101 | + | ||
| 102 | +void InsertTable(const std::string &dbPath, const std::string &tableName, const TableColumns &cols) | ||
| 103 | +{ | ||
| 104 | + std::shared_ptr<DBRunner> dbRunner; | ||
| 105 | + MAKE_SHARED_RETURN_VOID(dbRunner, DBRunner, dbPath); | ||
| 106 | + EXPECT_TRUE(dbRunner->CreateTable(tableName, cols)); | ||
| 107 | +} | ||
| 108 | + | ||
| 109 | +template <typename T> | ||
| 110 | +void InsertTableData(const std::string &dbPath, const std::string &tableName, const TableColumns &cols, const T &data) | ||
| 111 | +{ | ||
| 112 | + std::shared_ptr<DBRunner> dbRunner; | ||
| 113 | + MAKE_SHARED_RETURN_VOID(dbRunner, DBRunner, dbPath); | ||
| 114 | + EXPECT_TRUE(dbRunner->CreateTable(tableName, cols)); | ||
| 115 | + if (!data.empty()) { | ||
| 116 | + EXPECT_TRUE(dbRunner->InsertData(tableName, data)); | ||
| 117 | + } | ||
| 118 | +} | ||
| 119 | + | ||
| 120 | +void WriteAiCpuData(uint16_t deviceId, const AiCpuInsert &data) | ||
| 121 | +{ | ||
| 122 | + InsertTableData(File::PathJoin({SqlitePath(deviceId), DB_NAME_AI_CPU}), TABLE_NAME_AI_CPU, AICPU_TABLE_COLS, data); | ||
| 123 | +} | ||
| 124 | + | ||
| 125 | +void WriteDpData(uint16_t deviceId, const DpInsert &data) | ||
| 126 | +{ | ||
| 127 | + InsertTableData(File::PathJoin({SqlitePath(deviceId), DB_NAME_AI_CPU}), TABLE_NAME_AI_CPU_DP, AICPU_DP_TABLE_COLS, | ||
| 128 | + data); | ||
| 129 | +} | ||
| 130 | + | ||
| 131 | +void WriteMiData(uint16_t deviceId, const MiInsert &data) | ||
| 132 | +{ | ||
| 133 | + InsertTableData(File::PathJoin({SqlitePath(deviceId), DB_NAME_DATA_PREPROCESS}), TABLE_NAME_DATA_QUEUE, | ||
| 134 | + DATA_QUEUE_TABLE_COLS, data); | ||
| 135 | +} | ||
| 136 | + | ||
| 137 | +AscendTaskData MakeAscendTask(uint16_t deviceId, uint32_t streamId, uint32_t taskId, uint64_t startNs, uint64_t endNs, | ||
| 138 | + uint32_t batchId, const std::string &hostType) | ||
| 139 | +{ | ||
| 140 | + AscendTaskData task; | ||
| 141 | + task.deviceId = deviceId; | ||
| 142 | + task.streamId = streamId; | ||
| 143 | + task.taskId = taskId; | ||
| 144 | + task.timestamp = startNs; | ||
| 145 | + task.end = endNs; | ||
| 146 | + task.batchId = batchId; | ||
| 147 | + task.hostType = hostType; | ||
| 148 | + return task; | ||
| 149 | +} | ||
| 150 | + | ||
| 151 | +TaskInfoData MakeTaskInfo(uint16_t deviceId, uint32_t streamId, uint32_t taskId, uint32_t batchId, | ||
| 152 | + const std::string &taskType, const std::string &opName) | ||
| 153 | +{ | ||
| 154 | + TaskInfoData info; | ||
| 155 | + info.deviceId = deviceId; | ||
| 156 | + info.streamId = streamId; | ||
| 157 | + info.taskId = taskId; | ||
| 158 | + info.batchId = batchId; | ||
| 159 | + info.taskType = taskType; | ||
| 160 | + info.opName = opName; | ||
| 161 | + return info; | ||
| 162 | +} | ||
| 163 | + | ||
| 164 | +template <typename T> | ||
| 165 | +void InjectVector(DataInventory &dataInventory, const std::vector<T> &data) | ||
| 166 | +{ | ||
| 167 | + std::shared_ptr<std::vector<T>> holder; | ||
| 168 | + MAKE_SHARED_NO_OPERATION(holder, std::vector<T>, data); | ||
| 169 | + dataInventory.Inject(holder); | ||
| 170 | +} | ||
| 171 | + | ||
| 172 | +const AicpuSummaryData *FindSummary(const std::vector<AicpuSummaryData> &data, uint16_t deviceId, uint32_t streamId, | ||
| 173 | + uint32_t taskId, uint64_t timestampNs) | ||
| 174 | +{ | ||
| 175 | + for (size_t i = 0; i < data.size(); ++i) { | ||
| 176 | + if (data[i].deviceId == deviceId && data[i].streamId == streamId && data[i].taskId == taskId && | ||
| 177 | + data[i].timestampNs == timestampNs) { | ||
| 178 | + return &data[i]; | ||
| 179 | + } | ||
| 180 | + } | ||
| 181 | + return nullptr; | ||
| 182 | +} | ||
| 183 | +} // namespace | ||
| 184 | + | ||
| 185 | +class AicpuProcessorUTest : public testing::Test { | ||
| 186 | +protected: | ||
| 187 | + void SetUp() override | ||
| 188 | + { | ||
| 189 | + if (File::Check(BASE_PATH)) { | ||
| 190 | + File::RemoveDir(BASE_PATH, DEPTH); | ||
| 191 | + } | ||
| 192 | + EXPECT_TRUE(File::CreateDir(BASE_PATH)); | ||
| 193 | + EXPECT_TRUE(File::CreateDir(PROF_PATH)); | ||
| 194 | + MOCKER_CPP(&Environment::Context::GetInfoByDeviceId).stubs().will(returnValue(BuildTimeRecord("0", "0", "5"))); | ||
| 195 | + } | ||
| 196 | + | ||
| 197 | + void TearDown() override | ||
| 198 | + { | ||
| 199 | + GlobalMockObject::verify(); | ||
| 200 | + if (File::Check(BASE_PATH)) { | ||
| 201 | + EXPECT_TRUE(File::RemoveDir(BASE_PATH, DEPTH)); | ||
| 202 | + } | ||
| 203 | + } | ||
| 204 | +}; | ||
| 205 | + | ||
| 206 | +TEST_F(AicpuProcessorUTest, ShouldLoadAllThreeTypesAndFillDerivedFields) | ||
| 207 | +{ | ||
| 208 | + CreateDeviceDir(0); | ||
| 209 | + AiCpuInsert aicpuData{ | ||
| 210 | + {10, 20, 1000000.0, 1500000.0, "", 1500.0, 2500.0, 500000.0, 500.0, 10500.0}, | ||
| 211 | + {11, 30, 4000000.0, 3500000.0, "InvEnd", 3000.0, 4000.0, 8000.0, 1000.0, 20000.0}, | ||
| 212 | + }; | ||
| 213 | + DpInsert dpData{ | ||
| 214 | + {1000000.0, "enqueue", "src0", 128}, | ||
| 215 | + {2000000.0, "dequeue", "src1", 256}, | ||
| 216 | + }; | ||
| 217 | + MiInsert miData{ | ||
| 218 | + {"QueueA", 8, 100.7, 200.2, 99.5}, | ||
| 219 | + {"QueueB", 16, 300.0, 400.0, 100.0}, | ||
| 220 | + }; | ||
| 221 | + WriteAiCpuData(0, aicpuData); | ||
| 222 | + WriteDpData(0, dpData); | ||
| 223 | + WriteMiData(0, miData); | ||
| 224 | + | ||
| 225 | + DataInventory dataInventory; | ||
| 226 | + AicpuProcessor processor(PROF_PATH); | ||
| 227 | + EXPECT_TRUE(processor.Run(dataInventory, PROCESSOR_NAME_AICPU)); | ||
| 228 | + | ||
| 229 | + auto summary = dataInventory.GetPtr<std::vector<AicpuSummaryData>>(); | ||
| 230 | + ASSERT_NE(nullptr, summary); | ||
| 231 | + ASSERT_EQ(2ul, summary->size()); | ||
| 232 | + EXPECT_EQ(0u, summary->at(0).deviceId); | ||
| 233 | + EXPECT_EQ(10u, summary->at(0).streamId); | ||
| 234 | + EXPECT_EQ(20u, summary->at(0).taskId); | ||
| 235 | + EXPECT_EQ(1000000ull, summary->at(0).timestampNs); | ||
| 236 | + EXPECT_EQ(1500000ull, summary->at(0).endNs); | ||
| 237 | + EXPECT_EQ(NA, summary->at(0).nodeName); | ||
| 238 | + EXPECT_DOUBLE_EQ(1.5, summary->at(0).computeTimeUs); | ||
| 239 | + EXPECT_DOUBLE_EQ(2.5, summary->at(0).memcpyTimeUs); | ||
| 240 | + EXPECT_DOUBLE_EQ(500.0, summary->at(0).taskTimeUs); | ||
| 241 | + EXPECT_DOUBLE_EQ(0.5, summary->at(0).dispatchTimeUs); | ||
| 242 | + EXPECT_DOUBLE_EQ(10.5, summary->at(0).totalTimeUs); | ||
| 243 | + EXPECT_EQ(UINT32_MAX, summary->at(0).batchId); | ||
| 244 | + | ||
| 245 | + EXPECT_EQ("InvEnd", summary->at(1).nodeName); | ||
| 246 | + EXPECT_DOUBLE_EQ(3.0, summary->at(1).computeTimeUs); | ||
| 247 | + EXPECT_DOUBLE_EQ(4.0, summary->at(1).memcpyTimeUs); | ||
| 248 | + EXPECT_DOUBLE_EQ(8.0, summary->at(1).taskTimeUs); | ||
| 249 | + EXPECT_DOUBLE_EQ(1.0, summary->at(1).dispatchTimeUs); | ||
| 250 | + EXPECT_DOUBLE_EQ(20.0, summary->at(1).totalTimeUs); | ||
| 251 | + | ||
| 252 | + auto dp = dataInventory.GetPtr<std::vector<AicpuDpData>>(); | ||
| 253 | + ASSERT_NE(nullptr, dp); | ||
| 254 | + ASSERT_EQ(2ul, dp->size()); | ||
| 255 | + EXPECT_EQ(1000000ull, dp->at(0).timestamp); | ||
| 256 | + EXPECT_EQ("enqueue", dp->at(0).action); | ||
| 257 | + EXPECT_EQ("src0", dp->at(0).source); | ||
| 258 | + EXPECT_EQ(128ull, dp->at(0).bufferSize); | ||
| 259 | + | ||
| 260 | + auto mi = dataInventory.GetPtr<std::vector<AicpuMiData>>(); | ||
| 261 | + ASSERT_NE(nullptr, mi); | ||
| 262 | + ASSERT_EQ(2ul, mi->size()); | ||
| 263 | + EXPECT_EQ("QueueA", mi->at(0).nodeName); | ||
| 264 | + EXPECT_EQ(100ull, mi->at(0).startTime); | ||
| 265 | + EXPECT_EQ(200ull, mi->at(0).endTime); | ||
| 266 | + EXPECT_EQ(8ull, mi->at(0).queueSize); | ||
| 267 | +} | ||
| 268 | + | ||
| 269 | +TEST_F(AicpuProcessorUTest, ShouldSkipRecordsBeforeCollectStart) | ||
| 270 | +{ | ||
| 271 | + MOCKER_CPP(&Environment::Context::GetInfoByDeviceId).reset(); | ||
| 272 | + MOCKER_CPP(&Environment::Context::GetInfoByDeviceId).stubs().will(returnValue(BuildTimeRecord("2", "2000", "5"))); | ||
| 273 | + CreateDeviceDir(0); | ||
| 274 | + AiCpuInsert aicpuData{ | ||
| 275 | + {1, 1, 1000.0, 1500.0, "BeforeStart", 1.0, 1.0, 500.0, 1.0, 3.0}, | ||
| 276 | + {1, 2, 5000.0, 6000.0, "AfterStart", 2.0, 2.0, 1000.0, 2.0, 6.0}, | ||
| 277 | + }; | ||
| 278 | + WriteAiCpuData(0, aicpuData); | ||
| 279 | + | ||
| 280 | + DataInventory dataInventory; | ||
| 281 | + AicpuProcessor processor(PROF_PATH); | ||
| 282 | + EXPECT_TRUE(processor.Run(dataInventory, PROCESSOR_NAME_AICPU)); | ||
| 283 | + | ||
| 284 | + auto summary = dataInventory.GetPtr<std::vector<AicpuSummaryData>>(); | ||
| 285 | + ASSERT_NE(nullptr, summary); | ||
| 286 | + ASSERT_EQ(1ul, summary->size()); | ||
| 287 | + EXPECT_EQ("AfterStart", summary->at(0).nodeName); | ||
| 288 | + EXPECT_EQ(5000ull, summary->at(0).timestampNs); | ||
| 289 | +} | ||
| 290 | + | ||
| 291 | +TEST_F(AicpuProcessorUTest, ShouldFillBatchAndNodeWhenNonV6Matched) | ||
| 292 | +{ | ||
| 293 | + CreateDeviceDir(0); | ||
| 294 | + AiCpuInsert aicpuData{ | ||
| 295 | + {10, 20, 1000000.0, 1500000.0, "", 1.0, 1.0, 0.0, 1.0, 3.0}, | ||
| 296 | + {10, 20, 2000000.0, 2500000.0, "Raw", 1.0, 1.0, 0.0, 1.0, 3.0}, | ||
| 297 | + {11, 30, 3000000.0, 3100000.0, "KeepMe", 1.0, 1.0, 0.0, 1.0, 3.0}, | ||
| 298 | + }; | ||
| 299 | + WriteAiCpuData(0, aicpuData); | ||
| 300 | + | ||
| 301 | + std::vector<AscendTaskData> tasks; | ||
| 302 | + tasks.push_back(MakeAscendTask(0, 10, 20, 900000, 1600000, 7, KERNEL_AICPU_TASK_TYPE)); | ||
| 303 | + tasks.push_back(MakeAscendTask(0, 10, 20, 1900000, 2600000, 8, KERNEL_AICPU_TASK_TYPE)); | ||
| 304 | + tasks.push_back(MakeAscendTask(0, 10, 20, 500000, 4000000, 99, KERNEL_AICORE_TASK_TYPE)); | ||
| 305 | + tasks.push_back(MakeAscendTask(0, 11, 30, 2900000, 3200000, 1, KERNEL_AICPU_TASK_TYPE)); | ||
| 306 | + | ||
| 307 | + std::vector<TaskInfoData> geInfos; | ||
| 308 | + geInfos.push_back(MakeTaskInfo(0, 10, 20, 7, AI_CPU, "Conv2D")); | ||
| 309 | + geInfos.push_back(MakeTaskInfo(0, 10, 20, 8, AI_CPU, "MatMul")); | ||
| 310 | + geInfos.push_back(MakeTaskInfo(0, 11, 30, 1, "AI_CORE", "ShouldNotMatch")); | ||
| 311 | + | ||
| 312 | + DataInventory dataInventory; | ||
| 313 | + InjectVector(dataInventory, tasks); | ||
| 314 | + InjectVector(dataInventory, geInfos); | ||
| 315 | + | ||
| 316 | + AicpuProcessor processor(PROF_PATH); | ||
| 317 | + EXPECT_TRUE(processor.Run(dataInventory, PROCESSOR_NAME_AICPU)); | ||
| 318 | + | ||
| 319 | + auto summary = dataInventory.GetPtr<std::vector<AicpuSummaryData>>(); | ||
| 320 | + ASSERT_NE(nullptr, summary); | ||
| 321 | + ASSERT_EQ(3ul, summary->size()); | ||
| 322 | + | ||
| 323 | + const AicpuSummaryData *first = FindSummary(*summary, 0, 10, 20, 1000000ull); | ||
| 324 | + const AicpuSummaryData *second = FindSummary(*summary, 0, 10, 20, 2000000ull); | ||
| 325 | + const AicpuSummaryData *third = FindSummary(*summary, 0, 11, 30, 3000000ull); | ||
| 326 | + ASSERT_NE(nullptr, first); | ||
| 327 | + ASSERT_NE(nullptr, second); | ||
| 328 | + ASSERT_NE(nullptr, third); | ||
| 329 | + EXPECT_EQ(7u, first->batchId); | ||
| 330 | + EXPECT_EQ("Conv2D", first->nodeName); | ||
| 331 | + EXPECT_EQ(8u, second->batchId); | ||
| 332 | + EXPECT_EQ("MatMul", second->nodeName); | ||
| 333 | + EXPECT_EQ(1u, third->batchId); | ||
| 334 | + EXPECT_EQ("KeepMe", third->nodeName); | ||
| 335 | +} | ||
| 336 | + | ||
| 337 | +TEST_F(AicpuProcessorUTest, ShouldSkipUnmatchedAicpuWithoutConsumingLaterTask) | ||
| 338 | +{ | ||
| 339 | + CreateDeviceDir(0); | ||
| 340 | + AiCpuInsert aicpuData{ | ||
| 341 | + {10, 20, 1000000.0, 1100000.0, "Gap", 1.0, 1.0, 0.0, 1.0, 3.0}, | ||
| 342 | + {10, 20, 2000000.0, 2300000.0, "Hit", 1.0, 1.0, 0.0, 1.0, 3.0}, | ||
| 343 | + }; | ||
| 344 | + WriteAiCpuData(0, aicpuData); | ||
| 345 | + | ||
| 346 | + std::vector<AscendTaskData> tasks; | ||
| 347 | + tasks.push_back(MakeAscendTask(0, 10, 20, 2000000, 2500000, 8, KERNEL_AICPU_TASK_TYPE)); | ||
| 348 | + std::vector<TaskInfoData> geInfos; | ||
| 349 | + geInfos.push_back(MakeTaskInfo(0, 10, 20, 8, AI_CPU, "MatchedOp")); | ||
| 350 | + | ||
| 351 | + DataInventory dataInventory; | ||
| 352 | + InjectVector(dataInventory, tasks); | ||
| 353 | + InjectVector(dataInventory, geInfos); | ||
| 354 | + | ||
| 355 | + AicpuProcessor processor(PROF_PATH); | ||
| 356 | + EXPECT_TRUE(processor.Run(dataInventory, PROCESSOR_NAME_AICPU)); | ||
| 357 | + | ||
| 358 | + auto summary = dataInventory.GetPtr<std::vector<AicpuSummaryData>>(); | ||
| 359 | + ASSERT_NE(nullptr, summary); | ||
| 360 | + ASSERT_EQ(2ul, summary->size()); | ||
| 361 | + EXPECT_EQ(UINT32_MAX, summary->at(0).batchId); | ||
| 362 | + EXPECT_EQ("Gap", summary->at(0).nodeName); | ||
| 363 | + EXPECT_EQ(8u, summary->at(1).batchId); | ||
| 364 | + EXPECT_EQ("MatchedOp", summary->at(1).nodeName); | ||
| 365 | +} | ||
| 366 | + | ||
| 367 | +TEST_F(AicpuProcessorUTest, ShouldMatchNodeByStreamTaskAndSkipBatchOnV6) | ||
| 368 | +{ | ||
| 369 | + MOCKER_CPP(&Environment::Context::GetPlatformVersion).stubs().will(returnValue(static_cast<uint16_t>(Chip::CHIP_V6_1_0))); | ||
| 370 | + CreateDeviceDir(0); | ||
| 371 | + AiCpuInsert aicpuData{ | ||
| 372 | + {10, 20, 1000000.0, 1500000.0, "Raw", 1.0, 1.0, 0.0, 1.0, 3.0}, | ||
| 373 | + }; | ||
| 374 | + WriteAiCpuData(0, aicpuData); | ||
| 375 | + | ||
| 376 | + std::vector<AscendTaskData> tasks; | ||
| 377 | + tasks.push_back(MakeAscendTask(0, 10, 20, 900000, 1600000, 7, KERNEL_AICPU_TASK_TYPE)); | ||
| 378 | + std::vector<TaskInfoData> geInfos; | ||
| 379 | + geInfos.push_back(MakeTaskInfo(0, 10, 20, 99, "AI_CORE", "V6Op")); | ||
| 380 | + | ||
| 381 | + DataInventory dataInventory; | ||
| 382 | + InjectVector(dataInventory, tasks); | ||
| 383 | + InjectVector(dataInventory, geInfos); | ||
| 384 | + | ||
| 385 | + AicpuProcessor processor(PROF_PATH); | ||
| 386 | + EXPECT_TRUE(processor.Run(dataInventory, PROCESSOR_NAME_AICPU)); | ||
| 387 | + | ||
| 388 | + auto summary = dataInventory.GetPtr<std::vector<AicpuSummaryData>>(); | ||
| 389 | + ASSERT_NE(nullptr, summary); | ||
| 390 | + ASSERT_EQ(1ul, summary->size()); | ||
| 391 | + EXPECT_EQ(UINT32_MAX, summary->at(0).batchId); | ||
| 392 | + EXPECT_EQ("V6Op", summary->at(0).nodeName); | ||
| 393 | +} | ||
| 394 | + | ||
| 395 | +TEST_F(AicpuProcessorUTest, ShouldNotCrossMatchDevicesAndShouldSortByTimestamp) | ||
| 396 | +{ | ||
| 397 | + CreateDeviceDir(0); | ||
| 398 | + CreateDeviceDir(1); | ||
| 399 | + AiCpuInsert device0{ | ||
| 400 | + {10, 20, 3000000.0, 3500000.0, "Dev0", 1.0, 1.0, 0.0, 1.0, 3.0}, | ||
| 401 | + }; | ||
| 402 | + AiCpuInsert device1{ | ||
| 403 | + {10, 20, 1000000.0, 1500000.0, "Dev1", 1.0, 1.0, 0.0, 1.0, 3.0}, | ||
| 404 | + }; | ||
| 405 | + WriteAiCpuData(0, device0); | ||
| 406 | + WriteAiCpuData(1, device1); | ||
| 407 | + | ||
| 408 | + std::vector<AscendTaskData> tasks; | ||
| 409 | + tasks.push_back(MakeAscendTask(0, 10, 20, 2900000, 3600000, 7, KERNEL_AICPU_TASK_TYPE)); | ||
| 410 | + tasks.push_back(MakeAscendTask(1, 10, 20, 900000, 1600000, 8, KERNEL_AICPU_TASK_TYPE)); | ||
| 411 | + std::vector<TaskInfoData> geInfos; | ||
| 412 | + geInfos.push_back(MakeTaskInfo(0, 10, 20, 7, AI_CPU, "Op0")); | ||
| 413 | + geInfos.push_back(MakeTaskInfo(1, 10, 20, 8, AI_CPU, "Op1")); | ||
| 414 | + | ||
| 415 | + DataInventory dataInventory; | ||
| 416 | + InjectVector(dataInventory, tasks); | ||
| 417 | + InjectVector(dataInventory, geInfos); | ||
| 418 | + | ||
| 419 | + AicpuProcessor processor(PROF_PATH); | ||
| 420 | + EXPECT_TRUE(processor.Run(dataInventory, PROCESSOR_NAME_AICPU)); | ||
| 421 | + | ||
| 422 | + auto summary = dataInventory.GetPtr<std::vector<AicpuSummaryData>>(); | ||
| 423 | + ASSERT_NE(nullptr, summary); | ||
| 424 | + ASSERT_EQ(2ul, summary->size()); | ||
| 425 | + EXPECT_EQ(1u, summary->at(0).deviceId); | ||
| 426 | + EXPECT_EQ(1000000ull, summary->at(0).timestampNs); | ||
| 427 | + EXPECT_EQ(8u, summary->at(0).batchId); | ||
| 428 | + EXPECT_EQ("Op1", summary->at(0).nodeName); | ||
| 429 | + EXPECT_EQ(0u, summary->at(1).deviceId); | ||
| 430 | + EXPECT_EQ(3000000ull, summary->at(1).timestampNs); | ||
| 431 | + EXPECT_EQ(7u, summary->at(1).batchId); | ||
| 432 | + EXPECT_EQ("Op0", summary->at(1).nodeName); | ||
| 433 | +} | ||
| 434 | + | ||
| 435 | +TEST_F(AicpuProcessorUTest, ShouldApplyWallClockOffsetToDpAndAicpuTimestamp) | ||
| 436 | +{ | ||
| 437 | + MOCKER_CPP(&Environment::Context::GetInfoByDeviceId).reset(); | ||
| 438 | + MOCKER_CPP(&Environment::Context::GetInfoByDeviceId).stubs().will(returnValue(BuildTimeRecord("100", "1000", "5"))); | ||
| 439 | + CreateDeviceDir(0); | ||
| 440 | + const double rawNs = 1000000.0; | ||
| 441 | + const uint64_t expectedLocalNs = static_cast<uint64_t>(rawNs) + 100UL * MILLI_SECOND - 1000UL; | ||
| 442 | + AiCpuInsert aicpuData{ | ||
| 443 | + {10, 20, rawNs, 1500000.0, "OffsetNode", 1500.0, 2500.0, 500000.0, 500.0, 10500.0}, | ||
| 444 | + }; | ||
| 445 | + DpInsert dpData{ | ||
| 446 | + {rawNs, "enqueue", "src0", 128}, | ||
| 447 | + }; | ||
| 448 | + WriteAiCpuData(0, aicpuData); | ||
| 449 | + WriteDpData(0, dpData); | ||
| 450 | + | ||
| 451 | + DataInventory dataInventory; | ||
| 452 | + AicpuProcessor processor(PROF_PATH); | ||
| 453 | + EXPECT_TRUE(processor.Run(dataInventory, PROCESSOR_NAME_AICPU)); | ||
| 454 | + | ||
| 455 | + auto summary = dataInventory.GetPtr<std::vector<AicpuSummaryData>>(); | ||
| 456 | + ASSERT_NE(nullptr, summary); | ||
| 457 | + ASSERT_EQ(1ul, summary->size()); | ||
| 458 | + EXPECT_EQ(expectedLocalNs, summary->at(0).timestampNs); | ||
| 459 | + | ||
| 460 | + auto dp = dataInventory.GetPtr<std::vector<AicpuDpData>>(); | ||
| 461 | + ASSERT_NE(nullptr, dp); | ||
| 462 | + ASSERT_EQ(1ul, dp->size()); | ||
| 463 | + EXPECT_EQ(expectedLocalNs, dp->at(0).timestamp); | ||
| 464 | +} | ||
| 465 | + | ||
| 466 | +TEST_F(AicpuProcessorUTest, ShouldKeepEqualTimestampOrderAfterStableSort) | ||
| 467 | +{ | ||
| 468 | + CreateDeviceDir(0); | ||
| 469 | + AiCpuInsert aicpuData{ | ||
| 470 | + {1, 1, 1000000.0, 1100000.0, "First", 1000.0, 1000.0, 100000.0, 1000.0, 3000.0}, | ||
| 471 | + {2, 2, 1000000.0, 1200000.0, "Second", 1000.0, 1000.0, 200000.0, 1000.0, 3000.0}, | ||
| 472 | + }; | ||
| 473 | + WriteAiCpuData(0, aicpuData); | ||
| 474 | + | ||
| 475 | + DataInventory dataInventory; | ||
| 476 | + AicpuProcessor processor(PROF_PATH); | ||
| 477 | + EXPECT_TRUE(processor.Run(dataInventory, PROCESSOR_NAME_AICPU)); | ||
| 478 | + | ||
| 479 | + auto summary = dataInventory.GetPtr<std::vector<AicpuSummaryData>>(); | ||
| 480 | + ASSERT_NE(nullptr, summary); | ||
| 481 | + ASSERT_EQ(2ul, summary->size()); | ||
| 482 | + EXPECT_EQ("First", summary->at(0).nodeName); | ||
| 483 | + EXPECT_EQ("Second", summary->at(1).nodeName); | ||
| 484 | + EXPECT_EQ(summary->at(0).timestampNs, summary->at(1).timestampNs); | ||
| 485 | +} | ||
| 486 | + | ||
| 487 | +TEST_F(AicpuProcessorUTest, ShouldSucceedWhenAicpuOnly) | ||
| 488 | +{ | ||
| 489 | + CreateDeviceDir(0); | ||
| 490 | + AiCpuInsert aicpuData{ | ||
| 491 | + {1, 2, 1000000.0, 1100000.0, "OnlyAicpu", 1.0, 1.0, 0.0, 1.0, 3.0}, | ||
| 492 | + }; | ||
| 493 | + WriteAiCpuData(0, aicpuData); | ||
| 494 | + | ||
| 495 | + DataInventory dataInventory; | ||
| 496 | + AicpuProcessor processor(PROF_PATH); | ||
| 497 | + EXPECT_TRUE(processor.Run(dataInventory, PROCESSOR_NAME_AICPU)); | ||
| 498 | + ASSERT_NE(nullptr, dataInventory.GetPtr<std::vector<AicpuSummaryData>>()); | ||
| 499 | + EXPECT_EQ(nullptr, dataInventory.GetPtr<std::vector<AicpuDpData>>()); | ||
| 500 | + EXPECT_EQ(nullptr, dataInventory.GetPtr<std::vector<AicpuMiData>>()); | ||
| 501 | +} | ||
| 502 | + | ||
| 503 | +TEST_F(AicpuProcessorUTest, ShouldSucceedWhenDpOnly) | ||
| 504 | +{ | ||
| 505 | + CreateDeviceDir(0); | ||
| 506 | + DpInsert dpData{ | ||
| 507 | + {1000000.0, "enqueue", "src", 64}, | ||
| 508 | + }; | ||
| 509 | + WriteDpData(0, dpData); | ||
| 510 | + | ||
| 511 | + DataInventory dataInventory; | ||
| 512 | + AicpuProcessor processor(PROF_PATH); | ||
| 513 | + EXPECT_TRUE(processor.Run(dataInventory, PROCESSOR_NAME_AICPU)); | ||
| 514 | + EXPECT_EQ(nullptr, dataInventory.GetPtr<std::vector<AicpuSummaryData>>()); | ||
| 515 | + ASSERT_NE(nullptr, dataInventory.GetPtr<std::vector<AicpuDpData>>()); | ||
| 516 | + EXPECT_EQ(1ul, dataInventory.GetPtr<std::vector<AicpuDpData>>()->size()); | ||
| 517 | + EXPECT_EQ(nullptr, dataInventory.GetPtr<std::vector<AicpuMiData>>()); | ||
| 518 | +} | ||
| 519 | + | ||
| 520 | +TEST_F(AicpuProcessorUTest, ShouldSucceedWhenMiOnly) | ||
| 521 | +{ | ||
| 522 | + CreateDeviceDir(0); | ||
| 523 | + MiInsert miData{ | ||
| 524 | + {"OnlyMi", 4, 11.0, 22.0, 11.0}, | ||
| 525 | + }; | ||
| 526 | + WriteMiData(0, miData); | ||
| 527 | + | ||
| 528 | + DataInventory dataInventory; | ||
| 529 | + AicpuProcessor processor(PROF_PATH); | ||
| 530 | + EXPECT_TRUE(processor.Run(dataInventory, PROCESSOR_NAME_AICPU)); | ||
| 531 | + EXPECT_EQ(nullptr, dataInventory.GetPtr<std::vector<AicpuSummaryData>>()); | ||
| 532 | + EXPECT_EQ(nullptr, dataInventory.GetPtr<std::vector<AicpuDpData>>()); | ||
| 533 | + ASSERT_NE(nullptr, dataInventory.GetPtr<std::vector<AicpuMiData>>()); | ||
| 534 | + EXPECT_EQ("OnlyMi", dataInventory.GetPtr<std::vector<AicpuMiData>>()->at(0).nodeName); | ||
| 535 | +} | ||
| 536 | + | ||
| 537 | +TEST_F(AicpuProcessorUTest, ShouldSucceedWhenTablesMissing) | ||
| 538 | +{ | ||
| 539 | + CreateDeviceDir(0); | ||
| 540 | + InsertTable(File::PathJoin({SqlitePath(0), DB_NAME_AI_CPU}), "DummyTable", | ||
| 541 | + TableColumns{{"id", SQL_INTEGER_TYPE}}); | ||
| 542 | + InsertTable(File::PathJoin({SqlitePath(0), DB_NAME_DATA_PREPROCESS}), "DummyTable", | ||
| 543 | + TableColumns{{"id", SQL_INTEGER_TYPE}}); | ||
| 544 | + | ||
| 545 | + DataInventory dataInventory; | ||
| 546 | + AicpuProcessor processor(PROF_PATH); | ||
| 547 | + EXPECT_TRUE(processor.Run(dataInventory, PROCESSOR_NAME_AICPU)); | ||
| 548 | + EXPECT_EQ(nullptr, dataInventory.GetPtr<std::vector<AicpuSummaryData>>()); | ||
| 549 | + EXPECT_EQ(nullptr, dataInventory.GetPtr<std::vector<AicpuDpData>>()); | ||
| 550 | + EXPECT_EQ(nullptr, dataInventory.GetPtr<std::vector<AicpuMiData>>()); | ||
| 551 | +} | ||
| 552 | + | ||
| 553 | +TEST_F(AicpuProcessorUTest, ShouldSucceedWhenNoDeviceDir) | ||
| 554 | +{ | ||
| 555 | + DataInventory dataInventory; | ||
| 556 | + AicpuProcessor processor(PROF_PATH); | ||
| 557 | + EXPECT_TRUE(processor.Run(dataInventory, PROCESSOR_NAME_AICPU)); | ||
| 558 | + EXPECT_EQ(nullptr, dataInventory.GetPtr<std::vector<AicpuSummaryData>>()); | ||
| 559 | +} | ||
| 560 | + | ||
| 561 | +TEST_F(AicpuProcessorUTest, ShouldReturnFalseWhenInvalidDeviceId) | ||
| 562 | +{ | ||
| 563 | + CreateDeviceDir(0); | ||
| 564 | + WriteAiCpuData(0, AiCpuInsert{{1, 1, 1000000.0, 1100000.0, "x", 1.0, 1.0, 0.0, 1.0, 3.0}}); | ||
| 565 | + MOCKER_CPP(&Utils::GetDeviceIdByDevicePath).stubs().will(returnValue(static_cast<uint16_t>(INVALID_DEVICE_ID))); | ||
| 566 | + | ||
| 567 | + DataInventory dataInventory; | ||
| 568 | + AicpuProcessor processor(PROF_PATH); | ||
| 569 | + EXPECT_FALSE(processor.Run(dataInventory, PROCESSOR_NAME_AICPU)); | ||
| 570 | +} | ||
| 571 | + | ||
| 572 | +TEST_F(AicpuProcessorUTest, ShouldReturnFalseWhenGetProfTimeRecordInfoFailed) | ||
| 573 | +{ | ||
| 574 | + CreateDeviceDir(0); | ||
| 575 | + MOCKER_CPP(&Environment::Context::GetProfTimeRecordInfo).stubs().will(returnValue(false)); | ||
| 576 | + | ||
| 577 | + DataInventory dataInventory; | ||
| 578 | + AicpuProcessor processor(PROF_PATH); | ||
| 579 | + EXPECT_FALSE(processor.Run(dataInventory, PROCESSOR_NAME_AICPU)); | ||
| 580 | +} | ||
| 581 | + | ||
| 582 | +TEST_F(AicpuProcessorUTest, ShouldReturnFalseWhenConstructDBRunnerFailed) | ||
| 583 | +{ | ||
| 584 | + CreateDeviceDir(0); | ||
| 585 | + WriteAiCpuData(0, AiCpuInsert{{1, 1, 1000000.0, 1100000.0, "x", 1.0, 1.0, 0.0, 1.0, 3.0}}); | ||
| 586 | + MOCKER_CPP(&DBInfo::ConstructDBRunner).stubs().will(returnValue(false)); | ||
| 587 | + | ||
| 588 | + DataInventory dataInventory; | ||
| 589 | + AicpuProcessor processor(PROF_PATH); | ||
| 590 | + EXPECT_FALSE(processor.Run(dataInventory, PROCESSOR_NAME_AICPU)); | ||
| 591 | +} | ||
| 592 | + | ||
| 593 | +TEST_F(AicpuProcessorUTest, ShouldReturnFalseWhenFileCheckFailed) | ||
| 594 | +{ | ||
| 595 | + CreateDeviceDir(0); | ||
| 596 | + WriteAiCpuData(0, AiCpuInsert{{1, 1, 1000000.0, 1100000.0, "x", 1.0, 1.0, 0.0, 1.0, 3.0}}); | ||
| 597 | + MOCKER_CPP(&FileReader::Check).stubs().will(returnValue(false)); | ||
| 598 | + | ||
| 599 | + DataInventory dataInventory; | ||
| 600 | + AicpuProcessor processor(PROF_PATH); | ||
| 601 | + EXPECT_FALSE(processor.Run(dataInventory, PROCESSOR_NAME_AICPU)); | ||
| 602 | +} | ||
| 603 | + | ||
| 604 | +TEST_F(AicpuProcessorUTest, ShouldReturnFalseWhenSaveToDataInventoryFailed) | ||
| 605 | +{ | ||
| 606 | + CreateDeviceDir(0); | ||
| 607 | + WriteAiCpuData(0, AiCpuInsert{{1, 1, 1000000.0, 1100000.0, "x", 1.0, 1.0, 0.0, 1.0, 3.0}}); | ||
| 608 | + MOCKER_CPP(&DataProcessor::SaveToDataInventory<AicpuSummaryData>).stubs().will(returnValue(false)); | ||
| 609 | + | ||
| 610 | + DataInventory dataInventory; | ||
| 611 | + AicpuProcessor processor(PROF_PATH); | ||
| 612 | + EXPECT_FALSE(processor.Run(dataInventory, PROCESSOR_NAME_AICPU)); | ||
| 613 | +} | ||
| 614 | + | ||
| 615 | +TEST_F(AicpuProcessorUTest, ShouldRegisterAicpuProcessor) | ||
| 616 | +{ | ||
| 617 | + const auto *definition = TopoNodeRegistry::FindProcessorByName(PROCESSOR_NAME_AICPU); | ||
| 618 | + ASSERT_NE(definition, nullptr); | ||
| 619 | + EXPECT_EQ(definition->runtimeType, std::type_index(typeid(AicpuProcessor))); | ||
| 620 | + EXPECT_TRUE(static_cast<bool>(definition->creatorFactory)); | ||
| 621 | +} | ||


[Review] LoadAiCpuData 有 if (data.timestampNs < timeRecord.startTimeNs) 的判断,但 LoadDpData/LoadMiData 没有。导致同一次导出中 aicpu.csv 只覆盖采集窗口,而 dp/aicpu_mi 可能包含窗口前的数据。建议确认这是否符合预期,若需要一致性可补充同样的过滤。