Skip to content

Commit 661debe

Browse files
authored
Merge pull request #2985 from verilog-to-routing/temp_chann_util_report
Write routing channel occupancies to files.
2 parents 1dff246 + 9e83292 commit 661debe

File tree

2 files changed

+86
-52
lines changed

2 files changed

+86
-52
lines changed

vpr/src/base/stats.cpp

+81-25
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
1-
#include <cmath>
1+
2+
#include "stats.h"
3+
24
#include <set>
5+
#include <fstream>
6+
#include <string>
7+
#include <iomanip>
38

49
#include "physical_types_util.h"
510
#include "route_tree.h"
@@ -15,25 +20,45 @@
1520
#include "rr_graph_area.h"
1621
#include "segment_stats.h"
1722
#include "channel_stats.h"
18-
#include "stats.h"
1923

2024
/********************** Subroutines local to this module *********************/
2125

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

34+
/**
35+
* @brief Writes channel occupancy data to a file.
36+
*
37+
* Each row contains:
38+
* - (x, y) coordinate
39+
* - Occupancy count
40+
* - Occupancy percentage (occupancy / capacity)
41+
* - Channel capacity
42+
*
43+
* @param filename Output file path.
44+
* @param occupancy Matrix of occupancy counts.
45+
* @param capacity_list List of channel capacities (per y for chanx, per x for chany).
46+
*/
47+
static void write_channel_occupancy_table(const std::string_view filename,
48+
const vtr::Matrix<int>& occupancy,
49+
const std::vector<int>& capacity_list);
50+
51+
/**
52+
* @brief Figures out maximum, minimum and average number of bends
53+
* and net length in the routing.
54+
*/
2655
static void length_and_bends_stats(const Netlist<>& net_list, bool is_flat);
2756

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

3060
/************************* Subroutine definitions ****************************/
3161

32-
/**
33-
* @brief Prints out various statistics about the current routing.
34-
*
35-
* Both a routing and an rr_graph must exist when you call this routine.
36-
*/
3762
void routing_stats(const Netlist<>& net_list,
3863
bool full_stats,
3964
enum e_route_type route_type,
@@ -105,10 +130,6 @@ void routing_stats(const Netlist<>& net_list,
105130
}
106131
}
107132

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

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

