已合并
adapt dpu data #208
wangzixuan创建于 4月25日
adapt dpu data #208
已合并
共 20 个文件变更+725-19
| @@ -475,3 +475,11 @@ class AiStackDataCheckManager(DataCheckManager): | |||
| 475 | """ | 475 | """ |
| 476 | return cls.check_data_exist(result_dir, file_name_manager.get_v5_stars_profile_compiles(), | 476 | return cls.check_data_exist(result_dir, file_name_manager.get_v5_stars_profile_compiles(), |
| 477 | device_id=device_id) | 477 | device_id=device_id) |
| 478 | + | ||
| 479 | + | ||
| 480 | + def contain_dpu_data(cls: any, result_dir: str, device_id: any = None) -> bool: | ||
| 481 | + """ | ||
| 482 | + The data path contain dpu data or not | ||
| 483 | + """ | ||
| 484 | + return cls.check_data_exist(result_dir, file_name_manager.get_dpu_track_compact_compiles()) or \ | ||
| 485 | + cls.check_data_exist(result_dir, file_name_manager.get_dpu_hccl_track_compact_compiles()) | ||
| @@ -110,6 +110,7 @@ class DBNameConstant(metaclass=ABCMeta): | |||
| 110 | DB_SOC_PMU = "soc_pmu.db" | 110 | DB_SOC_PMU = "soc_pmu.db" |
| 111 | DB_VOLTAGE = "voltage.db" | 111 | DB_VOLTAGE = "voltage.db" |
| 112 | DB_FUSION_TASK = "fusion_task.db" | 112 | DB_FUSION_TASK = "fusion_task.db" |
| 113 | + DB_DPU = "dpu.db" | ||
| 113 | 114 | ||
| 114 | # DB tables | 115 | # DB tables |
| 115 | TABLE_ACL_DATA = "AclData" | 116 | TABLE_ACL_DATA = "AclData" |
| @@ -355,6 +356,10 @@ class DBNameConstant(metaclass=ABCMeta): | |||
| 355 | TABLE_HCCL_OP_INFO = "HcclOpInfo" | 356 | TABLE_HCCL_OP_INFO = "HcclOpInfo" |
| 356 | TABLE_STREAM_EXPAND_SPEC = "StreamExpandSpec" | 357 | TABLE_STREAM_EXPAND_SPEC = "StreamExpandSpec" |
| 357 | 358 | ||
| 359 | + # dpu | ||
| 360 | + TABLE_DPU_TASK_TRACK = "DPUTaskTrack" | ||
| 361 | + TABLE_DPU_HCCL_TRACK = 'DPUHcclTrack' | ||
| 362 | + | ||
| 358 | # v5 | 363 | # v5 |
| 359 | TABLE_V5_TASK = "V5Task" | 364 | TABLE_V5_TASK = "V5Task" |
| 360 | 365 | ||
| @@ -250,6 +250,10 @@ class FileNameManagerConstant: | |||
| 250 | AICPU_FILE_PATTERN = r"^aicpu\.data\.(\d+)\.slice_\d+" | 250 | AICPU_FILE_PATTERN = r"^aicpu\.data\.(\d+)\.slice_\d+" |
| 251 | HCCL_OP_INFO_FILE_PATTERN = r"^(unaging|aging)\.compact\.hccl_op_info\.slice_\d+" | 251 | HCCL_OP_INFO_FILE_PATTERN = r"^(unaging|aging)\.compact\.hccl_op_info\.slice_\d+" |
| 252 | 252 | ||
| 253 | + # dpu | ||
| 254 | + DPU_TASK_TRACK_FILE_PATTERN = r"^(aging|unaging)\.compact\.dpu_track\.slice_\d+" | ||
| 255 | + DPU_HCCL_TRACK_FILE_PATTERN = r"^(aging|unaging)\.additional\.dpu_hccl_track\.slice_\d+" | ||
| 256 | + | ||
| 253 | # V5 | 257 | # V5 |
| 254 | V5_MODEL_EXEOM_PATTERN = r"^unaging\.additional\.model_exeom\.slice_\d+" | 258 | V5_MODEL_EXEOM_PATTERN = r"^unaging\.additional\.model_exeom\.slice_\d+" |
| 255 | V5_STARS_PROFILE_PATTERN = r"^nano_stars_profile\.data.\d+\.slice_\d+" | 259 | V5_STARS_PROFILE_PATTERN = r"^nano_stars_profile\.data.\d+\.slice_\d+" |
| @@ -1171,3 +1175,21 @@ def get_dbg_file_compiles() -> tuple: | |||
| 1171 | :return: v5 host info files regex | 1175 | :return: v5 host info files regex |
| 1172 | """ | 1176 | """ |
| 1173 | return (re.compile(FileNameManagerConstant.DBG_PATTERN),) | 1177 | return (re.compile(FileNameManagerConstant.DBG_PATTERN),) |
| 1178 | + | ||
| 1179 | + | ||
| 1180 | +def get_dpu_track_compact_compiles() -> tuple: | ||
| 1181 | + """ | ||
| 1182 | + get dpu task track regex compiles | ||
| 1183 | + """ | ||
| 1184 | + return ( | ||
| 1185 | + re.compile(FileNameManagerConstant.DPU_TASK_TRACK_FILE_PATTERN), | ||
| 1186 | + ) | ||
| 1187 | + | ||
| 1188 | + | ||
| 1189 | +def get_dpu_hccl_track_compact_compiles() -> tuple: | ||
| 1190 | + """ | ||
| 1191 | + get runtime task track regex compiles | ||
| 1192 | + """ | ||
| 1193 | + return ( | ||
| 1194 | + re.compile(FileNameManagerConstant.DPU_HCCL_TRACK_FILE_PATTERN), | ||
| 1195 | + ) | ||
| @@ -113,7 +113,7 @@ class PathManager: | |||
| 113 | DBNameConstant.DB_MULTI_THREAD, DBNameConstant.DB_TENSOR_ADD_INFO, DBNameConstant.DB_NODE_BASIC_INFO, | 113 | DBNameConstant.DB_MULTI_THREAD, DBNameConstant.DB_TENSOR_ADD_INFO, DBNameConstant.DB_NODE_BASIC_INFO, |
| 114 | DBNameConstant.DB_FUSION_ADD_INFO, DBNameConstant.DB_GRAPH_ADD_INFO, DBNameConstant.DB_CTX_ID, | 114 | DBNameConstant.DB_FUSION_ADD_INFO, DBNameConstant.DB_GRAPH_ADD_INFO, DBNameConstant.DB_CTX_ID, |
| 115 | DBNameConstant.DB_SYNC_ACL_NPU, DBNameConstant.DB_MEMORY_OP, DBNameConstant.DB_GE_LOGIC_STREAM_INFO, | 115 | DBNameConstant.DB_SYNC_ACL_NPU, DBNameConstant.DB_MEMORY_OP, DBNameConstant.DB_GE_LOGIC_STREAM_INFO, |
| 116 | - DBNameConstant.DB_MC2_COMM_INFO, DBNameConstant.DB_STREAM_INFO | 116 | + DBNameConstant.DB_MC2_COMM_INFO, DBNameConstant.DB_STREAM_INFO, DBNameConstant.DB_DPU |
| 117 | } | 117 | } |
| 118 | base_result_dir = result_dir | 118 | base_result_dir = result_dir |
| 119 | if db_name in db_filter: | 119 | if db_name in db_filter: |
| @@ -81,9 +81,11 @@ class TraceViewHeaderConstant: | |||
| 81 | PROCESS_VOLTAGE = "Voltage Info" | 81 | PROCESS_VOLTAGE = "Voltage Info" |
| 82 | PROCESS_AI_CORE_VOLTAGE = "Aicore Voltage" | 82 | PROCESS_AI_CORE_VOLTAGE = "Aicore Voltage" |
| 83 | PROCESS_BUS_VOLTAGE = "Bus Voltage" | 83 | PROCESS_BUS_VOLTAGE = "Bus Voltage" |
| 84 | + PROCESS_DPU = "DPU" | ||
| 84 | 85 | ||
| 85 | # trace general layer | 86 | # trace general layer |
| 86 | GENERAL_LAYER_CPU = "CPU" | 87 | GENERAL_LAYER_CPU = "CPU" |
| 88 | + GENERAL_LAYER_DPU = "DPU" | ||
| 87 | GENERAL_LAYER_NPU = "NPU" | 89 | GENERAL_LAYER_NPU = "NPU" |
| 88 | 90 | ||
| 89 | # trace component layer | 91 | # trace component layer |
| @@ -98,6 +100,7 @@ class TraceViewHeaderConstant: | |||
| 98 | COMPONENT_LAYER_AICORE_FREQ = "AI Core Freq" | 100 | COMPONENT_LAYER_AICORE_FREQ = "AI Core Freq" |
| 99 | COMPONENT_LAYER_HCCL = "Communication" | 101 | COMPONENT_LAYER_HCCL = "Communication" |
| 100 | COMPONENT_LAYER_VOLTAGE = "Voltage Info" | 102 | COMPONENT_LAYER_VOLTAGE = "Voltage Info" |
| 103 | + COMPONENT_LAYER_DPU = "DPU" | ||
| 101 | 104 | ||
| 102 | # filtering msprof timeline trace | 105 | # filtering msprof timeline trace |
| 103 | MSPROF_TIMELINE_FILTER_LIST = (PROCESS_ALL_REDUCE, PROCESS_AI_CPU) | 106 | MSPROF_TIMELINE_FILTER_LIST = (PROCESS_ALL_REDUCE, PROCESS_AI_CPU) |
| @@ -105,16 +108,17 @@ class TraceViewHeaderConstant: | |||
| 105 | # component_layer_sort | 108 | # component_layer_sort |
| 106 | LAYER_FRAMEWORK_SORT = 6 | 109 | LAYER_FRAMEWORK_SORT = 6 |
| 107 | LAYER_CANN_SORT = 7 | 110 | LAYER_CANN_SORT = 7 |
| 108 | - LAYER_CPU_USAGE_SORT = 8 | 111 | + LAYER_DPU_SORT = 8 |
| 109 | - LAYER_MEMORY_USAGE_SORT = 9 | 112 | + LAYER_CPU_USAGE_SORT = 9 |
| 110 | - LAYER_NETWORK_USAGE_SORT = 10 | 113 | + LAYER_MEMORY_USAGE_SORT = 10 |
| 111 | - LAYER_DISK_USAGE_SORT = 11 | 114 | + LAYER_NETWORK_USAGE_SORT = 11 |
| 112 | - LAYER_OS_RUNTIME_API_SORT = 12 | 115 | + LAYER_DISK_USAGE_SORT = 12 |
| 113 | - LAYER_ASCEND_HW_SORT = 13 | 116 | + LAYER_OS_RUNTIME_API_SORT = 13 |
| 114 | - LAYER_ASCEND_AICORE_FREQ_SORT = 14 | 117 | + LAYER_ASCEND_HW_SORT = 14 |
| 115 | - LAYER_VOLTAGE_SORT = 15 | 118 | + LAYER_ASCEND_AICORE_FREQ_SORT = 15 |
| 116 | - LAYER_HCCL = 16 | 119 | + LAYER_VOLTAGE_SORT = 16 |
| 117 | - DEFAULT_LAYER_SORT_START = 17 | 120 | + LAYER_HCCL_SORT = 17 |
| 121 | + DEFAULT_LAYER_SORT_START = 18 | ||
| 118 | 122 | ||
| 119 | # namedtuple configuration of LayerInfo | 123 | # namedtuple configuration of LayerInfo |
| 120 | LayerInfo = namedtuple('LayerInfo', ['component_layer', 'general_layer', 'sort_index']) | 124 | LayerInfo = namedtuple('LayerInfo', ['component_layer', 'general_layer', 'sort_index']) |
| @@ -138,7 +142,8 @@ class TraceViewHeaderConstant: | |||
| 138 | PROCESS_OS_RUNTIME_API: LayerInfo(COMPONENT_LAYER_OS_RUNTIME_API, GENERAL_LAYER_CPU, LAYER_OS_RUNTIME_API_SORT), | 142 | PROCESS_OS_RUNTIME_API: LayerInfo(COMPONENT_LAYER_OS_RUNTIME_API, GENERAL_LAYER_CPU, LAYER_OS_RUNTIME_API_SORT), |
| 139 | PROCESS_AI_CORE_FREQ: LayerInfo(COMPONENT_LAYER_AICORE_FREQ, GENERAL_LAYER_NPU, LAYER_ASCEND_AICORE_FREQ_SORT), | 143 | PROCESS_AI_CORE_FREQ: LayerInfo(COMPONENT_LAYER_AICORE_FREQ, GENERAL_LAYER_NPU, LAYER_ASCEND_AICORE_FREQ_SORT), |
| 140 | PROCESS_VOLTAGE: LayerInfo(COMPONENT_LAYER_VOLTAGE, GENERAL_LAYER_NPU, LAYER_VOLTAGE_SORT), | 144 | PROCESS_VOLTAGE: LayerInfo(COMPONENT_LAYER_VOLTAGE, GENERAL_LAYER_NPU, LAYER_VOLTAGE_SORT), |
| 141 | - PROCESS_COMMUNICATION: LayerInfo(COMPONENT_LAYER_HCCL, GENERAL_LAYER_NPU, LAYER_HCCL), | 145 | + PROCESS_COMMUNICATION: LayerInfo(COMPONENT_LAYER_HCCL, GENERAL_LAYER_NPU, LAYER_HCCL_SORT), |
| 146 | + PROCESS_DPU: LayerInfo(COMPONENT_LAYER_DPU, GENERAL_LAYER_DPU, LAYER_DPU_SORT), | ||
| 142 | } | 147 | } |
| 143 | 148 | ||
| 144 | 149 | ||
| @@ -157,7 +157,10 @@ class TraceViewManager: | |||
| 157 | :return: format_pid: Uint32: pid use high 22bit, index_id use middle 5bit, device_id use low 5bit | 157 | :return: format_pid: Uint32: pid use high 22bit, index_id use middle 5bit, device_id use low 5bit |
| 158 | ps: pid_max is 10^22 - 1 | 158 | ps: pid_max is 10^22 - 1 |
| 159 | """ | 159 | """ |
| 160 | - if layer_info.general_layer == TraceViewHeaderConstant.GENERAL_LAYER_CPU or \ | 160 | + if layer_info.general_layer == TraceViewHeaderConstant.GENERAL_LAYER_DPU: |
| 161 | + device_id = pid | ||
| 162 | + pid = InfoConfReader().get_json_pid_data() | ||
| 163 | + elif layer_info.general_layer == TraceViewHeaderConstant.GENERAL_LAYER_CPU or \ | ||
| 161 | not is_number(InfoConfReader().get_device_id()): | 164 | not is_number(InfoConfReader().get_device_id()): |
| 162 | # host device_id is 31, we cannot use NumberConstant.HOST_ID, | 165 | # host device_id is 31, we cannot use NumberConstant.HOST_ID, |
| 163 | # cause this value is also been used in record time. | 166 | # cause this value is also been used in record time. |
| @@ -103,6 +103,8 @@ from common_func.file_name_manager import get_soc_pmu_compiles | |||
| 103 | from common_func.file_name_manager import get_lpm_info_compiles | 103 | from common_func.file_name_manager import get_lpm_info_compiles |
| 104 | from common_func.file_name_manager import get_host_stream_expand_spec_info_compiles | 104 | from common_func.file_name_manager import get_host_stream_expand_spec_info_compiles |
| 105 | from common_func.file_name_manager import get_runtime_op_info_compiles | 105 | from common_func.file_name_manager import get_runtime_op_info_compiles |
| 106 | +from common_func.file_name_manager import get_dpu_track_compact_compiles | ||
| 107 | +from common_func.file_name_manager import get_dpu_hccl_track_compact_compiles | ||
| 106 | from common_func.ms_constant.str_constant import StrConstant | 108 | from common_func.ms_constant.str_constant import StrConstant |
| 107 | from common_func.path_manager import PathManager | 109 | from common_func.path_manager import PathManager |
| 108 | from framework.prof_factory_maker import ProfFactoryMaker | 110 | from framework.prof_factory_maker import ProfFactoryMaker |
| @@ -201,6 +203,8 @@ class FileDispatch: | |||
| 201 | DataTag.V5_MODEL_EXEOM: get_v5_model_exeom_compiles(), | 203 | DataTag.V5_MODEL_EXEOM: get_v5_model_exeom_compiles(), |
| 202 | DataTag.V5_STARS_PROFILE: get_v5_stars_profile_compiles(), | 204 | DataTag.V5_STARS_PROFILE: get_v5_stars_profile_compiles(), |
| 203 | DataTag.DBG_FILE: get_dbg_file_compiles(), | 205 | DataTag.DBG_FILE: get_dbg_file_compiles(), |
| 206 | + DataTag.DPU_TASK_TRACK: get_dpu_track_compact_compiles(), | ||
| 207 | + DataTag.DPU_HCCL_TRACK: get_dpu_hccl_track_compact_compiles(), | ||
| 204 | } | 208 | } |
| 205 | 209 | ||
| 206 | def __init__(self: any, sample_config: dict) -> None: | 210 | def __init__(self: any, sample_config: dict) -> None: |
| @@ -1334,6 +1334,46 @@ class TablesConfig(MetaConfig): | |||
| 1334 | ('timestamp', 'NUMERIC,null'), | 1334 | ('timestamp', 'NUMERIC,null'), |
| 1335 | ('connection_id', 'INTEGER,null'), | 1335 | ('connection_id', 'INTEGER,null'), |
| 1336 | ], | 1336 | ], |
| 1337 | + 'DPUTaskTrackMap': [ | ||
| 1338 | + ('dpu_device_id', 'INTEGER,null'), | ||
| 1339 | + ('thread_id', 'INTEGER,null'), | ||
| 1340 | + ('start_time', 'NUMERIC,null'), | ||
| 1341 | + ('end_time', 'NUMERIC,null'), | ||
| 1342 | + ('task_type', 'TEXT,null'), | ||
| 1343 | + ('stream_id', 'INTEGER,null'), | ||
| 1344 | + ('task_id', 'INTEGER,null'), | ||
| 1345 | + ('kernel_name', 'TEXT,null'), | ||
| 1346 | + ], | ||
| 1347 | + 'DPUHcclTrackMap': [ | ||
| 1348 | + ('npu_device_id', 'INTEGER,null'), | ||
| 1349 | + ('dpu_device_id', 'INTEGER,null'), | ||
| 1350 | + ('thread_id', 'INTEGER,null'), | ||
| 1351 | + ('start_time', 'NUMERIC,null'), | ||
| 1352 | + ('end_time', 'NUMERIC,null'), | ||
| 1353 | + ('op_name', 'TEXT,null'), | ||
| 1354 | + ('group_name', 'TEXT,null'), | ||
| 1355 | + ('local_rank', 'INTEGER,null'), | ||
| 1356 | + ('remote_rank', 'INTEGER,null'), | ||
| 1357 | + ('rank_size', 'INTEGER,null'), | ||
| 1358 | + ('duration_estimated', 'NUMERIC,null'), | ||
| 1359 | + ('src_addr', 'TEXT,null'), | ||
| 1360 | + ('dst_addr', 'TEXT,null'), | ||
| 1361 | + ('data_size', 'INTEGER,null'), | ||
| 1362 | + ('stream_id', 'INTEGER,null'), | ||
| 1363 | + ('task_id', 'INTEGER,null'), | ||
| 1364 | + ('aicpu_task_id', 'INTEGER,null'), | ||
| 1365 | + ('plane_id', 'INTEGER,null'), | ||
| 1366 | + ('op_type', 'TEXT,null'), | ||
| 1367 | + ('data_type', 'TEXT,null'), | ||
| 1368 | + ('link_type', 'TEXT,null'), | ||
| 1369 | + ('transport_type', 'TEXT,null'), | ||
| 1370 | + ('rdma_type', 'TEXT,null'), | ||
| 1371 | + ('role', 'TEXT,null'), | ||
| 1372 | + ('ccl_tag', 'TEXT,null'), | ||
| 1373 | + ('notify_id', 'TEXT,null'), | ||
| 1374 | + ('work_flow_mode', 'TEXT,null'), | ||
| 1375 | + ('stage', 'TEXT,null') | ||
| 1376 | + ], | ||
| 1337 | 'AscendTaskMap': [ | 1377 | 'AscendTaskMap': [ |
| 1338 | ('model_id', 'INTEGER,null'), | 1378 | ('model_id', 'INTEGER,null'), |
| 1339 | ('index_id', 'INTEGER,null'), | 1379 | ('index_id', 'INTEGER,null'), |
The file is empty
| @@ -0,0 +1,73 @@ | |||
| 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 | +import logging | ||
| 18 | + | ||
| 19 | +from common_func.db_manager import DBManager | ||
| 20 | +from common_func.db_name_constant import DBNameConstant | ||
| 21 | +from common_func.ms_constant.str_constant import StrConstant | ||
| 22 | +from msmodel.interface.parser_model import ParserModel | ||
| 23 | +from msmodel.interface.view_model import ViewModel | ||
| 24 | +from profiling_bean.db_dto.dpu_track_dto import DPUTrackDto | ||
| 25 | + | ||
| 26 | + | ||
| 27 | +class DPUTaskModel(ParserModel): | ||
| 28 | + """ | ||
| 29 | + class used to operate all dpu track | ||
| 30 | + """ | ||
| 31 | + | ||
| 32 | + def __init__(self: any, result_dir: str) -> None: | ||
| 33 | + super(DPUTaskModel, self).__init__(result_dir, DBNameConstant.DB_DPU, | ||
| 34 | + [DBNameConstant.TABLE_DPU_TASK_TRACK, DBNameConstant.TABLE_DPU_HCCL_TRACK]) | ||
| 35 | + | ||
| 36 | + def flush(self: any, data_list: list, table_name: str = DBNameConstant.TABLE_DPU_TASK_TRACK) -> None: | ||
| 37 | + """ | ||
| 38 | + flush to db | ||
| 39 | + :param data_list: data | ||
| 40 | + :param table_name: table name | ||
| 41 | + :return: | ||
| 42 | + """ | ||
| 43 | + self.insert_data_to_db(table_name, data_list) | ||
| 44 | + | ||
| 45 | + | ||
| 46 | +class DPUTaskViewModel(ViewModel): | ||
| 47 | + """ | ||
| 48 | + class for dpu task viewer | ||
| 49 | + """ | ||
| 50 | + | ||
| 51 | + def __init__(self: any, result_dir: str, db_name: str, table_list: list) -> None: | ||
[review] 问题:db_name 和 table_list 完全由外部传入,但类名是 DPUTaskViewModel,理论上应绑定 DPU 相关 DB 和表。 影响:调用方可能传入错误 DB 或表,导致 get_timeline_data 查询固定 DPU 表时与初始化表列表不一致。 建议: 如果该类只服务 DPU,建议构造函数内部固定使用 DBNameConstant.DB_DPU 和 DPU 表列表;如果必须外部传参,需要校验参数合法性。 ![]() ![]() | |||
| 52 | + super().__init__(result_dir, db_name, table_list) | ||
| 53 | + | ||
| 54 | + def get_timeline_data(self: any) -> tuple: | ||
[review] 问题: DPUTrackDto 同时用于 task track 和 HCCL track 两种字段数量、字段语义明显不同的数据。 影响:DTO 字段如果不完全兼容,可能出现字段错位、属性缺失或后续解析逻辑混乱。 建议: 建议分别定义 DPUTaskTrackDto 和 DPUHcclTrackDto;如果必须复用,需要确认 DTO 明确支持两类查询结果,并补充注释说明 ![]() ![]() | |||
| 55 | + task_track = [] | ||
| 56 | + hccl_track = [] | ||
| 57 | + if DBManager.judge_table_exist(self.cur, DBNameConstant.TABLE_DPU_TASK_TRACK): | ||
| 58 | + sql = "select dpu_device_id, thread_id, start_time, end_time, task_type, stream_id, task_id, kernel_name "\ | ||
| 59 | + "from {} ".format(DBNameConstant.TABLE_DPU_TASK_TRACK) | ||
| 60 | + task_track = DBManager.fetch_all_data(self.cur, sql, dto_class=DPUTrackDto) | ||
| 61 | + | ||
| 62 | + if DBManager.judge_table_exist(self.cur, DBNameConstant.TABLE_DPU_HCCL_TRACK): | ||
| 63 | + sql = "select npu_device_id, dpu_device_id, thread_id, start_time, end_time, op_name, group_name, " \ | ||
| 64 | + "local_rank, remote_rank, rank_size, duration_estimated, src_addr, dst_addr, data_size, " \ | ||
| 65 | + "stream_id, task_id, aicpu_task_id, plane_id, op_type, data_type, link_type, transport_type, " \ | ||
| 66 | + "rdma_type, role, ccl_tag, notify_id, work_flow_mode, stage " \ | ||
| 67 | + "from {} ".format(DBNameConstant.TABLE_DPU_HCCL_TRACK) | ||
| 68 | + hccl_track = DBManager.fetch_all_data(self.cur, sql, dto_class=DPUTrackDto) | ||
| 69 | + return task_track, hccl_track | ||
| 70 | + | ||
| 71 | + | ||
| 72 | + | ||
| 73 | + | ||
| @@ -0,0 +1,248 @@ | |||
| 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 | +from msparser.add_info.add_info_bean import AddInfoBean | ||
| 18 | + | ||
| 19 | + | ||
| 20 | +class DPUHcclTrackBean(AddInfoBean): | ||
| 21 | + """ | ||
| 22 | + DPU hccl information bean data for the data parsing by acl parser. | ||
| 23 | + """ | ||
| 24 | + | ||
| 25 | + def __init__(self: any, *args) -> None: | ||
| 26 | + super().__init__(*args) | ||
| 27 | + filed = args[0] | ||
| 28 | + self._item_id = filed[6] | ||
| 29 | + self._ccl_tag = filed[7] | ||
| 30 | + self._group_name = filed[8] | ||
| 31 | + self._local_rank = filed[9] | ||
| 32 | + self._remote_rank = filed[10] | ||
| 33 | + self._rank_size = filed[11] | ||
| 34 | + self._stage = filed[12] | ||
| 35 | + self._notify_id = filed[13] | ||
| 36 | + self._start_time = filed[14] | ||
| 37 | + self._duration_estimated = filed[15] | ||
| 38 | + self._src_addr = filed[16] | ||
| 39 | + self._dst_addr = filed[17] | ||
| 40 | + self._data_size = filed[18] | ||
| 41 | + self._task_id = filed[19] | ||
| 42 | + self._aicpu_task_id = filed[20] | ||
| 43 | + self._stream_id = filed[21] | ||
| 44 | + self._plane_id = filed[22] | ||
| 45 | + self._npu_device_id = filed[23] | ||
| 46 | + self._dev_type = (filed[24] >> 12) & 0xF | ||
| 47 | + self._dpu_device_id = filed[24] & 0xFFF | ||
| 48 | + self._op_type = filed[25] | ||
| 49 | + self._data_type = filed[26] | ||
| 50 | + self._link_type = filed[27] | ||
| 51 | + self._transport_type = filed[28] | ||
| 52 | + self._rdma_type = filed[29] | ||
| 53 | + self._role = filed[30] | ||
| 54 | + self._work_flow_mode = filed[31] | ||
| 55 | + | ||
| 56 | + | ||
| 57 | + def item_id(self: any) -> str: | ||
| 58 | + """ | ||
| 59 | + hccl information id | ||
| 60 | + :return: hccl information id | ||
| 61 | + """ | ||
| 62 | + return str(self._item_id) | ||
| 63 | + | ||
| 64 | + | ||
| 65 | + def ccl_tag(self: any) -> str: | ||
| 66 | + """ | ||
| 67 | + hash number for ccl | ||
| 68 | + :return: hash number for ccl | ||
| 69 | + """ | ||
| 70 | + return str(self._ccl_tag) | ||
| 71 | + | ||
| 72 | + | ||
| 73 | + def group_name(self: any) -> str: | ||
| 74 | + """ | ||
| 75 | + hash number for ccl group | ||
| 76 | + :return: hash number for ccl group | ||
| 77 | + """ | ||
| 78 | + return str(self._group_name) | ||
| 79 | + | ||
| 80 | + | ||
| 81 | + def local_rank(self: any) -> int: | ||
| 82 | + """ | ||
| 83 | + local rank number | ||
| 84 | + :return: local rank number | ||
| 85 | + """ | ||
| 86 | + return self._local_rank | ||
| 87 | + | ||
| 88 | + | ||
| 89 | + def remote_rank(self: any) -> int: | ||
| 90 | + """ | ||
| 91 | + remote rank number | ||
| 92 | + :return: remote rank number | ||
| 93 | + """ | ||
| 94 | + return self._remote_rank | ||
| 95 | + | ||
| 96 | + | ||
| 97 | + def rank_size(self: any) -> int: | ||
| 98 | + """ | ||
| 99 | + hccl information rank size | ||
| 100 | + """ | ||
| 101 | + return self._rank_size | ||
| 102 | + | ||
| 103 | + | ||
| 104 | + def stage(self: any) -> str: | ||
| 105 | + """ | ||
| 106 | + communicate algorithm stage | ||
| 107 | + """ | ||
| 108 | + return str(self._stage) | ||
| 109 | + | ||
| 110 | + | ||
| 111 | + def notify_id(self: any) -> str: | ||
| 112 | + """ | ||
| 113 | + notify id | ||
| 114 | + """ | ||
| 115 | + return str(self._notify_id) | ||
| 116 | + | ||
| 117 | + | ||
| 118 | + def start_time(self: any) -> int: | ||
| 119 | + """ | ||
| 120 | + start time | ||
| 121 | + """ | ||
| 122 | + return self._start_time | ||
| 123 | + | ||
| 124 | + | ||
| 125 | + def duration_estimated(self: any) -> float: | ||
| 126 | + """ | ||
| 127 | + duration estimated | ||
| 128 | + """ | ||
| 129 | + return float(self._duration_estimated) | ||
| 130 | + | ||
| 131 | + | ||
| 132 | + def src_addr(self: any) -> str: | ||
| 133 | + """ | ||
| 134 | + source address | ||
| 135 | + """ | ||
| 136 | + return str(self._src_addr) | ||
| 137 | + | ||
| 138 | + | ||
| 139 | + def dst_addr(self: any) -> str: | ||
| 140 | + """ | ||
| 141 | + destination address | ||
| 142 | + """ | ||
| 143 | + return str(self._dst_addr) | ||
| 144 | + | ||
| 145 | + | ||
| 146 | + def data_size(self: any) -> int: | ||
| 147 | + """ | ||
| 148 | + data size | ||
| 149 | + """ | ||
| 150 | + return self._data_size | ||
| 151 | + | ||
| 152 | + | ||
| 153 | + def task_id(self: any) -> int: | ||
| 154 | + """ | ||
| 155 | + task id | ||
| 156 | + """ | ||
| 157 | + return self._task_id | ||
| 158 | + | ||
| 159 | + | ||
| 160 | + def aicpu_task_id(self: any) -> int: | ||
| 161 | + """ | ||
| 162 | + ai cpu task id | ||
| 163 | + """ | ||
| 164 | + return self._aicpu_task_id | ||
| 165 | + | ||
| 166 | + | ||
| 167 | + def stream_id(self: any) -> int: | ||
| 168 | + """ | ||
| 169 | + stream id | ||
| 170 | + """ | ||
| 171 | + return self._stream_id | ||
| 172 | + | ||
| 173 | + | ||
| 174 | + def plane_id(self: any) -> int: | ||
| 175 | + """ | ||
| 176 | + plane id | ||
| 177 | + """ | ||
| 178 | + return self._plane_id | ||
| 179 | + | ||
| 180 | + | ||
| 181 | + def npu_device_id(self: any) -> int: | ||
| 182 | + """ | ||
| 183 | + npu device id | ||
| 184 | + """ | ||
| 185 | + return self._npu_device_id | ||
| 186 | + | ||
| 187 | + | ||
| 188 | + def is_dpu(self: any) -> bool: | ||
| 189 | + """ | ||
| 190 | + Used to distinguish the device type(DPU:1/NPU:0) of tasks. | ||
| 191 | + """ | ||
| 192 | + return bool(self._dev_type) | ||
| 193 | + | ||
| 194 | + | ||
| 195 | + def dpu_device_id(self: any) -> int: | ||
| 196 | + """ | ||
| 197 | + device id | ||
| 198 | + """ | ||
| 199 | + return self._dpu_device_id | ||
| 200 | + | ||
| 201 | + | ||
| 202 | + def op_type(self: any) -> str: | ||
| 203 | + """ | ||
| 204 | + op type | ||
| 205 | + """ | ||
| 206 | + return str(self._op_type) | ||
| 207 | + | ||
| 208 | + | ||
| 209 | + def data_type(self: any) -> str: | ||
| 210 | + """ | ||
| 211 | + data type | ||
| 212 | + """ | ||
| 213 | + return str(self._data_type) | ||
| 214 | + | ||
| 215 | + | ||
| 216 | + def link_type(self: any) -> str: | ||
| 217 | + """ | ||
| 218 | + link type | ||
| 219 | + """ | ||
| 220 | + return str(self._link_type) | ||
| 221 | + | ||
| 222 | + | ||
| 223 | + def transport_type(self: any) -> str: | ||
| 224 | + """ | ||
| 225 | + transport type | ||
| 226 | + """ | ||
| 227 | + return str(self._transport_type) | ||
| 228 | + | ||
| 229 | + | ||
| 230 | + def rdma_type(self: any) -> str: | ||
| 231 | + """ | ||
| 232 | + RDMA type | ||
| 233 | + """ | ||
| 234 | + return str(self._rdma_type) | ||
| 235 | + | ||
| 236 | + | ||
| 237 | + def role(self: any) -> str: | ||
| 238 | + """ | ||
| 239 | + role | ||
| 240 | + """ | ||
| 241 | + return str(self._role) | ||
| 242 | + | ||
| 243 | + | ||
| 244 | + def work_flow_mode(self: any) -> str: | ||
| 245 | + """ | ||
| 246 | + mode of the work flow | ||
| 247 | + """ | ||
| 248 | + return str(self._work_flow_mode) | ||
| @@ -86,7 +86,7 @@ class HcclInfoParser(DataParser, MsMultiProcess): | |||
| 86 | self.save() | 86 | self.save() |
| 87 | 87 | ||
| 88 | def reformat_data(self) -> list: | 88 | def reformat_data(self) -> list: |
| 89 | - type_info_data = HashDictData(self._project_path).get_type_hash_dict().get("hccl", {}) | 89 | + type_info_data = HashDictData(self._project_path).get_type_hash_dict().get("communication", {}) |
| 90 | hash_data = HashDictData(self._project_path).get_ge_hash_dict() | 90 | hash_data = HashDictData(self._project_path).get_ge_hash_dict() |
| 91 | reformat = [] | 91 | reformat = [] |
| 92 | for data in self._hccl_info_data: | 92 | for data in self._hccl_info_data: |
| @@ -87,7 +87,7 @@ class MultiThreadParser(DataParser, MsMultiProcess): | |||
| 87 | self.save() | 87 | self.save() |
| 88 | 88 | ||
| 89 | def reformat_data(self) -> list: | 89 | def reformat_data(self) -> list: |
| 90 | - type_info_data = HashDictData(self._project_path).get_type_hash_dict().get("hccl", {}) | 90 | + type_info_data = HashDictData(self._project_path).get_type_hash_dict().get("communication", {}) |
| 91 | return [ | 91 | return [ |
| 92 | [data.level, type_info_data.get(data.struct_type, data.struct_type), data.thread_id, data.data_len, | 92 | [data.level, type_info_data.get(data.struct_type, data.struct_type), data.thread_id, data.data_len, |
| 93 | data.timestamp, data.thread_num, data.sub_thread_id] | 93 | data.timestamp, data.thread_num, data.sub_thread_id] |
| @@ -24,13 +24,21 @@ class TaskTrackBean(CompactInfoBean): | |||
| 24 | def __init__(self: any, *args) -> None: | 24 | def __init__(self: any, *args) -> None: |
| 25 | super().__init__(*args) | 25 | super().__init__(*args) |
| 26 | data = args[0] | 26 | data = args[0] |
| 27 | - self._device_id = data[6] | 27 | + self._dev_type = (data[6] >> 12) & 0xF |
| 28 | + self._device_id = data[6] & 0xFFF | ||
| 28 | self._stream_id = data[7] | 29 | self._stream_id = data[7] |
| 29 | self._task_id = data[8] | 30 | self._task_id = data[8] |
| 30 | self._batch_id = data[9] | 31 | self._batch_id = data[9] |
| 31 | self._task_type = data[10] | 32 | self._task_type = data[10] |
| 32 | self._kernel_name = data[11] | 33 | self._kernel_name = data[11] |
| 33 | 34 | ||
| 35 | + | ||
| 36 | + def is_dpu(self: any) -> bool: | ||
| 37 | + """ | ||
| 38 | + Used to distinguish the device type(DPU:1/NPU:0) of tasks. | ||
| 39 | + """ | ||
| 40 | + return bool(self._dev_type) | ||
| 41 | + | ||
| 34 | 42 | ||
| 35 | def device_id(self: any) -> int: | 43 | def device_id(self: any) -> int: |
| 36 | """ | 44 | """ |
| @@ -94,3 +102,53 @@ class TaskTrackChip6Bean(TaskTrackBean): | |||
| 94 | self._task_id = data[9] << 16 | data[8] | 102 | self._task_id = data[9] << 16 | data[8] |
| 95 | self._batch_id = 0 | 103 | self._batch_id = 0 |
| 96 | self._task_type = data[10] | 104 | self._task_type = data[10] |
| 105 | + | ||
| 106 | + | ||
| 107 | +class DPUTaskTrackBean(CompactInfoBean): | ||
| 108 | + """ | ||
| 109 | + dpu start log bean | ||
| 110 | + """ | ||
| 111 | + def __init__(self: any, *args) -> None: | ||
| 112 | + super().__init__(*args) | ||
| 113 | + data = args[0] | ||
| 114 | + self._dev_type = (data[6] >> 12) & 0xF | ||
| 115 | + self._device_id = data[6] & 0xFFF | ||
| 116 | + self._stream_id = data[7] | ||
| 117 | + self._task_id = data[8] | ||
| 118 | + self._task_type = data[9] | ||
| 119 | + self._start_time = data[11] | ||
| 120 | + | ||
| 121 | + | ||
| 122 | + def device_id(self: any) -> int: | ||
| 123 | + """ | ||
| 124 | + dpu task device_id | ||
| 125 | + """ | ||
| 126 | + return self._device_id | ||
| 127 | + | ||
| 128 | + | ||
| 129 | + def stream_id(self: any) -> int: | ||
| 130 | + """ | ||
| 131 | + dpu task stream_id | ||
| 132 | + """ | ||
| 133 | + return self._stream_id | ||
| 134 | + | ||
| 135 | + | ||
| 136 | + def task_id(self: any) -> int: | ||
| 137 | + """ | ||
| 138 | + dpu task task_id | ||
| 139 | + """ | ||
| 140 | + return self._task_id | ||
| 141 | + | ||
| 142 | + | ||
| 143 | + def task_type(self: any) -> str: | ||
| 144 | + """ | ||
| 145 | + dpu task task_type | ||
| 146 | + """ | ||
| 147 | + return str(self._task_type) | ||
| 148 | + | ||
| 149 | + | ||
| 150 | + def start_time(self: any) -> int: | ||
| 151 | + """ | ||
| 152 | + dpu task start_time | ||
| 153 | + """ | ||
| 154 | + return self._start_time | ||
| @@ -212,6 +212,14 @@ class StructFmt: | |||
| 212 | TASK_TRACK_FMT = "HHIIIQHHHHQQ" + "B" * TASK_TRACK_RESIDUAL_SIZE | 212 | TASK_TRACK_FMT = "HHIIIQHHHHQQ" + "B" * TASK_TRACK_RESIDUAL_SIZE |
| 213 | TASK_TRACK_DATA_SIZE = struct.calcsize(TASK_TRACK_FMT) | 213 | TASK_TRACK_DATA_SIZE = struct.calcsize(TASK_TRACK_FMT) |
| 214 | 214 | ||
| 215 | + # DPU | ||
| 216 | + DPU_TASK_TRACK_RESIDUAL_SIZE = 16 | ||
| 217 | + DPU_TASK_TRACK_FMT = "HHIIIQHHIIIQ" + "B" * DPU_TASK_TRACK_RESIDUAL_SIZE | ||
| 218 | + DPU_TASK_TRACK_SIZE = struct.calcsize(DPU_TASK_TRACK_FMT) | ||
| 219 | + DPU_HCCL_TRACK_RESIDUAL_SIZE = 120 | ||
| 220 | + DPU_HCCL_TRACK_FMT = "HHIIIQQQQIIIIQQQQQQIIHHHHBBBBBBBB" + "B" * DPU_HCCL_TRACK_RESIDUAL_SIZE | ||
| 221 | + DPU_HCCL_TRACK_SIZE = struct.calcsize(DPU_HCCL_TRACK_FMT) | ||
| 222 | + | ||
| 215 | # capture | 223 | # capture |
| 216 | CAPTURE_STREAM_INFO_RESIDUAL_SIZE = 32 | 224 | CAPTURE_STREAM_INFO_RESIDUAL_SIZE = 32 |
| 217 | CAPTURE_STREAM_INFO_FMT = "HHIIIQHHHH" + "B" * CAPTURE_STREAM_INFO_RESIDUAL_SIZE | 225 | CAPTURE_STREAM_INFO_FMT = "HHIIIQHHHH" + "B" * CAPTURE_STREAM_INFO_RESIDUAL_SIZE |
| @@ -0,0 +1,53 @@ | |||
| 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 | +from dataclasses import dataclass | ||
| 18 | +from common_func.constant import Constant | ||
| 19 | +from profiling_bean.db_dto.dto_meta_class import InstanceCheckMeta | ||
| 20 | + | ||
| 21 | + | ||
| 22 | + | ||
| 23 | +class DPUTrackDto(metaclass=InstanceCheckMeta): | ||
| 24 | + npu_device_id: int = Constant.DEFAULT_INVALID_VALUE | ||
| 25 | + dpu_device_id: int = Constant.DEFAULT_INVALID_VALUE | ||
| 26 | + start_time: int = Constant.DEFAULT_INVALID_VALUE | ||
| 27 | + end_time: int = Constant.DEFAULT_INVALID_VALUE | ||
| 28 | + stream_id: int = Constant.DEFAULT_INVALID_VALUE | ||
| 29 | + aicpu_task_id: int = Constant.DEFAULT_INVALID_VALUE | ||
| 30 | + task_id: int = Constant.DEFAULT_INVALID_VALUE | ||
| 31 | + task_type: str = Constant.NA | ||
| 32 | + kernel_name: str = Constant.NA | ||
| 33 | + ccl_tag: str = Constant.NA | ||
| 34 | + data_type: str = Constant.NA | ||
| 35 | + dst_addr: str = Constant.DEFAULT_INVALID_VALUE | ||
| 36 | + duration_estimated: int = Constant.DEFAULT_INVALID_VALUE | ||
| 37 | + group_name: str = Constant.NA | ||
| 38 | + link_type: str = Constant.NA | ||
| 39 | + local_rank: int = Constant.DEFAULT_INVALID_VALUE | ||
| 40 | + notify_id: int = Constant.DEFAULT_INVALID_VALUE | ||
| 41 | + op_name: str = Constant.NA | ||
| 42 | + op_type: str = Constant.NA | ||
| 43 | + plane_id: int = Constant.DEFAULT_INVALID_VALUE | ||
| 44 | + rank_size: int = Constant.DEFAULT_INVALID_VALUE | ||
| 45 | + rdma_type: str = Constant.NA | ||
| 46 | + remote_rank: int = Constant.DEFAULT_INVALID_VALUE | ||
| 47 | + role: str = Constant.NA | ||
| 48 | + data_size: int = Constant.DEFAULT_INVALID_VALUE | ||
| 49 | + src_addr: str = Constant.DEFAULT_INVALID_VALUE | ||
| 50 | + stage: str = Constant.DEFAULT_INVALID_VALUE | ||
| 51 | + thread_id: int = Constant.DEFAULT_INVALID_VALUE | ||
| 52 | + transport_type: str = Constant.NA | ||
| 53 | + work_flow_mode: str = Constant.NA | ||
| @@ -110,6 +110,8 @@ class DataTag(Enum): | |||
| 110 | LPM_INFO = 88 | 110 | LPM_INFO = 88 |
| 111 | STREAM_EXPAND = 89 | 111 | STREAM_EXPAND = 89 |
| 112 | RUNTIME_OP_INFO = 90 | 112 | RUNTIME_OP_INFO = 90 |
| 113 | + DPU_HCCL_TRACK = 91 | ||
| 114 | + DPU_TASK_TRACK = 92 | ||
| 113 | 115 | ||
| 114 | 116 | ||
| 115 | 117 | ||
| @@ -95,6 +95,8 @@ class StructDecoder: | |||
| 95 | "RuntimeOpInfo256Bean": StructFmt.RUNTIME_OP_INFO_256_FMT, | 95 | "RuntimeOpInfo256Bean": StructFmt.RUNTIME_OP_INFO_256_FMT, |
| 96 | "V5ExeomBean": StructFmt.V5_MODEL_EXEOM_FMT, | 96 | "V5ExeomBean": StructFmt.V5_MODEL_EXEOM_FMT, |
| 97 | "V5StarsBean": StructFmt.V5_STARS_PROFILE_FMT, | 97 | "V5StarsBean": StructFmt.V5_STARS_PROFILE_FMT, |
| 98 | + "DPUHcclInfoBean":StructFmt.DPU_HCCL_TRACK_FMT, | ||
| 99 | + "DPUTaskTrackBean":StructFmt.DPU_TASK_TRACK_FMT, | ||
| 98 | } | 100 | } |
| 99 | 101 | ||
| 100 | 102 | ||
| @@ -1,6 +1,18 @@ | |||
| 1 | -#!/usr/bin/python3 | 1 | +# ------------------------------------------------------------------------- |
| 2 | -# -*- coding: utf-8 -*- | 2 | +# Copyright (c) 2026 Huawei Technologies Co., Ltd. |
| 3 | -# Copyright (c) Huawei Technologies Co., Ltd. 2024. All rights reserved. | 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 | +# ------------------------------------------------------------------------- | ||
| 4 | 16 | ||
| 5 | from abc import ABC | 17 | from abc import ABC |
| 6 | 18 | ||
| @@ -0,0 +1,163 @@ | |||
| 1 | +#!/usr/bin/env python | ||
| 2 | +# coding=utf-8 | ||
| 3 | +# ------------------------------------------------------------------------- | ||
| 4 | +# Copyright (c) 2026 Huawei Technologies Co., Ltd. | ||
| 5 | +# This file is part of the MindStudio project. | ||
| 6 | +# | ||
| 7 | +# MindStudio is licensed under Mulan PSL v2. | ||
| 8 | +# You can use this software according to the terms and conditions of the Mulan PSL v2. | ||
| 9 | +# You may obtain a copy of Mulan PSL v2 at: | ||
| 10 | +# | ||
| 11 | +# http://license.coscl.org.cn/MulanPSL2 | ||
| 12 | +# | ||
| 13 | +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, | ||
| 14 | +# EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, | ||
| 15 | +# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. | ||
| 16 | +# See the Mulan PSL v2 for more details. | ||
| 17 | +# ------------------------------------------------------------------------- | ||
| 18 | + | ||
| 19 | +import unittest | ||
| 20 | + | ||
| 21 | +from common_func.trace_view_manager import TraceViewManager | ||
| 22 | +from common_func.trace_view_header_constant import TraceViewHeaderConstant | ||
| 23 | +from common_func.info_conf_reader import InfoConfReader | ||
| 24 | + | ||
| 25 | +NAMESPACE = 'common_func.trace_view_manager' | ||
| 26 | + | ||
| 27 | + | ||
| 28 | +class TestTraceViewManager(unittest.TestCase): | ||
| 29 | + | ||
| 30 | + def setUp(self): | ||
| 31 | + """初始化测试环境""" | ||
| 32 | + self.PID_OFFSET = TraceViewManager.PID_OFFSET | ||
| 33 | + self.INDEX_OFFSET = TraceViewManager.INDEX_OFFSET | ||
| 34 | + self.HOST_ID_FOR_PID = TraceViewManager.HOST_ID_FOR_PID | ||
| 35 | + InfoConfReader()._info_json = {"pid": 111, "devices": "2"} | ||
| 36 | + | ||
| 37 | + def tearDown(self): | ||
| 38 | + InfoConfReader()._info_json.clear() | ||
| 39 | + | ||
| 40 | + def _create_layer_info(self, general_layer, sort_index=0): | ||
| 41 | + """创建 LayerInfo 测试对象""" | ||
| 42 | + return TraceViewHeaderConstant.LayerInfo( | ||
| 43 | + component_layer=TraceViewHeaderConstant.COMPONENT_LAYER_CANN, | ||
| 44 | + general_layer=general_layer, | ||
| 45 | + sort_index=sort_index | ||
| 46 | + ) | ||
| 47 | + | ||
| 48 | + def test_get_format_pid_with_dpu_layer(self): | ||
| 49 | + """测试 DPU 层的 format_pid 计算""" | ||
| 50 | + layer_info = self._create_layer_info( | ||
| 51 | + general_layer=TraceViewHeaderConstant.GENERAL_LAYER_DPU, | ||
| 52 | + sort_index=5 | ||
| 53 | + ) | ||
| 54 | + | ||
| 55 | + # pid=1 会被用作 device_id,然后 pid 被重新赋值为 11 | ||
| 56 | + result = TraceViewManager.get_format_pid(pid=1, layer_info=layer_info) | ||
| 57 | + | ||
| 58 | + # format_pid = (111 << 22) | (5 << 5) | 1 | ||
| 59 | + expected = (111 << self.PID_OFFSET) | (5 << self.INDEX_OFFSET) | 1 | ||
| 60 | + self.assertEqual(result, expected) | ||
| 61 | + | ||
| 62 | + def test_get_format_pid_with_cpu_layer(self): | ||
| 63 | + """测试 CPU 层的 format_pid 计算""" | ||
| 64 | + layer_info = self._create_layer_info( | ||
| 65 | + general_layer=TraceViewHeaderConstant.GENERAL_LAYER_CPU, | ||
| 66 | + sort_index=10 | ||
| 67 | + ) | ||
| 68 | + | ||
| 69 | + # CPU 层使用 HOST_ID_FOR_PID 作为 device_id | ||
| 70 | + result = TraceViewManager.get_format_pid(pid=200, layer_info=layer_info) | ||
| 71 | + | ||
| 72 | + # format_pid = (200 << 22) | (10 << 5) | HOST_ID_FOR_PID | ||
| 73 | + expected = (200 << self.PID_OFFSET) | (10 << self.INDEX_OFFSET) | self.HOST_ID_FOR_PID | ||
| 74 | + self.assertEqual(result, expected) | ||
| 75 | + | ||
| 76 | + def test_get_format_pid_with_invalid_device_id(self): | ||
| 77 | + """测试无效 device_id 的情况""" | ||
| 78 | + layer_info = self._create_layer_info( | ||
| 79 | + general_layer='OTHER_LAYER', # 非 DPU、非 CPU | ||
| 80 | + sort_index=3 | ||
| 81 | + ) | ||
| 82 | + InfoConfReader()._info_json = {"pid": 111, "devices": "kk"} | ||
| 83 | + result = TraceViewManager.get_format_pid(pid=150, layer_info=layer_info) | ||
| 84 | + | ||
| 85 | + # 无效 device_id 时使用 HOST_ID_FOR_PID | ||
| 86 | + expected = (150 << self.PID_OFFSET) | (3 << self.INDEX_OFFSET) | self.HOST_ID_FOR_PID | ||
| 87 | + self.assertEqual(result, expected) | ||
| 88 | + | ||
| 89 | + def test_get_format_pid_with_valid_device_id(self): | ||
| 90 | + """测试有效 device_id 的情况""" | ||
| 91 | + layer_info = self._create_layer_info( | ||
| 92 | + general_layer='OTHER_LAYER', | ||
| 93 | + sort_index=7 | ||
| 94 | + ) | ||
| 95 | + | ||
| 96 | + result = TraceViewManager.get_format_pid(pid=300, layer_info=layer_info) | ||
| 97 | + | ||
| 98 | + # format_pid = (300 << 22) | (7 << 5) | 2 | ||
| 99 | + expected = (300 << self.PID_OFFSET) | (7 << self.INDEX_OFFSET) | 2 | ||
| 100 | + self.assertEqual(result, expected) | ||
| 101 | + | ||
| 102 | + def test_get_format_pid_with_zero_sort_index(self): | ||
| 103 | + """测试 sort_index 为 0 的情况""" | ||
| 104 | + layer_info = self._create_layer_info( | ||
| 105 | + general_layer='OTHER_LAYER', | ||
| 106 | + sort_index=0 | ||
| 107 | + ) | ||
| 108 | + | ||
| 109 | + result = TraceViewManager.get_format_pid(pid=50, layer_info=layer_info) | ||
| 110 | + | ||
| 111 | + expected = (50 << self.PID_OFFSET) | (0 << self.INDEX_OFFSET) | 2 | ||
| 112 | + self.assertEqual(result, expected) | ||
| 113 | + | ||
| 114 | + def test_get_format_pid_bit_structure(self): | ||
| 115 | + """验证位结构正确性""" | ||
| 116 | + layer_info = self._create_layer_info( | ||
| 117 | + general_layer='OTHER_LAYER', | ||
| 118 | + sort_index=15 | ||
| 119 | + ) | ||
| 120 | + | ||
| 121 | + test_pid = 1000 | ||
| 122 | + result = TraceViewManager.get_format_pid(pid=test_pid, layer_info=layer_info) | ||
| 123 | + | ||
| 124 | + # 验证各个字段的提取 | ||
| 125 | + extracted_device_id = result & 0x1F # 低 5 位 | ||
| 126 | + extracted_sort_index = (result >> self.INDEX_OFFSET) & 0x1F # 中间 5 位 | ||
| 127 | + extracted_pid = result >> self.PID_OFFSET # 高 22 位 | ||
| 128 | + | ||
| 129 | + self.assertEqual(extracted_device_id, 2) | ||
| 130 | + self.assertEqual(extracted_sort_index, 15) | ||
| 131 | + self.assertEqual(extracted_pid, test_pid) | ||
| 132 | + | ||
| 133 | + def test_get_format_pid_dpu_layer_preserves_original_pid_as_device_id(self): | ||
| 134 | + """测试 DPU 层中原始 pid 被用作 device_id""" | ||
| 135 | + layer_info = self._create_layer_info( | ||
| 136 | + general_layer=TraceViewHeaderConstant.GENERAL_LAYER_DPU, | ||
| 137 | + sort_index=1 | ||
| 138 | + ) | ||
| 139 | + | ||
| 140 | + original_pid = 7 | ||
| 141 | + result = TraceViewManager.get_format_pid(pid=original_pid, layer_info=layer_info) | ||
| 142 | + | ||
| 143 | + # 验证 device_id 是原始的 pid | ||
| 144 | + extracted_device_id = result & 0x1F | ||
| 145 | + self.assertEqual(extracted_device_id, original_pid) | ||
| 146 | + | ||
| 147 | + # 验证 pid 被替换为 get_json_pid_data 的返回值 | ||
| 148 | + extracted_pid = result >> self.PID_OFFSET | ||
| 149 | + self.assertEqual(extracted_pid, 111) | ||
| 150 | + | ||
| 151 | + def test_get_format_pid_string_device_id_conversion(self): | ||
| 152 | + """测试字符串 device_id 转换为整数""" | ||
| 153 | + layer_info = self._create_layer_info( | ||
| 154 | + general_layer='OTHER_LAYER', | ||
| 155 | + sort_index=2 | ||
| 156 | + ) | ||
| 157 | + | ||
| 158 | + result = TraceViewManager.get_format_pid(pid=100, layer_info=layer_info) | ||
| 159 | + | ||
| 160 | + extracted_device_id = result & 0x1F | ||
| 161 | + self.assertEqual(extracted_device_id, 2) | ||
| 162 | + self.assertIsInstance(extracted_device_id, int) | ||
| 163 | + | ||


[review] 问题: data_list: list 类型过于宽泛,未说明元素类型。 影响:调用方无法明确需要传入什么结构的数据,后续维护和静态检查困难。 建议: 建议改成更明确的类型,例如 list[DPUTrackDto]、list[tuple] 或 Sequence[...],根据 insert_data_to_db 实际要求确定。