Skip to content

Commit

Permalink
Add flag to restart place-and-route on failed target frequency
Browse files Browse the repository at this point in the history
* Add --restart-on-failed-target-frequency flag and logic to restart the
  place-and-route process if the target frequency is not achieved.

* This flag is intended to be used with the --randomize-seed option to
  generate a new random seed for every run. This can significantly
  improve the chances of achieving a higher clock frequency compared to
  using the default seed.

* Move print_net_source out of log_crit_paths() to remove the 'static'
  keyword, which could otherwise cause a segmentation fault if the
  context is changed.
  • Loading branch information
jthornblad committed Sep 26, 2024
1 parent 437fb70 commit a0356aa
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 26 deletions.
31 changes: 30 additions & 1 deletion common/kernel/command.cc
Original file line number Diff line number Diff line change
Expand Up @@ -345,7 +345,9 @@ po::options_description CommandHandler::getGeneralOptions()
general.add_options()("top", po::value<std::string>(), "name of top module");
general.add_options()("seed", po::value<uint64_t>(), "seed value for random number generator");
general.add_options()("randomize-seed,r", "randomize seed value for random number generator");

general.add_options()("restart-on-failed-target-frequency",
"restart place and route if target frequency is not achieved (use together with "
"--randomize-seed option)");
general.add_options()(
"placer", po::value<std::string>(),
std::string("placer algorithm to use; available: " + boost::algorithm::join(Arch::availablePlacers, ", ") +
Expand Down Expand Up @@ -673,6 +675,17 @@ int CommandHandler::executeMain(std::unique_ptr<Context> ctx)
ctx->debug = true;
if (!ctx->place() && !ctx->force)
log_error("Placing design failed.\n");
if (vm.count("restart-on-failed-target-frequency")) {
if (!ctx->target_frequency_achieved) {
log_break();
log_info("Target frequency not achieved, restarting...\n");
log_break();
#ifndef NO_PYTHON
deinit_python();
#endif
return 2;
}
}
ctx->debug = saved_debug;
ctx->check();
if (vm.count("placed-svg"))
Expand All @@ -686,6 +699,17 @@ int CommandHandler::executeMain(std::unique_ptr<Context> ctx)
ctx->debug = true;
if (!ctx->route() && !ctx->force)
log_error("Routing design failed.\n");
if (vm.count("restart-on-failed-target-frequency")) {
if (!ctx->target_frequency_achieved) {
log_break();
log_info("Target frequency not achieved, restarting...\n");
log_break();
#ifndef NO_PYTHON
deinit_python();
#endif
return 2;
}
}
ctx->debug = saved_debug;
run_script_hook("post-route");
if (vm.count("routed-svg"))
Expand Down Expand Up @@ -753,10 +777,15 @@ int CommandHandler::exec()
return 0;

dict<std::string, Property> values;
restart:
std::unique_ptr<Context> ctx = createContext(values);
setupContext(ctx.get());
setupArchContext(ctx.get());
int rc = executeMain(std::move(ctx));
if (rc == 2) {
ctx.reset();
goto restart;
}
printFooter();
log_break();
log_info("Program finished normally.\n");
Expand Down
2 changes: 2 additions & 0 deletions common/kernel/context.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ struct Context : Arch, DeterministicRNG
bool disable_critical_path_source_print = false;
// True when detailed per-net timing is to be stored / reported
bool detailed_timing_report = false;
// Default to true, will update when timing analysis is run
bool target_frequency_achieved = true;

ArchArgs arch_args;

Expand Down
10 changes: 10 additions & 0 deletions common/kernel/timing.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1339,6 +1339,16 @@ void timing_analysis(Context *ctx, bool print_slack_histogram, bool print_fmax,

if (update_results)
ctx->timing_result = result;

ctx->target_frequency_achieved = true;
for (auto &clock : result.clock_paths) {
float fmax = result.clock_fmax[clock.first].achieved;
float target = result.clock_fmax[clock.first].constraint;
bool passed = target < fmax;
if (!passed) {
ctx->target_frequency_achieved = false;
}
}
}

NEXTPNR_NAMESPACE_END
51 changes: 26 additions & 25 deletions common/kernel/timing_log.cc
Original file line number Diff line number Diff line change
Expand Up @@ -38,35 +38,36 @@ static std::string clock_event_name(const Context *ctx, const ClockEvent &e, int
return value;
};

static void log_crit_paths(const Context *ctx, TimingResult &result)
static void print_net_source(const Context *ctx, const NetInfo *net)
{
static auto print_net_source = [ctx](const NetInfo *net) {
// Check if this net is annotated with a source list
auto sources = net->attrs.find(ctx->id("src"));
if (sources == net->attrs.end()) {
// No sources for this net, can't print anything
return;
}
// Check if this net is annotated with a source list
auto sources = net->attrs.find(ctx->id("src"));
if (sources == net->attrs.end()) {
// No sources for this net, can't print anything
return;
}

// Sources are separated by pipe characters.
// There is no guaranteed ordering on sources, so we just print all
auto sourcelist = sources->second.as_string();
std::vector<std::string> source_entries;
size_t current = 0, prev = 0;
while ((current = sourcelist.find("|", prev)) != std::string::npos) {
source_entries.emplace_back(sourcelist.substr(prev, current - prev));
prev = current + 1;
}
// Ensure we emplace the final entry
// Sources are separated by pipe characters.
// There is no guaranteed ordering on sources, so we just print all
auto sourcelist = sources->second.as_string();
std::vector<std::string> source_entries;
size_t current = 0, prev = 0;
while ((current = sourcelist.find("|", prev)) != std::string::npos) {
source_entries.emplace_back(sourcelist.substr(prev, current - prev));
prev = current + 1;
}
// Ensure we emplace the final entry
source_entries.emplace_back(sourcelist.substr(prev, current - prev));

// Iterate and print our source list at the correct indentation level
log_info(" Defined in:\n");
for (auto entry : source_entries) {
log_info(" %s\n", entry.c_str());
}
};
// Iterate and print our source list at the correct indentation level
log_info(" Defined in:\n");
for (auto entry : source_entries) {
log_info(" %s\n", entry.c_str());
}
}

static void log_crit_paths(const Context *ctx, TimingResult &result)
{
// A helper function for reporting one critical path
auto print_path_report = [ctx](const CriticalPath &path) {
delay_t total(0), logic_total(0), route_total(0);
Expand Down Expand Up @@ -137,7 +138,7 @@ static void log_crit_paths(const Context *ctx, TimingResult &result)
}

if (!ctx->disable_critical_path_source_print) {
print_net_source(net);
print_net_source(ctx, net);
}
}
}
Expand Down

0 comments on commit a0356aa

Please sign in to comment.