blob: c5e5737caca675722dd197de7f5a323e675de4ba [file] [log] [blame]
#include <vector>
#include "globals.h"
#include "vpr_types.h"
#include "route_profiling.h"
namespace profiling {
#ifndef PROFILE
void net_rerouted() {}
void route_tree_pruned() {}
void route_tree_preserved() {}
void mark_for_forced_reroute() {}
void perform_forced_reroute() {}
// timing functions where *_start starts a clock and *_end terminates the clock
void sink_criticality_start() {}
void sink_criticality_end(float /*target_criticality*/) {}
void net_rebuild_start() {}
void net_rebuild_end(unsigned /*net_fanout*/, unsigned /*sinks_left_to_route*/) {}
void net_fanout_start() {}
void net_fanout_end(unsigned /*net_fanout*/) {}
// analysis functions for printing out the profiling data for an iteration
void congestion_analysis() {}
void time_on_criticality_analysis() {}
void time_on_fanout_analysis() {}
void profiling_initialization(unsigned /*max_net_fanout*/) {}
#else
constexpr unsigned int fanout_per_bin = 1;
constexpr float criticality_per_bin = 0.05;
// data structures indexed by fanout bin (ex. fanout of x is in bin x/fanout_per_bin)
static std::vector<float> time_on_fanout;
static std::vector<float> time_on_fanout_rebuild;
static std::vector<float> time_on_criticality;
static std::vector<int> itry_on_fanout;
static std::vector<int> itry_on_criticality;
static std::vector<int> rerouted_sinks;
static std::vector<int> finished_sinks;
// action counters for what setup routing resources did
static int entire_net_rerouted;
void net_rerouted() { ++entire_net_rerouted; }
static int entire_tree_pruned;
void route_tree_pruned() { ++entire_tree_pruned; }
static int part_tree_preserved;
void route_tree_preserved() { ++part_tree_preserved; }
static int connections_forced_to_reroute;
void mark_for_forced_reroute() { ++connections_forced_to_reroute; }
static int connections_rerouted_due_to_forcing;
void perform_forced_reroute() { ++connections_rerouted_due_to_forcing; }
// timing functions where *_start starts a clock and *_end terminates the clock
static clock_t sink_criticality_clock;
void sink_criticality_start() { sink_criticality_clock = clock(); }
void sink_criticality_end(float target_criticality) {
if (!time_on_criticality.empty()) {
time_on_criticality[target_criticality / criticality_per_bin] += static_cast<float>(clock() - sink_criticality_clock) / CLOCKS_PER_SEC;
++itry_on_criticality[target_criticality / criticality_per_bin];
}
}
static clock_t net_rebuild_clock;
void net_rebuild_start() { net_rebuild_clock = clock(); }
void net_rebuild_end(unsigned net_fanout, unsigned sinks_left_to_route) {
unsigned int bin{net_fanout / fanout_per_bin};
unsigned int sinks_already_routed = net_fanout - sinks_left_to_route;
float rebuild_time{static_cast<float>(clock() - net_rebuild_clock) / CLOCKS_PER_SEC};
finished_sinks[bin] += sinks_already_routed;
rerouted_sinks[bin] += sinks_left_to_route;
time_on_fanout_rebuild[bin] += rebuild_time;
}
static clock_t net_fanout_clock;
void net_fanout_start() {
net_fanout_clock = clock();
}
void net_fanout_end(unsigned net_fanout) {
float time_for_net = static_cast<float>(clock() - net_fanout_clock) / CLOCKS_PER_SEC;
time_on_fanout[net_fanout / fanout_per_bin] += time_for_net;
itry_on_fanout[net_fanout / fanout_per_bin] += 1;
}
void time_on_fanout_analysis() {
VTR_LOG("%d entire net rerouted, %d entire trees pruned (route to each sink from scratch), %d partially rerouted\n",
entire_net_rerouted, entire_tree_pruned, part_tree_preserved);
VTR_LOG("%d connections marked for forced reroute, %d forced reroutes performed\n", connections_forced_to_reroute, connections_rerouted_due_to_forcing);
// using the global time_on_fanout and itry_on_fanout
VTR_LOG("fanout low time (s) attemps rebuild tree time (s) finished sinks rerouted sinks\n");
for (size_t bin = 0; bin < time_on_fanout.size(); ++bin) {
if (itry_on_fanout[bin]) { // avoid printing the many 0 bins
VTR_LOG("%4d %14.3f %12d %14.3f %12d %12d\n",
bin * fanout_per_bin,
time_on_fanout[bin],
itry_on_fanout[bin],
time_on_fanout_rebuild[bin],
finished_sinks[bin],
rerouted_sinks[bin]);
}
// clear the non-cumulative values
finished_sinks[bin] = 0;
rerouted_sinks[bin] = 0;
}
connections_forced_to_reroute = connections_rerouted_due_to_forcing = 0;
return;
}
void time_on_criticality_analysis() {
VTR_LOG("criticality low time (s) attemps\n");
for (size_t bin = 0; bin < time_on_criticality.size(); ++bin) {
if (itry_on_criticality[bin]) { // avoid printing the many 0 bins
VTR_LOG("%4f %14.3f %12d\n", bin * criticality_per_bin, time_on_criticality[bin], itry_on_criticality[bin]);
}
}
return;
}
// at the end of a routing iteration, profile how much congestion is taken up by each type of rr_node
// efficient bit array for checking against congested type
struct Congested_node_types {
uint32_t mask;
Congested_node_types()
: mask{0} {}
void set_congested(int rr_node_type) { mask |= (1 << rr_node_type); }
void clear_congested(int rr_node_type) { mask &= ~(1 << rr_node_type); }
bool is_congested(int rr_node_type) const { return mask & (1 << rr_node_type); }
bool empty() const { return mask == 0; }
};
void congestion_analysis() {
# if 0
// each type indexes into array which holds the congestion for that type
std::vector<int> congestion_per_type((size_t)NUM_RR_TYPES, 0);
// print out specific node information if congestion for type is low enough
int total_congestion = 0;
for (int inode = 0; inode < device_ctx.rr_nodes.size(); ++inode) {
const t_rr_node& node = device_ctx.rr_nodes[inode];
int congestion = node.get_occ() - node.get_capacity();
if (congestion > 0) {
total_congestion += congestion;
congestion_per_type[node.type] += congestion;
}
}
constexpr int specific_node_print_threshold = 5;
Congested_node_types congested;
for (int type = SOURCE; type < NUM_RR_TYPES; ++type) {
float congestion_percentage = (float)congestion_per_type[type] / (float) total_congestion * 100;
VTR_LOG(" %6s: %10.6f %\n", node_typename[type], congestion_percentage);
// nodes of that type need specific printing
if (congestion_per_type[type] > 0 &&
congestion_per_type[type] < specific_node_print_threshold) congested.set_congested(type);
}
// specific print out each congested node
if (!congested.empty()) {
VTR_LOG("Specific congested nodes\nxlow ylow type\n");
for (int inode = 0; inode < device_ctx.rr_nodes.size(); ++inode) {
const t_rr_node& node = device_ctx.rr_nodes[inode];
if (congested.is_congested(node.type) && (node.get_occ() - node.get_capacity()) > 0) {
VTR_LOG("(%3d,%3d) %6s\n", node.get_xlow(), node.get_ylow(), node_typename[node.type]);
}
}
}
return;
# endif
}
void profiling_initialization(unsigned max_fanout) {
// add 1 so that indexing on the max fanout would still be valid
time_on_fanout.resize((max_fanout / fanout_per_bin) + 1, 0);
itry_on_fanout.resize((max_fanout / fanout_per_bin) + 1, 0);
time_on_fanout_rebuild.resize((max_fanout / fanout_per_bin) + 1, 0);
rerouted_sinks.resize((max_fanout / fanout_per_bin) + 1, 0);
finished_sinks.resize((max_fanout / fanout_per_bin) + 1, 0);
time_on_criticality.resize((1 / criticality_per_bin) + 1, 0);
itry_on_criticality.resize((1 / criticality_per_bin) + 1, 0);
entire_net_rerouted = 0;
entire_tree_pruned = 0;
part_tree_preserved = 0;
connections_forced_to_reroute = 0;
connections_rerouted_due_to_forcing = 0;
return;
}
#endif
} // end namespace profiling