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"""map_file_to_code""" 16 17import os 18import argparse 19 20 21class ParseIrInfo: 22 """ 23 Parse and return the operation info from ir file. 24 """ 25 26 def __init__(self, ir_file): 27 self.no_in_file_operation = [] 28 self.ir_file_path = self.ir_path_parse(ir_file) 29 self.operation_info_dict = self.ir_info_parse() 30 31 def __len__(self): 32 return len(self.operation_info_dict) 33 34 def ir_path_parse(self, ir_file): 35 """ 36 parse the map file path. 37 """ 38 if ir_file == "": 39 print("[WARNING] No graph_path parameter, use current path as graph path.") 40 ir_file = os.path.abspath(os.path.dirname(__file__)) 41 42 map_ir_file = "" 43 file_size = 0 44 map_ir_filename = "trace_code_graph" 45 for filename in os.listdir(os.path.join(ir_file)): 46 if map_ir_filename not in filename: 47 continue 48 tmp_file = os.path.join(ir_file, filename) 49 tmp_file_size = os.path.getsize(tmp_file) 50 if tmp_file_size >= file_size: 51 file_size = tmp_file_size 52 map_ir_file = tmp_file 53 if map_ir_file == "": 54 exit("[ERROR] Please set \"save_graphs=True\" in context to save {} file!".format(map_ir_filename)) 55 return map_ir_file 56 57 def ir_info_parse(self): 58 """ 59 parse the ir file and save code line corresponding to the operator 60 """ 61 62 all_op_info_dict = {} # recode all operation info 63 single_op_info_dict = {} # recode single operation info 64 op_start_char_flag = False # Start operator fragment 65 op_end_char_flag = False # End of operator fragment 66 op_start_info_num = 0 # Accumulate the num to recode operation 67 operation_line = 0 # The line number of the operator 68 op_start_line_num = 0 # The line number of starting operator information 69 op_start_info_flag = False # Start operator information 70 71 with open(self.ir_file_path, 'r+') as file: 72 txt_context_list = file.readlines() 73 74 for line_num, txt_context in enumerate(txt_context_list): 75 txt_context = txt_context.strip() 76 # Start operator fragment 77 if txt_context.endswith(") {"): 78 op_start_char_flag = True 79 op_end_char_flag = False 80 81 # End of operator fragment 82 if txt_context == "}": 83 op_end_char_flag = True 84 85 # Determine whether it is operator information 86 if txt_context.startswith("%") and ") = " in txt_context and txt_context[1].isdigit(): 87 op_start_info_flag = True 88 op_start_line_num = line_num 89 op_start_info_num += 1 90 single_op_info_dict = {"in_file": []} 91 92 # Judge and start to recode operation info 93 if op_start_char_flag and not op_end_char_flag and op_start_info_flag and line_num != op_start_line_num: 94 if "-op" in txt_context and txt_context.split("-op")[-1].split(")")[0].isdigit(): 95 single_op_info_dict["origin_op_name"] = txt_context.split("-op")[0].split("/")[-1] 96 single_op_info_dict["op_name"] = txt_context.split("-op")[0].split("/")[-1].lower() 97 single_op_info_dict["op_num"] = "op" + txt_context.split("-op")[-1].split(")")[0] 98 operation_line = line_num 99 if "In file" in txt_context: 100 in_file_info = txt_context.split("#")[-1].strip().rstrip("/") 101 single_op_info_dict["in_file"].append(in_file_info) 102 if line_num - operation_line == 1 and "In file" not in txt_context and "op_num" in single_op_info_dict: 103 self.no_in_file_operation.append(single_op_info_dict["op_num"]) 104 op_start_info_flag = False 105 all_op_info_dict[op_start_info_num] = single_op_info_dict 106 107 return all_op_info_dict 108 109 110class MapOperationToLine: 111 """ 112 to show operation info 113 """ 114 def __init__(self, dump_op, ir_info_dict): 115 self.dump_op = dump_op 116 self.ir_info_dict = ir_info_dict 117 118 def show_operator_info(self): 119 """ 120 find operator 121 """ 122 origin_dump_op_name = self.dump_op.split("-")[0] 123 dump_op_name = origin_dump_op_name.lower() 124 dump_op_num = self.dump_op.split("-")[-1] 125 for _, op_info in self.ir_info_dict.items(): 126 if op_info["op_num"] == dump_op_num and op_info["in_file"] is not None: 127 if dump_op_name in (dump_op_num, op_info["op_name"]): 128 if not op_info["in_file"]: 129 print("[WARNING] Cannot find {}'s source code in ir file.".format(op_info["origin_op_name"])) 130 return False 131 print("[INFO] Find operation '{}'.".format(op_info["origin_op_name"])) 132 for line in op_info["in_file"]: 133 print(" {}".format(line.split(" ")[0])) 134 print(" {}".format(line.split(" ")[-1])) 135 return True 136 print("[WARNING] Cannot find operation {}'s in ir file.".format(origin_dump_op_name)) 137 return False 138 139 140def start_find(dump_op, map_code_file): 141 """ 142 start find error operation in code. 143 """ 144 145 print("[INFO] Start to map the dump file to source code.") 146 ir_op_info_dict = ParseIrInfo(map_code_file).operation_info_dict 147 MapOperationToLine(dump_op, ir_op_info_dict).show_operator_info() 148 149 150if __name__ == "__main__": 151 parser = argparse.ArgumentParser(description='Find the dump operator in the user code') 152 parser.add_argument('--graph_path', '-p', type=str, default="", help='Save graph files path (option)') 153 parser.add_argument('--dump_op', '-o', type=str, default="", required=True, 154 help="Dump operator id, case insensitive, such as 'op3352'.") 155 args_opt = parser.parse_args() 156 start_find(args_opt.dump_op, args_opt.graph_path) 157