• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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