From 9280f421a54e8344c8d22e7a42e11a09d49dd6f1 Mon Sep 17 00:00:00 2001 From: z30043230 Date: Sat, 6 Sep 2025 14:47:55 +0800 Subject: [PATCH] =?UTF-8?q?mstt=20cluster=5Frecipe=E9=83=A8=E5=88=86UT?= =?UTF-8?q?=E8=A1=A5=E5=85=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../recipes/test_mstx2commop.py | 97 +++++++++++++++++++ .../recipes/test_p2p_pairing.py | 71 ++++++++++++++ .../cluster_analyse/recipes/test_slow_rank.py | 42 +++++++- 3 files changed, 207 insertions(+), 3 deletions(-) create mode 100644 profiler/msprof_analyze/test/ut/cluster_analyse/recipes/test_mstx2commop.py create mode 100644 profiler/msprof_analyze/test/ut/cluster_analyse/recipes/test_p2p_pairing.py diff --git a/profiler/msprof_analyze/test/ut/cluster_analyse/recipes/test_mstx2commop.py b/profiler/msprof_analyze/test/ut/cluster_analyse/recipes/test_mstx2commop.py new file mode 100644 index 000000000..2d00eb1c0 --- /dev/null +++ b/profiler/msprof_analyze/test/ut/cluster_analyse/recipes/test_mstx2commop.py @@ -0,0 +1,97 @@ +# Copyright (c) 2025, Huawei Technologies Co., Ltd. +# All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os +import unittest +from unittest.mock import patch +import pandas as pd + +from msprof_analyze.cluster_analyse.recipes.mstx2commop.mstx2commop import Mstx2Commop +from msprof_analyze.prof_common.constant import Constant + + +class TestMstx2Commop(unittest.TestCase): + + @patch("msprof_analyze.prof_common.db_manager.DBManager.insert_data_into_db") + @patch("msprof_analyze.cluster_analyse.recipes.base_recipe_analysis.BaseRecipeAnalysis.dump_data") + @patch("msprof_analyze.prof_exports.base_stats_export.BaseStatsExport.read_export_db") + @patch("msprof_analyze.cluster_analyse.recipes.ep_load_balance.ep_load_balance.DatabaseService.query_data") + @patch("msprof_analyze.prof_common.db_manager.DBManager.check_tables_in_db", return_value=False) + def test_mapper_func_should_convert_mstx_checkpoints_to_communication_operators(self, mock_check_tables_in_db, + mock_db_service, mock_read_export_db, mock_dump_data, mock_insert_data_into_db): + mock_db_service.return_value = { + "ENUM_HCCL_DATA_TYPE": pd.DataFrame( + { + "id": [0, 1], + "name": ["INT64", "BFP16"] + } + ), + "STRING_IDS": pd.DataFrame( + { + "id": [0, 1], + "value": ["AIC", "AIV"] + } + ) + } + mock_read_export_db.return_value = pd.DataFrame( + { + "startNs": [1755066160966106180, 1755066161966106180], + "endNs": [1755066160966206180, 1755066161966206180], + "connectionId": [4000000004, 4000000005], + "value": [ + '{"streamId": "9","count": "8194","dataType": "int64",' + '"groupName": "group_name_29","opName": "HcclBroadcast"}', + '{"streamId": "10","count": "8","dataType": "bfp16",' + '"groupName": "group_name_84","opName": "HcclAlltoAllV"}' + ], + } + ) + params = {Constant.EXPORT_TYPE: Constant.DB} + recipe = Mstx2Commop(params) + recipe.copy_db = False + data_map = {Constant.RANK_ID: 0, Constant.PROFILER_DB_PATH: "", + Constant.ANALYSIS_DB_PATH: "", Constant.STEP_RANGE: {}} + recipe._mapper_func(data_map, "Mstx2Commop") + args, kwargs = mock_dump_data.call_args + communication_op = kwargs["data"] + args, kwargs = mock_insert_data_into_db.call_args + string_ids_insert = args[2] + new_value = {x[1] for x in string_ids_insert} + min_id = min([x[0] for x in string_ids_insert]) + self.assertEqual(len(communication_op), 2) + self.assertEqual(min_id, 2) + self.assertEqual(new_value, {"HcclAlltoAllV_", "HcclBroadcast_", "group_name_29", "group_name_84", + "HcclAlltoAllV__648_0_1", "HcclBroadcast__843_0_1"}) + + @patch("shutil.copyfile") + @patch("msprof_analyze.prof_common.path_manager.PathManager.make_dir_safety") + def test_prepare_output_profiler_db_should_return_new_db_path_when_copy_db_is_true(self, mock_make_dir_safety, + mock_copyfile): + params = { + Constant.COLLECTION_PATH: "./", + Constant.DATA_TYPE: Constant.DB, + Constant.CLUSTER_ANALYSIS_OUTPUT_PATH: "", + Constant.RECIPE_NAME: "Mstx2Commop", + Constant.EXPORT_TYPE: Constant.DB, + } + recipe = Mstx2Commop(params) + new_db_path = recipe._prepare_output_profiler_db( + os.path.join("msprof_ascend_pt", "ASCEND_PROFILER_OUTPUT", "ascend_pytorch_profiler_0.db") + ) + expected_db_path = os.path.join( + "cluster_analysis_output", "Mstx2Commop", "msprof_ascend_pt", + "ASCEND_PROFILER_OUTPUT", "ascend_pytorch_profiler_0.db" + ) + self.assertEqual(new_db_path, expected_db_path) \ No newline at end of file diff --git a/profiler/msprof_analyze/test/ut/cluster_analyse/recipes/test_p2p_pairing.py b/profiler/msprof_analyze/test/ut/cluster_analyse/recipes/test_p2p_pairing.py new file mode 100644 index 000000000..52266b969 --- /dev/null +++ b/profiler/msprof_analyze/test/ut/cluster_analyse/recipes/test_p2p_pairing.py @@ -0,0 +1,71 @@ +# Copyright (c) 2025, Huawei Technologies Co., Ltd. +# All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import unittest +from unittest.mock import patch +import pandas as pd + +from msprof_analyze.cluster_analyse.recipes.p2p_pairing.p2p_pairing import P2PPairing +from msprof_analyze.prof_common.constant import Constant + + +class TestP2PPairing(unittest.TestCase): + + @patch("msprof_analyze.cluster_analyse.recipes.p2p_pairing.p2p_pairing.DBManager") + def test_mapper_func_should_convert_mstx_checkpoints_to_communication_operators(self, mock_db_manager_class): + mock_db_manager_class.create_connect_db.return_value = (None, None) + mock_db_manager_class.check_columns_exist.return_value = set() + recipe = P2PPairing({}) + expected_result = pd.DataFrame( + { + "opNameId": [707], + "opConnectionId": ["849_0_0_0"] + } + ) + recipe.update_connection_info_to_table(expected_result, "") + + + @patch("msprof_analyze.cluster_analyse.recipes.p2p_pairing.p2p_pairing.P2PPairing.update_connection_info_to_table") + @patch("msprof_analyze.prof_exports.base_stats_export.BaseStatsExport.read_export_db") + @patch("msprof_analyze.prof_common.db_manager.DBManager.check_tables_in_db", return_value=True) + def test_mapper_func_should_generate_p2p_connection_ids(self, mock_check_tables_in_db, + mock_read_export_db, mock_update_connection_info_to_table): + mock_read_export_db.return_value = pd.DataFrame( + { + "opNameId": [707, 707], + "opName": ["hcom_send__849_56_1", "hcom_send__849_56_1"], + "startTime": [1755066160966106180, 1755066161066106180], + "endTime": [1755066160966206180, 1755066161066206180], + "globalRank": [0, 0], + "srcRank": [0, 0], + "dstRank": [0, 4294967295], + "taskType": ["Notify_Record", "Reduce+Inline"], + "coGroupName": ["100%enp189s0f1_55000_0_1738895521183247", "100%enp189s0f1_55000_0_1738895521183247"], + "ctiGroupName": ["100%enp189s0f1_55000_0_1738895521183247", "100%enp189s0f1_55000_0_1738895521183247"], + } + ) + recipe = P2PPairing({}) + data_map = {Constant.RANK_ID: 0, Constant.PROFILER_DB_PATH: "", + Constant.ANALYSIS_DB_PATH: "", Constant.STEP_RANGE: {}} + recipe._mapper_func(data_map, "P2PPairing") + args, kwargs = mock_update_connection_info_to_table.call_args + expected_result = pd.DataFrame( + { + "opNameId": [707], + "opConnectionId": ["849_0_0_0"] + } + ) + self.assertTrue(expected_result.equals(args[0])) + diff --git a/profiler/msprof_analyze/test/ut/cluster_analyse/recipes/test_slow_rank.py b/profiler/msprof_analyze/test/ut/cluster_analyse/recipes/test_slow_rank.py index 9fecb4f2a..deb183a92 100644 --- a/profiler/msprof_analyze/test/ut/cluster_analyse/recipes/test_slow_rank.py +++ b/profiler/msprof_analyze/test/ut/cluster_analyse/recipes/test_slow_rank.py @@ -13,12 +13,13 @@ # See the License for the specific language governing permissions and # limitations under the License. - import unittest - +from unittest.mock import patch import pandas as pd -from msprof_analyze.cluster_analyse.recipes.slow_rank.slow_rank import judge_norm, judge_dixon, SlowRankVoteAnalysis +from msprof_analyze.cluster_analyse.recipes.slow_rank.slow_rank import (judge_norm, judge_dixon, + SlowRankVoteAnalysis, SlowRankAnalysis) +from msprof_analyze.prof_common.constant import Constant class TestJudgeNorm(unittest.TestCase): @@ -48,6 +49,12 @@ class TestJudgeDixon(unittest.TestCase): res = judge_dixon(data_with_outlier) self.assertEqual(res, [i]) + def test_judge_dixon_should_return_empty_list_when_time_list_length_less_than_3(self): + self.assertEqual(judge_dixon([1, 2]), []) + + def test_judge_dixon_should_return_empty_list_when_the_denominator_maybe_zero(self): + self.assertEqual(judge_dixon([1, 2, 3, 3, 1]), []) + class TestVoteAnalysis(unittest.TestCase): @@ -99,3 +106,32 @@ class TestVoteAnalysis(unittest.TestCase): } } self.assertEqual(res, golden_res) + + +class TestSlowRankAnalysis(unittest.TestCase): + + @patch("msprof_analyze.cluster_analyse.recipes.base_recipe_analysis.BaseRecipeAnalysis.dump_data") + @patch("msprof_analyze.cluster_analyse.recipes.base_recipe_analysis.BaseRecipeAnalysis.add_helper_file") + @patch("msprof_analyze.cluster_analyse.recipes.base_recipe_analysis.BaseRecipeAnalysis.create_notebook") + @patch("msprof_analyze.cluster_analyse.recipes.base_recipe_analysis.BaseRecipeAnalysis.mapper_func") + def test_run_should_save_db_or_notebook(self, mock_mapper_func, mock_create_notebook, + mock_add_helper_file, mock_dump_data): + mock_mapper_func.return_value = [ + pd.DataFrame({ + "rankId": [0, 0], + "groupName": ["100%enp189s0f1_55000_0_1738895521183247", "100%enp189s0f1_55000_0_1738895521183247"], + "opName": ["hcom_broadcast__559_0_1", "hcom_broadcast__559_0_1"], + "communication_time": [16225.3, 555.7] + }), + pd.DataFrame({ + "rankId": [1, 1], + "groupName": ["100%enp189s0f1_55000_0_1738895521183247", "100%enp189s0f1_55000_0_1738895521183247"], + "opName": ["hcom_broadcast__559_0_1", "hcom_broadcast__559_0_1"], + "communication_time": [24224.1, 555.6] + }) + ] + params = {Constant.EXPORT_TYPE: Constant.DB} + recipe = SlowRankAnalysis(params) + recipe.run(context=None) + recipe._export_type = "notebook" + recipe.run(context=None) \ No newline at end of file -- Gitee