已合并
bugfix:统一db问题修正 #487
wangzixuan创建于 22 天前
bugfix:统一db问题修正 #487
已合并
wangzixuan创建于 22 天前
共 28 个文件变更+480-199
@@ -84,11 +84,11 @@ using CommunicationOpDataFormat =
84 std::vector<std::tuple<uint64_t, uint64_t, uint64_t, uint64_t, uint64_t, int64_t, int32_t, int32_t, uint64_t,84 std::vector<std::tuple<uint64_t, uint64_t, uint64_t, uint64_t, uint64_t, int64_t, int32_t, int32_t, uint64_t,
85 uint64_t, uint64_t, uint64_t, uint16_t, int64_t>>;85 uint64_t, uint64_t, uint64_t, uint16_t, int64_t>>;
86// 小算子数据86// 小算子数据
87-// name, globalTaskId, taskType, planeId, groupName, notifyId, rdmaType, srcRank, dstRank, transportType,87+// timestampNs, name, globalTaskId, taskType, planeId, groupName, notifyId, rdmaType, srcRank, dstRank, transportType,
88// size, dataType, linkType, opId, isMaster, bandwidth88// size, dataType, linkType, opId, isMaster, bandwidth
89using CommunicationTaskDataFormat =89using CommunicationTaskDataFormat =
90- std::vector<std::tuple<uint64_t, uint64_t, uint64_t, uint32_t, uint64_t, uint64_t, uint64_t, int64_t, int64_t,90+ std::vector<std::tuple<uint64_t, uint64_t, uint64_t, uint64_t, uint32_t, uint64_t, uint64_t, uint64_t, int64_t,
91- uint64_t, uint64_t, uint64_t, uint64_t, int64_t, uint16_t, double>>;91+ int64_t, uint64_t, uint64_t, uint64_t, uint64_t, int64_t, uint16_t, double>>;
92 92 
93enum class DevType93enum class DevType
94{94{
@@ -273,9 +273,9 @@ void ConvertTaskData(CommunicationTaskDataFormat& processedTaskData, const std::
273 DataProcessor::GetEnumTypeValue(item.linkType, NAME_STR(HCCL_LINK_TYPE_TABLE), HCCL_LINK_TYPE_TABLE);273 DataProcessor::GetEnumTypeValue(item.linkType, NAME_STR(HCCL_LINK_TYPE_TABLE), HCCL_LINK_TYPE_TABLE);
274 uint32_t assocId =274 uint32_t assocId =
275 IdPool::GetInstance().GetUint32Id(std::to_string(item.opId) + "_" + std::to_string(item.iterId));275 IdPool::GetInstance().GetUint32Id(std::to_string(item.opId) + "_" + std::to_string(item.iterId));
276- processedTaskData.emplace_back(opName, globalTaskId, taskType, item.planeId, groupName, notifyId, rdmaType,276+ processedTaskData.emplace_back(item.timestamp, opName, globalTaskId, taskType, item.planeId, groupName,
277- item.srcRank, item.dstRank, transportType, item.size, dataType, linkType,277+ notifyId, rdmaType, item.srcRank, item.dstRank, transportType, item.size,
278- assocId, item.isMaster,278+ dataType, linkType, assocId, item.isMaster,
279 item.bandwidth * Common::BYTES_PER_GB); // GB/s -> B/s,字节按1024换算279 item.bandwidth * Common::BYTES_PER_GB); // GB/s -> B/s,字节按1024换算
280 }280 }
281}281}
@@ -985,9 +985,9 @@ bool SaveRoCEData(DataInventory& dataInventory, DBInfo& msprofDB, const std::str
985 985 
986bool SaveTaskPmuData(DataInventory& dataInventory, DBInfo& msprofDB, const std::string& profPath)986bool SaveTaskPmuData(DataInventory& dataInventory, DBInfo& msprofDB, const std::string& profPath)
987{987{
988- // UnifiedTaskPMU deviceId, streamId, taskId, subtaskId, batchId, header, value988+ // UnifiedTaskPMU deviceId, streamId, taskId, subtaskId, batchId, header, value, timestamp
989- // ProcessedTaskFormat globalTaskId, header(uint64id), value989+ // ProcessedTaskFormat timestampNs, globalTaskId, header(uint64id), value
990- using PTFormat = std::vector<std::tuple<uint64_t, uint64_t, double>>;990+ using PTFormat = std::vector<std::tuple<uint64_t, uint64_t, uint64_t, double>>;
991 PTFormat res;991 PTFormat res;
992 auto unifiedTaskPmuData = dataInventory.GetPtr<std::vector<UnifiedTaskPmu>>();992 auto unifiedTaskPmuData = dataInventory.GetPtr<std::vector<UnifiedTaskPmu>>();
993 if (unifiedTaskPmuData == nullptr)993 if (unifiedTaskPmuData == nullptr)
@@ -1006,7 +1006,7 @@ bool SaveTaskPmuData(DataInventory& dataInventory, DBInfo& msprofDB, const std::
1006 uint64_t globalTaskId = IdPool::GetInstance().GetId(1006 uint64_t globalTaskId = IdPool::GetInstance().GetId(
1007 std::make_tuple(static_cast<uint16_t>(item.deviceId), item.streamId, item.taskId, item.subtaskId,1007 std::make_tuple(static_cast<uint16_t>(item.deviceId), item.streamId, item.taskId, item.subtaskId,
1008 item.batchId, static_cast<uint32_t>(DevType::NPU)));1008 item.batchId, static_cast<uint32_t>(DevType::NPU)));
1009- res.emplace_back(globalTaskId, IdPool::GetInstance().GetUint64Id(item.header), item.value);1009+ res.emplace_back(item.timestamp, globalTaskId, IdPool::GetInstance().GetUint64Id(item.header), item.value);
1010 }1010 }
1011 return SaveData(res, TABLE_NAME_TASK_PMU_INFO, msprofDB);1011 return SaveData(res, TABLE_NAME_TASK_PMU_INFO, msprofDB);
1012}1012}
@@ -1304,7 +1304,7 @@ bool SaveDPUData(DataInventory& dataInventory, DBInfo& msprofDB, const std::stri
1304 }1304 }
1305 1305 
1306 using DPUTaskFormat = std::vector<1306 using DPUTaskFormat = std::vector<
1307- std::tuple<uint16_t, uint32_t, uint64_t, uint64_t, uint64_t, uint32_t, uint32_t, uint64_t, uint64_t>>;1307+ std::tuple<uint16_t, uint64_t, uint64_t, uint64_t, uint64_t, uint32_t, uint32_t, uint64_t, uint64_t>>;
1308 1308 
1309 DPUTaskFormat res;1309 DPUTaskFormat res;
1310 if (!Reserve(res, dpuData->size()))1310 if (!Reserve(res, dpuData->size()))
@@ -1313,6 +1313,7 @@ bool SaveDPUData(DataInventory& dataInventory, DBInfo& msprofDB, const std::stri
1313 return false;1313 return false;
1314 }1314 }
1315 1315 
1316+ uint32_t pid = Environment::Context::GetInstance().GetPidFromInfoJson(HOST_ID, profPath);
1316 for (const auto& data : *dpuData)1317 for (const auto& data : *dpuData)
1317 {1318 {
1318 uint64_t globalTaskId = IdPool::GetInstance().GetId(std::make_tuple(1319 uint64_t globalTaskId = IdPool::GetInstance().GetId(std::make_tuple(
@@ -1361,8 +1362,8 @@ bool SaveDPUData(DataInventory& dataInventory, DBInfo& msprofDB, const std::stri
1361 jsonWriter.EndArray();1362 jsonWriter.EndArray();
1362 std::string args = jsonWriter.GetString();1363 std::string args = jsonWriter.GetString();
1363 uint64_t argsId = IdPool::GetInstance().GetUint64Id(args);1364 uint64_t argsId = IdPool::GetInstance().GetUint64Id(args);
1364- res.emplace_back(data.dpuDeviceId, data.threadId, data.timestamp, data.endTime, globalTaskId, data.streamId,1365+ res.emplace_back(data.dpuDeviceId, Utils::Contact(pid, data.threadId), data.timestamp, data.endTime,
1365- data.taskId, opNameId, argsId);1366+ globalTaskId, data.streamId, data.taskId, opNameId, argsId);
1366 }1367 }
1367 1368 
1368 return SaveData(res, TABLE_NAME_DPU_TASK, msprofDB);1369 return SaveData(res, TABLE_NAME_DPU_TASK, msprofDB);
@@ -69,12 +69,12 @@ const TableColumns COMMUNICATION_SCHEDULE_TASK_INFO = {{"name", SQL_INTEGER_TYPE
69 {"opType", SQL_INTEGER_TYPE}};69 {"opType", SQL_INTEGER_TYPE}};
70 70 
71const TableColumns COMMUNICATION_TASK_INFO = {71const TableColumns COMMUNICATION_TASK_INFO = {
72- {"name", SQL_INTEGER_TYPE}, {"globalTaskId", SQL_INTEGER_TYPE}, {"taskType", SQL_INTEGER_TYPE},72+ {"timestampNs", SQL_INTEGER_TYPE}, {"name", SQL_INTEGER_TYPE}, {"globalTaskId", SQL_INTEGER_TYPE},
73- {"planeId", SQL_INTEGER_TYPE}, {"groupName", SQL_INTEGER_TYPE}, {"notifyId", SQL_INTEGER_TYPE},73+ {"taskType", SQL_INTEGER_TYPE}, {"planeId", SQL_INTEGER_TYPE}, {"groupName", SQL_INTEGER_TYPE},
74- {"rdmaType", SQL_INTEGER_TYPE}, {"srcRank", SQL_INTEGER_TYPE}, {"dstRank", SQL_INTEGER_TYPE},74+ {"notifyId", SQL_INTEGER_TYPE}, {"rdmaType", SQL_INTEGER_TYPE}, {"srcRank", SQL_INTEGER_TYPE},
75- {"transportType", SQL_INTEGER_TYPE}, {"size", SQL_INTEGER_TYPE}, {"dataType", SQL_INTEGER_TYPE},75+ {"dstRank", SQL_INTEGER_TYPE}, {"transportType", SQL_INTEGER_TYPE}, {"size", SQL_INTEGER_TYPE},
76- {"linkType", SQL_INTEGER_TYPE}, {"opId", SQL_INTEGER_TYPE}, {"isMaster", SQL_INTEGER_TYPE},76+ {"dataType", SQL_INTEGER_TYPE}, {"linkType", SQL_INTEGER_TYPE}, {"opId", SQL_INTEGER_TYPE},
77- {"bandwidth", SQL_NUMERIC_TYPE},77+ {"isMaster", SQL_INTEGER_TYPE}, {"bandwidth", SQL_NUMERIC_TYPE},
78};78};
79 79 
80const TableColumns COMMUNICATION_OP = {80const TableColumns COMMUNICATION_OP = {
@@ -132,8 +132,10 @@ const TableColumns LLC = {
132 {"hitRate", SQL_REAL_TYPE}, {"throughput", SQL_INTEGER_TYPE}, {"mode", SQL_INTEGER_TYPE},132 {"hitRate", SQL_REAL_TYPE}, {"throughput", SQL_INTEGER_TYPE}, {"mode", SQL_INTEGER_TYPE},
133};133};
134 134 
135-const TableColumns TASK_PMU_INFO = {135+const TableColumns TASK_PMU_INFO = {{"timestampNs", SQL_INTEGER_TYPE},
136- {"globalTaskId", SQL_INTEGER_TYPE}, {"name", SQL_INTEGER_TYPE}, {"value", SQL_NUMERIC_TYPE}};136+ {"globalTaskId", SQL_INTEGER_TYPE},
137+ {"name", SQL_INTEGER_TYPE},
138+ {"value", SQL_NUMERIC_TYPE}};
137 139 
138const TableColumns SAMPLE_PMU_TIMELINE = {140const TableColumns SAMPLE_PMU_TIMELINE = {
139 {"deviceId", SQL_INTEGER_TYPE}, {"timestampNs", SQL_INTEGER_TYPE}, {"totalCycle", SQL_INTEGER_TYPE},141 {"deviceId", SQL_INTEGER_TYPE}, {"timestampNs", SQL_INTEGER_TYPE}, {"totalCycle", SQL_INTEGER_TYPE},
@@ -15,6 +15,7 @@
15 * -------------------------------------------------------------------------*/15 * -------------------------------------------------------------------------*/
16#include "analysis/csrc/domain/data_process/ai_task/unified_pmu_processor.h"16#include "analysis/csrc/domain/data_process/ai_task/unified_pmu_processor.h"
17 17 
18+#include <algorithm>
18#include <unordered_set>19#include <unordered_set>
19 20 
20#include "analysis/csrc/application/credential/id_pool.h"21#include "analysis/csrc/application/credential/id_pool.h"
@@ -39,6 +40,10 @@ const std::set<std::string> SAMPLE_BASED_DB_NAMES = {AI_VECTOR_CORE_DB, AI_CORE_
39const std::set<std::string> INVALID_COLUMN_NAMES = {"task_id", "stream_id", "subtask_id", "batch_id", "task_type",40const std::set<std::string> INVALID_COLUMN_NAMES = {"task_id", "stream_id", "subtask_id", "batch_id", "task_type",
40 "start_time", "end_time", "ffts_type", "core_type"};41 "start_time", "end_time", "ffts_type", "core_type"};
41const std::string TASK_BASED = "task-based";42const std::string TASK_BASED = "task-based";
43+// metric_summary 中每算子一行的时间列,不作为 metric 行落盘,仅用于携带到每行 metric 的 timestampNs
44+// 列值由写侧(GetTimeFromSyscnt/time_from_syscnt)换算到 host 开机 monotonic ns,读侧再经 GetLocalTime 转世界时;
45+// C++侧metric_summary_persistence(chipV4)与python侧stars(ffts/chip6)落库的时间列名统一为 end_time
46+const std::string END_TIME_COLUMN_NAME = "end_time";
42const double DOUBLE_ZERO = 0.0;47const double DOUBLE_ZERO = 0.0;
43 48 
44struct TaskPmuData49struct TaskPmuData
@@ -175,12 +180,23 @@ bool UnifiedPmuProcessor::ProcessTaskBasedData(const std::unordered_map<std::str
175 DataInventory &dataInventory)180 DataInventory &dataInventory)
176{181{
177 bool flag = true;182 bool flag = true;
183+ // task-based 场景的 metric_summary 统一带时间列 end_time(C++ chipV4落库与python侧stars落库一致),
184+ // 每个算子一行。GetTaskBasedData 在查 metric 值的同时把该行 end_time 一并查出,FormatTaskBasedData 内
185+ // 按 device 的 ProfTimeRecord 经 GetLocalTime 平移到世界时轴,使每条 metric 行携带所属算子自身的时间,
186+ // 不按算子四元组单独建表 join。若某张表确实缺 end_time 列,查询会直接失败并报错(符合预期)。
178 std::vector<UnifiedTaskPmu> processedData;187 std::vector<UnifiedTaskPmu> processedData;
179 for (const auto &dbPathAndDeviceId : dbPathAndDeviceIds)188 for (const auto &dbPathAndDeviceId : dbPathAndDeviceIds)
180 {189 {
190+ Utils::ProfTimeRecord record;
191+ if (!Context::GetInstance().GetProfTimeRecordInfo(record, profPath_, dbPathAndDeviceId.second))
192+ {
193+ ERROR("GetProfTimeRecordInfo failed, profPath is %, device id is %.", profPath_, dbPathAndDeviceId.second);
194+ flag = false;
195+ continue;
196+ }
181 for (const auto &header : headers)197 for (const auto &header : headers)
182 {198 {
183- if (!ProcessTaskBasedDataByHeader(dbPathAndDeviceId, metricDB, header, processedData))199+ if (!ProcessTaskBasedDataByHeader(dbPathAndDeviceId, metricDB, record, header, processedData))
184 {200 {
185 flag = false;201 flag = false;
186 ERROR("Process task_based data failed, failed device is %", dbPathAndDeviceId.second);202 ERROR("Process task_based data failed, failed device is %", dbPathAndDeviceId.second);
@@ -196,7 +212,8 @@ bool UnifiedPmuProcessor::ProcessTaskBasedData(const std::unordered_map<std::str
196}212}
197 213 
198bool UnifiedPmuProcessor::ProcessTaskBasedDataByHeader(const std::pair<std::string, uint16_t> &dbPathAndDeviceId,214bool UnifiedPmuProcessor::ProcessTaskBasedDataByHeader(const std::pair<std::string, uint16_t> &dbPathAndDeviceId,
199- Analysis::Infra::DBInfo &metricDB, const std::string &header,215+ Analysis::Infra::DBInfo &metricDB,
216+ const Utils::ProfTimeRecord &record, const std::string &header,
200 std::vector<UnifiedTaskPmu> &processedData)217 std::vector<UnifiedTaskPmu> &processedData)
201{218{
202 if (INVALID_COLUMN_NAMES.find(header) != INVALID_COLUMN_NAMES.end())219 if (INVALID_COLUMN_NAMES.find(header) != INVALID_COLUMN_NAMES.end())
@@ -205,7 +222,7 @@ bool UnifiedPmuProcessor::ProcessTaskBasedDataByHeader(const std::pair<std::stri
205 return true;222 return true;
206 }223 }
207 OTFormat pmuData = GetTaskBasedData(dbPathAndDeviceId.first, header, metricDB);224 OTFormat pmuData = GetTaskBasedData(dbPathAndDeviceId.first, header, metricDB);
208- if (!FormatTaskBasedData(pmuData, processedData, header, dbPathAndDeviceId.second))225+ if (!FormatTaskBasedData(pmuData, processedData, header, dbPathAndDeviceId.second, record))
209 {226 {
210 ERROR("FormatData failed, dbPath is %.", dbPathAndDeviceId.first);227 ERROR("FormatData failed, dbPath is %.", dbPathAndDeviceId.first);
211 return false;228 return false;
@@ -235,7 +252,13 @@ UnifiedPmuProcessor::OTFormat UnifiedPmuProcessor::GetTaskBasedData(const std::s
235 subtaskIdSql = "subtask_id, ";252 subtaskIdSql = "subtask_id, ";
236 }253 }
237 std::string sql = "SELECT stream_id, task_id, ";254 std::string sql = "SELECT stream_id, task_id, ";
238- sql.append(subtaskIdSql).append(" batch_id, ").append(columnName).append(" FROM ").append(metricDB.tableName);255+ sql.append(subtaskIdSql)
256+ .append(" batch_id, ")
257+ .append(columnName)
258+ .append(", ")
259+ .append(END_TIME_COLUMN_NAME)
260+ .append(" FROM ")
261+ .append(metricDB.tableName);
239 if (!metricDB.dbRunner->QueryData(sql, oriData))262 if (!metricDB.dbRunner->QueryData(sql, oriData))
240 {263 {
241 ERROR("Query task-based % data failed, db path is %.", columnName, dbPath);264 ERROR("Query task-based % data failed, db path is %.", columnName, dbPath);
@@ -272,7 +295,8 @@ uint64_t UnifiedPmuProcessor::UpdateColumnName(std::string &columnName)
272}295}
273 296 
274bool UnifiedPmuProcessor::FormatTaskBasedData(const OTFormat &oriData, std::vector<UnifiedTaskPmu> &processedData,297bool UnifiedPmuProcessor::FormatTaskBasedData(const OTFormat &oriData, std::vector<UnifiedTaskPmu> &processedData,
275- std::string columnName, const uint16_t &deviceId)298+ std::string columnName, const uint16_t &deviceId,
299+ const Utils::ProfTimeRecord &record)
276{300{
277 INFO("FormatTaskBasedData.");301 INFO("FormatTaskBasedData.");
278 if (oriData.empty())302 if (oriData.empty())
@@ -289,11 +313,20 @@ bool UnifiedPmuProcessor::FormatTaskBasedData(const OTFormat &oriData, std::vect
289 // 1、没有考虑memory_bound或是cube utilization的计算313 // 1、没有考虑memory_bound或是cube utilization的计算
290 auto valueScale = UpdateColumnName(columnName);314 auto valueScale = UpdateColumnName(columnName);
291 TaskPmuData tempData;315 TaskPmuData tempData;
316+ uint64_t endTime = 0;
292 for (const auto &row : oriData)317 for (const auto &row : oriData)
293 {318 {
294- std::tie(tempData.streamId, tempData.taskId, tempData.subtaskId, tempData.batchId, tempData.value) = row;319+ // OTFormat: stream_id, task_id, subtask_id, batch_id, value, end_time
320+ std::tie(tempData.streamId, tempData.taskId, tempData.subtaskId, tempData.batchId, tempData.value, endTime) =
321+ row;
322+ // end_time 列值在写侧(GetTimeFromSyscnt/time_from_syscnt)仅换算到 host 开机 monotonic ns,尚未叠加
323+ // 采集起始的“世界时”偏移。其它上 timeline 的 task/事件行写盘前都经 GetLocalTime 平移(见
324+ // fusion_task_processor 同款注释),此处对每行自身 end_time 补 GetLocalTime 后才与 task 时间对齐;
325+ // 直接从 uint64 构造 HPFloat,避免经 double 丢低位精度
326+ Utils::HPFloat endTimeHP(endTime);
327+ uint64_t timestamp = Utils::GetLocalTime(endTimeHP, record).Uint64();
295 processedData.emplace_back(deviceId, tempData.streamId, tempData.taskId, tempData.subtaskId, tempData.batchId,328 processedData.emplace_back(deviceId, tempData.streamId, tempData.taskId, tempData.subtaskId, tempData.batchId,
296- columnName, tempData.value * valueScale);329+ columnName, tempData.value * valueScale, timestamp);
297 }330 }
298 if (processedData.empty())331 if (processedData.empty())
299 {332 {
@@ -16,52 +16,55 @@
16#ifndef ANALYSIS_DOMAIN_UNIFIED_PMU_PROCESSOR_H16#ifndef ANALYSIS_DOMAIN_UNIFIED_PMU_PROCESSOR_H
17#define ANALYSIS_DOMAIN_UNIFIED_PMU_PROCESSOR_H17#define ANALYSIS_DOMAIN_UNIFIED_PMU_PROCESSOR_H
18 18 
19+#include <tuple>
19 20 
20-#include <map>
21#include "analysis/csrc/domain/data_process/data_processor.h"21#include "analysis/csrc/domain/data_process/data_processor.h"
22-#include "analysis/csrc/domain/valueobject/include/task_id.h"
23#include "analysis/csrc/domain/entities/viewer_data/ai_task/include/unified_pmu_data.h"22#include "analysis/csrc/domain/entities/viewer_data/ai_task/include/unified_pmu_data.h"
23+#include "analysis/csrc/domain/valueobject/include/task_id.h"
24#include "analysis/csrc/infrastructure/utils/time_utils.h"24#include "analysis/csrc/infrastructure/utils/time_utils.h"
25 25 
26-namespace Analysis {26+namespace Analysis
27-namespace Domain {27+{
28+namespace Domain
29+{
28 30 
29-class UnifiedPmuProcessor : public DataProcessor {31+class UnifiedPmuProcessor : public DataProcessor
30-// Original Sample Timeline Format:aicore/ai_vector_core中的AICoreOriginalData32+{
31-// timestamp, task_cyc, coreid33+ // Original Sample Timeline Format:aicore/ai_vector_core中的AICoreOriginalData
32-using OSTFormat = std::vector<std::tuple<uint64_t, std::string, uint32_t>>;34+ // timestamp, task_cyc, coreid
33-// Original Sample Summary Format:aicore/ai_vector_core中的MetricSummary35+ using OSTFormat = std::vector<std::tuple<uint64_t, std::string, uint32_t>>;
34-// metric, value, coreid36+ // Original Sample Summary Format:aicore/ai_vector_core中的MetricSummary
35-using OSSFormat = std::vector<std::tuple<std::string, double, uint32_t>>;37+ // metric, value, coreid
36-// Original Task Format: 只取id + 对应字段的value38+ using OSSFormat = std::vector<std::tuple<std::string, double, uint32_t>>;
37-// stream_id, task_id, subtask_id, batch_id, value39+ // Original Task Format: 只取id + 对应字段的value + 该行的算子时间列end_time
38-using OTFormat = std::vector<std::tuple<uint32_t, uint32_t, uint32_t, uint32_t, double>>;40+ // stream_id, task_id, subtask_id, batch_id, value, end_time(host开机monotonic ns,Format时再GetLocalTime)
41+ using OTFormat = std::vector<std::tuple<uint32_t, uint32_t, uint32_t, uint32_t, double, uint64_t>>;
39 42 
40-public:43+ public:
41 UnifiedPmuProcessor() = default;44 UnifiedPmuProcessor() = default;
42 explicit UnifiedPmuProcessor(const std::string &profPath);45 explicit UnifiedPmuProcessor(const std::string &profPath);
43-private:46+ 
47+ private:
44 bool Process(DataInventory &dataInventory) override;48 bool Process(DataInventory &dataInventory) override;
45 bool TaskBasedProcess(DataInventory &data_inventory);49 bool TaskBasedProcess(DataInventory &data_inventory);
46 bool SampleBasedProcess(DataInventory &data_inventory);50 bool SampleBasedProcess(DataInventory &data_inventory);
47 static std::vector<std::string> GetAndCheckTableColumns(51 static std::vector<std::string> GetAndCheckTableColumns(
48- const std::unordered_map<std::string, uint16_t> &dbPathAndDeviceID, Analysis::Infra::DBInfo &metricDB);52+ const std::unordered_map<std::string, uint16_t> &dbPathAndDeviceID, Analysis::Infra::DBInfo &metricDB);
49 bool TaskBasedProcess(const std::string &fileDir);53 bool TaskBasedProcess(const std::string &fileDir);
50 bool ProcessTaskBasedData(const std::unordered_map<std::string, uint16_t> &dbPathAndDeviceId,54 bool ProcessTaskBasedData(const std::unordered_map<std::string, uint16_t> &dbPathAndDeviceId,
51- Analysis::Infra::DBInfo &metricDB, std::vector<std::string> &headers,55+ Analysis::Infra::DBInfo &metricDB, std::vector<std::string> &headers,
52- DataInventory &dataInventory);56+ DataInventory &dataInventory);
53 bool ProcessTaskBasedDataByHeader(const std::pair<std::string, uint16_t> &dbPathAndDeviceId,57 bool ProcessTaskBasedDataByHeader(const std::pair<std::string, uint16_t> &dbPathAndDeviceId,
54- Analysis::Infra::DBInfo &metricDB, const std::string &header,58+ Analysis::Infra::DBInfo &metricDB, const Utils::ProfTimeRecord &record,
55- std::vector<UnifiedTaskPmu> &processedData);59+ const std::string &header, std::vector<UnifiedTaskPmu> &processedData);
56 UnifiedPmuProcessor::OTFormat GetTaskBasedData(const std::string &dbPath, const std::string &columnName,60 UnifiedPmuProcessor::OTFormat GetTaskBasedData(const std::string &dbPath, const std::string &columnName,
57- DBInfo &metricDB);61+ DBInfo &metricDB);
58 static uint64_t UpdateColumnName(std::string &columnName);62 static uint64_t UpdateColumnName(std::string &columnName);
59 bool FormatTaskBasedData(const OTFormat &oriData, std::vector<UnifiedTaskPmu> &processedData,63 bool FormatTaskBasedData(const OTFormat &oriData, std::vector<UnifiedTaskPmu> &processedData,
60- std::string columnName, const uint16_t &deviceId);64+ std::string columnName, const uint16_t &deviceId, const Utils::ProfTimeRecord &record);
61 bool SampleBasedProcess(const std::string &fileDir);65 bool SampleBasedProcess(const std::string &fileDir);
62- bool SampleBasedTimelineProcess(66+ bool SampleBasedTimelineProcess(const std::unordered_map<std::string, std::tuple<uint16_t, uint64_t>> &dbPathTable,
63- const std::unordered_map<std::string, std::tuple<uint16_t, uint64_t>> &dbPathTable,67+ DataInventory &dataInventory);
64- DataInventory &dataInventory);
65 UnifiedPmuProcessor::OSTFormat GetSampleBasedTimelineData(const std::string &dbPath);68 UnifiedPmuProcessor::OSTFormat GetSampleBasedTimelineData(const std::string &dbPath);
66 bool FormatSampleBasedTimelineData(const OSTFormat &oriData, std::vector<UnifiedSampleTimelinePmu> &processedData,69 bool FormatSampleBasedTimelineData(const OSTFormat &oriData, std::vector<UnifiedSampleTimelinePmu> &processedData,
67 const Utils::LocaltimeContext &localtimeContext, const double freq,70 const Utils::LocaltimeContext &localtimeContext, const double freq,
@@ -73,7 +76,7 @@ private:
73 const uint16_t deviceId, const uint64_t coreType);76 const uint16_t deviceId, const uint64_t coreType);
74};77};
75 78 
76-} // Domain79+} // namespace Domain
77-} // Analysis80+} // namespace Analysis
78 81 
79-#endif // ANALYSIS_DOMAIN_UNIFIED_PMU_PROCESSOR_H82+#endif // ANALYSIS_DOMAIN_UNIFIED_PMU_PROCESSOR_H
@@ -19,24 +19,32 @@
19 19 
20#include <cstdint>20#include <cstdint>
21#include <vector>21#include <vector>
22+ 
22#include "analysis/csrc/domain/entities/hal/include/hal.h"23#include "analysis/csrc/domain/entities/hal/include/hal.h"
23#include "analysis/csrc/domain/entities/metric/include/metric.h"24#include "analysis/csrc/domain/entities/metric/include/metric.h"
24 25 
25-namespace Analysis {26+namespace Analysis
26-namespace Domain {27+{
28+namespace Domain
29+{
27 30 
28-struct PmuBaseInfo {31+struct PmuBaseInfo
32+{
29 AcceleratorType type = INVALID;33 AcceleratorType type = INVALID;
34+ // 关联的 context PMU 时间,由 context 侧 syscnt 换算后的 wall-clock 时间(ns)
35+ uint64_t timestamp = 0;
30 virtual ~PmuBaseInfo() = default;36 virtual ~PmuBaseInfo() = default;
31};37};
32 38 
33-struct PmuInfoSingleAccelerator : public PmuBaseInfo {39+struct PmuInfoSingleAccelerator : public PmuBaseInfo
40+{
34 double totalTime = 0;41 double totalTime = 0;
35 uint64_t totalCycles = 0;42 uint64_t totalCycles = 0;
36 std::vector<double> pmuResult;43 std::vector<double> pmuResult;
37};44};
38 45 
39-struct PmuInfoMixAccelerator : public PmuBaseInfo {46+struct PmuInfoMixAccelerator : public PmuBaseInfo
47+{
40 uint32_t totalBlockCount = 0;48 uint32_t totalBlockCount = 0;
41 uint64_t mainTimestamp = 0;49 uint64_t mainTimestamp = 0;
42 double aiCoreTime = 0;50 double aiCoreTime = 0;
@@ -46,6 +54,6 @@ struct PmuInfoMixAccelerator : public PmuBaseInfo {
46 std::vector<double> aicPmuResult;54 std::vector<double> aicPmuResult;
47 std::vector<double> aivPmuResult;55 std::vector<double> aivPmuResult;
48};56};
49-}57+} // namespace Domain
50-}58+} // namespace Analysis
51-#endif // MSPROF_ANALYSIS_PMU_INFO_H59+#endif // MSPROF_ANALYSIS_PMU_INFO_H
@@ -21,12 +21,16 @@
21#include <string>21#include <string>
22#include <utility>22#include <utility>
23#include <vector>23#include <vector>
24-#include "analysis/csrc/domain/valueobject/include/task_id.h"
25-#include "analysis/csrc/domain/entities/viewer_data/basic_data.h"
26 24 
27-namespace Analysis {25+#include "analysis/csrc/domain/entities/viewer_data/basic_data.h"
28-namespace Domain {26+#include "analysis/csrc/domain/valueobject/include/task_id.h"
29-struct UnifiedTaskPmu {27+ 
28+namespace Analysis
29+{
30+namespace Domain
31+{
32+struct UnifiedTaskPmu
33+{
30 uint16_t deviceId = UINT16_MAX;34 uint16_t deviceId = UINT16_MAX;
31 uint32_t streamId = UINT32_MAX;35 uint32_t streamId = UINT32_MAX;
32 uint32_t taskId = UINT32_MAX;36 uint32_t taskId = UINT32_MAX;
@@ -34,15 +38,24 @@ struct UnifiedTaskPmu {
34 uint32_t batchId = UINT32_MAX;38 uint32_t batchId = UINT32_MAX;
35 double value = 0.0;39 double value = 0.0;
36 std::string header;40 std::string header;
41+ // 算子 context PMU 时间,换算后的 wall-clock ns,随每行 metric 重复落盘到 TASK_PMU_INFO.timestampNs
42+ uint64_t timestamp = 0;
37 43 
38 UnifiedTaskPmu() = default;44 UnifiedTaskPmu() = default;
39 UnifiedTaskPmu(uint16_t deviceId_, uint32_t streamId_, uint32_t taskId_, uint32_t subtaskId_, uint32_t batchId_,45 UnifiedTaskPmu(uint16_t deviceId_, uint32_t streamId_, uint32_t taskId_, uint32_t subtaskId_, uint32_t batchId_,
40- std::string header_, double value_) : deviceId(deviceId_), streamId(streamId_),46+ std::string header_, double value_, uint64_t timestamp_ = 0)
41- taskId(taskId_), subtaskId(subtaskId_), batchId(batchId_),47+ : deviceId(deviceId_),
42- header(std::move(header_)), value(value_) {};48+ streamId(streamId_),
49+ taskId(taskId_),
50+ subtaskId(subtaskId_),
51+ batchId(batchId_),
52+ header(std::move(header_)),
53+ value(value_),
54+ timestamp(timestamp_) {};
43};55};
44 56 
45-struct UnifiedSampleTimelinePmu : public BasicData {57+struct UnifiedSampleTimelinePmu : public BasicData
58+{
46 uint16_t deviceId = UINT16_MAX;59 uint16_t deviceId = UINT16_MAX;
47 uint16_t coreId = UINT16_MAX;60 uint16_t coreId = UINT16_MAX;
48 double usage = 0.0;61 double usage = 0.0;
@@ -51,13 +64,19 @@ struct UnifiedSampleTimelinePmu : public BasicData {
51 uint64_t coreType = UINT64_MAX;64 uint64_t coreType = UINT64_MAX;
52 65 
53 UnifiedSampleTimelinePmu() = default;66 UnifiedSampleTimelinePmu() = default;
54- UnifiedSampleTimelinePmu(uint16_t deviceId_, uint64_t timestamp_, uint64_t totalCycle_, double usage_,67+ UnifiedSampleTimelinePmu(uint16_t deviceId_, uint64_t timestamp_, uint64_t totalCycle_, double usage_, double freq_,
55- double freq_, uint16_t coreId_, uint64_t coreType_)68+ uint16_t coreId_, uint64_t coreType_)
56- : BasicData(timestamp_), deviceId(deviceId_), totalCycle(totalCycle_), usage(usage_),69+ : BasicData(timestamp_),
57- freq(freq_), coreId(coreId_), coreType(coreType_) {};70+ deviceId(deviceId_),
71+ totalCycle(totalCycle_),
72+ usage(usage_),
73+ freq(freq_),
74+ coreId(coreId_),
75+ coreType(coreType_) {};
58};76};
59 77 
60-struct UnifiedSampleSummaryPmu {78+struct UnifiedSampleSummaryPmu
79+{
61 uint16_t deviceId = UINT16_MAX;80 uint16_t deviceId = UINT16_MAX;
62 uint16_t coreId = UINT16_MAX;81 uint16_t coreId = UINT16_MAX;
63 double value = 0.0;82 double value = 0.0;
@@ -66,9 +85,9 @@ struct UnifiedSampleSummaryPmu {
66 85 
67 UnifiedSampleSummaryPmu() = default;86 UnifiedSampleSummaryPmu() = default;
68 UnifiedSampleSummaryPmu(uint16_t deviceId_, std::string metric_, double value_, uint16_t coreId_,87 UnifiedSampleSummaryPmu(uint16_t deviceId_, std::string metric_, double value_, uint16_t coreId_,
69- uint64_t coreType_) : deviceId(deviceId_), metric(std::move(metric_)),88+ uint64_t coreType_)
70- value(value_), coreId(coreId_), coreType(coreType_) {};89+ : deviceId(deviceId_), metric(std::move(metric_)), value(value_), coreId(coreId_), coreType(coreType_) {};
71};90};
72-}91+} // namespace Domain
73-}92+} // namespace Analysis
74-#endif // MSPROF_ANALYSIS_UNIFIED_PMU_DATA_H93+#endif // MSPROF_ANALYSIS_UNIFIED_PMU_DATA_H
@@ -42,7 +42,6 @@ namespace
42const uint64_t DEFAULT_MODEL_ID = UINT32_MAX;42const uint64_t DEFAULT_MODEL_ID = UINT32_MAX;
43const int32_t DEFAULT_INDEX_ID = -1;43const int32_t DEFAULT_INDEX_ID = -1;
44const int64_t DEFAULT_CONNECTION_ID = -1;44const int64_t DEFAULT_CONNECTION_ID = -1;
45-const uint64_t MILLI_SECOND = 1000;
46const std::unordered_map<uint32_t, std::string> deviceTaskAcsqTypeMap{45const std::unordered_map<uint32_t, std::string> deviceTaskAcsqTypeMap{
47 {0, "AI_CORE"}, {1, "AI_CPU"}, {2, "AIV_SQE"}, {3, "PLACE_HOLDER_SQE"},46 {0, "AI_CORE"}, {1, "AI_CPU"}, {2, "AIV_SQE"}, {3, "PLACE_HOLDER_SQE"},
48 {4, "EVENT_RECORD_SQE"}, {5, "EVENT_WAIT_SQE"}, {6, "NOTIFY_RECORD_SQE"}, {7, "NOTIFY_WAIT_SQE"},47 {4, "EVENT_RECORD_SQE"}, {5, "EVENT_WAIT_SQE"}, {6, "NOTIFY_RECORD_SQE"}, {7, "NOTIFY_WAIT_SQE"},
@@ -66,28 +65,6 @@ const std::unordered_map<uint32_t, std::string> deviceTaskFftsPlusTypeMap{{0, "A
66 {13, "Load Context"},65 {13, "Load Context"},
67 {15, "DSA"}};66 {15, "DSA"}};
68 67 
69-SyscntConversionParams GetSyscntConversionParams(const DeviceContext& context)
70-{
71- CpuInfo cpuInfo;
72- context.Getter(cpuInfo);
73- HostStartLog hostStartLog;
74- context.Getter(hostStartLog);
75- uint64_t hostMonotonic = hostStartLog.clockMonotonicRaw;
76- DeviceInfo deviceInfo;
77- context.Getter(deviceInfo);
78- DeviceStartLog deviceStartLog;
79- context.Getter(deviceStartLog);
80- if (!IsDoubleEqual(cpuInfo.frequency, 0.0) && hostStartLog.cntVctDiff)
81- {
82- uint64_t diffTime = static_cast<uint64_t>(hostStartLog.cntVctDiff * MILLI_SECOND / cpuInfo.frequency);
83- if (UINT64_MAX - hostStartLog.clockMonotonicRaw >= diffTime)
84- {
85- hostMonotonic = hostStartLog.clockMonotonicRaw + diffTime;
86- }
87- }
88- SyscntConversionParams params{deviceInfo.hwtsFrequency, deviceStartLog.cntVct, hostMonotonic};
89- return params;
90-}
91} // namespace68} // namespace
92 69 
93std::string GetDeviceTaskTypeStr(const DeviceTask& task)70std::string GetDeviceTaskTypeStr(const DeviceTask& task)
@@ -224,7 +201,7 @@ void FillDeviceTaskStreamId(std::shared_ptr<HostStreamInfo> streamIdInfo,
224uint32_t AscendTaskAssociation::ProcessEntry(DataInventory& dataInventory, const Context& context)201uint32_t AscendTaskAssociation::ProcessEntry(DataInventory& dataInventory, const Context& context)
225{202{
226 const DeviceContext& deviceContext = static_cast<const DeviceContext&>(context);203 const DeviceContext& deviceContext = static_cast<const DeviceContext&>(context);
227- auto params = GetSyscntConversionParams(deviceContext);204+ auto params = deviceContext.GetSyscntConversionParams();
228 auto hostTasks = dataInventory.GetPtr<std::map<TaskId, std::vector<HostTask>>>();205 auto hostTasks = dataInventory.GetPtr<std::map<TaskId, std::vector<HostTask>>>();
229 auto deviceTasks = dataInventory.GetPtr<std::map<TaskId, std::vector<DeviceTask>>>();206 auto deviceTasks = dataInventory.GetPtr<std::map<TaskId, std::vector<DeviceTask>>>();
230 if (deviceContext.isChipV6())207 if (deviceContext.isChipV6())
@@ -24,6 +24,7 @@
24#include "analysis/csrc/domain/entities/hal/include/hal_pmu.h"24#include "analysis/csrc/domain/entities/hal/include/hal_pmu.h"
25#include "analysis/csrc/domain/services/association/calculator/include/metric_calculator_factory.h"25#include "analysis/csrc/domain/services/association/calculator/include/metric_calculator_factory.h"
26#include "analysis/csrc/infrastructure/process/include/process.h"26#include "analysis/csrc/infrastructure/process/include/process.h"
27+#include "analysis/csrc/infrastructure/utils/time_utils.h"
27 28 
28namespace Analysis29namespace Analysis
29{30{
@@ -51,6 +52,8 @@ class PmuAssociation : public Process
51 std::map<TaskId, std::vector<HalPmuData*>> blockPmuTask_;52 std::map<TaskId, std::vector<HalPmuData*>> blockPmuTask_;
52 std::unique_ptr<MetricCalculator> aicCalculator_;53 std::unique_ptr<MetricCalculator> aicCalculator_;
53 std::unique_ptr<MetricCalculator> aivCalculator_;54 std::unique_ptr<MetricCalculator> aivCalculator_;
55+ // context侧 syscnt 转 wall-clock 的换算参数,ProcessEntry 中按 deviceContext 计算一次
56+ Analysis::Utils::SyscntConversionParams syscntParams_;
54};57};
55} // namespace Domain58} // namespace Domain
56} // namespace Analysis59} // namespace Analysis
@@ -152,6 +152,8 @@ void PmuAssociation::CalculateContextPmu(HalPmuData& pmuData, DeviceTask& task,
152{152{
153 task.acceleratorType = pmuData.pmu.acceleratorType;153 task.acceleratorType = pmuData.pmu.acceleratorType;
154 CalculationElements params;154 CalculationElements params;
155+ // 始终取 context 侧 PMU 时间(hd.timestamp),换算成 wall-clock ns 后随 pmuInfo 供下游落盘
156+ uint64_t contextTimeNs = GetTimeFromSyscnt(pmuData.hd.timestamp, syscntParams_).Uint64();
155 if (task.acceleratorType == MIX_AIC || task.acceleratorType == MIX_AIV)157 if (task.acceleratorType == MIX_AIC || task.acceleratorType == MIX_AIV)
156 {158 {
157 PmuInfoMixAccelerator pmuInfoMix;159 PmuInfoMixAccelerator pmuInfoMix;
@@ -170,6 +172,7 @@ void PmuAssociation::CalculateContextPmu(HalPmuData& pmuData, DeviceTask& task,
170 pmuInfoMix.aivTime = params.totalTime;172 pmuInfoMix.aivTime = params.totalTime;
171 }173 }
172 pmuInfoMix.mainTimestamp = pmuData.pmu.timeList[1];174 pmuInfoMix.mainTimestamp = pmuData.pmu.timeList[1];
175+ pmuInfoMix.timestamp = contextTimeNs;
173 task.pmuInfo = MAKE_UNIQUE_PTR<PmuInfoMixAccelerator>(pmuInfoMix);176 task.pmuInfo = MAKE_UNIQUE_PTR<PmuInfoMixAccelerator>(pmuInfoMix);
174 }177 }
175 else178 else
@@ -187,6 +190,7 @@ void PmuAssociation::CalculateContextPmu(HalPmuData& pmuData, DeviceTask& task,
187 }190 }
188 pmuInfoNormal.totalTime = params.totalTime;191 pmuInfoNormal.totalTime = params.totalTime;
189 pmuInfoNormal.pmuResult.swap(res);192 pmuInfoNormal.pmuResult.swap(res);
193+ pmuInfoNormal.timestamp = contextTimeNs;
190 task.pmuInfo = MAKE_UNIQUE_PTR<PmuInfoSingleAccelerator>(pmuInfoNormal);194 task.pmuInfo = MAKE_UNIQUE_PTR<PmuInfoSingleAccelerator>(pmuInfoNormal);
191 }195 }
192}196}
@@ -196,6 +200,8 @@ void PmuAssociation::CalculateContextPmuV6(HalPmuData& pmuData, DeviceTask& task
196{200{
197 task.acceleratorType = pmuData.pmu.acceleratorType;201 task.acceleratorType = pmuData.pmu.acceleratorType;
198 CalculationElements params;202 CalculationElements params;
203+ // 始终取 context 侧 PMU 时间(hd.timestamp),换算成 wall-clock ns 后随 pmuInfo 供下游落盘
204+ uint64_t contextTimeNs = GetTimeFromSyscnt(pmuData.hd.timestamp, syscntParams_).Uint64();
199 if (task.acceleratorType == MIX_AIC || task.acceleratorType == MIX_AIV)205 if (task.acceleratorType == MIX_AIC || task.acceleratorType == MIX_AIV)
200 {206 {
201 // mix场景:同一task有两个PMU(AIC+AIV),需要合并而非覆盖207 // mix场景:同一task有两个PMU(AIC+AIV),需要合并而非覆盖
@@ -240,6 +246,7 @@ void PmuAssociation::CalculateContextPmuV6(HalPmuData& pmuData, DeviceTask& task
240 }246 }
241 }247 }
242 pmuInfoMix.mainTimestamp = pmuData.pmu.timeList[1];248 pmuInfoMix.mainTimestamp = pmuData.pmu.timeList[1];
249+ pmuInfoMix.timestamp = contextTimeNs;
243 task.pmuInfo = MAKE_UNIQUE_PTR<PmuInfoMixAccelerator>(pmuInfoMix);250 task.pmuInfo = MAKE_UNIQUE_PTR<PmuInfoMixAccelerator>(pmuInfoMix);
244 }251 }
245 else252 else
@@ -259,6 +266,7 @@ void PmuAssociation::CalculateContextPmuV6(HalPmuData& pmuData, DeviceTask& task
259 }266 }
260 pmuInfoNormal.totalTime = params.totalTime;267 pmuInfoNormal.totalTime = params.totalTime;
261 pmuInfoNormal.pmuResult.swap(res);268 pmuInfoNormal.pmuResult.swap(res);
269+ pmuInfoNormal.timestamp = contextTimeNs;
262 task.pmuInfo = MAKE_UNIQUE_PTR<PmuInfoSingleAccelerator>(pmuInfoNormal);270 task.pmuInfo = MAKE_UNIQUE_PTR<PmuInfoSingleAccelerator>(pmuInfoNormal);
263 }271 }
264}272}
@@ -438,6 +446,7 @@ uint32_t PmuAssociation::ProcessEntry(Infra::DataInventory& dataInventory, const
438 }446 }
439 }447 }
440 }448 }
449+ syscntParams_ = deviceContext.GetSyscntConversionParams();
441 SplitPmu(*pmuData);450 SplitPmu(*pmuData);
442 if (deviceContext.GetChipID() != CHIP_V4_1_0)451 if (deviceContext.GetChipID() != CHIP_V4_1_0)
443 {452 {
@@ -22,6 +22,8 @@
22#include "analysis/csrc/infrastructure/context/include/context.h"22#include "analysis/csrc/infrastructure/context/include/context.h"
23#include "analysis/csrc/infrastructure/data_inventory/include/data_inventory.h"23#include "analysis/csrc/infrastructure/data_inventory/include/data_inventory.h"
24#include "analysis/csrc/infrastructure/resource/chip_id.h"24#include "analysis/csrc/infrastructure/resource/chip_id.h"
25+#include "analysis/csrc/infrastructure/utils/time_utils.h"
26+#include "analysis/csrc/infrastructure/utils/utils.h"
25 27 
26namespace Analysis28namespace Analysis
27{29{
@@ -196,6 +198,27 @@ class DeviceContext : public Infra::Context
196 198 
197 std::string GetDeviceFilePath() const { return this->deviceContextInfo.deviceFilePath; }199 std::string GetDeviceFilePath() const { return this->deviceContextInfo.deviceFilePath; }
198 200 
201+ // 获取 syscnt 转 wall-clock 所需的换算参数,源数据取自本 context 已加载的 host/device 启动日志
202+ // 内联实现以复用宿主数据的换算逻辑,避免各调用侧重复定义相同换算代码
203+ Analysis::Utils::SyscntConversionParams GetSyscntConversionParams() const
xfeng
xfengxfeng17 天前

[review] [建议] [代码冗余] 问题:GetSyscntConversionParams 与 persistence_utils.cpp 中已有实现功能完全一致,存在重复定义。 修改建议:仅保留一份实现,删除重复函数,避免逻辑散落在多处,降低后续维护成本。

likedislike
wangzixuan
17 天前 评论:
204+ {
205+ uint64_t hostMonotonic = deviceContextInfo.hostStartLog.clockMonotonicRaw;
206+ // host侧高频计数导致 host 单调时钟与实际开机时长存在偏差,用 cntVctDiff 校正
207+ if (!Analysis::Utils::IsDoubleEqual(deviceContextInfo.cpuInfo.frequency, 0.0) &&
208+ deviceContextInfo.hostStartLog.cntVctDiff)
209+ {
210+ uint64_t diffTime =
211+ static_cast<uint64_t>(deviceContextInfo.hostStartLog.cntVctDiff * Analysis::Common::MILLI_SECOND /
212+ deviceContextInfo.cpuInfo.frequency);
213+ if (UINT64_MAX - deviceContextInfo.hostStartLog.clockMonotonicRaw >= diffTime)
214+ {
215+ hostMonotonic = deviceContextInfo.hostStartLog.clockMonotonicRaw + diffTime;
216+ }
217+ }
218+ return Analysis::Utils::SyscntConversionParams(deviceContextInfo.deviceInfo.hwtsFrequency,
219+ deviceContextInfo.deviceStart.cntVct, hostMonotonic);
220+ }
221+ 
199 const std::string &GetDfxStopAtName() const override { return deviceContextInfo.dfxInfo.stopAt; }222 const std::string &GetDfxStopAtName() const override { return deviceContextInfo.dfxInfo.stopAt; }
200 223 
201 bool Init(const std::string &devicePath);224 bool Init(const std::string &devicePath);
@@ -22,7 +22,6 @@
22#include "analysis/csrc/domain/services/device_context/device_context.h"22#include "analysis/csrc/domain/services/device_context/device_context.h"
23#include "analysis/csrc/domain/services/parser/parser_item/qos_parser_item.h"23#include "analysis/csrc/domain/services/parser/parser_item/qos_parser_item.h"
24#include "analysis/csrc/domain/services/parser/parser_item_factory.h"24#include "analysis/csrc/domain/services/parser/parser_item_factory.h"
25-#include "analysis/csrc/domain/services/persistence/device/persistence_utils.h"
26#include "analysis/csrc/infrastructure/dfx/error_code.h"25#include "analysis/csrc/infrastructure/dfx/error_code.h"
27#include "analysis/csrc/infrastructure/process/include/process_register.h"26#include "analysis/csrc/infrastructure/process/include/process_register.h"
28#include "analysis/csrc/infrastructure/resource/binary_struct_info.h"27#include "analysis/csrc/infrastructure/resource/binary_struct_info.h"
@@ -56,7 +55,7 @@ bool QosParserBase::ParseDataItem(uint8_t *binaryData,
56uint32_t QosParserBase::ParseData(Infra::DataInventory &dataInventory, const Infra::Context &context)55uint32_t QosParserBase::ParseData(Infra::DataInventory &dataInventory, const Infra::Context &context)
57{56{
58 const DeviceContext &deviceContext = static_cast<const DeviceContext &>(context);57 const DeviceContext &deviceContext = static_cast<const DeviceContext &>(context);
59- const Utils::SyscntConversionParams timeParams = GenerateSyscntConversionParams(deviceContext);58+ const Utils::SyscntConversionParams timeParams = deviceContext.GetSyscntConversionParams();
60 const size_t recordCount = binaryDataSize / Analysis::QOS_STRUCT_SIZE;59 const size_t recordCount = binaryDataSize / Analysis::QOS_STRUCT_SIZE;
61 const size_t remainingBytes = binaryDataSize % Analysis::QOS_STRUCT_SIZE;60 const size_t remainingBytes = binaryDataSize % Analysis::QOS_STRUCT_SIZE;
62 if (remainingBytes != 0)61 if (remainingBytes != 0)
@@ -36,7 +36,7 @@ using ProcessedDataFormat = std::vector<std::tuple<uint16_t, uint64_t, uint64_t,
36 36 
37ProcessedDataFormat GenerateAccPmuData(std::vector<HalLogData>& logData, const DeviceContext& context)37ProcessedDataFormat GenerateAccPmuData(std::vector<HalLogData>& logData, const DeviceContext& context)
38{38{
39- auto params = GenerateSyscntConversionParams(context);39+ auto params = context.GetSyscntConversionParams();
40 ProcessedDataFormat processedData;40 ProcessedDataFormat processedData;
41 for (auto& data : logData)41 for (auto& data : logData)
42 {42 {
@@ -40,29 +40,6 @@ namespace
40{40{
41static const std::string MI_NAME = "GetNext_dequeue_wait";41static const std::string MI_NAME = "GetNext_dequeue_wait";
42static const std::string EMPTY_NAME;42static const std::string EMPTY_NAME;
43-SyscntConversionParams GetSyscntConversionParams(const DeviceContext& context)
44-{
45- CpuInfo cpuInfo;
46- context.Getter(cpuInfo);
47- HostStartLog hostStartLog;
48- context.Getter(hostStartLog);
49- uint64_t hostMonotonic = hostStartLog.clockMonotonicRaw;
50- DeviceInfo deviceInfo;
51- context.Getter(deviceInfo);
52- DeviceStartLog deviceStartLog;
53- context.Getter(deviceStartLog);
54- if (!IsDoubleEqual(cpuInfo.frequency, 0.0) && hostStartLog.cntVctDiff)
55- {
56- uint64_t diffTime = static_cast<uint64_t>(hostStartLog.cntVctDiff * MILLI_SECOND / cpuInfo.frequency);
57- if (UINT64_MAX - hostStartLog.clockMonotonicRaw >= diffTime)
58- {
59- hostMonotonic = hostStartLog.clockMonotonicRaw + diffTime;
60- }
61- }
62- SyscntConversionParams params{deviceInfo.hwtsFrequency, deviceStartLog.cntVct, hostMonotonic};
63- return params;
64-}
65- 
66// stream_id, task_id, sys_start, sys_end, node_name, compute_time, memcpy_time, task_time, dispatch_time, total_time43// stream_id, task_id, sys_start, sys_end, node_name, compute_time, memcpy_time, task_time, dispatch_time, total_time
67// 时间列全部为 ns;compute/memcpy/dispatch 的 payload 为 us,乘 1000 转 ns44// 时间列全部为 ns;compute/memcpy/dispatch 的 payload 为 us,乘 1000 转 ns
68using NodeFormat =45using NodeFormat =
@@ -767,7 +744,7 @@ uint32_t AicpuPersistence::ProcessEntry(DataInventory& dataInventory, const Cont
767 ERROR("There is no aicpu data, don't need to persistence");744 ERROR("There is no aicpu data, don't need to persistence");
768 return ANALYSIS_ERROR;745 return ANALYSIS_ERROR;
769 }746 }
770- params_ = GetSyscntConversionParams(deviceContext);747+ params_ = deviceContext.GetSyscntConversionParams();
771 hostStreamInfo_ = *hostStreamInfo;748 hostStreamInfo_ = *hostStreamInfo;
772 deviceStreamInfo_ = *deviceStreamInfo;749 deviceStreamInfo_ = *deviceStreamInfo;
773 geHashMap_ = *geHashMap;750 geHashMap_ = *geHashMap;
@@ -68,7 +68,7 @@ bool GenerateLowPowerData(const std::vector<HalSocProfileData>& source, const De
68 ERROR("Reserve for LowPower persistence data failed");68 ERROR("Reserve for LowPower persistence data failed");
69 return false;69 return false;
70 }70 }
71- const auto params = GenerateSyscntConversionParams(context);71+ const auto params = context.GetSyscntConversionParams();
72 for (const auto& item : source)72 for (const auto& item : source)
73 {73 {
74 if (item.type != SOC_PROFILE_LOW_POWER)74 if (item.type != SOC_PROFILE_LOW_POWER)
@@ -89,6 +89,10 @@ bool MetricSummaryPersistence::BindAndExecuteInsert(std::unordered_map<PmuHeader
89 {89 {
90 sqlite3_bind_double(stmt_, ++index, value);90 sqlite3_bind_double(stmt_, ++index, value);
91 }91 }
92+ for (auto& value : ids[PMU_TIMESTAMP])
93+ {
94+ sqlite3_bind_int64(stmt_, ++index, value);
95+ }
92 auto rc = sqlite3_step(stmt_);96 auto rc = sqlite3_step(stmt_);
93 if (rc != SQLITE_DONE)97 if (rc != SQLITE_DONE)
94 {98 {
@@ -158,6 +162,8 @@ bool MetricSummaryPersistence::ConstructData(std::unordered_map<PmuHeaderType, s
158 {162 {
159 return false;163 return false;
160 }164 }
165+ // end_time列绑定在表末尾,此处对齐追加,值为context PMU时间换算后的wall-clock ns
166+ ids[PMU_TIMESTAMP].push_back(task.pmuInfo->timestamp);
161 return true;167 return true;
162}168}
163 169 
@@ -192,6 +198,8 @@ TableColumns MetricSummaryPersistence::GetTableColumn(const DeviceContext& conte
192 {198 {
193 res.emplace_back((AIV_PREFIX + str), SQL_NUMERIC_TYPE);199 res.emplace_back((AIV_PREFIX + str), SQL_NUMERIC_TYPE);
194 }200 }
201+ // 附加列放到最后,避免影响原有字段顺序;列名统一为end_time,与python侧stars落库列名保持一致
202+ res.emplace_back("end_time", SQL_INTEGER_TYPE);
195 }203 }
196 return res;204 return res;
197}205}
@@ -314,7 +322,7 @@ uint32_t MetricSummaryPersistence::SaveV6BlockPmuData(DataInventory& dataInvento
314 ERROR("Hal pmu data is null.");322 ERROR("Hal pmu data is null.");
315 return ANALYSIS_ERROR;323 return ANALYSIS_ERROR;
316 }324 }
317- const auto params = GenerateSyscntConversionParams(deviceContext);325+ const auto params = deviceContext.GetSyscntConversionParams();
318 if (IsDoubleEqual(params.freq, 0.0))326 if (IsDoubleEqual(params.freq, 0.0))
319 {327 {
320 ERROR("Invalid hwts frequency %, skip saving V6BlockPmu.", params.freq);328 ERROR("Invalid hwts frequency %, skip saving V6BlockPmu.", params.freq);
@@ -36,7 +36,8 @@ enum PmuHeaderType
36 AIC_PMU_RESULT,36 AIC_PMU_RESULT,
37 AIV_TOTAL_CYCLE,37 AIV_TOTAL_CYCLE,
38 AIV_TOTAL_TIME,38 AIV_TOTAL_TIME,
39- AIV_PMU_RESULT39+ AIV_PMU_RESULT,
40+ PMU_TIMESTAMP
40};41};
41// V6BlockPmu表落盘数据行: stream_id, task_id, subtask_id, batch_id, start_time, duration, core_type, core_id42// V6BlockPmu表落盘数据行: stream_id, task_id, subtask_id, batch_id, start_time, duration, core_type, core_id
42using V6BlockPmuData = std::tuple<uint32_t, uint32_t, uint32_t, uint32_t, uint64_t, double, uint8_t, uint8_t>;43using V6BlockPmuData = std::tuple<uint32_t, uint32_t, uint32_t, uint32_t, uint64_t, double, uint8_t, uint8_t>;
@@ -15,32 +15,3 @@
15 * -------------------------------------------------------------------------*/15 * -------------------------------------------------------------------------*/
16 16 
17#include "analysis/csrc/domain/services/persistence/device/persistence_utils.h"17#include "analysis/csrc/domain/services/persistence/device/persistence_utils.h"
18- 
19-namespace Analysis {
20-namespace Domain {
21-namespace {
22-const uint64_t MILLI_SECOND = 1000;
23-}
24- 
25-SyscntConversionParams GenerateSyscntConversionParams(const DeviceContext& context)
26-{
27- CpuInfo cpuInfo;
28- context.Getter(cpuInfo);
29- HostStartLog hostStartLog;
30- context.Getter(hostStartLog);
31- uint64_t hostMonotonic = hostStartLog.clockMonotonicRaw;
32- DeviceInfo deviceInfo;
33- context.Getter(deviceInfo);
34- DeviceStartLog deviceStartLog;
35- context.Getter(deviceStartLog);
36- if (!IsDoubleEqual(cpuInfo.frequency, 0.0) && hostStartLog.cntVctDiff) {
37- uint64_t diffTime = static_cast<uint64_t>(hostStartLog.cntVctDiff * MILLI_SECOND / cpuInfo.frequency);
38- if (UINT64_MAX - hostStartLog.clockMonotonicRaw >= diffTime) {
39- hostMonotonic = hostStartLog.clockMonotonicRaw + diffTime;
40- }
41- }
42- SyscntConversionParams params{deviceInfo.hwtsFrequency, deviceStartLog.cntVct, hostMonotonic};
43- return params;
44-}
45-}
46-}
@@ -71,8 +71,6 @@ bool SaveData(const std::vector<std::tuple<Args...>>& data, DBInfo& dbInfo, std:
71 }71 }
72 return true;72 return true;
73}73}
74- 
75-SyscntConversionParams GenerateSyscntConversionParams(const DeviceContext& context);
76} // namespace Domain74} // namespace Domain
77} // namespace Analysis75} // namespace Analysis
78#endif // ANALYSIS_DOMAIN_SERVICES_PERSISTENCE_PERSISTENCE_UTILS_H76#endif // ANALYSIS_DOMAIN_SERVICES_PERSISTENCE_PERSISTENCE_UTILS_H
@@ -124,7 +124,7 @@ bool SaveTaskFlipData(const std::vector<HalTrackData>& dataS, const DeviceContex
124 MAKE_SHARED0_RETURN_VALUE(tsTrackDB.database, StepTraceDB, ANALYSIS_ERROR);124 MAKE_SHARED0_RETURN_VALUE(tsTrackDB.database, StepTraceDB, ANALYSIS_ERROR);
125 std::string dbPath = Utils::File::PathJoin({deviceContext.GetDeviceFilePath(), SQLITE, tsTrackDB.dbName});125 std::string dbPath = Utils::File::PathJoin({deviceContext.GetDeviceFilePath(), SQLITE, tsTrackDB.dbName});
126 MAKE_SHARED_RETURN_VALUE(tsTrackDB.dbRunner, DBRunner, ANALYSIS_ERROR, dbPath);126 MAKE_SHARED_RETURN_VALUE(tsTrackDB.dbRunner, DBRunner, ANALYSIS_ERROR, dbPath);
127- auto params = GenerateSyscntConversionParams(deviceContext);127+ auto params = deviceContext.GetSyscntConversionParams();
128 std::vector<TaskFlipDataFormat> taskFlips;128 std::vector<TaskFlipDataFormat> taskFlips;
129 for (const auto& data : dataS)129 for (const auto& data : dataS)
130 {130 {
@@ -47,7 +47,7 @@ from mscalculate.aic.aic_utils import AicPmuUtils
47from mscalculate.aic.pmu_calculator import PmuCalculator47from mscalculate.aic.pmu_calculator import PmuCalculator
48from mscalculate.calculate_ai_core_data import CalculateAiCoreData48from mscalculate.calculate_ai_core_data import CalculateAiCoreData
49from mscalculate.flip.flip_calculator import FlipCalculator49from mscalculate.flip.flip_calculator import FlipCalculator
50-from msmodel.aic.aic_pmu_model import AicPmuModel50+from msmodel.aic.aic_pmu_model import FftsV1PmuModel
51from msmodel.freq.freq_parser_model import FreqParserModel51from msmodel.freq.freq_parser_model import FreqParserModel
52from msmodel.iter_rec.iter_rec_model import HwtsIterModel52from msmodel.iter_rec.iter_rec_model import HwtsIterModel
53from msmodel.stars.ffts_pmu_model import FftsPmuModel53from msmodel.stars.ffts_pmu_model import FftsPmuModel
@@ -225,9 +225,6 @@ class FftsPmuCalculator(PmuCalculator, MsMultiProcess):
225 self.calculate_pmu_list(self.pmu_data)225 self.calculate_pmu_list(self.pmu_data)
226 if ChipManager().is_chip_all_data_export() and InfoConfReader().is_all_export_version():226 if ChipManager().is_chip_all_data_export() and InfoConfReader().is_all_export_version():
227 self.pmu_data = FlipCalculator.set_device_batch_id(self.pmu_data, self._result_dir)227 self.pmu_data = FlipCalculator.set_device_batch_id(self.pmu_data, self._result_dir)
228- if not self._is_mix_needed:
229- # 去除timestamp字段
230- self.pmu_data = [pmu_data[:-1] for pmu_data in self.pmu_data]
231 228 
232 def save(self: any) -> None:229 def save(self: any) -> None:
233 """230 """
@@ -677,7 +674,8 @@ class FftsPmuCalculator(PmuCalculator, MsMultiProcess):
677 self._block_num['mix_block_num'].setdefault(_key, []).append(int(data.mix_block_num))674 self._block_num['mix_block_num'].setdefault(_key, []).append(int(data.mix_block_num))
678 675 
679 def __update_model_instance(self):676 def __update_model_instance(self):
680- self._model = AicPmuModel(self._project_path)677+ # 非mix(7/8/11)场景:AIC表尾追加end_time
678+ self._model = FftsV1PmuModel(self._project_path)
681 679 
682 def _set_ffts_table_name_list(self):680 def _set_ffts_table_name_list(self):
683 """681 """
@@ -64,9 +64,6 @@ class V5AicPmuModel(AicPmuModel):
64 v5 pmu model.64 v5 pmu model.
65 """65 """
66 66 
67- def __init__(self: any, result_dir: str) -> None:
68- super().__init__(result_dir)
69- 
70 def create_table(self: any) -> None:67 def create_table(self: any) -> None:
71 """68 """
72 create aic and aiv table by sample.json69 create aic and aiv table by sample.json
@@ -76,3 +73,20 @@ class V5AicPmuModel(AicPmuModel):
76 aic_profiling_events = get_metrics_from_sample_config(self.result_dir)73 aic_profiling_events = get_metrics_from_sample_config(self.result_dir)
77 column_list = AicPmuUtils.remove_unused_column(aic_profiling_events)74 column_list = AicPmuUtils.remove_unused_column(aic_profiling_events)
78 create_metric_table(self.conn, column_list, DBNameConstant.TABLE_METRIC_SUMMARY)75 create_metric_table(self.conn, column_list, DBNameConstant.TABLE_METRIC_SUMMARY)
76+ 
77+ 
78+class FftsV1PmuModel(AicPmuModel):
79+ """
80+ 7/8/11(V1.1.x) ffts 非mix场景的MetricSummary模型。
81+ 在AIC表基础上于表尾追加end_time列,保存每算子context PMU的wall-clock结束时间,
82+ 供C++ unified task-pmu读取作为算子的时间(与chip5/chip6 python侧写end_time语义一致)。
83+ """
84+ 
85+ def create_table(self: any) -> None:
86+ """
87+ create aic metric table and append end_time column at the tail.
88+ :return:
89+ """
90+ super().create_table()
91+ sql = "ALTER TABLE {0} ADD COLUMN end_time INT".format(DBNameConstant.TABLE_METRIC_SUMMARY)
92+ DBManager.execute_sql(self.conn, sql)
C
Cchenhao_120917 天前

【review】【编码】FftsV1PmuModel.create_table() 未检查 ALTER TABLE 返回值

  • 问题描述:create_table() 中调用 DBManager.execute_sql 执行 ALTER TABLE 追加 end_time 列,但未检查其返回值。
  • 问题原因:DBManager.execute_sql 失败时仅返回 False 而不抛异常;若 super().create_table() 成功而 ALTER TABLE 因磁盘异常、并发写库等原因失败,MetricSummary 表将缺少 end_time 列,后续 C++ UnifiedPmuProcessor 执行 SELECT ... end_time FROM MetricSummary 时会以 SQL 报错失败,用户难以定位根因。
  • 修改建议:检查 execute_sql 返回值,失败时记录 error 日志(含表名与列名)或直接抛出异常快速失败,便于问题定位。
likedislike
wangzixuan
17 天前 评论:
@@ -391,6 +391,7 @@ The `--task-time`, `--hccl`, and `--ascendcl` options control the collection of
391 391 
392|Field|Type| Description |392|Field|Type| Description |
393|--|--|------------------------------------------------------------------------|393|--|--|------------------------------------------------------------------------|
394+|timestampNs|INTEGER| Start time of the small communication operator (ns). |
394|name|INTEGER| Operator name, which maps to `STRING_IDS(name)`. |395|name|INTEGER| Operator name, which maps to `STRING_IDS(name)`. |
395|globalTaskId|INTEGER| Global operator task ID, which is used as an index named `CommunicationTaskIndex` to associate with the `TASK` table. |396|globalTaskId|INTEGER| Global operator task ID, which is used as an index named `CommunicationTaskIndex` to associate with the `TASK` table. |
396|taskType|INTEGER| Operator task type, which maps to `STRING_IDS(taskType)`. |397|taskType|INTEGER| Operator task type, which maps to `STRING_IDS(taskType)`. |
@@ -507,7 +508,7 @@ This table is controlled by `--sys-hardware-mem` and `--sys-hardware-mem-freq`.
507|Field|Type|Description|508|Field|Type|Description|
508|--|--|--|509|--|--|--|
509|l2BufferBwLevel|INTEGER|L2 buffer bandwidth level|510|l2BufferBwLevel|INTEGER|L2 buffer bandwidth level|
510-|mataBwLevel|INTEGER|Mata bandwidth level|511+|mataBwLevel|INTEGER|Mata bandwidth level| <!-- codespell:ignore -->
511|timestampNs|NUMERIC|Local time (ns)|512|timestampNs|NUMERIC|Local time (ns)|
512|deviceId|INTEGER|Device ID|513|deviceId|INTEGER|Device ID|
513 514 
@@ -424,6 +424,7 @@ task数据,呈现所有硬件执行的算子信息。
424 424 
425|字段名|类型| 含义 |425|字段名|类型| 含义 |
426|--|--|------------------------------------------------------------------------|426|--|--|------------------------------------------------------------------------|
427+|timestampNs|INTEGER| 通信小算子开始时间,单位ns |
427|name|INTEGER| 算子名,STRING_IDS(name) |428|name|INTEGER| 算子名,STRING_IDS(name) |
428|globalTaskId|INTEGER| 索引,索引名称CommunicationTaskIndex,全局算子任务ID,用于关联TASK表 |429|globalTaskId|INTEGER| 索引,索引名称CommunicationTaskIndex,全局算子任务ID,用于关联TASK表 |
429|taskType|INTEGER| 算子类型,STRING_IDS(taskType) |430|taskType|INTEGER| 算子类型,STRING_IDS(taskType) |
@@ -634,6 +634,7 @@ static std::vector<UnifiedTaskPmu> GenerateUnifiedTaskPmuData()
634 data.batchId = 4294967295; // batchId 4294967295634 data.batchId = 4294967295; // batchId 4294967295
635 data.header = "aic_total_time";635 data.header = "aic_total_time";
636 data.value = 318360.0; // value 318360.0636 data.value = 318360.0; // value 318360.0
637+ data.timestamp = 1701121739053206801; // context PMU时间换算后的wall-clock ns
637 res.push_back(data);638 res.push_back(data);
638 return res;639 return res;
639}640}
@@ -1009,17 +1010,19 @@ TEST_F(DBAssemblerUTest, TestRunHcclDataShouldReturnTrueWhenRunSuccess)
1009 1010 
1010 uint64_t expectName = IdPool::GetInstance().GetUint64Id("hcom_broadcast__674_0_1");1011 uint64_t expectName = IdPool::GetInstance().GetUint64Id("hcom_broadcast__674_0_1");
1011 // 小算子数据1012 // 小算子数据
1012- // name, globalTaskId, taskType, planeId, groupName, notifyId, rdmaType, srcRank, dstRank, transportType,1013+ // timestampNs, name, globalTaskId, taskType, planeId, groupName, notifyId, rdmaType, srcRank, dstRank,
1013- // size, dataType, linkType, opId, isMaster, bandwidth1014+ // transportType, size, dataType, linkType, opId, isMaster, bandwidth
1014- using CommunicationTaskDataFormat = std::vector<std::tuple<uint64_t, uint64_t, uint64_t, uint32_t, uint64_t,1015+ using CommunicationTaskDataFormat =
1015- uint64_t, uint64_t, int64_t, int64_t, uint64_t, uint64_t, uint64_t, uint64_t, int64_t, uint16_t,1016+ std::vector<std::tuple<uint64_t, uint64_t, uint64_t, uint64_t, uint32_t, uint64_t, uint64_t, uint64_t, int64_t,
1016- double>>;1017+ int64_t, uint64_t, uint64_t, uint64_t, uint64_t, int64_t, uint16_t, double>>;
1017 CommunicationTaskDataFormat taskResult;1018 CommunicationTaskDataFormat taskResult;
1018 std::string sql{"SELECT * FROM " + TABLE_NAME_COMMUNICATION_TASK_INFO};1019 std::string sql{"SELECT * FROM " + TABLE_NAME_COMMUNICATION_TASK_INFO};
1019 std::shared_ptr<DBRunner> msprofDBRunner;1020 std::shared_ptr<DBRunner> msprofDBRunner;
1020 MAKE_SHARED0_NO_OPERATION(msprofDBRunner, DBRunner, GetMsprofDbPath());1021 MAKE_SHARED0_NO_OPERATION(msprofDBRunner, DBRunner, GetMsprofDbPath());
1021 msprofDBRunner->QueryData(sql, taskResult);1022 msprofDBRunner->QueryData(sql, taskResult);
1022- uint64_t opName = std::get<0>(taskResult[0]);1023+ ASSERT_FALSE(taskResult.empty());
1024+ EXPECT_EQ(std::get<0>(taskResult[0]), 1717575960213957957);
1025+ uint64_t opName = std::get<1>(taskResult[0]);
1023 EXPECT_EQ(expectName, opName);1026 EXPECT_EQ(expectName, opName);
1024 1027 
1025 // 大算子数据1028 // 大算子数据
@@ -1036,11 +1039,11 @@ TEST_F(DBAssemblerUTest, TestRunHcclDataShouldReturnTrueWhenRunSuccess)
1036TEST_F(DBAssemblerUTest, TestRunHcclDataShouldReturnFalseWhenReserveFailed)1039TEST_F(DBAssemblerUTest, TestRunHcclDataShouldReturnFalseWhenReserveFailed)
1037{1040{
1038 // 小算子数据1041 // 小算子数据
1039- // name, globalTaskId, taskType, planeId, groupName, notifyId, rdmaType, srcRank, dstRank, transportType,1042+ // timestampNs, name, globalTaskId, taskType, planeId, groupName, notifyId, rdmaType, srcRank, dstRank,
1040- // size, dataType, linkType, opId, isMaster, bandwidth1043+ // transportType, size, dataType, linkType, opId, isMaster, bandwidth
1041- using CommunicationTaskDataFormat = std::vector<std::tuple<uint64_t, uint64_t, uint64_t, uint32_t, uint64_t,1044+ using CommunicationTaskDataFormat =
1042- uint64_t, uint64_t, int64_t, int64_t, uint64_t, uint64_t, uint64_t, uint64_t, int64_t, uint16_t,1045+ std::vector<std::tuple<uint64_t, uint64_t, uint64_t, uint64_t, uint32_t, uint64_t, uint64_t, uint64_t, int64_t,
1043- double>>;1046+ int64_t, uint64_t, uint64_t, uint64_t, uint64_t, int64_t, uint16_t, double>>;
1044 // 大算子数据1047 // 大算子数据
1045 // opName, start, end, connectionId, group_name, opId, relay, retry, data_type, alg_type, count, op_type, deviceId,1048 // opName, start, end, connectionId, group_name, opId, relay, retry, data_type, alg_type, count, op_type, deviceId,
1046 // rank_size1049 // rank_size
@@ -1771,6 +1774,18 @@ TEST_F(DBAssemblerUTest, TestRunSaveTaskPmuDataShouldReturnTrueWhenRunSuccess)
1771 MAKE_SHARED0_NO_OPERATION(dataS, std::vector<UnifiedTaskPmu>, data);1774 MAKE_SHARED0_NO_OPERATION(dataS, std::vector<UnifiedTaskPmu>, data);
1772 dataInventory.Inject<std::vector<UnifiedTaskPmu>>(dataS);1775 dataInventory.Inject<std::vector<UnifiedTaskPmu>>(dataS);
1773 EXPECT_TRUE(assembler.Run(dataInventory));1776 EXPECT_TRUE(assembler.Run(dataInventory));
1777+ 
1778+ // 读回校验:TASK_PMU_INFO 表列为 timestampNs, globalTaskId, name(header), value
1779+ using TaskPmuResultFormat = std::vector<std::tuple<uint64_t, uint64_t, uint64_t, double>>;
1780+ TaskPmuResultFormat result;
1781+ std::string sql{"SELECT * FROM " + TABLE_NAME_TASK_PMU_INFO};
1782+ std::shared_ptr<DBRunner> msprofDBRunner;
1783+ MAKE_SHARED0_NO_OPERATION(msprofDBRunner, DBRunner, GetMsprofDbPath());
1784+ EXPECT_TRUE(msprofDBRunner->QueryData(sql, result));
1785+ ASSERT_EQ(result.size(), data.size());
1786+ EXPECT_EQ(std::get<0>(result[0]), data[0].timestamp);
1787+ EXPECT_EQ(std::get<2>(result[0]), IdPool::GetInstance().GetUint64Id(data[0].header));
1788+ EXPECT_DOUBLE_EQ(std::get<3>(result[0]), data[0].value);
1774}1789}
1775 1790 
1776TEST_F(DBAssemblerUTest, TestRunSaveSamplePmuTimelineDataShouldReturnTrueWhenRunSuccess)1791TEST_F(DBAssemblerUTest, TestRunSaveSamplePmuTimelineDataShouldReturnTrueWhenRunSuccess)
@@ -1797,7 +1812,8 @@ TEST_F(DBAssemblerUTest, TestRunSaveSamplePmuSummaryDataShouldReturnTrueWhenRunS
1797 1812 
1798TEST_F(DBAssemblerUTest, TestRunSaveTaskPmuDataShouldReturnFalseWhenReserveFailedThenDataIsEmpty)1813TEST_F(DBAssemblerUTest, TestRunSaveTaskPmuDataShouldReturnFalseWhenReserveFailedThenDataIsEmpty)
1799{1814{
1800- using PTFormat = std::vector<std::tuple<uint64_t, uint64_t, double>>;1815+ // 与 SaveTaskPmuData 中 PTFormat 保持一致:timestampNs, globalTaskId, name(header), value
1816+ using PTFormat = std::vector<std::tuple<uint64_t, uint64_t, uint64_t, double>>;
1801 auto assembler = DBAssembler(PROF, File::PathJoin(std::vector<std::string>{PROF, OUTPUT_PATH}));1817 auto assembler = DBAssembler(PROF, File::PathJoin(std::vector<std::string>{PROF, OUTPUT_PATH}));
1802 auto dataInventory = DataInventory();1818 auto dataInventory = DataInventory();
1803 auto data = GenerateUnifiedTaskPmuData();1819 auto data = GenerateUnifiedTaskPmuData();
@@ -2059,7 +2075,7 @@ TEST_F(DBAssemblerUTest, TestRunSaveDPUDataShouldReturnTrueWhenRunSuccess)
2059 EXPECT_TRUE(assembler.Run(dataInventory));2075 EXPECT_TRUE(assembler.Run(dataInventory));
C
Cchenhao_120922 天前

【review】【测试】建议补充 info.json 缺失 pid 的边界用例

  • 问题描述:TestRunSaveDPUDataShouldReturnTrueWhenRunSuccess 仅覆盖了 info.json 正常提供 pid 的场景,未覆盖 pid 缺失时 globalTid 的降级行为
  • 问题原因:SaveDPUData 通过 GetPidFromInfoJson(HOST_ID, profPath) 获取 pid,若 info.json 中无 pid,globalTid 高位为 0,DPU 任务线程会全部落到 pid 0 之下,该边界目前无用例看护
  • 修改建议:补充一个 info.json 无 pid 字段的用例,断言降级时的行为符合预期;该行为与既有 saver(API/MSTx/NpuOpMem)保持一致,不阻断合入
likedislike
2060 2076 
2061 // dpuDeviceId, globalTid, startNs, endNs, globalTaskId, streamId, taskId, opName, args2077 // dpuDeviceId, globalTid, startNs, endNs, globalTaskId, streamId, taskId, opName, args
2062- using DPUDataFormat = std::vector<std::tuple<uint16_t, uint32_t, uint64_t, uint64_t,2078+ using DPUDataFormat = std::vector<std::tuple<uint16_t, uint64_t, uint64_t, uint64_t,
2063 uint64_t, uint32_t, uint32_t, uint64_t, uint64_t>>;2079 uint64_t, uint32_t, uint32_t, uint64_t, uint64_t>>;
2064 DPUDataFormat dpuResult;2080 DPUDataFormat dpuResult;
2065 std::shared_ptr<DBRunner> msprofDBRunner;2081 std::shared_ptr<DBRunner> msprofDBRunner;
@@ -2070,13 +2086,13 @@ TEST_F(DBAssemblerUTest, TestRunSaveDPUDataShouldReturnTrueWhenRunSuccess)
2070 EXPECT_TRUE(msprofDBRunner->QueryData(sql, dpuResult));2086 EXPECT_TRUE(msprofDBRunner->QueryData(sql, dpuResult));
2071 ASSERT_EQ(2, dpuResult.size());2087 ASSERT_EQ(2, dpuResult.size());
2072 EXPECT_EQ(2, std::get<0>(dpuResult[0]));2088 EXPECT_EQ(2, std::get<0>(dpuResult[0]));
2073- EXPECT_EQ(123, std::get<1>(dpuResult[0]));2089+ EXPECT_EQ(Contact(1, 123), std::get<1>(dpuResult[0])); // globalTid = pid(1)<<32 | threadId
2074 EXPECT_EQ(1717575960208020750, std::get<2>(dpuResult[0]));2090 EXPECT_EQ(1717575960208020750, std::get<2>(dpuResult[0]));
2075 EXPECT_EQ(1717575960208021750, std::get<3>(dpuResult[0]));2091 EXPECT_EQ(1717575960208021750, std::get<3>(dpuResult[0]));
2076 EXPECT_EQ(7, std::get<5>(dpuResult[0]));2092 EXPECT_EQ(7, std::get<5>(dpuResult[0]));
2077 EXPECT_EQ(23, std::get<6>(dpuResult[0]));2093 EXPECT_EQ(23, std::get<6>(dpuResult[0]));
2078 EXPECT_EQ(3, std::get<0>(dpuResult[1]));2094 EXPECT_EQ(3, std::get<0>(dpuResult[1]));
2079- EXPECT_EQ(124, std::get<1>(dpuResult[1]));2095+ EXPECT_EQ(Contact(1, 124), std::get<1>(dpuResult[1])); // globalTid = pid(1)<<32 | threadId
2080 EXPECT_EQ(8, std::get<5>(dpuResult[1]));2096 EXPECT_EQ(8, std::get<5>(dpuResult[1]));
2081 EXPECT_EQ(24, std::get<6>(dpuResult[1]));2097 EXPECT_EQ(24, std::get<6>(dpuResult[1]));
2082 2098 
@@ -2102,9 +2118,34 @@ TEST_F(DBAssemblerUTest, TestRunSaveDPUDataShouldReturnTrueWhenRunSuccess)
2102 EXPECT_NE(std::string::npos, hcclArgs.find("1024000"));2118 EXPECT_NE(std::string::npos, hcclArgs.find("1024000"));
2103}2119}
2104 2120 
2121+TEST_F(DBAssemblerUTest, TestRunSaveDPUDataShouldUseZeroPidWhenPidMissing)
2122+{
2123+ MOCKER_CPP(&Analysis::Domain::Environment::Context::GetPidFromInfoJson).stubs().will(returnValue(0u));
2124+ auto assembler = DBAssembler(PROF, File::PathJoin(std::vector<std::string>{PROF, OUTPUT_PATH}));
2125+ auto dataInventory = DataInventory();
2126+ auto data = GenerateDPUData();
2127+ std::shared_ptr<std::vector<DPUData>> dataS;
2128+ MAKE_SHARED0_NO_OPERATION(dataS, std::vector<DPUData>, data);
2129+ dataInventory.Inject<std::vector<DPUData>>(dataS);
2130+ EXPECT_TRUE(assembler.Run(dataInventory));
2131+ 
2132+ using DPUDataFormat = std::vector<std::tuple<uint16_t, uint64_t, uint64_t, uint64_t,
2133+ uint64_t, uint32_t, uint32_t, uint64_t, uint64_t>>;
2134+ DPUDataFormat dpuResult;
2135+ std::shared_ptr<DBRunner> msprofDBRunner;
2136+ MAKE_SHARED0_NO_OPERATION(msprofDBRunner, DBRunner, GetMsprofDbPath());
2137+ ASSERT_NE(msprofDBRunner, nullptr);
2138+ std::string sql = "SELECT dpuDeviceId, globalTid, startNs, endNs, globalTaskId, streamId, taskId, opName, args FROM "
2139+ + TABLE_NAME_DPU_TASK + " ORDER BY startNs";
2140+ EXPECT_TRUE(msprofDBRunner->QueryData(sql, dpuResult));
2141+ ASSERT_EQ(2, dpuResult.size());
2142+ EXPECT_EQ(Contact(0, 123), std::get<1>(dpuResult[0]));
2143+ EXPECT_EQ(Contact(0, 124), std::get<1>(dpuResult[1]));
2144+}
2145+ 
2105TEST_F(DBAssemblerUTest, TestRunSaveDPUDataShouldReturnFalseWhenReserveFailed)2146TEST_F(DBAssemblerUTest, TestRunSaveDPUDataShouldReturnFalseWhenReserveFailed)
2106{2147{
2107- using DPUDataFormat = std::vector<std::tuple<uint16_t, uint32_t, uint64_t, uint64_t,2148+ using DPUDataFormat = std::vector<std::tuple<uint16_t, uint64_t, uint64_t, uint64_t,
2108 uint64_t, uint32_t, uint32_t, uint64_t, uint64_t>>;2149 uint64_t, uint32_t, uint32_t, uint64_t, uint64_t>>;
2109 auto assembler = DBAssembler(PROF, File::PathJoin(std::vector<std::string>{PROF, OUTPUT_PATH}));2150 auto assembler = DBAssembler(PROF, File::PathJoin(std::vector<std::string>{PROF, OUTPUT_PATH}));
2110 auto dataInventory = DataInventory();2151 auto dataInventory = DataInventory();
@@ -31,9 +31,9 @@ using OSTFormat = std::vector<std::tuple<uint64_t, std::string, uint32_t>>;
31// Original Sample Summary Format:aicore/ai_vector_core中的MetricSummary31// Original Sample Summary Format:aicore/ai_vector_core中的MetricSummary
32// metric, value, coreid32// metric, value, coreid
33using OSSFormat = std::vector<std::tuple<std::string, double, uint32_t>>;33using OSSFormat = std::vector<std::tuple<std::string, double, uint32_t>>;
34-// Original Task Format: 只取id + 对应字段的value34+// Original Task Format: 只取id + 对应字段的value + 时间列end_time
35-// stream_id, task_id, subtask_id, batch_id, value35+// stream_id, task_id, subtask_id, batch_id, value, end_time
36-using OTFormat = std::vector<std::tuple<uint32_t, uint32_t, uint32_t, uint32_t, double>>;36+using OTFormat = std::vector<std::tuple<uint32_t, uint32_t, uint32_t, uint32_t, double, uint64_t>>;
37// 手动设置task-based pmu表Format37// 手动设置task-based pmu表Format
38// aic_total_time, aic_total_cycles, aic_mac_time, aic_mac_ratio_extra,38// aic_total_time, aic_total_cycles, aic_mac_time, aic_mac_ratio_extra,
39// aiv_total_time, aiv_total_cycles, aiv_vec_time, aiv_vec_ratio, task_id, stream_id, subtask_id,39// aiv_total_time, aiv_total_cycles, aiv_vec_time, aiv_vec_ratio, task_id, stream_id, subtask_id,
@@ -170,6 +170,150 @@ TEST_F(UnifiedPmuProcessorUTest, TestTaskRunShouldReturnTrueWhenRunSuccess)
170 MOCKER_CPP(&Context::GetInfoByDeviceId).reset();170 MOCKER_CPP(&Context::GetInfoByDeviceId).reset();
171}171}
172 172 
173+TEST_F(UnifiedPmuProcessorUTest, TestTaskRunShouldCarryEndTimeForChipV1WithoutSubtaskColumn)
174+{
175+ // 7/8/11(chipV1)场景:python侧FftsV1落库的metric_summary无subtask_id列、时间在表尾end_time列
176+ // C++读该表应回退subtask_id为UINT32_MAX常量,并读end_time使每条metric行携带所属算子的wall-clock时间
177+ nlohmann::json record = {
178+ {"startCollectionTimeBegin", "1701069323851824"},
179+ {"endCollectionTimeEnd", "1701069338041681"},
180+ {"startClockMonotonicRaw", "36470610791630"},
181+ {"DeviceInfo", {{{"aic_frequency", "1000"}}}},
182+ {"ai_core_profiling_mode", TASK_BASED},
183+ {"platform_version", "8"},
184+ };
185+ MOCKER_CPP(&Context::GetInfoByDeviceId).stubs().will(returnValue(record));
186+ 
187+ std::string profDir = File::PathJoin({UNIFIED_PMU_DIR, "PROF_TS_V1"});
188+ std::string deviceDir = File::PathJoin({profDir, DEVICE_PREFIX + "0"});
189+ std::string sqliteDir = File::PathJoin({deviceDir, SQLITE});
190+ EXPECT_TRUE(File::CreateDir(profDir));
191+ EXPECT_TRUE(File::CreateDir(deviceDir));
192+ EXPECT_TRUE(File::CreateDir(sqliteDir));
193+ std::shared_ptr<DBRunner> metricRunner;
194+ MAKE_SHARED0_NO_OPERATION(metricRunner, DBRunner, File::PathJoin({sqliteDir, "metric_summary.db"}));
195+ ASSERT_NE(metricRunner, nullptr);
196+ 
197+ // 列顺序对齐python FftsV1 metric_summary:metric列/算子id列在前,无subtask_id列,end_time在表末尾
198+ const TableColumns v1MetricSummary = {
199+ {"aic_total_time", SQL_NUMERIC_TYPE},
200+ {"aiv_vec_time", SQL_NUMERIC_TYPE},
201+ {"stream_id", SQL_INTEGER_TYPE},
202+ {"task_id", SQL_INTEGER_TYPE},
203+ {"core_type", SQL_INTEGER_TYPE},
204+ {"batch_id", SQL_INTEGER_TYPE},
205+ {"end_time", SQL_INTEGER_TYPE},
206+ };
207+ // aic_total_time, aiv_vec_time, stream_id, task_id, core_type, batch_id, end_time
208+ using V1TaskFormat = std::vector<std::tuple<double, double, uint32_t, uint32_t, uint32_t, uint32_t, uint64_t>>;
209+ const V1TaskFormat v1TaskData = {
210+ {318.36, 75.1, 68, 22, 0, 0, 1701121739053206801},
211+ {313.94, 61.91, 68, 23, 0, 0, 1701121739053206803},
212+ };
213+ EXPECT_TRUE(metricRunner->CreateTable("MetricSummary", v1MetricSummary));
214+ EXPECT_TRUE(metricRunner->InsertData("MetricSummary", v1TaskData));
215+ 
216+ DataInventory dataInventory;
217+ auto processor = UnifiedPmuProcessor(profDir);
218+ EXPECT_TRUE(processor.Run(dataInventory, PROCESSOR_NAME_UNIFIED_PMU));
219+ 
220+ // 2个metric列 × 2个算子行 = 4条metric,end_time列不作为metric行落盘
221+ auto pmuData = dataInventory.GetPtr<std::vector<UnifiedTaskPmu>>();
222+ ASSERT_NE(pmuData, nullptr);
223+ ASSERT_EQ(pmuData->size(), 4u);
224+ for (const auto &item : *pmuData)
225+ {
226+ EXPECT_NE(item.header, "end_time");
227+ // chipV1无subtask_id列,读取时统一归一到UINT32_MAX,作为op四元组(subtask)取end_time
228+ EXPECT_EQ(item.subtaskId, UINT32_MAX);
229+ uint64_t expectTs = 0;
230+ // end_time列值为host开机monotonic ns,读侧经GetLocalTime叠加世界时偏移后才是与task对齐的时间:
231+ // 偏移 = startTimeNs - baseTimeNs = 1701069323851824000 - 36470610791630 = 1701032853241032370
232+ constexpr uint64_t LOCAL_TIME_OFFSET = 1701032853241032370;
233+ if (item.taskId == 22) {
234+ expectTs = 1701121739053206801 + LOCAL_TIME_OFFSET;
235+ } else {
236+ ASSERT_EQ(item.taskId, 23u);
237+ expectTs = 1701121739053206803 + LOCAL_TIME_OFFSET;
238+ }
239+ // 同一算子的metric行携带同一end_time,不同算子各取各的
240+ EXPECT_EQ(item.timestamp, expectTs);
241+ }
242+ MOCKER_CPP(&Context::GetInfoByDeviceId).reset();
243+ EXPECT_TRUE(File::RemoveDir(profDir, 0));
244+}
245+ 
246+TEST_F(UnifiedPmuProcessorUTest, TestTaskRunShouldCarryEndTimeWhenMetricSummaryHasEndTimeColumn)
247+{
248+ // metric_summary统一以end_time为时间列(如C++侧metric_summary_persistence chipV4落库、python侧stars落库)
249+ // 该场景下每条metric行都应携带所属算子的end_time,end_time列不落成metric行
250+ nlohmann::json record = {
251+ {"startCollectionTimeBegin", "1701069323851824"},
252+ {"endCollectionTimeEnd", "1701069338041681"},
253+ {"startClockMonotonicRaw", "36470610791630"},
254+ {"DeviceInfo", {{{"aic_frequency", "1000"}}}},
255+ {"ai_core_profiling_mode", TASK_BASED},
256+ {"platform_version", "5"},
257+ };
258+ MOCKER_CPP(&Context::GetInfoByDeviceId).stubs().will(returnValue(record));
259+ 
260+ std::string profDir = File::PathJoin({UNIFIED_PMU_DIR, "PROF_TS_END"});
261+ std::string deviceDir = File::PathJoin({profDir, DEVICE_PREFIX + "0"});
262+ std::string sqliteDir = File::PathJoin({deviceDir, SQLITE});
263+ EXPECT_TRUE(File::CreateDir(profDir));
264+ EXPECT_TRUE(File::CreateDir(deviceDir));
265+ EXPECT_TRUE(File::CreateDir(sqliteDir));
266+ std::shared_ptr<DBRunner> metricRunner;
267+ MAKE_SHARED0_NO_OPERATION(metricRunner, DBRunner, File::PathJoin({sqliteDir, "metric_summary.db"}));
268+ ASSERT_NE(metricRunner, nullptr);
269+ 
270+ // 列顺序对齐metric_summary:metric列/算子id列在前,end_time在表末尾
271+ const TableColumns endTsMetricSummary = {
272+ {"aic_total_time", SQL_NUMERIC_TYPE},
273+ {"aiv_vec_time", SQL_NUMERIC_TYPE},
274+ {"task_id", SQL_INTEGER_TYPE},
275+ {"stream_id", SQL_INTEGER_TYPE},
276+ {"subtask_id", SQL_INTEGER_TYPE},
277+ {"batch_id", SQL_INTEGER_TYPE},
278+ {"end_time", SQL_INTEGER_TYPE},
279+ };
280+ // aic_total_time, aiv_vec_time, task_id, stream_id, subtask_id, batch_id, end_time
281+ using EndTsTaskFormat = std::vector<std::tuple<double, double, uint32_t, uint32_t, uint32_t, uint32_t, uint64_t>>;
282+ const EndTsTaskFormat endTsTaskData = {
283+ {318.36, 75.1, 22, 68, 2344, 0, 1701121739053206801},
284+ {313.94, 61.91, 22, 68, 2357, 0, 1701121739053206803},
285+ };
286+ EXPECT_TRUE(metricRunner->CreateTable("MetricSummary", endTsMetricSummary));
287+ EXPECT_TRUE(metricRunner->InsertData("MetricSummary", endTsTaskData));
288+ 
289+ DataInventory dataInventory;
290+ auto processor = UnifiedPmuProcessor(profDir);
291+ EXPECT_TRUE(processor.Run(dataInventory, PROCESSOR_NAME_UNIFIED_PMU));
292+ 
293+ // 2个metric列 × 2个算子行 = 4条metric,end_time列不作为metric行落盘
294+ auto pmuData = dataInventory.GetPtr<std::vector<UnifiedTaskPmu>>();
295+ ASSERT_NE(pmuData, nullptr);
296+ ASSERT_EQ(pmuData->size(), 4u);
297+ for (const auto &item : *pmuData)
298+ {
299+ EXPECT_NE(item.header, "end_time");
300+ uint64_t expectTs = 0;
301+ // end_time列值为host开机monotonic ns,读侧经GetLocalTime叠加世界时偏移后才是与task对齐的时间:
302+ // 偏移 = startTimeNs - baseTimeNs = 1701069323851824000 - 36470610791630 = 1701032853241032370
303+ constexpr uint64_t LOCAL_TIME_OFFSET = 1701032853241032370;
304+ if (item.subtaskId == 2344) {
305+ expectTs = 1701121739053206801 + LOCAL_TIME_OFFSET;
306+ } else {
307+ ASSERT_EQ(item.subtaskId, 2357u);
308+ expectTs = 1701121739053206803 + LOCAL_TIME_OFFSET;
309+ }
310+ // 同一算子的metric行携带同一end_time,不同算子各取各的
311+ EXPECT_EQ(item.timestamp, expectTs);
312+ }
313+ MOCKER_CPP(&Context::GetInfoByDeviceId).reset();
314+ EXPECT_TRUE(File::RemoveDir(profDir, 0));
315+}
316+ 
173TEST_F(UnifiedPmuProcessorUTest, TestTaskRunShouldReturnFalseWhenCheckColumnsFailed)317TEST_F(UnifiedPmuProcessorUTest, TestTaskRunShouldReturnFalseWhenCheckColumnsFailed)
174{318{
175 nlohmann::json record = {319 nlohmann::json record = {
@@ -18,6 +18,7 @@ from unittest import mock
18 18 
19from common_func.info_conf_reader import InfoConfReader19from common_func.info_conf_reader import InfoConfReader
20from msmodel.aic.aic_pmu_model import AicPmuModel20from msmodel.aic.aic_pmu_model import AicPmuModel
21+from msmodel.aic.aic_pmu_model import FftsV1PmuModel
21 22 
22NAMESPACE = 'msmodel.aic.aic_pmu_model'23NAMESPACE = 'msmodel.aic.aic_pmu_model'
23 24 
@@ -52,3 +53,13 @@ class TestPcieModel(unittest.TestCase):
52 check = AicPmuModel('test')53 check = AicPmuModel('test')
53 check.clear()54 check.clear()
54 55 
56+ def test_ffts_v1_create_table_should_append_end_time_column(self):
57+ # FftsV1PmuModel(7/8/11 ffts非mix)在AIC表基础上于表尾追加end_time,供unified task-pmu读取wall-clock时间
58+ with mock.patch(NAMESPACE + '.AicPmuModel.create_table') as mock_base_create, \
59+ mock.patch(NAMESPACE + '.DBManager.execute_sql') as mock_execute:
60+ check = FftsV1PmuModel('test')
61+ check.create_table()
62+ mock_base_create.assert_called_once()
63+ alter_sql = mock_execute.call_args[0][1]
64+ self.assertIn('ALTER TABLE MetricSummary ADD COLUMN end_time INT', alter_sql)
65+ 
@@ -31,6 +31,7 @@ from common_func.profiling_scene import ExportMode
31from common_func.profiling_scene import ProfilingScene31from common_func.profiling_scene import ProfilingScene
32from constant.constant import CONFIG32from constant.constant import CONFIG
33from mscalculate.stars.ffts_pmu_calculator import FftsPmuCalculator33from mscalculate.stars.ffts_pmu_calculator import FftsPmuCalculator
34+from msmodel.aic.aic_pmu_model import FftsV1PmuModel
34from profiling_bean.prof_enum.chip_model import ChipModel35from profiling_bean.prof_enum.chip_model import ChipModel
35from profiling_bean.prof_enum.data_tag import DataTag36from profiling_bean.prof_enum.data_tag import DataTag
36from profiling_bean.stars.ffts_block_pmu import FftsBlockPmuBean37from profiling_bean.stars.ffts_block_pmu import FftsBlockPmuBean
@@ -640,5 +641,42 @@ class TestFftsPmuCalculator(TestCase):
640 check.calculate_pmu_list(pmu_data_list)641 check.calculate_pmu_list(pmu_data_list)
641 self.assertEqual(3, len(pmu_data_list))642 self.assertEqual(3, len(pmu_data_list))
642 643 
644+ def test_calculate_pmu_list_non_mix_should_use_ffts_v1_model_and_keep_end_time(self):
645+ # 7/8/11(V1.1.x) ffts非mix:__update_model_instance应切换到FftsV1PmuModel(AIC表尾带end_time列),
646+ # 且行尾保留每算子wall-clock结束时间(此前calculate()中会被[:-1]剥掉,导致unified读取落0)
647+ context_task = [
648+ FftsPmuBean([0, 0, 1, 1, 0, 0, 4294967295, 8192, 0, 0, 1111, 0,
649+ 0, 0, 0, 0, 0, 0, 0, 0, 10000, 10100]),
650+ ]
651+ pmu_value = {
652+ "l0a_read_bw(GB/s)": [0],
653+ "l0a_write_bw(GB/s)": [0],
654+ "l0b_read_bw(GB/s)": [0],
655+ "l0b_write_bw(GB/s)": [0],
656+ "l0c_read_bw(GB/s)": [0],
657+ "l0c_read_bw_cube(GB/s)": [0],
658+ "l0c_write_bw(GB/s)": [0],
659+ "l0c_write_bw_cube(GB/s)": [0],
660+ }
661+ pmu_data_list = [None] * len(context_task)
662+ InfoConfReader()._info_json = {"DeviceInfo": [{'aic_frequency': 1500, 'hwts_frequency': 1000}]}
663+ with mock.patch("common_func.config_mgr.ConfigMgr.read_sample_config", return_value={}), \
664+ mock.patch(NAMESPACE + '.FftsPmuCalculator._get_current_block', return_value=10), \
665+ mock.patch(NAMESPACE + '.CalculateAiCoreData.compute_ai_core_data', return_value=[0, pmu_value]):
666+ check = FftsPmuCalculator(self.file_list, CONFIG)
667+ check._data_list['context_task'] = context_task
668+ check._freq = 1000
669+ check._core_num_dict = {
670+ "aic": 1,
671+ "aiv": 1,
672+ }
673+ check.aic_table_name_list = list(pmu_value.keys())
674+ check.calculate_pmu_list(pmu_data_list)
675+ self.assertIsInstance(check._model, FftsV1PmuModel)
676+ # 行尾字段为timestamp(即wall-clock结束时间),保留以按位落入表尾end_time列
677+ self.assertEqual(pmu_data_list[0]._fields[-1], 'timestamp')
678+ self.assertEqual(pmu_data_list[0].timestamp,
679+ InfoConfReader().time_from_syscnt(context_task[0].time_list[1]))
680+ 
643if __name__ == '__main__':681if __name__ == '__main__':
644 unittest.main()682 unittest.main()
@@ -36,6 +36,7 @@ class TableFields:
36 "rankSize",36 "rankSize",
37 ]37 ]
38 COMMUNICATION_TASK_INFO = [38 COMMUNICATION_TASK_INFO = [
39+ "timestampNs",
39 "name",40 "name",
40 "globalTaskId",41 "globalTaskId",
41 "taskType",42 "taskType",
@@ -246,7 +247,7 @@ class TableFields:
246 "taskId",247 "taskId",
247 "modelId",248 "modelId",
248 ]249 ]
249- TASK_PMU_INFO = ["globalTaskId", "name", "value"]250+ TASK_PMU_INFO = ["timestampNs", "globalTaskId", "name", "value"]
250 RANK_DEVICE_MAP = ["rankId", "deviceId"]251 RANK_DEVICE_MAP = ["rankId", "deviceId"]
251 ClusterCommunicationBandwidth = [252 ClusterCommunicationBandwidth = [
252 "step",253 "step",