175195
auto chanx_occ = vtr::Matrix<int>({{
176196
device_ctx.grid.width(), //[0 .. device_ctx.grid.width() - 1] (length of x channel)
@@ -183,8 +203,12 @@ static void get_channel_occupancy_stats(const Netlist<>& net_list, bool /***/) {
183203
device_ctx.grid.height() //[0 .. device_ctx.grid.height() - 1] (length of y channel)
184204
}},
185205
0);
206+
186207
load_channel_occupancies(net_list, chanx_occ, chany_occ);
187208

209+
write_channel_occupancy_table("chanx_occupancy.txt", chanx_occ, device_ctx.chan_width.x_list);
210+
write_channel_occupancy_table("chany_occupancy.txt", chany_occ, device_ctx.chan_width.y_list);
211+
188212
VTR_LOG("\n");
189213
VTR_LOG("X - Directed channels: j max occ ave occ capacity\n");
190214
VTR_LOG(" ---- ------- ------- --------\n");
@@ -225,16 +249,50 @@ static void get_channel_occupancy_stats(const Netlist<>& net_list, bool /***/) {
225249
VTR_LOG("\n");
226250
}
227251

228-
/**
229-
* @brief Loads the two arrays passed in with the total occupancy at each of the
230-
* channel segments in the FPGA.
231-
*/
252+
static void write_channel_occupancy_table(const std::string_view filename,
253+
const vtr::Matrix<int>& occupancy,
254+
const std::vector<int>& capacity_list) {
255+
constexpr int w_coord = 6;
256+
constexpr int w_value = 12;
257+
constexpr int w_percent = 12;
258+
259+
std::ofstream file(filename.data());
260+
if (!file.is_open()) {
261+
VTR_LOG_WARN("Failed to open %s for writing.\n", filename.data());
262+
return;
263+
}
264+
265+
file << std::setw(w_coord) << "x"
266+
<< std::setw(w_coord) << "y"
267+
<< std::setw(w_value) << "occupancy"
268+
<< std::setw(w_percent) << "%"
269+
<< std::setw(w_value) << "capacity"
270+
<< "\n";
271+
272+
for (size_t y = 0; y < occupancy.dim_size(1); ++y) {
273+
int capacity = capacity_list[y];
274+
for (size_t x = 0; x < occupancy.dim_size(0); ++x) {
275+
int occ = occupancy[x][y];
276+
float percent = capacity > 0 ? static_cast<float>(occ) / capacity * 100.0f : 0.0f;
277+
278+
file << std::setw(w_coord) << x
279+
<< std::setw(w_coord) << y
280+
<< std::setw(w_value) << occ
281+
<< std::setw(w_percent) << std::fixed << std::setprecision(3) << percent
282+
<< std::setw(w_value) << capacity
283+
<< "\n";
284+
}
285+
}
286+
287+
file.close();
288+
}
289+
232290
static void load_channel_occupancies(const Netlist<>& net_list,
233291
vtr::Matrix<int>& chanx_occ,
234292
vtr::Matrix<int>& chany_occ) {
235-
auto& device_ctx = g_vpr_ctx.device();
293+
const auto& device_ctx = g_vpr_ctx.device();
236294
const auto& rr_graph = device_ctx.rr_graph;
237-
auto& route_ctx = g_vpr_ctx.routing();
295+
const auto& route_ctx = g_vpr_ctx.routing();
238296

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

253-
for (auto& rt_node : tree.value().all_nodes()) {
311+
for (const RouteTreeNode& rt_node : tree.value().all_nodes()) {
254312
RRNodeId inode = rt_node.inode;
255313
t_rr_type rr_type = rr_graph.node_type(inode);
256314

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

279-
int bends, length, segments;
280-
281-
bends = 0;
282-
length = 0;
283-
segments = 0;
337+
int bends = 0;
338+
int length = 0;
339+
int segments = 0;
284340

285341
const vtr::optional<RouteTree>& tree = route_ctx.route_trees[inet];
286342
if (!tree) {

vpr/src/base/stats.h

+5-27
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@
55
#include "vpr_types.h"
66
#include "netlist.h"
77

8+
/**
9+
* @brief Prints out various statistics about the current routing.
10+
*
11+
* Both a routing and an rr_graph must exist when you call this routine.
12+
*/
813
void routing_stats(const Netlist<>& net_list,
914
bool full_stats,
1015
enum e_route_type route_type,
@@ -42,30 +47,3 @@ void print_resource_usage();
4247
* @param target_device_utilization The target device utilization set by the user
4348
*/
4449
void print_device_utilization(const float target_device_utilization);
45-
46-
/**
47-
* @brief template functions must be defined in header, or explicitely
48-
* instantiated in definition file (defeats the point of template)
49-
*/
50-
template<typename T>
51-
double linear_regression_vector(const std::vector<T>& vals, size_t start_x = 0) {
52-
// returns slope; index is x, val is y
53-
size_t n{vals.size() - start_x};
54-
55-
double x_avg{0}, y_avg{0};
56-
for (size_t x = start_x; x < vals.size(); ++x) {
57-
x_avg += x;
58-
y_avg += vals[x];
59-
}
60-
x_avg /= (double)n;
61-
y_avg /= (double)n;
62-
63-
double numerator = 0, denominator = 0;
64-
for (size_t x = start_x; x < vals.size(); ++x) {
65-
numerator += (x - x_avg) * (vals[x] - y_avg);
66-
denominator += (x - x_avg) * (x - x_avg);
67-
}
68-
69-
if (denominator == 0) return std::numeric_limits<double>::max();
70-
return numerator / denominator;
71-
}

0 commit comments

Comments
 (0)