diff --git a/common/kernel/command.cc b/common/kernel/command.cc index dc178cd2..73c51228 100644 --- a/common/kernel/command.cc +++ b/common/kernel/command.cc @@ -404,6 +404,8 @@ po::options_description CommandHandler::getGeneralOptions() "enable experimental timing-driven ripup in router (deprecated; use --tmg-ripup instead)"); general.add_options()("router2-alt-weights", "use alternate router2 weights"); + general.add_options()("router2-heuristic-test", po::value(), + "write heuristic vs congestion-free delay data in CSV format to file"); general.add_options()("report", po::value(), "write timing and utilization report in JSON format to file"); @@ -546,6 +548,9 @@ void CommandHandler::setupContext(Context *ctx) if (vm.count("router2-alt-weights")) ctx->settings[ctx->id("router2/alt-weights")] = true; + if (vm.count("router2-heuristic-test")) + ctx->settings[ctx->id("router2/heuristic-test")] = vm["router2-heuristic-test"].as(); + if (vm.count("static-dump-density")) ctx->settings[ctx->id("static/dump_density")] = true; diff --git a/common/route/router2.cc b/common/route/router2.cc index 8dcec6e9..b2b8d6b8 100644 --- a/common/route/router2.cc +++ b/common/route/router2.cc @@ -1373,6 +1373,13 @@ struct Router2 void update_route_delays() { + std::ofstream f; + if (!cfg.heuristic_test.empty()) { + f.open(cfg.heuristic_test); + if (!f) + log_error("Failed to open heuristic test output file %s for writing.\n", cfg.heuristic_test.c_str()); + f << "source wire,sink wire,heuristic delay (ns),actual delay (ns)" << std::endl; + } for (int net : route_queue) { NetInfo *ni = nets_by_udata.at(net); #ifdef ARCH_ECP5 @@ -1382,8 +1389,16 @@ struct Router2 auto &nd = nets.at(net); for (auto usr : ni->users.enumerate()) { delay_t arc_delay = 0; - for (int j = 0; j < int(nd.arcs.at(usr.index.idx()).size()); j++) - arc_delay = std::max(arc_delay, get_route_delay(net, usr.index, j)); + for (int j = 0; j < int(nd.arcs.at(usr.index.idx()).size()); j++) { + delay_t route_delay = get_route_delay(net, usr.index, j); + if (f) { + auto src_wire = nd.src_wire; + auto sink_wire = nd.arcs.at(usr.index.idx()).at(j).sink_wire; + if (src_wire != WireId() && sink_wire != WireId()) + f << ctx->nameOfWire(src_wire) << "," << ctx->nameOfWire(sink_wire) << "," << ctx->getDelayNS(ctx->estimateDelay(src_wire, sink_wire)) << "," << ctx->getDelayNS(route_delay) << std::endl; + } + arc_delay = std::max(arc_delay, route_delay); + } tmg.set_route_delay(CellPortKey(usr.value), DelayPair(arc_delay)); } } @@ -1446,6 +1461,9 @@ struct Router2 write_wiretype_heatmap(cong_map); log_info(" wrote wiretype heatmap to %s.\n", filename.c_str()); } + + NPNR_ASSERT_MSG(cfg.heuristic_test.empty(), "congestion-free routing complete; nextpnr will exit now"); + int tmgfail = 0; if (timing_driven) tmg.run(false); @@ -1523,6 +1541,12 @@ Router2Cfg::Router2Cfg(Context *ctx) hist_cong_weight = ctx->setting("router2/histCongWeight", 0.5f); curr_cong_mult = ctx->setting("router2/currCongWeightMult", 0.0f); estimate_weight = ctx->setting("router2/estimateWeight", 1.0f); + } else if (ctx->settings.count(ctx->id("router2/heuristic-test"))) { + init_curr_cong_weight = 0.0f; + hist_cong_weight = 0.0f; + curr_cong_mult = 0.0f; + estimate_weight = 1.25f; + heuristic_test = ctx->settings.at(ctx->id("router2/heuristic-test")).as_string(); } else { init_curr_cong_weight = ctx->setting("router2/initCurrCongWeight", 0.5f); hist_cong_weight = ctx->setting("router2/histCongWeight", 1.0f); diff --git a/common/route/router2.h b/common/route/router2.h index 629453c6..e9c43d21 100644 --- a/common/route/router2.h +++ b/common/route/router2.h @@ -57,6 +57,8 @@ struct Router2Cfg // Print additional performance profiling information bool perf_profile = false; + std::string heuristic_test; + std::string heatmap; std::function get_base_cost = default_base_cost; }; diff --git a/python/plot_heuristic.py b/python/plot_heuristic.py new file mode 100644 index 00000000..873e7ff0 --- /dev/null +++ b/python/plot_heuristic.py @@ -0,0 +1,32 @@ +import matplotlib.pyplot as plt +import csv + +RED = '#ca684d' +GREEN = '#7aa354' +BLUE = '#5e84d0' + +EPSILON = 0.02 + +heuristic = [] +actual = [] +color = [] +with open('heuristic.csv') as f: + reader = csv.reader(f, delimiter=',') + rows = [row for row in reader] + for row in rows[1:]: + heuristic_value = float(row[2]) + actual_value = float(row[3]) + heuristic.append(heuristic_value) + actual.append(actual_value) + if heuristic_value > actual_value+EPSILON: + color.append(RED) + elif heuristic_value < actual_value-EPSILON: + color.append(BLUE) + else: + color.append(GREEN) + +plt.scatter(actual, heuristic, c=color) +plt.xlabel("Actual Delay (ns)") +plt.ylabel("Estimated Delay (ns)") +plt.savefig("heuristic_vs_actual.png") +