Skip to content

Write routing channel occupancies to files. #2985

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Apr 16, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
106 changes: 81 additions & 25 deletions vpr/src/base/stats.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
#include <cmath>

#include "stats.h"

#include <set>
#include <fstream>
#include <string>
#include <iomanip>

#include "physical_types_util.h"
#include "route_tree.h"
Expand All @@ -15,25 +20,45 @@
#include "rr_graph_area.h"
#include "segment_stats.h"
#include "channel_stats.h"
#include "stats.h"

/********************** Subroutines local to this module *********************/

/**
* @brief Loads the two arrays passed in with the total occupancy at each of the
* channel segments in the FPGA.
*/
static void load_channel_occupancies(const Netlist<>& net_list,
vtr::Matrix<int>& chanx_occ,
vtr::Matrix<int>& chany_occ);

/**
* @brief Writes channel occupancy data to a file.
*
* Each row contains:
* - (x, y) coordinate
* - Occupancy count
* - Occupancy percentage (occupancy / capacity)
* - Channel capacity
*
* @param filename Output file path.
* @param occupancy Matrix of occupancy counts.
* @param capacity_list List of channel capacities (per y for chanx, per x for chany).
*/
static void write_channel_occupancy_table(const std::string_view filename,
const vtr::Matrix<int>& occupancy,
const std::vector<int>& capacity_list);

/**
* @brief Figures out maximum, minimum and average number of bends
* and net length in the routing.
*/
static void length_and_bends_stats(const Netlist<>& net_list, bool is_flat);

///@brief Determines how many tracks are used in each channel.
static void get_channel_occupancy_stats(const Netlist<>& net_list, bool /***/);

/************************* Subroutine definitions ****************************/

/**
* @brief Prints out various statistics about the current routing.
*
* Both a routing and an rr_graph must exist when you call this routine.
*/
void routing_stats(const Netlist<>& net_list,
bool full_stats,
enum e_route_type route_type,
Expand Down Expand Up @@ -105,10 +130,6 @@ void routing_stats(const Netlist<>& net_list,
}
}

