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.

parsing_profiling_data.py 8.8 kB

5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. #!/usr/bin/env python3
  2. # coding: utf-8
  3. # Copyright 2019 Huawei Technologies Co., Ltd
  4. #
  5. # Licensed under the Apache License, Version 2.0 (the "License");
  6. # you may not use this file except in compliance with the License.
  7. # You may obtain a copy of the License at
  8. #
  9. # http://www.apache.org/licenses/LICENSE-2.0
  10. #
  11. # Unless required by applicable law or agreed to in writing, software
  12. # distributed under the License is distributed on an "AS IS" BASIS,
  13. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. # See the License for the specific language governing permissions and
  15. # limitations under the License.
  16. """parsing_profiling_data"""
  17. import os
  18. import subprocess
  19. import struct
  20. import re
  21. from akg import tvm
  22. OUTPUT_FORMAT_DATA = "./output_format_data_hwts.txt"
  23. max_time_consume = 9999999999
  24. def get_log_slice_id(file_name):
  25. pattern = re.compile(r'(?<=slice_)\d+')
  26. slice_ = pattern.findall(file_name)
  27. index = re.findall(r'\d+', slice_[0])
  28. return int(index[0])
  29. def get_file_join_name(input_path=None, file_name=None):
  30. """Function for getting join name from input path."""
  31. name_list = []
  32. file_join_name = ''
  33. if os.path.exists(input_path):
  34. files = os.listdir(input_path)
  35. for f in files:
  36. if file_name in f and not f.endswith('.done') and not f.endswith('.join'):
  37. name_list.append(f)
  38. # resort name_list
  39. name_list.sort(key=get_log_slice_id)
  40. if len(name_list) == 1:
  41. file_join_name = input_path + os.sep + name_list[0]
  42. elif len(name_list) > 1:
  43. file_join_name = input_path + os.sep + '%s.join' % file_name
  44. if os.path.exists(file_join_name):
  45. os.remove(file_join_name)
  46. with open(file_join_name, 'ab') as bin_data:
  47. for i in name_list:
  48. file = input_path + os.sep + i
  49. with open(file, 'rb') as txt:
  50. bin_data.write(txt.read())
  51. return file_join_name
  52. def fwrite_format(output_data_path=OUTPUT_FORMAT_DATA, data_source=None, is_start=False):
  53. if is_start and os.path.exists(OUTPUT_FORMAT_DATA):
  54. os.remove(OUTPUT_FORMAT_DATA)
  55. with open(output_data_path, 'a+') as f:
  56. if isinstance(data_source, (list, tuple)):
  57. for raw_data in data_source:
  58. if isinstance(raw_data, (list, tuple)):
  59. raw_data = map(str, raw_data)
  60. raw_data = " ".join(raw_data)
  61. f.write(raw_data)
  62. f.write("\n")
  63. else:
  64. f.write(data_source)
  65. f.write("\n")
  66. def validate_and_normalize_path(
  67. path,
  68. check_absolute_path=False,
  69. allow_parent_dir=True,
  70. ):
  71. """
  72. Validates path and returns its normalized form.
  73. If path has a valid scheme, treat path as url, otherwise consider path a
  74. unix local path.
  75. Note:
  76. File scheme (rfc8089) is currently not supported.
  77. Args:
  78. path (str): Path to be normalized.
  79. check_absolute_path (bool): Whether check path scheme is supported.
  80. allow_parent_dir (bool): Whether allow parent dir in path.
  81. Returns:
  82. str, normalized path.
  83. """
  84. if not path:
  85. raise RuntimeError("The path is invalid!")
  86. path_str = str(path)
  87. if not allow_parent_dir:
  88. path_components = path_str.split("/")
  89. if ".." in path_components:
  90. raise RuntimeError("The parent path is not allowed!")
  91. # path does not have valid schema, treat it as unix local path.
  92. if check_absolute_path:
  93. if not path_str.startswith("/"):
  94. raise RuntimeError("The path is invalid!")
  95. try:
  96. # most unix systems allow
  97. normalized_path = os.path.realpath(path)
  98. except ValueError:
  99. raise RuntimeError("The path is invalid!")
  100. return normalized_path
  101. class HWTSLogParser:
  102. """
  103. The Parser for hwts log files.
  104. Args:
  105. input_path (str): The profiling job path. Such as: '/var/log/npu/profiling/JOBAIFGJEJFEDCBAEADIFJAAAAAAAAAA".
  106. output_filename (str): The output data path and name. Such as: './output_format_data_hwts_0.txt'.
  107. """
  108. _source_file_target_old = 'hwts.log.data.45.dev.profiler_default_tag'
  109. _source_file_target = 'hwts.data'
  110. _dst_file_title = 'title:45 HWTS data'
  111. _dst_file_column_title = 'Type cnt Core_ID Block_ID Task_ID Cycle_counter Stream_ID'
  112. def __init__(self, input_path, output_filename=None, is_print=False):
  113. self._input_path = input_path
  114. self._output_filename = output_filename
  115. self._source_flie_name = self._get_source_file()
  116. self._is_print = is_print
  117. def _get_source_file(self):
  118. """Get hwts log file name, which was created by ada service."""
  119. file_name = get_file_join_name(self._input_path, self._source_file_target)
  120. if not file_name:
  121. file_name = get_file_join_name(self._input_path, self._source_file_target_old)
  122. if not file_name:
  123. data_path = os.path.join(self._input_path, "data")
  124. file_name = get_file_join_name(data_path, self._source_file_target)
  125. if not file_name:
  126. file_name = get_file_join_name(data_path, self._source_file_target_old)
  127. if not file_name:
  128. msg = "Fail to find hwts log file, under profiling directory"
  129. raise RuntimeError(msg)
  130. return file_name
  131. def execute(self):
  132. """
  133. Execute the parser, get result data, and write it to the output file.
  134. Returns:
  135. bool, whether succeed to analyse hwts log.
  136. """
  137. content_format = ['QIIIIIIIIIIII', 'QIIQIIIIIIII', 'IIIIQIIIIIIII']
  138. log_type = ['Start of task', 'End of task', 'Start of block', 'End of block', 'Block PMU']
  139. result_data = ""
  140. self._source_flie_name = validate_and_normalize_path(self._source_flie_name)
  141. last_syscnt = 0
  142. cycles = 0
  143. kernel_label = tvm.get_global_func("ascend_get_kernel_label")()
  144. with open(self._source_flie_name, 'rb') as hwts_data:
  145. while True:
  146. # read 64 bit data
  147. line = hwts_data.read(64)
  148. if line:
  149. if not line.strip():
  150. continue
  151. else:
  152. break
  153. byte_first_four = struct.unpack('BBHHH', line[0:8])
  154. # byte_first[0:4] refers to count. byte_first[4] refers to is_warn_res0_0v.
  155. # byte_first[5:8] refers to the type of ms.
  156. byte_first = bin(byte_first_four[0]).replace('0b', '').zfill(8)
  157. ms_type = byte_first[-3:]
  158. is_warn_res0_ov = byte_first[4]
  159. cnt = int(byte_first[0:4], 2)
  160. core_id = byte_first_four[1]
  161. blk_id, task_id = byte_first_four[3], byte_first_four[4]
  162. if ms_type in ['000', '001', '010']: # log type 0,1,2
  163. result = struct.unpack(content_format[0], line[8:])
  164. syscnt = result[0]
  165. stream_id = result[1]
  166. elif ms_type == '011': # log type 3
  167. result = struct.unpack(content_format[1], line[8:])
  168. syscnt = result[0]
  169. stream_id = result[1]
  170. elif ms_type == '100': # log type 4
  171. result = struct.unpack(content_format[2], line[8:])
  172. stream_id = result[2]
  173. if is_warn_res0_ov == '0':
  174. syscnt = result[4]
  175. else:
  176. syscnt = None
  177. else:
  178. logger.info("Profiling: invalid hwts log record type %s", ms_type)
  179. continue
  180. if int(task_id) < 25000:
  181. task_id = str(task_id)
  182. if kernel_label == (str(stream_id) + '_' +str(task_id)):
  183. if log_type[int(ms_type, 2)] == "Start of task":
  184. last_syscnt = syscnt
  185. elif log_type[int(ms_type, 2)] == "End of task":
  186. cycles += syscnt - last_syscnt
  187. if self._is_print:
  188. result_data += ("%-14s %-4s %-8s %-9s %-8s %-15s %s\n" %(log_type[int(ms_type, 2)], cnt, core_id,
  189. blk_id, task_id, syscnt, stream_id))
  190. if self._is_print:
  191. fwrite_format(self._output_filename, data_source=self._dst_file_title, is_start=True)
  192. fwrite_format(self._output_filename, data_source=self._dst_file_column_title)
  193. fwrite_format(self._output_filename, data_source=result_data)
  194. return cycles if cycles != 0 else max_time_consume