Added writing a CSV report with timing analysis of each net branch

Signed-off-by: Maciej Kurc <mkurc@antmicro.com>
This commit is contained in:
Maciej Kurc 2021-09-09 15:50:03 +02:00
parent 9d8d3bdbc4
commit 99ae5ef38e
4 changed files with 89 additions and 6 deletions

View File

@ -183,6 +183,9 @@ po::options_description CommandHandler::getGeneralOptions()
general.add_options()("placed-svg", po::value<std::string>(), "write render of placement to SVG file");
general.add_options()("routed-svg", po::value<std::string>(), "write render of routing to SVG file");
general.add_options()("timing-report", po::value<std::string>(),
"write timing analysis report in CSV format to file");
return general;
}
@ -249,6 +252,11 @@ void CommandHandler::setupContext(Context *ctx)
ctx->settings[ctx->id("timing/allowFail")] = true;
}
if (vm.count("timing-report")) {
std::string filename = vm["timing-report"].as<std::string>();
ctx->settings[ctx->id("timing/reportFile")] = filename;
}
if (vm.count("placer")) {
std::string placer = vm["placer"].as<std::string>();
if (std::find(Arch::availablePlacers.begin(), Arch::availablePlacers.end(), placer) ==

View File

@ -874,7 +874,7 @@ bool router1(Context *ctx, const Router1Cfg &cfg)
log_info("Checksum: 0x%08x\n", ctx->checksum());
timing_analysis(ctx, true /* slack_histogram */, true /* print_fmax */, true /* print_path */,
true /* warn_on_failure */);
true /* warn_on_failure */, true /* write_report */);
return true;
} catch (log_execution_error_exception) {

View File

@ -637,6 +637,16 @@ struct CriticalPath
typedef dict<ClockPair, CriticalPath> CriticalPathMap;
struct NetSinkTiming
{
ClockPair clock_pair;
PortRef sink;
delay_t delay;
delay_t budget;
};
typedef dict<const NetInfo*, std::vector<NetSinkTiming>, hash_ptr_ops> DetailedNetTimings;
struct Timing
{
Context *ctx;
@ -645,6 +655,7 @@ struct Timing
delay_t min_slack;
CriticalPathMap *crit_path;
DelayFrequency *slack_histogram;
DetailedNetTimings *detailed_net_timings;
IdString async_clock;
struct TimingData
@ -660,9 +671,11 @@ struct Timing
};
Timing(Context *ctx, bool net_delays, bool update, CriticalPathMap *crit_path = nullptr,
DelayFrequency *slack_histogram = nullptr)
DelayFrequency *slack_histogram = nullptr,
DetailedNetTimings *detailed_net_timings = nullptr)
: ctx(ctx), net_delays(net_delays), update(update), min_slack(1.0e12 / ctx->setting<float>("target_freq")),
crit_path(crit_path), slack_histogram(slack_histogram), async_clock(ctx->id("$async$"))
crit_path(crit_path), slack_histogram(slack_histogram), detailed_net_timings(detailed_net_timings),
async_clock(ctx->id("$async$"))
{
}
@ -948,6 +961,17 @@ struct Timing
ClockPair clockPair{startdomain.first, dest_ev};
nd.arrival_time[dest_ev] = std::max(nd.arrival_time[dest_ev], endpoint_arrival);
// Store the detailed timing for each net and user (a.k.a. sink)
if (detailed_net_timings) {
NetSinkTiming sink_timing;
sink_timing.clock_pair = clockPair;
sink_timing.sink = usr;
sink_timing.delay = endpoint_arrival;
sink_timing.budget = period;
(*detailed_net_timings)[net].push_back(sink_timing);
}
if (crit_path) {
if (!crit_nets.count(clockPair) || crit_nets.at(clockPair).first < endpoint_arrival) {
crit_nets[clockPair] = std::make_pair(endpoint_arrival, net);
@ -1111,7 +1135,7 @@ void assign_budget(Context *ctx, bool quiet)
log_info("Checksum: 0x%08x\n", ctx->checksum());
}
void timing_analysis(Context *ctx, bool print_histogram, bool print_fmax, bool print_path, bool warn_on_failure)
void timing_analysis(Context *ctx, bool print_histogram, bool print_fmax, bool print_path, bool warn_on_failure, bool write_report)
{
auto format_event = [ctx](const ClockEvent &e, int field_width = 0) {
std::string value;
@ -1126,9 +1150,10 @@ void timing_analysis(Context *ctx, bool print_histogram, bool print_fmax, bool p
CriticalPathMap crit_paths;
DelayFrequency slack_histogram;
DetailedNetTimings detailed_net_timings;
Timing timing(ctx, true /* net_delays */, false /* update */, (print_path || print_fmax) ? &crit_paths : nullptr,
print_histogram ? &slack_histogram : nullptr);
print_histogram ? &slack_histogram : nullptr, write_report ? &detailed_net_timings : nullptr);
timing.walk_paths();
std::map<IdString, std::pair<ClockPair, CriticalPath>> clock_reports;
std::map<IdString, double> clock_fmax;
@ -1411,6 +1436,56 @@ void timing_analysis(Context *ctx, bool print_histogram, bool print_fmax, bool p
std::string(bins[i] * bar_width / max_freq, '*').c_str(),
(bins[i] * bar_width) % max_freq > 0 ? '+' : ' ');
}
// Write detailed timing analysis report to file
std::string report_file;
if (write_report) {
if (ctx->settings.count(ctx->id("timing/reportFile"))) {
report_file = ctx->settings[ctx->id("timing/reportFile")].as_string();
}
}
if (!report_file.empty()) {
log_info("\nWriting timing analysis report...\n");
FILE* fp = fopen(report_file.c_str(), "w");
NPNR_ASSERT(fp != nullptr);
auto cellport = [&](const PortRef& port) {
std::string str;
if (port.cell != nullptr) {
str = std::string(port.cell->name.c_str(ctx));
} else {
str = "?";
}
return str + "." + std::string(port.port.c_str(ctx));
};
// Header
fprintf(fp, "net,source,sink,start,end,delay,budget\n");
// Content
for (const auto& it : detailed_net_timings) {
const NetInfo* net = it.first;
const std::string drv_port = cellport(net->driver);
for (const auto& sink_timing : it.second) {
fprintf(fp, "%s,%s,%s,%s %s,%s %s,%f,%f\n",
net->name.c_str(ctx),
drv_port.c_str(),
cellport(sink_timing.sink).c_str(),
edge_name(sink_timing.clock_pair.start.edge),
sink_timing.clock_pair.start.clock.c_str(ctx),
edge_name(sink_timing.clock_pair.end.edge),
sink_timing.clock_pair.end.clock.c_str(ctx),
ctx->getDelayNS(sink_timing.delay),
ctx->getDelayNS(sink_timing.budget)
);
}
}
fclose(fp);
}
}
NEXTPNR_NAMESPACE_END

View File

@ -252,7 +252,7 @@ void assign_budget(Context *ctx, bool quiet = false);
// Perform timing analysis and print out the fmax, and optionally the
// critical path
void timing_analysis(Context *ctx, bool slack_histogram = true, bool print_fmax = true, bool print_path = false,
bool warn_on_failure = false);
bool warn_on_failure = false, bool write_report = false);
NEXTPNR_NAMESPACE_END