| """ Gathers statistics from VPR runs, like pack/place/route runtimes and Fmax. |
| """ |
| import argparse |
| import csv |
| import os |
| import sys |
| import subprocess |
| |
| |
| def scan_runtime(step, fname): |
| """ Find runtime of VPR log (if any), else returns empty str. """ |
| try: |
| with open(fname, 'r') as f: |
| step_runtime = 0 |
| total_runtime = 0 |
| for line in f: |
| if line.startswith("# {} took".format(step)): |
| step_runtime = float(line.split()[3]) |
| |
| if line.startswith('The entire flow of VPR took'): |
| total_runtime = float(line.split()[6]) |
| |
| step_overhead = total_runtime - step_runtime |
| |
| return str(step_runtime), str(step_overhead) |
| except FileNotFoundError: |
| return "" |
| |
| |
| def scan_critical(fname): |
| """ Find critical path and Fmax from VPR log (if any). |
| |
| Returns |
| ------- |
| critical_path : str |
| Critical path delay in nsec |
| fmax : str |
| Fmax in MHz. |
| |
| """ |
| try: |
| with open(fname, 'r') as f: |
| final_cpd = 0.0 |
| final_fmax = 0.0 |
| |
| final_cpd_geomean = 0.0 |
| final_fmax_geomean = 0.0 |
| |
| for line in f: |
| if line.startswith('Final critical path delay'): |
| parts = line.split() |
| if len(parts) >= 9: |
| # Final critical path delay (least slack): 16.8182 ns, Fmax: 59.4592 MHz |
| final_cpd = float(parts[6]) |
| final_fmax = float(parts[9]) |
| elif len(parts) == 8 and parts[7].strip() == 'ns': |
| # Final critical path delay (least slack): 17.9735 ns |
| final_cpd = float(parts[6]) |
| final_fmax = 1000. / final_cpd |
| |
| if line.startswith( |
| 'Final geomean non-virtual intra-domain period'): |
| parts = line.split() |
| |
| final_cpd_geomean = parts[5] |
| |
| if final_cpd_geomean == "nan": |
| final_cpd_geomean = "N/A" |
| final_fmax_geomean = "N/A" |
| continue |
| |
| final_cpd_geomean = float(parts[5]) |
| final_fmax_geomean = 1000. / final_cpd_geomean |
| |
| return str(final_cpd), str(final_fmax), str( |
| final_cpd_geomean |
| ), str(final_fmax_geomean) |
| except FileNotFoundError: |
| pass |
| |
| return "", "" |
| |
| |
| def get_last_n_dirs(path, n): |
| dirs = path.split("/") |
| return "/".join(dirs[-n:]) |
| |
| |
| def main(): |
| parser = argparse.ArgumentParser(description=__doc__) |
| parser.add_argument("build_dir") |
| |
| args = parser.parse_args() |
| |
| fields = [ |
| "path", |
| "pack time (sec)", |
| "pack overhead (sec)", |
| "place time (sec)", |
| "place overhead (sec)", |
| "route time (sec)", |
| "route overhead (sec)", |
| "t_crit (ns)", |
| "Fmax (MHz)", |
| "t_crit geomean (ns)", |
| "Fmax geomean (MHz)", |
| ] |
| |
| print( |
| ''.join( |
| subprocess. |
| getoutput('git show --oneline -s --decorate --color=never') |
| ), |
| file=sys.stdout |
| ) |
| w = csv.DictWriter(sys.stdout, fields) |
| w.writeheader() |
| rows = list() |
| for root, dirs, files in os.walk(args.build_dir): |
| if 'pack.log' in files: |
| d = {} |
| |
| # Get step runtimes with the respective overhead |
| pack_time, pack_overhead = scan_runtime( |
| "Packing", os.path.join(root, 'pack.log') |
| ) |
| |
| place_time, place_overhead = scan_runtime( |
| "Placement", os.path.join(root, 'place.log') |
| ) |
| |
| route_time, route_overhead = scan_runtime( |
| "Routing", os.path.join(root, 'route.log') |
| ) |
| |
| final_cpd, final_fmax, final_cpd_geomean, final_fmax_geomean = scan_critical( |
| os.path.join(root, 'route.log') |
| ) |
| |
| d['path'] = get_last_n_dirs(root, 2) |
| d['pack time (sec)'] = pack_time |
| d['pack overhead (sec)'] = pack_overhead |
| d['place time (sec)'] = place_time |
| d['place overhead (sec)'] = place_overhead |
| d['route time (sec)'] = route_time |
| d['route overhead (sec)'] = route_overhead |
| d['t_crit (ns)'] = final_cpd |
| d['Fmax (MHz)'] = final_fmax |
| d['t_crit geomean (ns)'] = final_cpd_geomean |
| d['Fmax geomean (MHz)'] = final_fmax_geomean |
| |
| rows.append(d) |
| |
| rows = sorted(rows, key=lambda row: row['path']) |
| |
| for row in rows: |
| w.writerow(row) |
| |
| |
| if __name__ == "__main__": |
| main() |