blob: 2af2a6b63af6a93b8b484e4a1134a8313ab77793 [file] [log] [blame]
# Copyright 2020 Efabless Corporation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import click
import xlsxwriter
@click.command()
@click.option(
"--benchmark",
"-b",
"benchmark_file",
required=True,
help="The csv file from which to extract the benchmark results",
)
@click.option(
"--full-benchmark/--no-full-benchmark",
default=True,
help="If no, use the regression results instead of the benchmark as the design list, i.e., don't look for *every* design in the benchmark.",
)
@click.option(
"--output-report",
"-o",
"output_report_file",
required=True,
help="The file to print the final report in",
)
@click.option(
"--output-xlsx",
"-x",
"output_xlsx_file",
required=False,
help="The csv file to print a merged csv file benchmark vs regression_script in",
)
@click.argument("regression_results_file")
def cli(
benchmark_file,
full_benchmark,
output_report_file,
output_xlsx_file,
regression_results_file,
):
not_full_benchmark = not full_benchmark
benchmark = dict()
regression_results = dict()
output_report_list = []
testFail = False
configuration_mismatches = []
critical_mismatches = []
missing_configs = []
base_configs = [
"CLOCK_PERIOD",
"SYNTH_STRATEGY",
"SYNTH_MAX_FANOUT",
"FP_CORE_UTIL",
"FP_ASPECT_RATIO",
"FP_PDN_VPITCH",
"FP_PDN_HPITCH",
"PL_TARGET_DENSITY",
"GLB_RT_ADJUSTMENT",
"STD_CELL_LIBRARY",
"CELL_PAD",
"DIODE_INSERTION_STRATEGY",
]
tolerance = {
"general_tolerance": 1,
"tritonRoute_violations": 2,
"Magic_violations": 10,
"antenna_violations": 10,
"lvs_total_errors": 0,
}
critical_statistics = [
"tritonRoute_violations",
"Magic_violations",
"antenna_violations",
"lvs_total_errors",
]
note_worthy_statistics = []
ignore_list = ["", "design", "design_name", "config"]
def compare_vals(benchmark_value, regression_value, param):
if str(benchmark_value) == "-1":
return True
if str(regression_value) == "-1":
return False
tol = 0 - tolerance["general_tolerance"]
if param in tolerance.keys():
tol = 0 - tolerance[param]
if float(benchmark_value) - float(regression_value) >= tol:
return True
else:
return False
def findIdx(header, label):
for idx in range(len(header)):
if label == header[idx]:
return idx
else:
return -1
def diff_list(l1, l2):
return [x for x in l1 if x not in l2]
def parseCSV(csv_file, isBenchmark):
nonlocal note_worthy_statistics
map_out = dict()
csvOpener = open(csv_file, "r")
csvData = csvOpener.read().split("\n")
headerInfo = csvData[0].split(",")
designNameIdx = findIdx(headerInfo, "design")
if isBenchmark:
note_worthy_statistics = diff_list(
diff_list(diff_list(headerInfo, ignore_list), critical_statistics),
base_configs,
)
remover = 0
size = len(base_configs)
while remover < size:
if base_configs[remover] not in headerInfo:
missing_configs.append(base_configs[remover])
base_configs.pop(remover)
remover -= 1
size -= 1
remover += 1
if designNameIdx == -1:
print("Invalid report. No design name was found.")
exit(-1)
for i in range(1, len(csvData)):
if len(csvData[i]):
entry = csvData[i].split(",")
designName = entry[designNameIdx]
for idx in range(len(headerInfo)):
if idx != designNameIdx:
if designName not in map_out.keys():
map_out[designName] = dict()
if isBenchmark:
map_out[designName]["Status"] = "PASSED"
else:
map_out[designName]["Status"] = "----"
map_out[designName][headerInfo[idx]] = str(entry[idx])
return map_out
def configurationMismatch(benchmark, regression_results):
nonlocal configuration_mismatches
designList = list()
if not_full_benchmark:
designList = regression_results.keys()
else:
designList = benchmark.keys()
for design in designList:
output_report_list.append(
"\nComparing Configurations for: " + design + "\n"
)
configuration_mismatches.append(
"\nComparing Configurations for: " + design + "\n"
)
if design not in regression_results:
output_report_list.append(
"\tDesign "
+ design
+ " Not Found in the provided regression sheet\n"
)
configuration_mismatches.append(
"\tDesign "
+ design
+ " Not Found in the provided regression sheet\n"
)
continue
if design not in benchmark:
output_report_list.append(
"\tDesign "
+ design
+ " Not Found in the provided benchmark sheet\n"
)
configuration_mismatches.append(
"\tDesign "
+ design
+ " Not Found in the provided benchmark sheet\n"
)
continue
size_before = len(configuration_mismatches)
for config in base_configs:
if benchmark[design][config] == regression_results[design][config]:
output_report_list.append("\tConfiguration " + config + " MATCH\n")
output_report_list.append(
"\t\tConfiguration "
+ config
+ " value: "
+ benchmark[design][config]
+ "\n"
)
else:
configuration_mismatches.append(
"\tConfiguration " + config + " MISMATCH\n"
)
output_report_list.append(
"\tConfiguration " + config + " MISMATCH\n"
)
configuration_mismatches.append(
"\t\tDesign "
+ design
+ " Configuration "
+ config
+ " BENCHMARK value: "
+ benchmark[design][config]
+ "\n"
)
output_report_list.append(
"\t\tDesign "
+ design
+ " Configuration "
+ config
+ " BENCHMARK value: "
+ benchmark[design][config]
+ "\n"
)
configuration_mismatches.append(
"\t\tDesign "
+ design
+ " Configuration "
+ config
+ " USER value: "
+ regression_results[design][config]
+ "\n"
)
output_report_list.append(
"\t\tDesign "
+ design
+ " Configuration "
+ config
+ " USER value: "
+ regression_results[design][config]
+ "\n"
)
if size_before == len(configuration_mismatches):
configuration_mismatches = configuration_mismatches[:-1]
def criticalMistmatch(benchmark, regression_results):
nonlocal testFail
nonlocal critical_mismatches
designList = list()
if not_full_benchmark:
designList = regression_results.keys()
else:
designList = benchmark.keys()
for design in designList:
output_report_list.append(
"\nComparing Critical Statistics for: " + design + "\n"
)
critical_mismatches.append(
"\nComparing Critical Statistics for: " + design + "\n"
)
if design not in regression_results:
testFail = True
benchmark[design]["Status"] = "NOT FOUND"
output_report_list.append(
"\tDesign "
+ design
+ " Not Found in the provided regression sheet\n"
)
critical_mismatches.append(
"\tDesign "
+ design
+ " Not Found in the provided regression sheet\n"
)
continue
if design not in benchmark:
testFail = False
output_report_list.append(
"\tDesign "
+ design
+ " Not Found in the provided benchmark sheet\n"
)
critical_mismatches.append(
"\tDesign "
+ design
+ " Not Found in the provided benchmark sheet\n"
)
continue
size_before = len(critical_mismatches)
for stat in critical_statistics:
if compare_vals(
benchmark[design][stat], regression_results[design][stat], stat
):
output_report_list.append("\tStatistic " + stat + " MATCH\n")
output_report_list.append(
"\t\tStatistic "
+ stat
+ " value: "
+ benchmark[design][stat]
+ "\n"
)
else:
testFail = True
benchmark[design]["Status"] = "FAIL"
critical_mismatches.append("\tStatistic " + stat + " MISMATCH\n")
output_report_list.append("\tStatistic " + stat + " MISMATCH\n")
critical_mismatches.append(
"\t\tDesign "
+ design
+ " Statistic "
+ stat
+ " BENCHMARK value: "
+ benchmark[design][stat]
+ "\n"
)
output_report_list.append(
"\t\tDesign "
+ design
+ " Statistic "
+ stat
+ " BENCHMARK value: "
+ benchmark[design][stat]
+ "\n"
)
critical_mismatches.append(
"\t\tDesign "
+ design
+ " Statistic "
+ stat
+ " USER value: "
+ regression_results[design][stat]
+ "\n"
)
output_report_list.append(
"\t\tDesign "
+ design
+ " Statistic "
+ stat
+ " USER value: "
+ regression_results[design][stat]
+ "\n"
)
if len(critical_mismatches) == size_before:
critical_mismatches = critical_mismatches[:-1]
def noteWorthyMismatch(benchmark, regression_results):
designList = list()
if not_full_benchmark:
designList = regression_results.keys()
else:
designList = benchmark.keys()
for design in designList:
output_report_list.append(
"\nComparing Note Worthy Statistics for: " + design + "\n"
)
if design not in regression_results:
output_report_list.append(
"\tDesign "
+ design
+ " Not Found in the provided regression sheet\n"
)
continue
if design not in benchmark:
output_report_list.append(
"\tDesign "
+ design
+ " Not Found in the provided benchmark sheet\n"
)
continue
for stat in note_worthy_statistics:
if (
benchmark[design][stat] == regression_results[design][stat]
or benchmark[design][stat] == "-1"
):
output_report_list.append("\tStatistic " + stat + " MATCH\n")
output_report_list.append(
"\t\tStatistic "
+ stat
+ " value: "
+ benchmark[design][stat]
+ "\n"
)
else:
output_report_list.append("\tStatistic " + stat + " MISMATCH\n")
output_report_list.append(
"\t\tDesign "
+ design
+ " Statistic "
+ stat
+ " BENCHMARK value: "
+ benchmark[design][stat]
+ "\n"
)
output_report_list.append(
"\t\tDesign "
+ design
+ " Statistic "
+ stat
+ " USER value: "
+ regression_results[design][stat]
+ "\n"
)
flow_failures = []
def flowFailures(regression_results):
nonlocal flow_failures
for design in regression_results.keys():
if "failed" in regression_results[design]["flow_status"]:
flow_failures.append(design)
benchmark = parseCSV(benchmark_file, 1)
regression_results = parseCSV(regression_results_file, 0)
flowFailures(regression_results)
configurationMismatch(benchmark, regression_results)
criticalMistmatch(benchmark, regression_results)
noteWorthyMismatch(benchmark, regression_results)
with open(output_report_file, "w") as report_file:
def write(*args, **kwargs):
print(*args, **kwargs, file=report_file)
if testFail:
write("Failed")
else:
write("Passed")
write("---")
if len(flow_failures):
write("[OpenLane Flow Failures] (Designs where OpenLane failed outright)")
write("")
for failure in flow_failures:
write(failure)
write("")
write("---")
if len(missing_configs):
write("[Missing Configuration Variables] (Do not exist in the sheets.)")
write("")
for variable in missing_configs:
write(variable)
write("")
write("---")
if testFail:
write("[Critical Mismatches] (Cause Failures)")
write("".join(critical_mismatches))
write("---")
if testFail and len(configuration_mismatches):
write(
"[Configuration Mismatches] (May Contribute To Differences Between Results)"
)
write("".join(configuration_mismatches))
write("---")
write("[Full Report]")
write("".join(output_report_list))
def formNotFoundStatus(benchmark, regression_results):
for design in benchmark.keys():
if design not in regression_results:
benchmark[design]["Status"] = "NOT FOUND"
formNotFoundStatus(benchmark, regression_results)
if output_xlsx_file is None:
return
# Open an Excel workbook
workbook = xlsxwriter.Workbook(output_xlsx_file)
# Set up a format
fail_format = workbook.add_format(properties={"bold": True, "font_color": "red"})
pass_format = workbook.add_format(properties={"bold": True, "font_color": "green"})
diff_format = workbook.add_format(properties={"font_color": "blue"})
header_format = workbook.add_format(properties={"font_color": "gray"})
benchmark_format = workbook.add_format(
properties={"bold": True, "font_color": "navy"}
)
# Create a sheet
worksheet = workbook.add_worksheet("diff")
headerInfo = ["Owner", "design", "Status"]
headerInfo.extend(critical_statistics)
headerInfo.extend(note_worthy_statistics)
headerInfo.extend(base_configs)
# Write the headers
for col_num, header in enumerate(headerInfo):
worksheet.write(0, col_num, header, header_format)
# Save the data from the OrderedDict into the excel sheet
idx = 0
while idx < len(benchmark):
worksheet.write(idx * 2 + 1, 0, "Benchmark", benchmark_format)
worksheet.write(idx * 2 + 2, 0, "User")
design = str(list(benchmark.keys())[idx])
if design not in regression_results:
for col_num, header in enumerate(headerInfo):
if header == "Owner":
worksheet.write(idx * 2 + 1, col_num, "Benchmark", benchmark_format)
worksheet.write(idx * 2 + 2, col_num, "User")
continue
if header == "design":
worksheet.write(idx * 2 + 1, col_num, design)
worksheet.write(idx * 2 + 2, col_num, design)
continue
worksheet.write(idx * 2 + 1, col_num, benchmark[design][header])
else:
for col_num, header in enumerate(headerInfo):
if header == "Owner":
worksheet.write(idx * 2 + 1, col_num, "Benchmark", benchmark_format)
worksheet.write(idx * 2 + 2, col_num, "User")
continue
if header == "design":
worksheet.write(idx * 2 + 1, col_num, design)
worksheet.write(idx * 2 + 2, col_num, design)
continue
if header == "Status":
if benchmark[design][header] == "PASSED":
worksheet.write(
idx * 2 + 1, col_num, benchmark[design][header], pass_format
)
worksheet.write(
idx * 2 + 2,
col_num,
regression_results[design][header],
pass_format,
)
else:
worksheet.write(
idx * 2 + 1, col_num, benchmark[design][header], fail_format
)
worksheet.write(
idx * 2 + 2,
col_num,
regression_results[design][header],
fail_format,
)
continue
if benchmark[design][header] != regression_results[design][header]:
if header in critical_statistics:
if not compare_vals(
benchmark[design][header],
regression_results[design][header],
header,
):
worksheet.write(
idx * 2 + 1,
col_num,
benchmark[design][header],
fail_format,
)
worksheet.write(
idx * 2 + 2,
col_num,
regression_results[design][header],
fail_format,
)
else:
worksheet.write(
idx * 2 + 1,
col_num,
benchmark[design][header],
pass_format,
)
worksheet.write(
idx * 2 + 2,
col_num,
regression_results[design][header],
pass_format,
)
else:
worksheet.write(
idx * 2 + 1, col_num, benchmark[design][header], diff_format
)
worksheet.write(
idx * 2 + 2,
col_num,
regression_results[design][header],
diff_format,
)
else:
worksheet.write(idx * 2 + 1, col_num, benchmark[design][header])
worksheet.write(
idx * 2 + 2, col_num, regression_results[design][header]
)
idx += 1
# Close the workbook
workbook.close()
if __name__ == "__main__":
cli()