You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

aicpu_data_parser.py 7.8 kB

4 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. # Copyright 2020 Huawei Technologies Co., Ltd
  2. #
  3. # Licensed under the Apache License, Version 2.0 (the "License");
  4. # you may not use this file except in compliance with the License.
  5. # You may obtain a copy of the License at
  6. #
  7. # http://www.apache.org/licenses/LICENSE-2.0
  8. #
  9. # Unless required by applicable law or agreed to in writing, software
  10. # distributed under the License is distributed on an "AS IS" BASIS,
  11. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. # See the License for the specific language governing permissions and
  13. # limitations under the License.
  14. # ============================================================================
  15. """
  16. The parser for AI CPU preprocess data.
  17. """
  18. import os
  19. import stat
  20. from mindspore.profiler.common.util import fwrite_format, get_file_join_name
  21. from mindspore import log as logger
  22. class DataPreProcessParser:
  23. """
  24. The Parser for AI CPU preprocess data.
  25. Args:
  26. input_path(str): The profiling job path.
  27. output_filename(str): The output data path and name.
  28. """
  29. _source_file_target_old = 'DATA_PREPROCESS.dev.AICPU.'
  30. _source_file_target = 'DATA_PREPROCESS.AICPU.'
  31. _dst_file_title = 'title:DATA_PREPROCESS AICPU'
  32. _dst_file_column_title = ['serial_number', 'node_type_name', 'total_time(ms)',
  33. 'dispatch_time(ms)', 'execution_time(ms)', 'run_start',
  34. 'run_end']
  35. _ms_unit = 1000
  36. def __init__(self, input_path, output_filename):
  37. self._input_path = input_path
  38. self._output_filename = output_filename
  39. self._source_file_name = self._get_source_file()
  40. self._ms_kernel_flag = 3
  41. self._other_kernel_flag = 6
  42. self._ms_kernel_run_end_index = 2
  43. self._other_kernel_run_end_index = 5
  44. self._dispatch_time_index = 5
  45. self._total_time_index = 6
  46. self._result_list = []
  47. self._min_cycle_counter = float('inf')
  48. def _get_source_file(self):
  49. """Get log file name, which was created by ada service."""
  50. file_name = get_file_join_name(self._input_path, self._source_file_target)
  51. if not file_name:
  52. file_name = get_file_join_name(self._input_path, self._source_file_target_old)
  53. if not file_name:
  54. data_path = os.path.join(self._input_path, "data")
  55. file_name = get_file_join_name(data_path, self._source_file_target)
  56. if not file_name:
  57. file_name = get_file_join_name(data_path, self._source_file_target_old)
  58. return file_name
  59. def _get_kernel_result(self, number, node_list, thread_list):
  60. """Get the profiling data form different aicpu kernel"""
  61. try:
  62. if len(node_list) == self._ms_kernel_flag:
  63. node_type_name = node_list[0].split(':')[-1]
  64. run_end_index = self._ms_kernel_run_end_index
  65. elif len(node_list) == self._other_kernel_flag:
  66. node_type_name = node_list[0].split(':')[-1].split('/')[-1].split('-')[0]
  67. run_end_index = self._other_kernel_run_end_index
  68. else:
  69. logger.warning("the data format can't support 'node_list':%s", str(node_list))
  70. return None
  71. us_unit = 100 # Convert 10ns to 1us.
  72. run_start_counter = float(node_list[1].split(':')[-1].split(' ')[1]) / us_unit
  73. run_end_counter = float(node_list[run_end_index].split(':')[-1].split(' ')[1]) / us_unit
  74. run_start = node_list[1].split(':')[-1].split(' ')[0]
  75. run_end = node_list[run_end_index].split(':')[-1].split(' ')[0]
  76. exe_time = (float(run_end) - float(run_start)) / self._ms_unit
  77. total_time = float(thread_list[self._total_time_index].split('=')[-1].split()[0]) / self._ms_unit
  78. dispatch_time = float(thread_list[self._dispatch_time_index].split('=')[-1].split()[0]) / self._ms_unit
  79. return [number, node_type_name, total_time, dispatch_time, exe_time,
  80. run_start_counter, run_end_counter]
  81. except IndexError as e:
  82. logger.error(e)
  83. return None
  84. def execute(self):
  85. """Execute the parser, get result data, and write it to the output file."""
  86. if not os.path.exists(self._source_file_name):
  87. logger.info("Did not find the aicpu profiling source file")
  88. return
  89. with open(self._source_file_name, 'rb') as ai_cpu_data:
  90. ai_cpu_str = str(ai_cpu_data.read().replace(b'\n\x00', b' ___ ')
  91. .replace(b'\x00', b' ___ '))[2:-1]
  92. ai_cpu_lines = ai_cpu_str.split(" ___ ")
  93. os.chmod(self._source_file_name, stat.S_IREAD | stat.S_IWRITE)
  94. result_list = list()
  95. ai_cpu_total_time_summary = 0
  96. # Node serial number.
  97. serial_number = 1
  98. for i in range(len(ai_cpu_lines) - 1):
  99. node_line = ai_cpu_lines[i]
  100. thread_line = ai_cpu_lines[i + 1]
  101. if "Node" in node_line and "Thread" in thread_line:
  102. # Get the node data from node_line
  103. result = self._get_kernel_result(
  104. serial_number,
  105. node_line.split(','),
  106. thread_line.split(',')
  107. )
  108. if result is None:
  109. continue
  110. result_list.append(result)
  111. # Calculate the total time.
  112. total_time = result[2]
  113. ai_cpu_total_time_summary += total_time
  114. # Increase node serial number.
  115. serial_number += 1
  116. elif "Node" in node_line and "Thread" not in thread_line:
  117. node_type_name = node_line.split(',')[0].split(':')[-1]
  118. logger.warning("The node type:%s cannot find thread data", node_type_name)
  119. if result_list:
  120. ai_cpu_total_time = format(ai_cpu_total_time_summary, '.6f')
  121. result_list.append(["AI CPU Total Time(ms):", ai_cpu_total_time])
  122. fwrite_format(self._output_filename, " ".join(self._dst_file_column_title), is_start=True, is_print=True)
  123. fwrite_format(self._output_filename, result_list, is_print=True)
  124. # For timeline display.
  125. self._result_list = result_list
  126. def query_aicpu_data(self):
  127. """
  128. Get execution time of AI CPU operator.
  129. Returns:
  130. a dict, the metadata of AI CPU operator execution time.
  131. """
  132. stream_id = 0 # Default stream id for AI CPU.
  133. pid = 9000 # Default pid for AI CPU.
  134. total_time = 0
  135. min_cycle_counter = float('inf')
  136. aicpu_info = []
  137. op_count_list = []
  138. for aicpu_item in self._result_list:
  139. if "AI CPU Total Time(ms):" in aicpu_item:
  140. total_time = aicpu_item[-1]
  141. continue
  142. op_name = aicpu_item[1]
  143. start_time = float(aicpu_item[5]) / self._ms_unit
  144. min_cycle_counter = min(min_cycle_counter, start_time)
  145. duration = aicpu_item[4]
  146. aicpu_info.append([op_name, stream_id, start_time, duration, pid])
  147. # Record the number of operator types.
  148. if op_name not in op_count_list:
  149. op_count_list.append(op_name)
  150. self._min_cycle_counter = min_cycle_counter
  151. aicpu_dict = {
  152. 'info': aicpu_info,
  153. 'total_time': float(total_time),
  154. 'op_exe_times': len(aicpu_info),
  155. 'num_of_ops': len(op_count_list),
  156. 'num_of_streams': 1
  157. }
  158. return aicpu_dict
  159. @property
  160. def min_cycle_counter(self):
  161. """Get minimum cycle counter in AI CPU."""
  162. return self._min_cycle_counter