def blame(fail_dir, valid_res, fail_target, out_dir, lock, num, inplace): blame_str = "" stdout = stderr = b"" if not re.search("-O0", fail_target.args): blame_opts = compilers_blame_opts[fail_target.specs.name] phase_num = 0 try: for i in blame_opts: blame_str += i blame_str += execute_blame_phase(valid_res, fail_target, blame_str, num, phase_num) blame_str += " " phase_num += 1 except: common.log_msg(logging.ERROR, "Something went wrong while executing bpame_opt.py on " + str(fail_dir)) return False gen_test_makefile.gen_makefile(blame_test_makefile_name, True, None, fail_target, blame_str) ret_code, stdout, stderr, time_expired, elapsed_time = \ common.run_cmd(["make", "-f", blame_test_makefile_name, fail_target.name], run_gen.compiler_timeout, num) opt_name_pattern = re.compile(compilers_opt_name_cutter[fail_target.specs.name][0] + ".*" + compilers_opt_name_cutter[fail_target.specs.name][1]) opt_name = opt_name_pattern.findall(str(stderr, "utf-8"))[-1] opt_name = re.sub(compilers_opt_name_cutter[fail_target.specs.name][0], "", opt_name) opt_name = re.sub(compilers_opt_name_cutter[fail_target.specs.name][1], "", opt_name) real_opt_name = opt_name opt_name = opt_name.replace(" ", "_") else: real_opt_name = opt_name = "O0_bug" common.run_cmd(["make", "-f", blame_test_makefile_name, "clean"], run_gen.compiler_timeout, num) seed_dir = os.path.basename(os.path.normpath(fail_dir)) # Create log files in different places depending on "inplace" switch. if not inplace: full_out_path = os.path.join(os.path.join(out_dir, opt_name), seed_dir) common.copy_test_to_out(fail_dir, full_out_path, lock) else: full_out_path = "." # Write to log with open(os.path.join(full_out_path, "log.txt"), "a") as log_file: log_file.write("\nBlaming for " + fail_target.name + " optset was done.\n") log_file.write("Optimization to blame: " + real_opt_name + "\n") log_file.write("Blame opts: " + blame_str + "\n\n") log_file.write("Details of blaming run:\n") log_file.write("=== Compiler log ==================================================\n") log_file.write(str(stdout, "utf-8")) log_file.write("=== Compiler err ==================================================\n") log_file.write(str(stderr, "utf-8")) log_file.write("=== Compiler end ==================================================\n") common.log_msg(logging.DEBUG, "Done blaming") # Inplace mode require blaming string to be communicated back to the caller if not inplace: return True else: return real_opt_name
def blame(fail_dir, valid_res, fail_target, out_dir, lock, num, inplace): blame_str = "" stdout = stderr = b"" if not re.search("-O0", fail_target.args): blame_opts = compilers_blame_opts[fail_target.specs.name] phase_num = 0 blame_phase_num = 0 # Do blaming try: for i in blame_opts: blame_str += i blame_phase_num = execute_blame_phase(valid_res, fail_target, blame_str, num, phase_num) if fail_target.specs.name == "dpcpp": # Special case becasue triagging mechanism is different and there's only one level of triagging. blame_str += str(blame_phase_num - 1) else: blame_str += str(blame_phase_num) blame_str += " " phase_num += 1 except: common.log_msg( logging.ERROR, "Something went wrong while executing blame_opt.py on " + str(fail_dir)) return False # Wrap up results gen_test_makefile.gen_makefile( out_file_name=blame_test_makefile_name, force=True, config_file=None, only_target=fail_target, inject_blame_opt=blame_str if fail_target.specs.name != "dpcpp" else None, inject_blame_env=blame_str if fail_target.specs.name == "dpcpp" else None) ret_code, stdout, stderr, time_expired, elapsed_time = \ common.run_cmd(["make", "-f", blame_test_makefile_name, fail_target.name], run_gen.compiler_timeout, num) if fail_target.specs.name == "dpcpp": ret_code, stdout, stderr, time_expired, elapsed_time = \ common.run_cmd(["make", "-f", blame_test_makefile_name, "run_" + fail_target.name], run_gen.compiler_timeout, num) if fail_target.specs.name != "dpcpp": opt_name_pattern = re.compile( compilers_opt_name_cutter[fail_target.specs.name][0] + ".*" + compilers_opt_name_cutter[fail_target.specs.name][1]) opt_name = opt_name_pattern.findall(str(stderr, "utf-8"))[-1] opt_name = re.sub( compilers_opt_name_cutter[fail_target.specs.name][0], "", opt_name) opt_name = re.sub( compilers_opt_name_cutter[fail_target.specs.name][1], "", opt_name) real_opt_name = opt_name opt_name = opt_name.replace(" ", "_") else: if blame_phase_num == 1: # It's special case for DPC++. 1 means that triagging failed, no specific phase can be blamed. real_opt_name = opt_name = "FailedToBlame" else: opt_name_pattern = re.compile( compilers_opt_name_cutter[fail_target.specs.name][0] + ".*" + compilers_opt_name_cutter[fail_target.specs.name][1]) opt_name = opt_name_pattern.findall(str(stderr, "utf-8"))[0] opt_name = re.sub( compilers_opt_name_cutter[fail_target.specs.name][0], "", opt_name) opt_name = re.sub( compilers_opt_name_cutter[fail_target.specs.name][1], "", opt_name) real_opt_name = opt_name opt_name = opt_name.replace(" ", "_") else: real_opt_name = opt_name = "O0_bug" common.run_cmd(["make", "-f", blame_test_makefile_name, "clean"], run_gen.compiler_timeout, num) seed_dir = os.path.basename(os.path.normpath(fail_dir)) # Create log files in different places depending on "inplace" switch. if not inplace: full_out_path = os.path.join(os.path.join(out_dir, opt_name), seed_dir) common.copy_test_to_out(fail_dir, full_out_path, lock) else: full_out_path = "." # Write to log with open(os.path.join(full_out_path, "log.txt"), "a") as log_file: log_file.write("\nBlaming for " + fail_target.name + " optset was done.\n") log_file.write("Optimization to blame: " + real_opt_name + "\n") log_file.write("Blame opts: " + blame_str + "\n\n") log_file.write("Details of blaming run:\n") log_file.write( "=== Compiler log ==================================================\n" ) log_file.write(str(stdout, "utf-8")) log_file.write( "=== Compiler err ==================================================\n" ) log_file.write(str(stderr, "utf-8")) log_file.write( "=== Compiler end ==================================================\n" ) common.log_msg(logging.DEBUG, "Done blaming") # Inplace mode require blaming string to be communicated back to the caller if not inplace: return True else: return real_opt_name
def execute_blame_phase(valid_res, fail_target, inject_str, num, phase_num): gen_test_makefile.gen_makefile( out_file_name=blame_test_makefile_name, force=True, config_file=None, only_target=fail_target, inject_blame_opt=inject_str + "-1" if fail_target.specs.name != "dpcpp" else None, inject_blame_env=inject_str + "1" if fail_target.specs.name == "dpcpp" else None) ret_code, output, err_output, time_expired, elapsed_time = \ common.run_cmd(["make", "-f", blame_test_makefile_name, fail_target.name], run_gen.compiler_timeout, num) if fail_target.specs.name == "dpcpp": ret_code, output, err_output, time_expired, elapsed_time = \ common.run_cmd(["make", "-f", blame_test_makefile_name, "run_" + fail_target.name], run_gen.compiler_timeout, num) opt_num_regex = re.compile( compilers_blame_patterns[fail_target.specs.name][phase_num]) try: if fail_target.specs.name == "dpcpp": max_opt_num = 250 else: matches = opt_num_regex.findall(str(err_output, "utf-8")) # Some icc phases may not support going to phase "2", i.e. drilling down to num_case level, # in this case we are done. if phase_num == 2 and not matches: return str(-1) max_opt_num_str = matches[-1] remove_brackets_pattern = re.compile("\d+") max_opt_num = int( remove_brackets_pattern.findall(max_opt_num_str)[-1]) common.log_msg( logging.DEBUG, "Max opt num (process " + str(num) + "): " + str(max_opt_num)) except IndexError: common.log_msg( logging.ERROR, "Can't decode max opt number using \"" + compilers_blame_patterns[fail_target.specs.name][phase_num] + "\" regexp (phase " + str(phase_num) + ") in the following output:\n" + str(err_output, "utf-8") + " (process " + str(num) + "): ") raise start_opt = 0 end_opt = max_opt_num cur_opt = max_opt_num failed_flag = True time_to_finish = False while not time_to_finish: start_opt, end_opt, cur_opt = get_next_step(start_opt, end_opt, cur_opt, failed_flag) common.log_msg( logging.DEBUG, "Previous failed (process " + str(num) + "): " + str(failed_flag)) failed_flag = False eff = ((start_opt + 1) >= cur_opt) # Earliest fail was found common.log_msg( logging.DEBUG, "Trying opt (process " + str(num) + "): " + str(start_opt) + "/" + str(cur_opt) + "/" + str(end_opt)) gen_test_makefile.gen_makefile( out_file_name=blame_test_makefile_name, force=True, config_file=None, only_target=fail_target, inject_blame_opt=inject_str + str(cur_opt) if fail_target.specs.name != "dpcpp" else None, inject_blame_env=inject_str + str(cur_opt) if fail_target.specs.name == "dpcpp" else None) ret_code, output, err_output, time_expired, elapsed_time = \ common.run_cmd(["make", "-f", blame_test_makefile_name, fail_target.name], run_gen.compiler_timeout, num) if time_expired or ret_code != 0: dump_exec_output("Compilation failed", ret_code, output, err_output, time_expired, num) failed_flag = True if not eff: continue else: break ret_code, output, err_output, time_expired, elapsed_time = \ common.run_cmd(["make", "-f", blame_test_makefile_name, "run_" + fail_target.name], run_gen.run_timeout, num) if time_expired or ret_code != 0: dump_exec_output("Execution failed", ret_code, output, err_output, time_expired, num) failed_flag = True if not eff: continue else: break if str(output, "utf-8").split()[-1] != valid_res: common.log_msg( logging.DEBUG, "Output differs (process " + str(num) + "): " + str(output, "utf-8").split()[-1] + " vs " + valid_res + " (expected)") failed_flag = True if not eff: continue else: break time_to_finish = (eff and failed_flag) or (eff and not failed_flag and (cur_opt == (end_opt - 1))) common.log_msg( logging.DEBUG, "Time to finish (process " + str(num) + "): " + str(time_to_finish)) if not failed_flag: common.log_msg( logging.DEBUG, "Swapping current and end opt (process " + str(num) + ")") cur_opt = end_opt common.log_msg( logging.DEBUG, "Finished blame phase, result: " + str(inject_str) + str(cur_opt) + " (process " + str(num) + ")") return cur_opt