已合并
[feat][v2.10.0]torch_npu profiler analysis ability of display prof level0 && kernel shapes #44928
xieanran创建于 16 天前
[feat][v2.10.0]torch_npu profiler analysis ability of display prof level0 && kernel shapes #44928
已合并
共 3 个文件变更+96-49
| @@ -1,56 +1,94 @@ | |||
| 1 | -import unittest | 1 | +import tempfile |
| 2 | -from unittest.mock import patch, MagicMock | 2 | +from unittest.mock import patch |
| 3 | -from torch_npu.profiler.analysis.prof_common_func._constant import Constant | 3 | + |
| 4 | +from torch_npu.profiler.analysis.prof_bean._op_summary_bean import OpSummaryBean | ||
| 5 | +from torch_npu.profiler.analysis.prof_common_func._csv_headers import CsvHeaders | ||
| 4 | from torch_npu.profiler.analysis.prof_view._kernel_view_parser import KernelViewParser | 6 | from torch_npu.profiler.analysis.prof_view._kernel_view_parser import KernelViewParser |
| 7 | +from torch_npu.testing.testcase import TestCase, run_tests | ||
| 5 | 8 | ||
| 6 | 9 | ||
| 7 | -def run_test(): | 10 | +class TestKernelViewParser(TestCase): |
| 8 | - loader = unittest.TestLoader() | ||
| 9 | - suite = unittest.TestSuite() | ||
| 10 | - suite.addTests(loader.loadTestsFromTestCase(TestKernelViewParser)) | ||
| 11 | 11 | ||
| 12 | - runner = unittest.TextTestRunner(verbosity=2) | 12 | + def setUp(self): |
| 13 | - runner.run(suite) | 13 | + super().setUp() |
| 14 | - | 14 | + self.temp_dir = tempfile.TemporaryDirectory() |
| 15 | - | 15 | + self.parser_params = { |
| 16 | -class TestKernelViewParser(unittest.TestCase): | 16 | + "profiler_path": self.temp_dir.name, |
| 17 | - | 17 | + "output_path": self.temp_dir.name, |
| 18 | - def test_profect_map_for_headers_mixed(self): | ||
| 19 | - input_headers = ["Op Name", "Unknown Header", "Kernel Duration"] | ||
| 20 | - result = KernelViewParser._project_map_for_headers(input_headers) | ||
| 21 | - expected = {"op_name", "Unknown Header", "Kernel Duration"} | ||
| 22 | - self.assertEqual(result, expected) | ||
| 23 | - | ||
| 24 | - | ||
| 25 | - | ||
| 26 | - | ||
| 27 | - | ||
| 28 | - def test_run_success(self, mock_relation_parser, mock_file_manager, mock_cann_parser, | ||
| 29 | - mock_config): | ||
| 30 | - mock_config_instance = mock_config.return_value | ||
| 31 | - mock_config_instance.load_info.return_value = None | ||
| 32 | - mock_cann_parser_instance = mock_cann_parser.return_value | ||
| 33 | - mock_cann_parser_instance.get_file_list_by_type.return_value = ["test_file.csv"] | ||
| 34 | - mock_file_manager.read_csv_file.return_value = [MagicMock(row=["test", "data"])] | ||
| 35 | - mock_relation_parser_instance = mock_relation_parser.return_value | ||
| 36 | - mock_relation_parser_instance.get_step_range.return_value = [{"step_id": 1, "start_ts": 1000, "end_ts": 2000}] | ||
| 37 | - | ||
| 38 | - parser = KernelViewParser("test", {}) | ||
| 39 | - parser._profiler_path = "/test/path" | ||
| 40 | - parser._output_path = "/test/output" | ||
| 41 | - deps_data = { | ||
| 42 | - Constant.TREE_BUILD_PARSER: [MagicMock()], | ||
| 43 | - Constant.RELATION_PARSER: {"test": "data"} | ||
| 44 | } | 18 | } |
| 45 | - result = parser.run(deps_data) | 19 | + OpSummaryBean.headers = [] |
| 46 | - self.assertEqual(result, (Constant.SUCCESS, None)) | 20 | + |
| 21 | + def tearDown(self): | ||
| 22 | + OpSummaryBean.headers = [] | ||
| 23 | + self.temp_dir.cleanup() | ||
| 24 | + super().tearDown() | ||
| 25 | + | ||
| 26 | + def test_project_map_for_headers(self): | ||
| 27 | + input_headers = ["Op Name", "Unknown Header", "Task Duration(us)"] | ||
| 47 | 28 | ||
| 48 | - def test_profect_map_for_headers_matching(self): | ||
| 49 | - input_headers = ["Name", "Kernel Time (ns)", "Calls"] | ||
| 50 | result = KernelViewParser._project_map_for_headers(input_headers) | 29 | result = KernelViewParser._project_map_for_headers(input_headers) |
| 51 | - expected = ["op_name", "kernel_time", "calls"] | 30 | + |
| 52 | - self.assertEqual(result, expected) | 31 | + self.assertEqual(["Name", "Unknown Header", "Duration(us)"], result) |
| 32 | + | ||
| 33 | + def test_get_kernel_headers_for_level0_without_shape(self): | ||
| 34 | + all_headers = CsvHeaders.OP_SUMMARY_SHOW_HEADERS + ["Model ID"] | ||
| 35 | + | ||
| 36 | + result = KernelViewParser._get_kernel_headers(all_headers, False) | ||
| 37 | + | ||
| 38 | + self.assertEqual(CsvHeaders.OP_SUMMARY_SHOW_HEADERS, result) | ||
| 39 | + | ||
| 40 | + def test_get_kernel_headers_for_level0_with_shape(self): | ||
| 41 | + all_headers = (CsvHeaders.OP_SUMMARY_SHOW_HEADERS + ["Model ID"] | ||
| 42 | + + CsvHeaders.OP_SUMMARY_SHAPE_HEADERS) | ||
| 43 | + | ||
| 44 | + result = KernelViewParser._get_kernel_headers(all_headers, False) | ||
| 45 | + | ||
| 46 | + self.assertEqual(CsvHeaders.OP_SUMMARY_SHOW_HEADERS + CsvHeaders.OP_SUMMARY_SHAPE_HEADERS, result) | ||
| 47 | + | ||
| 48 | + def test_get_kernel_headers_for_non_level0(self): | ||
| 49 | + all_headers = CsvHeaders.OP_SUMMARY_SHOW_HEADERS + ["Model ID"] | ||
| 50 | + | ||
| 51 | + result = KernelViewParser._get_kernel_headers(all_headers, True) | ||
| 52 | + | ||
| 53 | + self.assertEqual(all_headers, result) | ||
| 54 | + | ||
| 55 | + | ||
| 56 | + | ||
| 57 | + | ||
| 58 | + def test_generate_level0_view_without_shape(self, mock_file_manager, mock_cann_parser, mock_config): | ||
| 59 | + source_headers = CsvHeaders.OP_SUMMARY_SHOW_HEADERS + ["Model ID"] | ||
| 60 | + source_data = {header: str(index) for index, header in enumerate(source_headers)} | ||
| 61 | + mock_cann_parser.return_value.get_file_list_by_type.return_value = ["op_summary.csv"] | ||
| 62 | + mock_file_manager.read_csv_file.return_value = [OpSummaryBean(source_data)] | ||
| 63 | + mock_config.return_value.is_all_kernel_headers.return_value = False | ||
| 64 | + parser = KernelViewParser("test", self.parser_params) | ||
| 65 | + | ||
| 66 | + parser.generate_view() | ||
| 67 | + | ||
| 68 | + expected_row = [[source_data.get(header) for header in CsvHeaders.OP_SUMMARY_SHOW_HEADERS]] | ||
| 69 | + mock_file_manager.create_csv_file.assert_called_once_with( | ||
| 70 | + parser._output_path, expected_row, parser.KERNEL_VIEW, CsvHeaders.OP_SUMMARY_KERNEL_BASE_HEADERS) | ||
| 71 | + | ||
| 72 | + | ||
| 73 | + | ||
| 74 | + | ||
| 75 | + def test_generate_level0_view_with_shape(self, mock_file_manager, mock_cann_parser, mock_config): | ||
| 76 | + source_headers = (CsvHeaders.OP_SUMMARY_SHOW_HEADERS + ["Model ID"] | ||
| 77 | + + CsvHeaders.OP_SUMMARY_SHAPE_HEADERS) | ||
| 78 | + source_data = {header: str(index) for index, header in enumerate(source_headers)} | ||
| 79 | + mock_cann_parser.return_value.get_file_list_by_type.return_value = ["op_summary.csv"] | ||
| 80 | + mock_file_manager.read_csv_file.return_value = [OpSummaryBean(source_data)] | ||
| 81 | + mock_config.return_value.is_all_kernel_headers.return_value = False | ||
| 82 | + parser = KernelViewParser("test", self.parser_params) | ||
| 83 | + | ||
| 84 | + parser.generate_view() | ||
| 85 | + | ||
| 86 | + expected_source_headers = CsvHeaders.OP_SUMMARY_SHOW_HEADERS + CsvHeaders.OP_SUMMARY_SHAPE_HEADERS | ||
| 87 | + expected_row = [[source_data.get(header) for header in expected_source_headers]] | ||
| 88 | + expected_output_headers = CsvHeaders.OP_SUMMARY_KERNEL_BASE_HEADERS + CsvHeaders.OP_SUMMARY_SHAPE_HEADERS | ||
| 89 | + mock_file_manager.create_csv_file.assert_called_once_with( | ||
| 90 | + parser._output_path, expected_row, parser.KERNEL_VIEW, expected_output_headers) | ||
| 53 | 91 | ||
| 54 | 92 | ||
| 55 | -if __name__ == '__main__': | 93 | +if __name__ == "__main__": |
| 56 | - run_test() | 94 | + run_tests() |
| @@ -3,5 +3,7 @@ class CsvHeaders(object): | |||
| 3 | TASK_START_TIME = "Task Start Time(us)" | 3 | TASK_START_TIME = "Task Start Time(us)" |
| 4 | OP_SUMMARY_SHOW_HEADERS = ["Device_id", "Op Name", "OP Type", "Task Type", TASK_START_TIME, "Task Duration(us)", | 4 | OP_SUMMARY_SHOW_HEADERS = ["Device_id", "Op Name", "OP Type", "Task Type", TASK_START_TIME, "Task Duration(us)", |
| 5 | "Task Wait Time(us)", "Block Num"] | 5 | "Task Wait Time(us)", "Block Num"] |
| 6 | + OP_SUMMARY_SHAPE_HEADERS = ["Input Shapes", "Input Data Types", "Input Formats", "Output Shapes", | ||
| 7 | + "Output Data Types", "Output Formats"] | ||
| 6 | OP_SUMMARY_KERNEL_BASE_HEADERS = ["Device_id", "Name", "Type", "Accelerator Core", "Start Time(us)", "Duration(us)", | 8 | OP_SUMMARY_KERNEL_BASE_HEADERS = ["Device_id", "Name", "Type", "Accelerator Core", "Start Time(us)", "Duration(us)", |
| 7 | "Wait Time(us)", "Block Num"] | 9 | "Wait Time(us)", "Block Num"] |
| @@ -32,6 +32,13 @@ class KernelViewParser(BaseParser): | |||
| 32 | output_headers.append(header) | 32 | output_headers.append(header) |
| 33 | return output_headers | 33 | return output_headers |
| 34 | 34 | ||
| 35 | + | ||
| 36 | + def _get_kernel_headers(cls, all_headers: list, is_all_kernel_headers: bool) -> list: | ||
| 37 | + if is_all_kernel_headers: | ||
| 38 | + return all_headers | ||
| 39 | + shape_headers = [header for header in CsvHeaders.OP_SUMMARY_SHAPE_HEADERS if header in all_headers] | ||
| 40 | + return CsvHeaders.OP_SUMMARY_SHOW_HEADERS + shape_headers | ||
| 41 | + | ||
| 35 | def run(self, deps_data: dict): | 42 | def run(self, deps_data: dict): |
| 36 | ProfilerLogger.init(self._profiler_path, "KernelViewParser") | 43 | ProfilerLogger.init(self._profiler_path, "KernelViewParser") |
| 37 | self.logger = ProfilerLogger.get_instance() | 44 | self.logger = ProfilerLogger.get_instance() |
| @@ -53,8 +60,8 @@ class KernelViewParser(BaseParser): | |||
| 53 | for file_path in op_summary_file_set: | 60 | for file_path in op_summary_file_set: |
| 54 | all_data = FileManager.read_csv_file(file_path, OpSummaryBean) | 61 | all_data = FileManager.read_csv_file(file_path, OpSummaryBean) |
| 55 | if all_data: | 62 | if all_data: |
| 56 | - OpSummaryBean.headers = all_data[ | 63 | + OpSummaryBean.headers = self._get_kernel_headers( |
| 57 | - 0].all_headers if ProfilerConfig().is_all_kernel_headers() else CsvHeaders.OP_SUMMARY_SHOW_HEADERS | 64 | + all_data[0].all_headers, ProfilerConfig().is_all_kernel_headers()) |
| 58 | output_headers = self._project_map_for_headers(OpSummaryBean.headers) | 65 | output_headers = self._project_map_for_headers(OpSummaryBean.headers) |
| 59 | if not self.step_range: | 66 | if not self.step_range: |
| 60 | summary_data.extend([data.row for data in all_data]) | 67 | summary_data.extend([data.row for data in all_data]) |