Skip to content

Commit ae57c3f

Browse files
Merge pull request verilog-to-routing#3162 from AlexandreSinger/feature-packer-state
[Packer] Reorganized Iterative Packer Algorithm
2 parents 3c1d7cd + 0c240d3 commit ae57c3f

File tree

1 file changed

+181
-41
lines changed

1 file changed

+181
-41
lines changed

vpr/src/pack/pack.cpp

Lines changed: 181 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,122 @@
2222
#include "vtr_assert.h"
2323
#include "vtr_log.h"
2424

25+
namespace {
26+
27+
/**
28+
* @brief Enumeration for the state of the packer.
29+
*
30+
* If the packer fails to find a dense enough packing, depending on how the
31+
* packer failed, the packer may iteratively retry packing with different
32+
* settings to try and find a denser packing. These states represent a
33+
* different type of iteration.
34+
*/
35+
enum class e_packer_state {
36+
/// @brief Default packer state.
37+
DEFAULT,
38+
/// @brief Succcess state for the packer. The packing looks feasible to
39+
/// fit on the device (does not exceed number of blocks of each
40+
/// type in the grid) and meets floorplanning constraints.
41+
SUCCESS,
42+
/// @brief Standard fallback where there are no region constraints. Turns
43+
/// on unrelated clustering and balanced packing if it can.
44+
UNRELATED_AND_BALANCED,
45+
/// @brief Region constraints: Turns on attraction groups for overfilled regions.
46+
ATTRACTION_GROUPS,
47+
/// @brief Region constraints: Turns on more attraction groups for overfilled regions.
48+
MORE_ATTRACTION_GROUPS,
49+
/// @brief Region constraints: Turns on more attraction groups for all regions.
50+
ATTRACTION_GROUPS_ALL_REGIONS,
51+
/// @brief Region constraints: Turns on more attraction groups for all regions
52+
/// and increases the target density of "clb" blocks.
53+
/// TODO: This should increase the target density of all overused blocks.
54+
ATTRACTION_GROUPS_ALL_REGIONS_AND_INCREASED_TARGET_DENSITY,
55+
/// @brief The failure state.
56+
FAILURE
57+
};
58+
59+
} // namespace
60+
2561
static bool try_size_device_grid(const t_arch& arch,
2662
const std::map<t_logical_block_type_ptr, size_t>& num_type_instances,
2763
float target_device_utilization,
2864
const std::string& device_layout_name);
2965

