Skip to content

Commit 9b06376

Browse files
[AP] Marking Global Nets in AP
After investigating how the placer and packer decide which nets are global, I realized that we were not marking any nets as global. The Atom Netlist annotates nets as global after packing, when loading the clustered netlist. It decides if a net is global or not if the net enters a global port in the clustered netlist. We can replicate this behaviour during AP by looking at the Atom Netlist and doing something similar. This allows us to tell if a net is global or not. In AP, we always want to ignore global nets since their cost does not play a role on the overall objective. By ignoring these nets, we can further improve the performance and quality of the solution. Now that we know which nets are global, I have also updated the wirelength estimator in the AP flow to make it align better with the placer's wirelength estimator. They now line up very closely, but are still slightly off due to some factors being unable to be ported over easily.
1 parent e62e8ff commit 9b06376

File tree

5 files changed

+62
-28
lines changed

5 files changed

+62
-28
lines changed

vpr/src/analytical_place/gen_ap_netlist_from_atoms.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,13 +126,38 @@ APNetlist gen_ap_netlist_from_atoms(const AtomNetlist& atom_netlist,
126126
ap_netlist.set_net_is_ignored(ap_net_id, true);
127127
continue;
128128
}
129+
129130
// Is the net global, if so mark as global for AP (also ignored)
130131
if (atom_netlist.net_is_global(atom_net_id)) {
131132
ap_netlist.set_net_is_global(ap_net_id, true);
132133
// Global nets are also ignored by the AP flow.
133134
ap_netlist.set_net_is_ignored(ap_net_id, true);
134135
continue;
135136
}
137+
138+
// Prior to AP, it is likely that the nets in the Atom Netlist have not
139+
// been annotated with being global or ignored. To get around this, we
140+
// annotate the AP Netlist speculatively.
141+
// We label a net as being global if one of its pin connect to a clock
142+
// port or a non-clock global model port.
143+
bool is_global = false;
144+
for (AtomPinId pin_id : atom_netlist.net_pins(atom_net_id)) {
145+
AtomPortId port_id = atom_netlist.pin_port(pin_id);
146+
if (atom_netlist.port_type(port_id) == PortType::CLOCK) {
147+
is_global = true;
148+
break;
149+
}
150+
if (atom_netlist.port_model(port_id)->is_non_clock_global) {
151+
is_global = true;
152+
break;
153+
}
154+
}
155+
if (is_global) {
156+
ap_netlist.set_net_is_global(ap_net_id, true);
157+
// Global nets are also ignored in the AP flow.
158+
ap_netlist.set_net_is_ignored(ap_net_id, true);
159+
}
160+
136161
// Get the unique blocks connectioned to this net
137162
std::unordered_set<APBlockId> net_blocks;
138163
for (APPinId ap_pin_id : ap_netlist.net_pins(ap_net_id)) {

vpr/src/analytical_place/global_placer.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ static void print_placement_stats(const PartialPlacement& p_placement,
132132
const PreClusterTimingManager& pre_cluster_timing_manager) {
133133
// Print the placement HPWL
134134
VTR_LOG("\tPlacement objective HPWL: %f\n", p_placement.get_hpwl(ap_netlist));
135-
VTR_LOG("\tPlacement estimated wirelength: %u\n", p_placement.estimate_post_placement_wirelength(ap_netlist));
135+
VTR_LOG("\tPlacement estimated wirelength: %g\n", p_placement.estimate_post_placement_wirelength(ap_netlist));
136136

137137
// Print the timing information.
138138
if (pre_cluster_timing_manager.is_valid()) {

vpr/src/analytical_place/partial_placement.cpp

Lines changed: 28 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include <cstddef>
1111
#include <limits>
1212
#include "ap_netlist.h"
13+
#include "net_cost_handler.h"
1314

1415
double PartialPlacement::get_hpwl(const APNetlist& netlist) const {
1516
double hpwl = 0.0;
@@ -27,6 +28,11 @@ double PartialPlacement::get_hpwl(const APNetlist& netlist) const {
2728
min_y = std::min(min_y, block_y_locs[blk_id]);
2829
max_y = std::max(max_y, block_y_locs[blk_id]);
2930
}
31+
// TODO: In the placer, the x and y dimensions are multiplied by cost
32+
// factors based on the channel width. Should somehow bring these
33+
// in here.
34+
// Vaughn thinks these may make sense in the objective HPWL, but
35+
// not the in the estimated post-placement wirelength.
3036
VTR_ASSERT_SAFE(max_x >= min_x && max_y >= min_y);
3137
hpwl += max_x - min_x + max_y - min_y;
3238
}
@@ -38,23 +44,26 @@ double PartialPlacement::estimate_post_placement_wirelength(const APNetlist& net
3844
// we want to estimate the post-placement wirelength, we do not want the
3945
// flat placement positions of the blocks. Instead we compute the HPWL over
4046
// the tiles that the flat placement is placing the blocks over.
41-
unsigned total_hpwl = 0;
47+
double total_hpwl = 0;
4248
for (APNetId net_id : netlist.nets()) {
43-
// Note: Other wirelength estimates in VTR ignore global nets; however
44-
// it is not known if a net is global or not until packing is
45-
// complete. For now, we just approximate post-placement wirelength
46-
// using the HPWL (in tile space).
47-
// TODO: The reason we do not know what nets are ignored / global is
48-
// because the pin on the tile that the net connects to is what
49-
// decides if a net is global / ignored for place and route. Since
50-
// we have not packed anything yet, we do not know what pin each
51-
// net will go to; however, we can probably get a good idea based
52-
// on some properties of the net and the tile its going to / from.
53-
// Should investigate this to get a better estimate of wirelength.
54-
double min_x = std::numeric_limits<unsigned>::max();
55-
double max_x = std::numeric_limits<unsigned>::lowest();
56-
double min_y = std::numeric_limits<unsigned>::max();
57-
double max_y = std::numeric_limits<unsigned>::lowest();
49+
// To align with other wirelength estimators in VTR (for example in the
50+
// placer), we do not include global nets (clocks, etc.) in the wirelength
51+
// calculation.
52+
if (netlist.net_is_global(net_id))
53+
continue;
54+
55+
// Similar to the placer, weight the wirelength of this net as a function
56+
// of its fanout. Since these fanouts are at the AP netlist (unclustered)
57+
// level, the correction factor may lead to a somewhat higher HPWL prediction
58+
// than after clustering.
59+
// TODO: Investigate the clustered vs unclustered factors further.
60+
// TODO: Should update the costs to 3D.
61+
double crossing = wirelength_crossing_count(netlist.net_pins(net_id).size());
62+
63+
double min_x = std::numeric_limits<double>::max();
64+
double max_x = std::numeric_limits<double>::lowest();
65+
double min_y = std::numeric_limits<double>::max();
66+
double max_y = std::numeric_limits<double>::lowest();
5867
for (APPinId pin_id : netlist.net_pins(net_id)) {
5968
APBlockId blk_id = netlist.pin_block(pin_id);
6069
min_x = std::min(min_x, block_x_locs[blk_id]);
@@ -66,10 +75,10 @@ double PartialPlacement::estimate_post_placement_wirelength(const APNetlist& net
6675

6776
// Floor the positions to get the x and y coordinates of the tiles each
6877
// block belongs to.
69-
unsigned tile_dx = std::floor(max_x) - std::floor(min_x);
70-
unsigned tile_dy = std::floor(max_y) - std::floor(min_y);
78+
double tile_dx = std::floor(max_x) - std::floor(min_x);
79+
double tile_dy = std::floor(max_y) - std::floor(min_y);
7180

72-
total_hpwl += tile_dx + tile_dy;
81+
total_hpwl += (tile_dx + tile_dy) * crossing;
7382
}
7483

7584
return total_hpwl;

vpr/src/place/net_cost_handler.cpp

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -84,13 +84,6 @@ static void add_block_to_bb(const t_physical_tile_loc& new_pin_loc,
8484
t_2D_bb& bb_edge_new,
8585
t_2D_bb& bb_coord_new);
8686

87-
/**
88-
* @brief To get the wirelength cost/est, BB perimeter is multiplied by a factor to approximately correct for the half-perimeter
89-
* bounding box wirelength's underestimate of wiring for nets with fanout greater than 2.
90-
* @return Multiplicative wirelength correction factor
91-
*/
92-
static double wirelength_crossing_count(size_t fanout);
93-
9487
/******************************* End of Function definitions ************************************/
9588

9689
NetCostHandler::NetCostHandler(const t_placer_opts& placer_opts,
@@ -1492,7 +1485,7 @@ double NetCostHandler::recompute_bb_cost_() {
14921485
return cost;
14931486
}
14941487

1495-
static double wirelength_crossing_count(size_t fanout) {
1488+
double wirelength_crossing_count(size_t fanout) {
14961489
/* Get the expected "crossing count" of a net, based on its number *
14971490
* of pins. Extrapolate for very large nets. */
14981491

vpr/src/place/net_cost_handler.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,13 @@
1515
class PlacerState;
1616
class PlacerCriticalities;
1717

18+
/**
19+
* @brief To get the wirelength cost/est, BB perimeter is multiplied by a factor to approximately correct for the half-perimeter
20+
* bounding box wirelength's underestimate of wiring for nets with fanout greater than 2.
21+
* @return Multiplicative wirelength correction factor
22+
*/
23+
double wirelength_crossing_count(size_t fanout);
24+
1825
/**
1926
* @brief The method used to calculate placement cost
2027
* @details For comp_cost. NORMAL means use the method that generates updatable bounding boxes for speed.

0 commit comments

Comments
 (0)