diff --git a/mindinsight/profiler/common/_utils.py b/mindinsight/profiler/common/_utils.py deleted file mode 100755 index 2c059ce3..00000000 --- a/mindinsight/profiler/common/_utils.py +++ /dev/null @@ -1,112 +0,0 @@ -# Copyright 2020 Huawei Technologies Co., Ltd -# -# 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. -# ============================================================================ -"""Profiler utils.""" -import os -import re - - -def fwrite_format(output_data_path, data_source=None, is_print=False, is_start=False): - """ - Write data to the output file. - - Args: - output_data_path (str): The output file path of the data. - data_source (list): The data to write. - is_print (bool): whether to print the data to stdout. - is_start (bool): Whether is the first line of the output file, will remove the old file if True." - """ - - if is_start is True and os.path.exists(output_data_path): - os.remove(output_data_path) - - if data_source.startswith("title:"): - title_label = '=' * 20 - data_source = title_label + data_source[6:] + title_label - - with open(output_data_path, 'a+') as f: - f.write(data_source) - f.write("\n") - - if is_print: - print(data_source) - - -def get_log_slice_id(file_name): - pattern = re.compile(r'(?<=slice_)\d+') - slice_list = pattern.findall(file_name) - index = re.findall(r'\d+', slice_list[0]) - return int(index[0]) - - -def get_file_join_name(input_path, file_name): - """ - Search files under the special path, and will join all the files to one file. - - Args: - input_path (str): The source path, will search files under it. - file_name (str): The target of the filename, such as 'hwts.log.data.45.dev'. - - Returns: - str, the join file name. - """ - name_list = [] - file_join_name = '' - input_path = os.path.realpath(input_path) - if os.path.exists(input_path): - files = os.listdir(input_path) - for f in files: - if file_name in f and not f.endswith('.done') and not f.endswith('.join') \ - and not f.endswith('.zip'): - name_list.append(f) - - # resort name_list - name_list.sort(key=get_log_slice_id) - - if len(name_list) == 1: - file_join_name = os.path.join(input_path, name_list[0]) - elif len(name_list) > 1: - file_join_name = os.path.join(input_path, '%s.join' % file_name) - if os.path.exists(file_join_name): - os.remove(file_join_name) - with open(file_join_name, 'ab') as bin_data: - for i in name_list: - file = input_path + os.sep + i - with open(file, 'rb') as txt: - bin_data.write(txt.read()) - return file_join_name - -def get_file_names(input_path, file_name): - """ - Search files under the special path. - - Args: - input_path (str): The source path, will search files under it. - file_name (str): The target of the filename, such as 'host_start_log'. - - Returns: - list, file name list. - """ - - input_path = os.path.realpath(input_path) - name_list = [] - if os.path.exists(input_path): - files = os.listdir(input_path) - for f in files: - if file_name in f and not f.endswith('.done') \ - and not f.endswith('.zip'): - name_list.append(f) - break - - return name_list diff --git a/tests/st/func/profiler/test_validator.py b/tests/st/func/profiler/test_validator.py index 5d43a1c8..9cc5c8ef 100644 --- a/tests/st/func/profiler/test_validator.py +++ b/tests/st/func/profiler/test_validator.py @@ -61,8 +61,8 @@ class TestValidate: @pytest.mark.platform_arm_ascend_training @pytest.mark.platform_x86_gpu_training @pytest.mark.platform_x86_ascend_training - def test_validate_condition_exception(self): - """Test the exception of validate condition.""" + def test_validate_op_type_exception(self): + """Test the operate type exception.""" condition = "not a dict" exception_message = 'Param type error. Invalid search_condition type, it should be dict.' with pytest.raises(ProfilerParamTypeErrorException) as exc_info: @@ -70,7 +70,6 @@ class TestValidate: assert exc_info.value.error_code == '50546082' assert exc_info.value.message == exception_message - # test the ProfilerOpTypeException condition_list = [{'op_type': "xxx"}, {}] exception_message = "The op_type in search_condition error, The op_type must in " \ "['aicpu_type','aicpu_detail', 'aicore_type', 'aicore_detail', "\ @@ -81,7 +80,14 @@ class TestValidate: assert exc_info.value.error_code == '50546183' assert exc_info.value.message == exception_message - # test the ProfilerGroupConditionException + @pytest.mark.level0 + @pytest.mark.env_single + @pytest.mark.platform_x86_cpu + @pytest.mark.platform_arm_ascend_training + @pytest.mark.platform_x86_gpu_training + @pytest.mark.platform_x86_ascend_training + def test_validate_group_condition_exception(self): + """test the group condition exception.""" condition_list = [ { 'op_type': 'aicpu_type', diff --git a/tests/ut/profiler/analyser/test_timeline_analyser.py b/tests/ut/profiler/analyser/test_timeline_analyser.py new file mode 100644 index 00000000..e19e0070 --- /dev/null +++ b/tests/ut/profiler/analyser/test_timeline_analyser.py @@ -0,0 +1,66 @@ +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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. +# ============================================================================ +""" +Function: + Test profiler to watch the performance of training. +Usage: + pytest tests/st/func/profiler +""" +import os +import pytest + +from mindinsight.profiler.analyser.analyser_factory import AnalyserFactory +from tests.st.func.profiler import PROFILER_DIR +from tests.utils.tools import compare_result_with_file + + +class TestTimelineAnalyser: + """Test timeline analyser module.""" + def setup_method(self): + """Create analyser.""" + self.profiler = PROFILER_DIR + self.device_id = 0 + self._analyser = AnalyserFactory.instance().get_analyser( + 'timeline', self.profiler, self.device_id) + + @pytest.mark.parametrize( + "device_target, filename", + [('gpu', 'gpu_timeline_display_{}.json'), + ('ascend', 'ascend_timeline_display_{}.json')] + ) + def test_get_display_timeline(self, device_target, filename): + """Test the function of get timeline detail data for UI display.""" + file_path = os.path.join( + self.profiler, + filename.format(self.device_id) + ) + + result = self._analyser.get_display_timeline(device_target) + compare_result_with_file(result, file_path) + + @pytest.mark.parametrize( + "device_target, filename", + [('gpu', 'gpu_timeline_summary_{}.json'), + ('ascend', 'ascend_timeline_summary_{}.json')] + ) + def test_get_timeline_summary(self, device_target, filename): + """Test the function of get timeline summary data for UI display.""" + file_path = os.path.join( + self.profiler, + filename.format(self.device_id) + ) + + result = self._analyser.get_timeline_summary(device_target) + compare_result_with_file(result, file_path) diff --git a/tests/ut/profiler/common/validator/test_validator.py b/tests/ut/profiler/common/validator/test_validator.py index 0c1c8c82..ccc468bd 100644 --- a/tests/ut/profiler/common/validator/test_validator.py +++ b/tests/ut/profiler/common/validator/test_validator.py @@ -18,9 +18,9 @@ import pytest from mindinsight.profiler.common.exceptions.exceptions import \ ProfilerParamTypeErrorException, ProfilerDeviceIdException, \ ProfilerGroupConditionException, ProfilerSortConditionException, \ - ProfilerFilterConditionException + ProfilerFilterConditionException, ProfilerOpTypeException from mindinsight.profiler.common.validator.validate import \ - validate_minddata_pipeline_condition + validate_minddata_pipeline_condition, validate_condition class TestMinddataPipelineCondition: @@ -210,3 +210,97 @@ class TestMinddataPipelineCondition: assert exc_info.value.error_code == '50546186' assert exc_info.value.message == 'The filter_condition in search_condition error, ' \ 'The item in filter value must be int.' + + +class TestValidateCondition: + """Test the function of validate condition.""" + def test_validate_condition_normal(self): + """Test the validate condition of normal input.""" + op_type_list = ['aicpu_type', 'aicpu_detail', 'aicore_type', 'aicore_detail', + 'gpu_op_type', 'gpu_op_info', 'gpu_cuda_activity'] + sort_name_list = ['op_type', 'serial_number', 'op_type', 'op_name', + 'op_type', 'op_side', 'name'] + for idx, op_type in enumerate(op_type_list): + condition = { + 'device_id': '0', + 'op_type': op_type, + 'filter_condition': { + 'op_id': 0 + }, + 'group_condition': { + 'limit': 1, + 'offset': 1 + }, + 'sort_condition': { + 'name': sort_name_list[idx], + 'type': 'ascending' + } + } + validate_condition(condition) + + def test_validate_condition_param_type_error_exception(self): + """Test the exception of parameter type error.""" + condition = "not a dict" + exception_message = 'Param type error. Invalid search_condition type, it should be dict.' + with pytest.raises(ProfilerParamTypeErrorException) as exc_info: + validate_condition(condition) + assert exc_info.value.error_code == '50546082' + assert exc_info.value.message == exception_message + + def test_validate_condition_op_type_exception(self): + """Test the exception of profiler operation type.""" + condition_list = [{'op_type': "xxx"}, {}] + exception_message = "The op_type in search_condition error, The op_type must in " \ + "['aicpu_type','aicpu_detail', 'aicore_type', 'aicore_detail', "\ + "'gpu_op_type', 'gpu_op_info', 'gpu_cuda_activity']" + for condition in condition_list: + with pytest.raises(ProfilerOpTypeException) as exc_info: + validate_condition(condition) + assert exc_info.value.error_code == '50546183' + assert exc_info.value.message == exception_message + + def test_validate_condition_group_exception(self): + """Test the exception of group condition related.""" + condition_list = [ + { + 'op_type': 'aicpu_type', + 'group_condition': 0 + }, + { + 'op_type': 'aicpu_type', + 'group_condition': {'limit': True} + }, + { + 'op_type': 'aicpu_type', + 'group_condition': {'limit': 0} + }, + { + 'op_type': 'aicpu_type', + 'group_condition': {'offset': True} + }, + { + 'op_type': 'aicpu_type', + 'group_condition': {'offset': -1} + }, + { + 'op_type': 'aicpu_type', + 'group_condition': {'offset': 10000000} + }, + ] + exception_message_list = [ + "The group condition must be dict.", + "The limit must be int.", + "The limit must in [1, 100].", + "The offset must be int.", + "The offset must ge 0.", + "The offset must le 1000000." + ] + exception_message_list = [ + 'The group_condition in search_condition error, ' + message + for message in exception_message_list + ] + for idx, condition in enumerate(condition_list): + with pytest.raises(ProfilerGroupConditionException) as exc_info: + validate_condition(condition) + assert exc_info.value.error_code == '50546184' + assert exc_info.value.message == exception_message_list[idx]