66+
/**
67+
* @brief The packer iteratively re-packes the netlist if it fails to find a
68+
* valid clustering. Each iteration is a state the packer is in, where
69+
* each state uses a different set of options. This method gets the next
70+
* state of the packer given the current state of the packer.
71+
*
72+
* @param current_packer_state
73+
* The current state of the packer (the state used to make the most recent
74+
* clustering).
75+
* @param fits_on_device
76+
* Whether the current clustering fits on the device or not.
77+
* @param floorplan_regions_overfull
78+
* Whether the current clustering has overfilled regions.
79+
* @param floorplan_not_fitting
80+
* Whether the current clustering is fitting on the current floorplan.
81+
*/
82+
static e_packer_state get_next_packer_state(e_packer_state current_packer_state,
83+
bool fits_on_device,
84+
bool floorplan_regions_overfull,
85+
bool floorplan_not_fitting) {
86+
// Next packer state logic
87+
e_packer_state next_packer_state = e_packer_state::FAILURE;
88+
if (fits_on_device && !floorplan_regions_overfull) {
89+
// If everything fits on the device and the floorplan regions are
90+
// not overfilled, the next state is success.
91+
next_packer_state = e_packer_state::SUCCESS;
92+
} else {
93+
if (floorplan_not_fitting) {
94+
// If there are overfilled region constraints.
95+
96+
// When running with tight floorplan constraints, some regions may become overfull with clusters (i.e.
97+
// the number of blocks assigned to the region exceeds the number of blocks available). When this occurs, we
98+
// cluster more densely to be able to adhere to the floorplan constraints. However, we do not want to cluster more
99+
// densely unnecessarily, as this can negatively impact wirelength. So, we have iterative approach. We check at the end
100+
// of every iteration if any floorplan regions are overfull. In the first iteration, we run
101+
// with no attraction groups (not packing more densely). If regions are overfull at the end of the first iteration,
102+
// we create attraction groups for partitions with overfull regions (pack those atoms more densely). We continue this way
103+
// until the last iteration, when we create attraction groups for every partition, if needed.
104+
105+
switch (current_packer_state) {
106+
case e_packer_state::DEFAULT:
107+
next_packer_state = e_packer_state::ATTRACTION_GROUPS;
108+
break;
109+
case e_packer_state::UNRELATED_AND_BALANCED:
110+
case e_packer_state::ATTRACTION_GROUPS:
111+
next_packer_state = e_packer_state::MORE_ATTRACTION_GROUPS;
112+
break;
113+
case e_packer_state::MORE_ATTRACTION_GROUPS:
114+
next_packer_state = e_packer_state::ATTRACTION_GROUPS_ALL_REGIONS;
115+
break;
116+
case e_packer_state::ATTRACTION_GROUPS_ALL_REGIONS:
117+
next_packer_state = e_packer_state::ATTRACTION_GROUPS_ALL_REGIONS_AND_INCREASED_TARGET_DENSITY;
118+
break;
119+
case e_packer_state::ATTRACTION_GROUPS_ALL_REGIONS_AND_INCREASED_TARGET_DENSITY:
120+
default:
121+
next_packer_state = e_packer_state::FAILURE;
122+
break;
123+
}
124+
} else {
125+
// If there are no overfilled region constraints, but some block
126+
// types on the grid are overfilled.
127+
switch (current_packer_state) {
128+
case e_packer_state::DEFAULT:
129+
next_packer_state = e_packer_state::UNRELATED_AND_BALANCED;
130+
break;
131+
default:
132+
next_packer_state = e_packer_state::FAILURE;
133+
break;
134+
}
135+
}
136+
}
137+
138+
return next_packer_state;
139+
}
140+
30141
bool try_pack(const t_packer_opts& packer_opts,
31142
const t_analysis_opts& analysis_opts,
32143
const t_ap_opts& ap_opts,
@@ -145,7 +256,10 @@ bool try_pack(const t_packer_opts& packer_opts,
145256

146257
g_vpr_ctx.mutable_atom().mutable_lookup().set_atom_pb_bimap_lock(true);
147258

148-
while (true) {
259+
// The current state of the packer during iterative packing.
260+
e_packer_state current_packer_state = e_packer_state::DEFAULT;
261+
262+
while (current_packer_state != e_packer_state::SUCCESS && current_packer_state != e_packer_state::FAILURE) {
149263
//Cluster the netlist
150264
// num_used_type_instances: A map used to save the number of used
151265
// instances from each logical block type.
@@ -157,7 +271,7 @@ bool try_pack(const t_packer_opts& packer_opts,
157271
attraction_groups,
158272
mutable_device_ctx);
159273

160-
//Try to size/find a device
274+
// Try to size/find a device
161275
bool fits_on_device = try_size_device_grid(arch, num_used_type_instances, packer_opts.target_device_utilization, packer_opts.device_layout);
162276

163277
/* We use this bool to determine the cause for the clustering not being dense enough. If the clustering
@@ -170,48 +284,56 @@ bool try_pack(const t_packer_opts& packer_opts,
170284

171285
bool floorplan_not_fitting = (floorplan_regions_overfull || g_vpr_ctx.floorplanning().constraints.get_num_partitions() > 0);
172286

173-
if (fits_on_device && !floorplan_regions_overfull) {
174-
break; //Done
175-
} else if (pack_iteration == 1 && !floorplan_not_fitting) {
176-
//1st pack attempt was unsuccessful (i.e. not dense enough) and we have control of unrelated clustering
177-
//
178-
//Turn it on to increase packing density
179-
if (packer_opts.allow_unrelated_clustering == e_unrelated_clustering::AUTO) {
180-
VTR_ASSERT(allow_unrelated_clustering == false);
181-
allow_unrelated_clustering = true;
287+
// Next packer state logic
288+
e_packer_state next_packer_state = get_next_packer_state(current_packer_state,
289+
fits_on_device,
290+
floorplan_regions_overfull,
291+
floorplan_not_fitting);
292+
293+
// Set up for the options used for the next packer state.
294+
// NOTE: This must be done here (and not at the start of the next packer
295+
// iteration) since we need to know information about the current
296+
// clustering to change the options for the next iteration.
297+
switch (next_packer_state) {
298+
case e_packer_state::UNRELATED_AND_BALANCED: {
299+
// 1st pack attempt was unsuccessful (i.e. not dense enough) and we have control of unrelated clustering
300+
//
301+
// Turn it on to increase packing density
302+
// TODO: This will have no affect if unrelated clustering and
303+
// balance block type utilization is not auto. Should update
304+
// the next state logic.
305+
if (packer_opts.allow_unrelated_clustering == e_unrelated_clustering::AUTO) {
306+
VTR_ASSERT(allow_unrelated_clustering == false);
307+
allow_unrelated_clustering = true;
308+
}
309+
if (packer_opts.balance_block_type_utilization == e_balance_block_type_util::AUTO) {
310+
VTR_ASSERT(balance_block_type_util == false);
311+
balance_block_type_util = true;
312+
}
313+
VTR_LOG("Packing failed to fit on device. Re-packing with: unrelated_logic_clustering=%s balance_block_type_util=%s\n",
314+
(allow_unrelated_clustering ? "true" : "false"),
315+
(balance_block_type_util ? "true" : "false"));
316+
break;
182317
}
183-
if (packer_opts.balance_block_type_utilization == e_balance_block_type_util::AUTO) {
184-
VTR_ASSERT(balance_block_type_util == false);
185-
balance_block_type_util = true;
318+
case e_packer_state::ATTRACTION_GROUPS: {
319+
VTR_LOG("Floorplan regions are overfull: trying to pack again using cluster attraction groups. \n");
320+
attraction_groups.create_att_groups_for_overfull_regions(overfull_partition_regions);
321+
attraction_groups.set_att_group_pulls(1);
322+
break;
186323
}
187-
VTR_LOG("Packing failed to fit on device. Re-packing with: unrelated_logic_clustering=%s balance_block_type_util=%s\n",
188-
(allow_unrelated_clustering ? "true" : "false"),
189-
(balance_block_type_util ? "true" : "false"));
190-
/*
191-
* When running with tight floorplan constraints, some regions may become overfull with clusters (i.e.
192-
* the number of blocks assigned to the region exceeds the number of blocks available). When this occurs, we
193-
* cluster more densely to be able to adhere to the floorplan constraints. However, we do not want to cluster more
194-
* densely unnecessarily, as this can negatively impact wirelength. So, we have iterative approach. We check at the end
195-
* of every iteration if any floorplan regions are overfull. In the first iteration, we run
196-
* with no attraction groups (not packing more densely). If regions are overfull at the end of the first iteration,
197-
* we create attraction groups for partitions with overfull regions (pack those atoms more densely). We continue this way
198-
* until the last iteration, when we create attraction groups for every partition, if needed.
199-
*/
200-
} else if (pack_iteration == 1 && floorplan_not_fitting) {
201-
VTR_LOG("Floorplan regions are overfull: trying to pack again using cluster attraction groups. \n");
202-
attraction_groups.create_att_groups_for_overfull_regions(overfull_partition_regions);
203-
attraction_groups.set_att_group_pulls(1);
204-
205-
} else if (pack_iteration >= 2 && pack_iteration < 5 && floorplan_not_fitting) {
206-
if (pack_iteration == 2) {
324+
case e_packer_state::MORE_ATTRACTION_GROUPS: {
207325
VTR_LOG("Floorplan regions are overfull: trying to pack again with more attraction groups exploration. \n");
208326
attraction_groups.create_att_groups_for_overfull_regions(overfull_partition_regions);
209327
VTR_LOG("Pack iteration is %d\n", pack_iteration);
210-
} else if (pack_iteration == 3) {
328+
break;
329+
}
330+
case e_packer_state::ATTRACTION_GROUPS_ALL_REGIONS: {
211331
attraction_groups.create_att_groups_for_all_regions();
212332
VTR_LOG("Floorplan regions are overfull: trying to pack again with more attraction groups exploration. \n");
213333
VTR_LOG("Pack iteration is %d\n", pack_iteration);
214-
} else if (pack_iteration == 4) {
334+
break;
335+
}
336+
case e_packer_state::ATTRACTION_GROUPS_ALL_REGIONS_AND_INCREASED_TARGET_DENSITY: {
215337
attraction_groups.create_att_groups_for_all_regions();
216338
VTR_LOG("Floorplan regions are overfull: trying to pack again with more attraction groups exploration and higher target pin utilization. \n");
217339
VTR_LOG("Pack iteration is %d\n", pack_iteration);
@@ -224,9 +346,18 @@ bool try_pack(const t_packer_opts& packer_opts,
224346
// do it for all block types. Doing it only for a clb
225347
// string is dangerous -VB.
226348
cluster_legalizer.get_target_external_pin_util().set_block_pin_util("clb", pin_util);
349+
break;
227350
}
351+
case e_packer_state::DEFAULT:
352+
case e_packer_state::SUCCESS:
353+
case e_packer_state::FAILURE:
354+
default:
355+
// Nothing to set up.
356+
break;
357+
}
228358

229-
} else { //Unable to pack densely enough: Give Up
359+
// Raise an error if the packer failed to pack.
360+
if (next_packer_state == e_packer_state::FAILURE) {
230361
if (floorplan_regions_overfull) {
231362
VPR_FATAL_ERROR(VPR_ERROR_OTHER,
232363
"Failed to find pack clusters densely enough to fit in the designated floorplan regions.\n"
@@ -255,14 +386,23 @@ bool try_pack(const t_packer_opts& packer_opts,
255386
VPR_FATAL_ERROR(VPR_ERROR_OTHER, "Failed to find device which satisfies resource requirements required: %s (available %s)", resource_reqs.c_str(), resource_avail.c_str());
256387
}
257388

258-
//Reset floorplanning constraints for re-packing
259-
g_vpr_ctx.mutable_floorplanning().cluster_constraints.clear();
389+
// If the packer was unsuccessful, reset the packed solution and try again.
390+
if (next_packer_state != e_packer_state::SUCCESS) {
391+
// Reset floorplanning constraints for re-packing
392+
g_vpr_ctx.mutable_floorplanning().cluster_constraints.clear();
393+
394+
// Reset the cluster legalizer for re-clustering.
395+
cluster_legalizer.reset();
396+
}
397+
398+
// Set the current state to the next state.
399+
current_packer_state = next_packer_state;
260400

261-
// Reset the cluster legalizer for re-clustering.
262-
cluster_legalizer.reset();
263401
++pack_iteration;
264402
}
265403

404+
VTR_ASSERT(current_packer_state == e_packer_state::SUCCESS);
405+
266406
/* Packing iterative improvement can be done here */
267407
/* Use the re-cluster API to edit it */
268408
/******************* Start *************************/

0 commit comments

Comments
 (0)