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 5 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
133 changes: 108 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,43 @@
#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 detailed channel occupancy info to text files.
*
* For each channel segment in X and Y directions, outputs:
* - Channel coordinate (x, y)
* - Occupancy count
* - Occupancy percentage (occupancy / capacity)
* - Channel capacity
*
* @param chanx_occ Matrix containing occupancy values for X-directed channels.
* @param chany_occ Matrix containing occupancy values for Y-directed channels.
*/
static void write_channel_occupancy_to_file(const vtr::Matrix<int>& chanx_occ,
const vtr::Matrix<int>& chany_occ);

/**
* @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 +128,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 +187,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 @@ -185,6 +203,8 @@ static void get_channel_occupancy_stats(const Netlist<>& net_list, bool /***/) {
0);
load_channel_occupancies(net_list, chanx_occ, chany_occ);

write_channel_occupancy_to_file(chanx_occ, chany_occ);

VTR_LOG("\n");
VTR_LOG("X - Directed channels: j max occ ave occ capacity\n");
VTR_LOG(" ---- ------- ------- --------\n");
Expand Down Expand Up @@ -225,16 +245,81 @@ 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_to_file(const vtr::Matrix<int>& chanx_occ,
const vtr::Matrix<int>& chany_occ) {
const auto& device_ctx = g_vpr_ctx.device();

constexpr int w_coord = 6;
constexpr int w_value = 12;
constexpr int w_percent = 10;

// Write X-directed channels
std::ofstream chanx_file("chanx_occupancy.txt");
if (chanx_file.is_open()) {
chanx_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 j = 0; j < chanx_occ.dim_size(1); ++j) {
int capacity = device_ctx.chan_width.x_list[j];
for (size_t i = 0; i < chanx_occ.dim_size(0); ++i) {
int occ = chanx_occ[i][j];
float percent = capacity > 0 ? static_cast<float>(occ) / capacity * 100.0f : 0.0f;

chanx_file << std::setw(w_coord) << i
<< std::setw(w_coord) << j
<< std::setw(w_value) << occ
<< std::setw(w_percent) << std::fixed << std::setprecision(3) << percent
<< std::setw(w_value) << capacity
<< "\n";
}
}

chanx_file.close();
} else {
VTR_LOG_WARN("Failed to open chanx_occupancy.txt for writing.\n");
}

// Write Y-directed channels
std::ofstream chany_file("chany_occupancy.txt");
if (chany_file.is_open()) {
chany_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 i = 0; i < chany_occ.dim_size(0); ++i) {
int capacity = device_ctx.chan_width.y_list[i];
for (size_t j = 0; j < chany_occ.dim_size(1); ++j) {
int occ = chany_occ[i][j];
float percent = capacity > 0 ? static_cast<float>(occ) / capacity * 100.0f : 0.0f;

chany_file << std::setw(w_coord) << i
<< std::setw(w_coord) << j
<< std::setw(w_value) << occ
<< std::setw(w_percent) << std::fixed << std::setprecision(3) << percent
<< std::setw(w_value) << capacity
<< "\n";
}
}

chany_file.close();
} else {
VTR_LOG_WARN("Failed to open chany_occupancy.txt for writing.\n");
}
}

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 +335,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 +361,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;
}
Loading