3 # Debugify summary for the original debug info testing.
6 from __future__
import print_function
10 from json
import loads
11 from collections
import defaultdict
12 from collections
import OrderedDict
16 def __init__(self
, action
, bb_name
, fn_name
, instr
):
18 self
.bb_name
= bb_name
19 self
.fn_name
= fn_name
23 return self
.action
+ self
.bb_name
+ self
.fn_name
+ self
.instr
27 def __init__(self
, action
, fn_name
):
29 self
.fn_name
= fn_name
32 return self
.action
+ self
.fn_name
36 def __init__(self
, action
, name
, fn_name
):
39 self
.fn_name
= fn_name
42 return self
.action
+ self
.name
+ self
.fn_name
45 # Report the bugs in form of html.
46 def generate_html_report(
50 di_location_bugs_summary
,
55 fileout
= open(html_file
, "w")
57 html_header
= """ <html>
61 border: 1px solid black;
72 # Create the table for Location bugs.
73 table_title_di_loc
= "Location Bugs found by the Debugify"
75 table_di_loc
= """<table>
76 <caption><b>{}</b></caption>
85 "LLVM IR Instruction",
91 for column
in header_di_loc
:
92 table_di_loc
+= " <th>{0}</th>\n".format(column
.strip())
93 table_di_loc
+= " </tr>\n"
95 at_least_one_bug_found
= False
97 # Handle loction bugs.
98 for file, per_file_bugs
in di_location_bugs
.items():
99 for llvm_pass
, per_pass_bugs
in per_file_bugs
.items():
100 # No location bugs for the pass.
101 if len(per_pass_bugs
) == 0:
103 at_least_one_bug_found
= True
105 table_di_loc
+= " </tr>\n"
107 for x
in per_pass_bugs
:
108 row
.append(" <tr>\n")
110 row
.append(llvm_pass
)
112 row
.append(x
.fn_name
)
113 row
.append(x
.bb_name
)
115 row
.append(" </tr>\n")
116 # Dump the bugs info into the table.
118 # The same file-pass pair can have multiple bugs.
119 if column
== " <tr>\n" or column
== " </tr>\n":
120 table_di_loc
+= column
122 table_di_loc
+= " <td>{0}</td>\n".format(column
.strip())
123 table_di_loc
+= " <tr>\n"
125 if not at_least_one_bug_found
:
126 table_di_loc
+= """ <tr>
127 <td colspan='7'> No bugs found </td>
130 table_di_loc
+= "</table>\n"
132 # Create the summary table for the loc bugs.
133 table_title_di_loc_sum
= "Summary of Location Bugs"
134 table_di_loc_sum
= """<table>
135 <caption><b>{}</b></caption>
138 table_title_di_loc_sum
141 header_di_loc_sum
= ["LLVM Pass Name", "Number of bugs"]
143 for column
in header_di_loc_sum
:
144 table_di_loc_sum
+= " <th>{0}</th>\n".format(column
.strip())
145 table_di_loc_sum
+= " </tr>\n"
149 for llvm_pass
, num
in sorted(di_location_bugs_summary
.items()):
150 row
.append(" <tr>\n")
151 row
.append(llvm_pass
)
153 row
.append(" </tr>\n")
155 if column
== " <tr>\n" or column
== " </tr>\n":
156 table_di_loc_sum
+= column
158 table_di_loc_sum
+= " <td>{0}</td>\n".format(column
.strip())
159 table_di_loc_sum
+= " <tr>\n"
161 if not at_least_one_bug_found
:
162 table_di_loc_sum
+= """<tr>
163 <td colspan='2'> No bugs found </td>
166 table_di_loc_sum
+= "</table>\n"
168 # Create the table for SP bugs.
169 table_title_di_sp
= "SP Bugs found by the Debugify"
170 table_di_sp
= """<table>
171 <caption><b>{}</b></caption>
177 header_di_sp
= ["File", "LLVM Pass Name", "Function Name", "Action"]
179 for column
in header_di_sp
:
180 table_di_sp
+= " <th>{0}</th>\n".format(column
.strip())
181 table_di_sp
+= " </tr>\n"
183 at_least_one_bug_found
= False
186 for file, per_file_bugs
in di_subprogram_bugs
.items():
187 for llvm_pass
, per_pass_bugs
in per_file_bugs
.items():
188 # No SP bugs for the pass.
189 if len(per_pass_bugs
) == 0:
191 at_least_one_bug_found
= True
193 table_di_sp
+= " </tr>\n"
195 for x
in per_pass_bugs
:
196 row
.append(" <tr>\n")
198 row
.append(llvm_pass
)
199 row
.append(x
.fn_name
)
201 row
.append(" </tr>\n")
202 # Dump the bugs info into the table.
204 # The same file-pass pair can have multiple bugs.
205 if column
== " <tr>\n" or column
== " </tr>\n":
206 table_di_sp
+= column
208 table_di_sp
+= " <td>{0}</td>\n".format(column
.strip())
209 table_di_sp
+= " <tr>\n"
211 if not at_least_one_bug_found
:
212 table_di_sp
+= """<tr>
213 <td colspan='4'> No bugs found </td>
216 table_di_sp
+= "</table>\n"
218 # Create the summary table for the sp bugs.
219 table_title_di_sp_sum
= "Summary of SP Bugs"
220 table_di_sp_sum
= """<table>
221 <caption><b>{}</b></caption>
224 table_title_di_sp_sum
227 header_di_sp_sum
= ["LLVM Pass Name", "Number of bugs"]
229 for column
in header_di_sp_sum
:
230 table_di_sp_sum
+= " <th>{0}</th>\n".format(column
.strip())
231 table_di_sp_sum
+= " </tr>\n"
235 for llvm_pass
, num
in sorted(di_sp_bugs_summary
.items()):
236 row
.append(" <tr>\n")
237 row
.append(llvm_pass
)
239 row
.append(" </tr>\n")
241 if column
== " <tr>\n" or column
== " </tr>\n":
242 table_di_sp_sum
+= column
244 table_di_sp_sum
+= " <td>{0}</td>\n".format(column
.strip())
245 table_di_sp_sum
+= " <tr>\n"
247 if not at_least_one_bug_found
:
248 table_di_sp_sum
+= """<tr>
249 <td colspan='2'> No bugs found </td>
252 table_di_sp_sum
+= "</table>\n"
254 # Create the table for Variable bugs.
255 table_title_di_var
= "Variable Location Bugs found by the Debugify"
256 table_di_var
= """<table>
257 <caption><b>{}</b></caption>
263 header_di_var
= ["File", "LLVM Pass Name", "Variable", "Function", "Action"]
265 for column
in header_di_var
:
266 table_di_var
+= " <th>{0}</th>\n".format(column
.strip())
267 table_di_var
+= " </tr>\n"
269 at_least_one_bug_found
= False
272 for file, per_file_bugs
in di_var_bugs
.items():
273 for llvm_pass
, per_pass_bugs
in per_file_bugs
.items():
274 # No SP bugs for the pass.
275 if len(per_pass_bugs
) == 0:
277 at_least_one_bug_found
= True
279 table_di_var
+= " </tr>\n"
281 for x
in per_pass_bugs
:
282 row
.append(" <tr>\n")
284 row
.append(llvm_pass
)
286 row
.append(x
.fn_name
)
288 row
.append(" </tr>\n")
289 # Dump the bugs info into the table.
291 # The same file-pass pair can have multiple bugs.
292 if column
== " <tr>\n" or column
== " </tr>\n":
293 table_di_var
+= column
295 table_di_var
+= " <td>{0}</td>\n".format(column
.strip())
296 table_di_var
+= " <tr>\n"
298 if not at_least_one_bug_found
:
299 table_di_var
+= """<tr>
300 <td colspan='4'> No bugs found </td>
303 table_di_var
+= "</table>\n"
305 # Create the summary table for the sp bugs.
306 table_title_di_var_sum
= "Summary of Variable Location Bugs"
307 table_di_var_sum
= """<table>
308 <caption><b>{}</b></caption>
311 table_title_di_var_sum
314 header_di_var_sum
= ["LLVM Pass Name", "Number of bugs"]
316 for column
in header_di_var_sum
:
317 table_di_var_sum
+= " <th>{0}</th>\n".format(column
.strip())
318 table_di_var_sum
+= " </tr>\n"
322 for llvm_pass
, num
in sorted(di_var_bugs_summary
.items()):
323 row
.append(" <tr>\n")
324 row
.append(llvm_pass
)
326 row
.append(" </tr>\n")
328 if column
== " <tr>\n" or column
== " </tr>\n":
329 table_di_var_sum
+= column
331 table_di_var_sum
+= " <td>{0}</td>\n".format(column
.strip())
332 table_di_var_sum
+= " <tr>\n"
334 if not at_least_one_bug_found
:
335 table_di_var_sum
+= """<tr>
336 <td colspan='2'> No bugs found </td>
339 table_di_var_sum
+= "</table>\n"
341 # Finish the html page.
342 html_footer
= """</body>
347 fileout
.writelines(html_header
)
348 fileout
.writelines(table_di_loc
)
349 fileout
.writelines(new_line
)
350 fileout
.writelines(table_di_loc_sum
)
351 fileout
.writelines(new_line
)
352 fileout
.writelines(new_line
)
353 fileout
.writelines(table_di_sp
)
354 fileout
.writelines(new_line
)
355 fileout
.writelines(table_di_sp_sum
)
356 fileout
.writelines(new_line
)
357 fileout
.writelines(new_line
)
358 fileout
.writelines(table_di_var
)
359 fileout
.writelines(new_line
)
360 fileout
.writelines(table_di_var_sum
)
361 fileout
.writelines(html_footer
)
364 print("The " + html_file
+ " generated.")
367 # Read the JSON file in chunks.
368 def get_json_chunk(file, start
, size
):
374 # The file contains json object per line.
375 # An example of the line (formatted json):
377 # "file": "simple.c",
378 # "pass": "Deduce function attributes in RPO",
383 # "metadata": "DISubprogram",
388 # "metadata": "DISubprogram",
394 with
open(file) as json_objects_file
:
395 for json_object_line
in json_objects_file
:
399 if line
>= start
+ size
:
402 json_object
= loads(json_object_line
)
406 di_checker_data
.append(json_object
)
408 return (di_checker_data
, skipped_lines
, line
)
411 # Parse the program arguments.
412 def parse_program_args(parser
):
413 parser
.add_argument("file_name", type=str, help="json file to process")
414 parser
.add_argument("html_file", type=str, help="html file to output data")
416 "-compress", action
="store_true", help="create reduced html report"
419 return parser
.parse_args()
423 parser
= argparse
.ArgumentParser()
424 opts
= parse_program_args(parser
)
426 if not opts
.html_file
.endswith(".html"):
427 print("error: The output file must be '.html'.")
430 # Use the defaultdict in order to make multidim dicts.
431 di_location_bugs
= defaultdict(lambda: defaultdict(dict))
432 di_subprogram_bugs
= defaultdict(lambda: defaultdict(dict))
433 di_variable_bugs
= defaultdict(lambda: defaultdict(dict))
435 # Use the ordered dict to make a summary.
436 di_location_bugs_summary
= OrderedDict()
437 di_sp_bugs_summary
= OrderedDict()
438 di_var_bugs_summary
= OrderedDict()
440 # Compress similar bugs.
441 # DILocBugs with same pass & instruction name.
442 di_loc_pass_instr_set
= set()
443 # DISPBugs with same pass & function name.
444 di_sp_pass_fn_set
= set()
445 # DIVarBugs with same pass & variable name.
446 di_var_pass_var_set
= set()
450 end_line
= chunk_size
- 1
453 # Process each chunk of 1 million JSON lines.
455 if start_line
> end_line
:
457 (debug_info_bugs
, skipped
, end_line
) = get_json_chunk(
458 opts
.file_name
, start_line
, chunk_size
460 start_line
+= chunk_size
461 skipped_lines
+= skipped
463 # Map the bugs into the file-pass pairs.
464 for bugs_per_pass
in debug_info_bugs
:
466 bugs_file
= bugs_per_pass
["file"]
467 bugs_pass
= bugs_per_pass
["pass"]
468 bugs
= bugs_per_pass
["bugs"][0]
477 # Omit duplicated bugs.
483 bugs_metadata
= bug
["metadata"]
488 if bugs_metadata
== "DILocation":
490 action
= bug
["action"]
491 bb_name
= bug
["bb-name"]
492 fn_name
= bug
["fn-name"]
497 di_loc_bug
= DILocBug(action
, bb_name
, fn_name
, instr
)
498 if not str(di_loc_bug
) in di_loc_set
:
499 di_loc_set
.add(str(di_loc_bug
))
501 pass_instr
= bugs_pass
+ instr
502 if not pass_instr
in di_loc_pass_instr_set
:
503 di_loc_pass_instr_set
.add(pass_instr
)
504 di_loc_bugs
.append(di_loc_bug
)
506 di_loc_bugs
.append(di_loc_bug
)
508 # Fill the summary dict.
509 if bugs_pass
in di_location_bugs_summary
:
510 di_location_bugs_summary
[bugs_pass
] += 1
512 di_location_bugs_summary
[bugs_pass
] = 1
513 elif bugs_metadata
== "DISubprogram":
515 action
= bug
["action"]
520 di_sp_bug
= DISPBug(action
, name
)
521 if not str(di_sp_bug
) in di_sp_set
:
522 di_sp_set
.add(str(di_sp_bug
))
524 pass_fn
= bugs_pass
+ name
525 if not pass_fn
in di_sp_pass_fn_set
:
526 di_sp_pass_fn_set
.add(pass_fn
)
527 di_sp_bugs
.append(di_sp_bug
)
529 di_sp_bugs
.append(di_sp_bug
)
531 # Fill the summary dict.
532 if bugs_pass
in di_sp_bugs_summary
:
533 di_sp_bugs_summary
[bugs_pass
] += 1
535 di_sp_bugs_summary
[bugs_pass
] = 1
536 elif bugs_metadata
== "dbg-var-intrinsic":
538 action
= bug
["action"]
539 fn_name
= bug
["fn-name"]
544 di_var_bug
= DIVarBug(action
, name
, fn_name
)
545 if not str(di_var_bug
) in di_var_set
:
546 di_var_set
.add(str(di_var_bug
))
548 pass_var
= bugs_pass
+ name
549 if not pass_var
in di_var_pass_var_set
:
550 di_var_pass_var_set
.add(pass_var
)
551 di_var_bugs
.append(di_var_bug
)
553 di_var_bugs
.append(di_var_bug
)
555 # Fill the summary dict.
556 if bugs_pass
in di_var_bugs_summary
:
557 di_var_bugs_summary
[bugs_pass
] += 1
559 di_var_bugs_summary
[bugs_pass
] = 1
561 # Unsupported metadata.
565 di_location_bugs
[bugs_file
][bugs_pass
] = di_loc_bugs
566 di_subprogram_bugs
[bugs_file
][bugs_pass
] = di_sp_bugs
567 di_variable_bugs
[bugs_file
][bugs_pass
] = di_var_bugs
569 generate_html_report(
573 di_location_bugs_summary
,
579 if skipped_lines
> 0:
580 print("Skipped lines: " + str(skipped_lines
))
582 print("Skipped bugs: " + str(skipped_bugs
))
585 if __name__
== "__main__":