Skip to content

Commit 0f4842d

Browse files
[Packer] Updated Clustering Algorithm Per Vaughn's Comments
Changed when the clustering progress stats are updated and printed to make them more accurate. Changed how the LE block counts are stored to make the code easier to read. Fixed some comments.
1 parent 7af4f2b commit 0f4842d

File tree

5 files changed

+111
-93
lines changed

5 files changed

+111
-93
lines changed

vpr/src/pack/cluster_legalizer.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -421,6 +421,13 @@ class ClusterLegalizer {
421421
return cluster.pr;
422422
}
423423

424+
/// @brief Gets the current number of molecules in the cluster.
425+
inline size_t get_num_molecules_in_cluster(LegalizationClusterId cluster_id) const {
426+
VTR_ASSERT_SAFE(cluster_id.is_valid() && (size_t)cluster_id < legalization_clusters_.size());
427+
const LegalizationCluster& cluster = legalization_clusters_[cluster_id];
428+
return cluster.molecules.size();
429+
}
430+
424431
/// @brief Gets the ID of the cluster that contains the given atom block.
425432
inline LegalizationClusterId get_atom_cluster(AtomBlockId blk_id) const {
426433
VTR_ASSERT_SAFE(blk_id.is_valid() && (size_t)blk_id < atom_cluster_.size());

vpr/src/pack/cluster_util.cpp

Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,8 @@ void print_pack_status(int tot_num_molecules,
172172

173173
int num_clusters_created = cluster_legalizer.clusters().size();
174174

175-
if (mols_since_last_print == int_molecule_increment) {
175+
if (mols_since_last_print >= int_molecule_increment ||
176+
num_molecules_processed == tot_num_molecules) {
176177
VTR_LOG(
177178
"%6d/%-6d %3d%% "
178179
"%26d "
@@ -1493,7 +1494,12 @@ t_pb_type* identify_le_block_type(t_logical_block_type_ptr logic_block_type) {
14931494
return nullptr;
14941495
}
14951496

1496-
void update_le_count(const t_pb* pb, const t_logical_block_type_ptr logic_block_type, const t_pb_type* le_pb_type, std::array<int, 3>& le_count) {
1497+
void update_le_count(const t_pb* pb,
1498+
const t_logical_block_type_ptr logic_block_type,
1499+
const t_pb_type* le_pb_type,
1500+
int& num_logic_le,
1501+
int& num_reg_le,
1502+
int& num_logic_and_reg_le) {
14971503
// if this cluster doesn't contain LEs or there
14981504
// are no les in this architecture, ignore it
14991505
if (!logic_block_type || pb->pb_graph_node != logic_block_type->pb_graph_head || !le_pb_type)
@@ -1519,15 +1525,15 @@ void update_le_count(const t_pb* pb, const t_logical_block_type_ptr logic_block_
15191525
auto has_used_adder = pb_used_for_blif_model(&parent_pb->child_pbs[0][ile], adder);
15201526
auto has_used_ff = pb_used_for_blif_model(&parent_pb->child_pbs[0][ile], ff);
15211527

1522-
// First type of LEs: used for logic and registers
15231528
if ((has_used_lut || has_used_adder) && has_used_ff) {
1524-
le_count[0]++;
1525-
// Second type of LEs: used for logic only
1529+
// First type of LEs: used for logic and registers
1530+
num_logic_and_reg_le++;
15261531
} else if (has_used_lut || has_used_adder) {
1527-
le_count[1]++;
1528-
// Third type of LEs: used for registers only
1532+
// Second type of LEs: used for logic only
1533+
num_logic_le++;
15291534
} else if (has_used_ff) {
1530-
le_count[2]++;
1535+
// Third type of LEs: used for registers only
1536+
num_reg_le++;
15311537
}
15321538
}
15331539
}
@@ -1559,12 +1565,19 @@ bool pb_used_for_blif_model(const t_pb* pb, const std::string& blif_model_name)
15591565
return false;
15601566
}
15611567

1562-
void print_le_count(const std::array<int, 3>& le_count, const t_pb_type* le_pb_type) {
1568+
void print_le_count(int num_logic_le,
1569+
int num_reg_le,
1570+
int num_logic_and_reg_le,
1571+
const t_pb_type* le_pb_type) {
1572+
VTR_ASSERT(le_pb_type != nullptr);
1573+
1574+
int num_total_le = num_logic_and_reg_le + num_logic_le + num_reg_le;
1575+
15631576
VTR_LOG("\nLogic Element (%s) detailed count:\n", le_pb_type->name);
1564-
VTR_LOG(" Total number of Logic Elements used : %d\n", le_count[0] + le_count[1] + le_count[2]);
1565-
VTR_LOG(" LEs used for logic and registers : %d\n", le_count[0]);
1566-
VTR_LOG(" LEs used for logic only : %d\n", le_count[1]);
1567-
VTR_LOG(" LEs used for registers only : %d\n\n", le_count[2]);
1577+
VTR_LOG(" Total number of Logic Elements used : %d\n", num_total_le);
1578+
VTR_LOG(" LEs used for logic and registers : %d\n", num_logic_and_reg_le);
1579+
VTR_LOG(" LEs used for logic only : %d\n", num_logic_le);
1580+
VTR_LOG(" LEs used for registers only : %d\n\n", num_reg_le);
15681581
}
15691582

15701583
t_pb* get_top_level_pb(t_pb* pb) {

vpr/src/pack/cluster_util.h

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -396,7 +396,12 @@ size_t update_pb_type_count(const t_pb* pb, std::map<t_pb_type*, int>& pb_type_c
396396
* @brief This function updates the le_count data structure from the given
397397
* packed cluster.
398398
*/
399-
void update_le_count(const t_pb* pb, const t_logical_block_type_ptr logic_block_type, const t_pb_type* le_pb_type, std::array<int, 3>& le_count);
399+
void update_le_count(const t_pb* pb,
400+
const t_logical_block_type_ptr logic_block_type,
401+
const t_pb_type* le_pb_type,
402+
int& num_logic_le,
403+
int& num_reg_le,
404+
int& num_logic_and_reg_le);
400405

401406
void print_pb_type_count_recurr(t_pb_type* type, size_t max_name_chars, size_t curr_depth, std::map<t_pb_type*, int>& pb_type_count);
402407

@@ -430,7 +435,10 @@ bool pb_used_for_blif_model(const t_pb* pb, const std::string& blif_model_name);
430435
/*
431436
* @brief Print the LE count data strurture.
432437
*/
433-
void print_le_count(const std::array<int, 3>& le_count, const t_pb_type* le_pb_type);
438+
void print_le_count(int num_logic_le,
439+
int num_reg_le,
440+
int num_logic_and_reg_le,
441+
const t_pb_type* le_pb_type);
434442

435443
/*
436444
* @brief Given a pointer to a pb in a cluster, this routine returns a pointer

vpr/src/pack/greedy_clusterer.cpp

Lines changed: 53 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@
3737
*/
3838

3939
#include "greedy_clusterer.h"
40-
#include <array>
4140
#include <cstdio>
4241
#include <map>
4342
#include <string>
@@ -56,6 +55,23 @@
5655
#include "vtr_math.h"
5756
#include "vtr_vector.h"
5857

58+
namespace {
59+
60+
/**
61+
* @brief Struct to hold statistics on the progress of clustering.
62+
*/
63+
struct t_cluster_progress_stats {
64+
// The total number of molecules in the design.
65+
int num_molecules = 0;
66+
// The number of molecules which have been clustered.
67+
int num_molecules_processed = 0;
68+
// The number of molecules clustered since the last time the status was
69+
// logged.
70+
int mols_since_last_print = 0;
71+
};
72+
73+
} // namespace
74+
5975
GreedyClusterer::GreedyClusterer(const t_packer_opts& packer_opts,
6076
const t_analysis_opts& analysis_opts,
6177
const AtomNetlist& atom_netlist,
@@ -93,9 +109,8 @@ GreedyClusterer::do_clustering(ClusterLegalizer& cluster_legalizer,
93109

94110
// The clustering stats holds information used for logging the progress
95111
// of the clustering to the user.
96-
// Reset the clustering stats in case the clusterer is called multiple times.
97-
clustering_stats_ = t_cluster_progress_stats();
98-
clustering_stats_.num_molecules = prepacker.get_num_molecules();
112+
t_cluster_progress_stats clustering_stats;
113+
clustering_stats.num_molecules = prepacker.get_num_molecules();
99114

100115
// TODO: Create a ClusteringTimingManager class.
101116
// This code relies on the prepacker, once the prepacker is moved to
@@ -124,7 +139,7 @@ GreedyClusterer::do_clustering(ClusterLegalizer& cluster_legalizer,
124139
alloc_and_init_clustering(max_molecule_stats,
125140
prepacker,
126141
clustering_data,
127-
clustering_stats_.num_molecules);
142+
clustering_stats.num_molecules);
128143

129144
// Create the greedy seed selector.
130145
GreedySeedSelector seed_selector(atom_netlist_,
@@ -156,7 +171,8 @@ GreedyClusterer::do_clustering(ClusterLegalizer& cluster_legalizer,
156171
// do full legalization for each molecule added to the cluster.
157172

158173
// Try to grow a cluster from the seed molecule without doing intra-lb
159-
// route for each molecule.
174+
// route for each molecule (i.e. just use faster but not fully
175+
// conservative legality checks).
160176
LegalizationClusterId new_cluster_id = try_grow_cluster(seed_mol,
161177
ClusterLegalizationStrategy::SKIP_INTRA_LB_ROUTE,
162178
cluster_legalizer,
@@ -192,6 +208,21 @@ GreedyClusterer::do_clustering(ClusterLegalizer& cluster_legalizer,
192208
VTR_ASSERT(new_cluster_id.is_valid());
193209
VTR_ASSERT(cluster_legalizer.is_mol_clustered(seed_mol));
194210

211+
// Update the clustering progress stats.
212+
size_t num_molecules_in_cluster = cluster_legalizer.get_num_molecules_in_cluster(new_cluster_id);
213+
clustering_stats.num_molecules_processed += num_molecules_in_cluster;
214+
clustering_stats.mols_since_last_print += num_molecules_in_cluster;
215+
216+
// Print the current progress of the packing after a cluster has been
217+
// successfully created.
218+
print_pack_status(clustering_stats.num_molecules,
219+
clustering_stats.num_molecules_processed,
220+
clustering_stats.mols_since_last_print,
221+
mutable_device_ctx.grid.width(),
222+
mutable_device_ctx.grid.height(),
223+
attraction_groups,
224+
cluster_legalizer);
225+
195226
// Pick new seed.
196227
seed_mol = seed_selector.get_next_seed(prepacker,
197228
cluster_legalizer);
@@ -236,15 +267,6 @@ LegalizationClusterId GreedyClusterer::try_grow_cluster(
236267
num_used_type_instances,
237268
mutable_device_ctx);
238269

239-
//initial molecule in cluster has been processed
240-
print_pack_status(clustering_stats_.num_molecules,
241-
clustering_stats_.num_molecules_processed,
242-
clustering_stats_.mols_since_last_print,
243-
mutable_device_ctx.grid.width(),
244-
mutable_device_ctx.grid.height(),
245-
attraction_groups,
246-
cluster_legalizer);
247-
248270
int high_fanout_threshold = high_fanout_thresholds_.get_threshold(cluster_legalizer.get_cluster_type(legalization_cluster_id)->name);
249271
update_cluster_stats(seed_mol,
250272
cluster_legalizer,
@@ -302,14 +324,6 @@ LegalizationClusterId GreedyClusterer::try_grow_cluster(
302324
// If the candidate molecule was clustered successfully, update
303325
// the cluster stats.
304326
if (success) {
305-
print_pack_status(clustering_stats_.num_molecules,
306-
clustering_stats_.num_molecules_processed,
307-
clustering_stats_.mols_since_last_print,
308-
mutable_device_ctx.grid.width(),
309-
mutable_device_ctx.grid.height(),
310-
attraction_groups,
311-
cluster_legalizer);
312-
313327
update_cluster_stats(candidate_mol,
314328
cluster_legalizer,
315329
is_clock_, //Set of all clocks
@@ -492,10 +506,6 @@ LegalizationClusterId GreedyClusterer::start_new_cluster(
492506
//Progress dot for seed-block
493507
fflush(stdout);
494508

495-
// Update the clustering progress stats.
496-
clustering_stats_.num_molecules_processed++;
497-
clustering_stats_.mols_since_last_print++;
498-
499509
// TODO: Below may make more sense in its own method.
500510

501511
// Successfully created cluster
@@ -563,13 +573,6 @@ bool GreedyClusterer::try_add_candidate_mol_to_cluster(t_pack_molecule* candidat
563573
fflush(stdout);
564574
}
565575

566-
// If candidate molecule was successfully added, update the clustering
567-
// progress stats.
568-
if (pack_status == e_block_pack_status::BLK_PASSED) {
569-
clustering_stats_.num_molecules_processed++;
570-
clustering_stats_.mols_since_last_print++;
571-
}
572-
573576
return pack_status == e_block_pack_status::BLK_PASSED;
574577
}
575578

@@ -584,27 +587,32 @@ void GreedyClusterer::report_le_physical_block_usage(const ClusterLegalizer& clu
584587
if (le_pb_type == nullptr)
585588
return;
586589

587-
// this data structure tracks the number of Logic Elements (LEs) used. It is
588-
// populated only for architectures which has LEs. The architecture is assumed
589-
// to have LEs only iff it has a logic block that contains LUT primitives and is
590-
// the first pb_block to have more than one instance from the top of the hierarchy
591-
// (All parent pb_block have one instance only and one mode only). Index 0 holds
592-
// the number of LEs that are used for both logic (LUTs/adders) and registers.
593-
// Index 1 holds the number of LEs that are used for logic (LUTs/adders) only.
594-
// Index 2 holds the number of LEs that are used for registers only.
595-
std::array<int, 3> le_count = {0, 0, 0};
590+
// Track the number of Logic Elements (LEs) used. This is populated only for
591+
// architectures which has LEs. The architecture is assumed to have LEs iff
592+
// it has a logic block that contains LUT primitives and is the first
593+
// pb_block to have more than one instance from the top of the hierarchy
594+
// (All parent pb_block have one instance only and one mode only).
595+
596+
// The number of LEs that are used for logic (LUTs/adders) only.
597+
int num_logic_le = 0;
598+
// The number of LEs that are used for registers only.
599+
int num_reg_le = 0;
600+
// The number of LEs that are used for both logic (LUTs/adders) and registers.
601+
int num_logic_and_reg_le = 0;
596602

597603
for (LegalizationClusterId cluster_id : cluster_legalizer.clusters()) {
598604
// Update the data structure holding the LE counts
599605
update_le_count(cluster_legalizer.get_cluster_pb(cluster_id),
600606
logic_block_type,
601607
le_pb_type,
602-
le_count);
608+
num_logic_le,
609+
num_reg_le,
610+
num_logic_and_reg_le);
603611
}
604612

605613
// if this architecture has LE physical block, report its usage
606614
if (le_pb_type) {
607-
print_le_count(le_count, le_pb_type);
615+
print_le_count(num_logic_le, num_reg_le, num_logic_and_reg_le, le_pb_type);
608616
}
609617
}
610618

vpr/src/pack/greedy_clusterer.h

Lines changed: 15 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -28,23 +28,6 @@ struct t_analysis_opts;
2828
struct t_clustering_data;
2929
struct t_packer_opts;
3030

31-
/**
32-
* @brief Struct to hold statistics on the progress of clustering.
33-
*
34-
* FIXME: These numbers only ever go up! This is a problem since some clusters
35-
* may be reclustered, leading to double counting. This is only a logging
36-
* bug, but should be thought about.
37-
*/
38-
struct t_cluster_progress_stats {
39-
// The total number of molecules in the design.
40-
int num_molecules = 0;
41-
// The number of molecules which have been clustered.
42-
int num_molecules_processed = 0;
43-
// The number of molecules clustered since the last time the status was
44-
// logged.
45-
int mols_since_last_print = 0;
46-
};
47-
4831
/**
4932
* @brief A clusterer that generates clusters by greedily choosing the clusters
5033
* which appear to have the best gain for a given neighbor.
@@ -151,7 +134,9 @@ class GreedyClusterer {
151134
private:
152135
/**
153136
* @brief Given a seed molecule and a legalization strategy, tries to grow
154-
* a cluster greedily. Will return the ID of the cluster created.
137+
* a cluster greedily, starting with the provided seed and adding
138+
* whatever other molecules seem beneficial and legal. Will return
139+
* the ID of the cluster created.
155140
*
156141
* If the strategy is set to SKIP_INTRA_LB_ROUTE, the cluster will grow
157142
* without performing intra-lb route every time a molecule is added to the
@@ -179,16 +164,16 @@ class GreedyClusterer {
179164
/**
180165
* @brief Given a seed molecule, starts a new cluster by trying to find a
181166
* good logical block type and mode to put it in. This method cannot
182-
* fail (only crash if the seed cannot be clustered), so should
167+
* fail (only crash if the seed cannot be clustered), so it should
183168
* always return a valid ID to the cluster created.
184169
*
185170
* When balance_block_type_utilization is set to true, this method will try
186171
* to select less used logical block types if it has the option to in order
187172
* to balance logical block type utilization.
188173
*
189-
* This method will try to grow the device grid if it find thats more
190-
* clusters of specific logical block types have been created than the
191-
* device can support.
174+
* If the device is to be auto-sized, this method will try to grow the
175+
* device grid if it find thats more clusters of specific logical block
176+
* types have been created than the device can support.
192177
*/
193178
LegalizationClusterId start_new_cluster(t_pack_molecule* seed_mol,
194179
ClusterLegalizer& cluster_legalizer,
@@ -254,17 +239,14 @@ class GreedyClusterer {
254239
/// each molecule.
255240
const int log_verbosity_;
256241

257-
/* Does the atom block that drives the output of this atom net also appear as a *
258-
* receiver (input) pin of the atom net?
259-
*
260-
* This is used in the gain routines to avoid double counting the connections from *
261-
* the current cluster to other blocks (hence yielding better clusterings). *
262-
* The only time an atom block should connect to the same atom net *
263-
* twice is when one connection is an output and the other is an input, *
264-
* so this should take care of all multiple connections. */
242+
/// @brief Does the atom block that drives the output of this atom net also
243+
/// appear as a receiver (input) pin of the atom net?
244+
///
245+
/// This is used in the gain routines to avoid double counting the
246+
/// connections from the current cluster to other blocks (hence yielding
247+
/// better clusterings). The only time an atom block should connect to the
248+
/// same atom net twice is when one connection is an output and the other
249+
/// is an input, so this should take care of all multiple connections.
265250
const std::unordered_set<AtomNetId> net_output_feeds_driving_block_input_;
266-
267-
/// @brief The current progress of the clustering. Used for logging.
268-
t_cluster_progress_stats clustering_stats_;
269251
};
270252

0 commit comments

Comments
 (0)