/**
* @brief Figures out maximum, minimum and average number of bends
* and net length in the routing.
*/
void length_and_bends_stats(const Netlist<>& net_list, bool is_flat) {
int max_bends = 0;
int total_bends = 0;
Expand Down Expand Up @@ -168,9 +189,8 @@ void length_and_bends_stats(const Netlist<>& net_list, bool is_flat) {
VTR_LOG("Total number of nets absorbed: %d\n", num_absorbed_nets);
}

///@brief Determines how many tracks are used in each channel.
static void get_channel_occupancy_stats(const Netlist<>& net_list, bool /***/) {
auto& device_ctx = g_vpr_ctx.device();
const auto& device_ctx = g_vpr_ctx.device();

auto chanx_occ = vtr::Matrix<int>({{
device_ctx.grid.width(), //[0 .. device_ctx.grid.width() - 1] (length of x channel)
Expand All @@ -183,8 +203,12 @@ static void get_channel_occupancy_stats(const Netlist<>& net_list, bool /***/) {
device_ctx.grid.height() //[0 .. device_ctx.grid.height() - 1] (length of y channel)
}},
0);

load_channel_occupancies(net_list, chanx_occ, chany_occ);

write_channel_occupancy_table("chanx_occupancy.txt", chanx_occ, device_ctx.chan_width.x_list);
write_channel_occupancy_table("chany_occupancy.txt", chany_occ, device_ctx.chan_width.y_list);

VTR_LOG("\n");
VTR_LOG("X - Directed channels: j max occ ave occ capacity\n");
VTR_LOG(" ---- ------- ------- --------\n");
Expand Down Expand Up @@ -225,16 +249,50 @@ static void get_channel_occupancy_stats(const Netlist<>& net_list, bool /***/) {
VTR_LOG("\n");
}

/**
* @brief Loads the two arrays passed in with the total occupancy at each of the
* channel segments in the FPGA.
*/
static void write_channel_occupancy_table(const std::string_view filename,
const vtr::Matrix<int>& occupancy,
const std::vector<int>& capacity_list) {
constexpr int w_coord = 6;
constexpr int w_value = 12;
constexpr int w_percent = 12;

std::ofstream file(filename.data());
if (!file.is_open()) {
VTR_LOG_WARN("Failed to open %s for writing.\n", filename.data());
return;
}

file << std::setw(w_coord) << "x"
<< std::setw(w_coord) << "y"
<< std::setw(w_value) << "occupancy"
<< std::setw(w_percent) << "%"
<< std::setw(w_value) << "capacity"
<< "\n";

for (size_t y = 0; y < occupancy.dim_size(1); ++y) {
int capacity = capacity_list[y];
for (size_t x = 0; x < occupancy.dim_size(0); ++x) {
int occ = occupancy[x][y];
float percent = capacity > 0 ? static_cast<float>(occ) / capacity * 100.0f : 0.0f;

file << std::setw(w_coord) << x
<< std::setw(w_coord) << y
<< std::setw(w_value) << occ
<< std::setw(w_percent) << std::fixed << std::setprecision(3) << percent
<< std::setw(w_value) << capacity
<< "\n";
}
}

file.close();
}

static void load_channel_occupancies(const Netlist<>& net_list,
vtr::Matrix<int>& chanx_occ,
vtr::Matrix<int>& chany_occ) {
auto& device_ctx = g_vpr_ctx.device();
const auto& device_ctx = g_vpr_ctx.device();
const auto& rr_graph = device_ctx.rr_graph;
auto& route_ctx = g_vpr_ctx.routing();
const auto& route_ctx = g_vpr_ctx.routing();

/* First set the occupancy of everything to zero. */
chanx_occ.fill(0);
Expand All @@ -250,7 +308,7 @@ static void load_channel_occupancies(const Netlist<>& net_list,
if (!tree)
continue;

for (auto& rt_node : tree.value().all_nodes()) {
for (const RouteTreeNode& rt_node : tree.value().all_nodes()) {
RRNodeId inode = rt_node.inode;
t_rr_type rr_type = rr_graph.node_type(inode);

Expand All @@ -276,11 +334,9 @@ void get_num_bends_and_length(ParentNetId inet, int* bends_ptr, int* len_ptr, in
auto& device_ctx = g_vpr_ctx.device();
const auto& rr_graph = device_ctx.rr_graph;

int bends, length, segments;

bends = 0;
length = 0;
segments = 0;
int bends = 0;
int length = 0;
int segments = 0;

const vtr::optional<RouteTree>& tree = route_ctx.route_trees[inet];
if (!tree) {
Expand Down
32 changes: 5 additions & 27 deletions vpr/src/base/stats.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@
#include "vpr_types.h"
#include "netlist.h"

/**
* @brief Prints out various statistics about the current routing.
*
* Both a routing and an rr_graph must exist when you call this routine.
*/
void routing_stats(const Netlist<>& net_list,
bool full_stats,
enum e_route_type route_type,
Expand Down Expand Up @@ -42,30 +47,3 @@ void print_resource_usage();
* @param target_device_utilization The target device utilization set by the user
*/
void print_device_utilization(const float target_device_utilization);

/**
* @brief template functions must be defined in header, or explicitely
* instantiated in definition file (defeats the point of template)
*/
template<typename T>
double linear_regression_vector(const std::vector<T>& vals, size_t start_x = 0) {
// returns slope; index is x, val is y
size_t n{vals.size() - start_x};

double x_avg{0}, y_avg{0};
for (size_t x = start_x; x < vals.size(); ++x) {
x_avg += x;
y_avg += vals[x];
}
x_avg /= (double)n;
y_avg /= (double)n;

double numerator = 0, denominator = 0;
for (size_t x = start_x; x < vals.size(); ++x) {
numerator += (x - x_avg) * (vals[x] - y_avg);
denominator += (x - x_avg) * (x - x_avg);
}

if (denominator == 0) return std::numeric_limits<double>::max();
return numerator / denominator;
}