Skip to content

Commit 3db44a2

Browse files
vpr: Fixed adding cluster molecule candidates by transitive connectivity
1 parent 0eb1e95 commit 3db44a2

File tree

3 files changed

+76
-80
lines changed

3 files changed

+76
-80
lines changed

vpr/src/pack/cluster.cpp

Lines changed: 71 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ using namespace std;
7272
#define AAPACK_MAX_NET_SINKS_IGNORE 64 /* The packer looks at all sinks of a net when deciding what next candidate block to pack, for high-fanout nets, this is too runtime costly for marginal benefit, thus ignore those high fanout nets */
7373
#define AAPACK_MAX_HIGH_FANOUT_EXPLORE 10 /* For high-fanout nets that are ignored, consider a maximum of this many sinks, must be less than AAPACK_MAX_FEASIBLE_BLOCK_ARRAY_SIZE */
7474
#define AAPACK_MAX_TRANSITIVE_FANOUT_EXPLORE 4 /* When investigating transitive fanout connections in packing, this is the highest fanout net that will be explored */
75-
#define AAPACK_MAX_TRANSITIVE_EXPLORE 4 /* When investigating transitive fanout connections in packing, consider a maximum of this many molecules, must be less tahn AAPACK_MAX_FEASIBLE_BLOCK_ARRAY_SIZE */
75+
#define AAPACK_MAX_TRANSITIVE_EXPLORE 40 /* When investigating transitive fanout connections in packing, consider a maximum of this many molecules, must be less than AAPACK_MAX_FEASIBLE_BLOCK_ARRAY_SIZE */
7676

7777
//Constant allowing all cluster pins to be used
7878
const t_ext_pin_util FULL_EXTERNAL_PIN_UTIL(1., 1.);
@@ -573,17 +573,18 @@ std::map<t_type_ptr,size_t> do_clustering(const t_packer_opts& packer_opts, cons
573573
clb_inter_blk_nets,
574574
clb_index, packer_opts.pack_verbosity);
575575
continue;
576-
} else {
577-
/* Continue packing by filling smallest cluster */
578-
if (verbosity > 2) {
579-
VTR_LOG("\tPASSED: '%s' (%s)", blk_name.c_str(), blk_model->name);
580-
VTR_LOGV(next_molecule->pack_pattern, " molecule %s molecule_size %zu",
581-
next_molecule->pack_pattern->name, next_molecule->atom_block_ids.size());
582-
VTR_LOG("\n");
583-
}
584-
VTR_LOGV(verbosity == 2, ".");
585-
fflush(stdout);
586576
}
577+
578+
/* Continue packing by filling smallest cluster */
579+
if (verbosity > 2) {
580+
VTR_LOG("\tPASSED: '%s' (%s)", blk_name.c_str(), blk_model->name);
581+
VTR_LOGV(next_molecule->pack_pattern, " molecule %s molecule_size %zu",
582+
next_molecule->pack_pattern->name, next_molecule->atom_block_ids.size());
583+
VTR_LOG("\n");
584+
}
585+
VTR_LOGV(verbosity == 2, ".");
586+
fflush(stdout);
587+
587588
update_cluster_stats(next_molecule, clb_index,
588589
is_clock, //Set of all clocks
589590
is_clock, //Set of all global signals (currently clocks)
@@ -617,6 +618,7 @@ std::map<t_type_ptr,size_t> do_clustering(const t_packer_opts& packer_opts, cons
617618
} else {
618619
is_cluster_legal = true;
619620
}
621+
620622
if (is_cluster_legal) {
621623
intra_lb_routing.push_back(router_data->saved_lb_nets);
622624
VTR_ASSERT((int)intra_lb_routing.size() == num_clb);
@@ -1077,13 +1079,13 @@ static void alloc_and_load_pb_stats(t_pb *pb) {
10771079
pb->pb_stats->connectiongain.clear();
10781080
pb->pb_stats->sharinggain.clear();
10791081
pb->pb_stats->hillgain.clear();
1082+
pb->pb_stats->transitive_fanout_candidates.clear();
10801083

10811084
pb->pb_stats->num_pins_of_net_in_pb.clear();
10821085

10831086
pb->pb_stats->num_child_blocks_in_pb = 0;
10841087

10851088
pb->pb_stats->explore_transitive_fanout = true;
1086-
pb->pb_stats->transitive_fanout_candidates = nullptr;
10871089
}
10881090
/*****************************************/
10891091

@@ -1732,11 +1734,11 @@ static void update_cluster_stats( const t_pack_molecule *molecule,
17321734
cur_pb = atom_ctx.lookup.atom_pb(blk_id)->parent_pb;
17331735
while (cur_pb) {
17341736
/* reset list of feasible blocks */
1735-
cur_pb->pb_stats->num_feasible_blocks = NOT_VALID;
1736-
cur_pb->pb_stats->num_child_blocks_in_pb++;
17371737
if (cur_pb->parent_pb == nullptr) {
17381738
cb = cur_pb;
17391739
}
1740+
cur_pb->pb_stats->num_feasible_blocks = NOT_VALID;
1741+
cur_pb->pb_stats->num_child_blocks_in_pb++;
17401742
cur_pb = cur_pb->parent_pb;
17411743
}
17421744

@@ -1789,6 +1791,10 @@ static void update_cluster_stats( const t_pack_molecule *molecule,
17891791

17901792
commit_lookahead_pins_used(cb);
17911793
}
1794+
1795+
// if this molecule came from the transitive fanout candidates remove it
1796+
cb->pb_stats->transitive_fanout_candidates.erase(molecule->atom_block_ids[molecule->root]);
1797+
cb->pb_stats->explore_transitive_fanout = true;
17921798
}
17931799

17941800
static void start_new_cluster(
@@ -1966,8 +1972,7 @@ static t_pack_molecule *get_highest_gain_molecule(
19661972
}
19671973

19681974
// 2. Find unpacked molecule based on transitive connections (eg. 2 hops away) with current cluster
1969-
if(cur_pb->pb_stats->num_feasible_blocks == 0 &&
1970-
cur_pb->pb_stats->explore_transitive_fanout == true) {
1975+
if(cur_pb->pb_stats->num_feasible_blocks == 0 && cur_pb->pb_stats->explore_transitive_fanout) {
19711976
add_cluster_molecule_candidates_by_transitive_connectivity(cur_pb, cluster_placement_stats_ptr, atom_molecules, clb_inter_blk_nets, cluster_index);
19721977
}
19731978

@@ -1979,13 +1984,11 @@ static t_pack_molecule *get_highest_gain_molecule(
19791984
/* Grab highest gain molecule */
19801985
t_pack_molecule* molecule = nullptr;
19811986
for (int j = 0; j < cur_pb->pb_stats->num_feasible_blocks; j++) {
1982-
if (cur_pb->pb_stats->num_feasible_blocks != 0) {
1983-
cur_pb->pb_stats->num_feasible_blocks--;
1984-
int index = cur_pb->pb_stats->num_feasible_blocks;
1985-
molecule = cur_pb->pb_stats->feasible_blocks[index];
1986-
VTR_ASSERT(molecule->valid == true);
1987-
return molecule;
1988-
}
1987+
cur_pb->pb_stats->num_feasible_blocks--;
1988+
int index = cur_pb->pb_stats->num_feasible_blocks;
1989+
molecule = cur_pb->pb_stats->feasible_blocks[index];
1990+
VTR_ASSERT(molecule->valid == true);
1991+
return molecule;
19891992
}
19901993

19911994
return molecule;
@@ -2094,42 +2097,35 @@ void add_cluster_molecule_candidates_by_transitive_connectivity(t_pb* cur_pb,
20942097

20952098
auto& atom_ctx = g_vpr_ctx.atom();
20962099

2097-
if(cur_pb->pb_stats->transitive_fanout_candidates == nullptr) {
2098-
/* First time finding transitive fanout candidates therefore alloc and load them */
2099-
cur_pb->pb_stats->transitive_fanout_candidates = new vector<t_pack_molecule *>;
2100-
load_transitive_fanout_candidates(cluster_index,
2101-
atom_molecules,
2102-
cur_pb->pb_stats,
2103-
clb_inter_blk_nets);
2104-
2105-
/* Only consider candidates that pass a very simple legality check */
2106-
for(int i = 0; i < (int) cur_pb->pb_stats->transitive_fanout_candidates->size(); i++) {
2107-
t_pack_molecule* molecule = (*cur_pb->pb_stats->transitive_fanout_candidates)[i];
2108-
if (molecule->valid) {
2109-
bool success = true;
2110-
for (int j = 0; j < get_array_size_of_molecule(molecule); j++) {
2111-
if (molecule->atom_block_ids[j]) {
2112-
VTR_ASSERT(atom_ctx.lookup.atom_clb(molecule->atom_block_ids[j]) == ClusterBlockId::INVALID());
2113-
auto blk_id = molecule->atom_block_ids[j];
2114-
if (!exists_free_primitive_for_atom_block(cluster_placement_stats_ptr, blk_id)) {
2115-
/* TODO: debating whether to check if placement exists for molecule (more
2116-
* robust) or individual atom blocks (faster) */
2117-
success = false;
2118-
break;
2119-
}
2100+
cur_pb->pb_stats->explore_transitive_fanout = false;
2101+
2102+
/* First time finding transitive fanout candidates therefore alloc and load them */
2103+
load_transitive_fanout_candidates(cluster_index,
2104+
atom_molecules,
2105+
cur_pb->pb_stats,
2106+
clb_inter_blk_nets);
2107+
/* Only consider candidates that pass a very simple legality check */
2108+
for(const auto& transitive_candidate : cur_pb->pb_stats->transitive_fanout_candidates) {
2109+
t_pack_molecule* molecule = transitive_candidate.second;
2110+
if (molecule->valid) {
2111+
bool success = true;
2112+
for (int j = 0; j < get_array_size_of_molecule(molecule); j++) {
2113+
if (molecule->atom_block_ids[j]) {
2114+
VTR_ASSERT(atom_ctx.lookup.atom_clb(molecule->atom_block_ids[j]) == ClusterBlockId::INVALID());
2115+
auto blk_id = molecule->atom_block_ids[j];
2116+
if (!exists_free_primitive_for_atom_block(cluster_placement_stats_ptr, blk_id)) {
2117+
/* TODO: debating whether to check if placement exists for molecule (more
2118+
* robust) or individual atom blocks (faster) */
2119+
success = false;
2120+
break;
21202121
}
21212122
}
2122-
if (success) {
2123-
add_molecule_to_pb_stats_candidates(molecule,
2124-
cur_pb->pb_stats->gain, cur_pb, min(AAPACK_MAX_FEASIBLE_BLOCK_ARRAY_SIZE,AAPACK_MAX_TRANSITIVE_EXPLORE));
2125-
}
2123+
}
2124+
if (success) {
2125+
add_molecule_to_pb_stats_candidates(molecule,
2126+
cur_pb->pb_stats->gain, cur_pb, min(AAPACK_MAX_FEASIBLE_BLOCK_ARRAY_SIZE, AAPACK_MAX_TRANSITIVE_EXPLORE));
21262127
}
21272128
}
2128-
} else {
2129-
/* Clean up, no more candidates in transitive fanout to consider */
2130-
delete cur_pb->pb_stats->transitive_fanout_candidates;
2131-
cur_pb->pb_stats->transitive_fanout_candidates = nullptr;
2132-
cur_pb->pb_stats->explore_transitive_fanout = false;
21332129
}
21342130
}
21352131

@@ -2149,11 +2145,11 @@ static t_pack_molecule *get_molecule_for_cluster(
21492145
* passed in. If no suitable block is found it returns ClusterBlockId::INVALID().
21502146
*/
21512147

2152-
t_pack_molecule *best_molecule;
2148+
VTR_ASSERT(!cur_pb->parent_pb);
21532149

21542150
/* If cannot pack into primitive, try packing into cluster */
21552151

2156-
best_molecule = get_highest_gain_molecule(cur_pb, atom_molecules,
2152+
auto best_molecule = get_highest_gain_molecule(cur_pb, atom_molecules,
21572153
NOT_HILL_CLIMBING, cluster_placement_stats_ptr, clb_inter_blk_nets, cluster_index);
21582154

21592155
/* If no blocks have any gain to the current cluster, the code above *
@@ -3009,26 +3005,38 @@ static void commit_lookahead_pins_used(t_pb *cur_pb) {
30093005
}
30103006
}
30113007

3012-
/* Score unclustered atoms that are two hops away from current cluster */
3008+
/**
3009+
* Score unclustered atoms that are two hops away from current cluster
3010+
* For example, consider a cluster that has a FF feeding an adder in another
3011+
* cluster. Since this FF is feeding an adder that is packed in another cluster
3012+
* this function should find other FFs that are feeding other inputs of this adder
3013+
* since they are two hops away from the FF packed in this cluster
3014+
*/
30133015
static void load_transitive_fanout_candidates(ClusterBlockId clb_index,
30143016
const std::multimap<AtomBlockId,t_pack_molecule*>& atom_molecules,
30153017
t_pb_stats *pb_stats,
30163018
vtr::vector<ClusterBlockId,std::vector<AtomNetId>> &clb_inter_blk_nets) {
30173019
auto& atom_ctx = g_vpr_ctx.atom();
30183020

3021+
// iterate over all the nets that have pins in this cluster
30193022
for(const auto net_id : pb_stats->marked_nets) {
3023+
// only consider small nets to constrain runtime
30203024
if(atom_ctx.nlist.net_pins(net_id).size() < AAPACK_MAX_TRANSITIVE_FANOUT_EXPLORE + 1) {
3025+
// iterate over all the pins of the net
30213026
for(const auto pin_id : atom_ctx.nlist.net_pins(net_id)) {
30223027
AtomBlockId atom_blk_id = atom_ctx.nlist.pin_block(pin_id);
3023-
ClusterBlockId tclb = atom_ctx.lookup.atom_clb(atom_blk_id); //The transitive CLB
3028+
// get the transitive cluster
3029+
ClusterBlockId tclb = atom_ctx.lookup.atom_clb(atom_blk_id);
3030+
// if the block connected to this pin is packed in another cluster
30243031
if(tclb != clb_index && tclb != ClusterBlockId::INVALID()) {
3025-
/* Explore transitive connections from already packed cluster */
3032+
// explore transitive nets from already packed cluster
30263033
for(AtomNetId tnet : clb_inter_blk_nets[tclb]) {
3034+
// iterate over all the pins of the net
30273035
for(AtomPinId tpin : atom_ctx.nlist.net_pins(tnet)) {
30283036
auto blk_id = atom_ctx.nlist.pin_block(tpin);
3037+
// This transitive atom is not packed, score and add
30293038
if(atom_ctx.lookup.atom_clb(blk_id) == ClusterBlockId::INVALID()) {
3030-
/* This transitive atom is not packed, score and add */
3031-
std::vector<t_pack_molecule *> &transitive_fanout_candidates = *(pb_stats->transitive_fanout_candidates);
3039+
auto& transitive_fanout_candidates = pb_stats->transitive_fanout_candidates;
30323040

30333041
if(pb_stats->gain.count(blk_id) == 0) {
30343042
pb_stats->gain[blk_id] = 0.001;
@@ -3039,19 +3047,7 @@ static void load_transitive_fanout_candidates(ClusterBlockId clb_index,
30393047
for(const auto& kv : vtr::make_range(rng.first, rng.second)) {
30403048
t_pack_molecule* molecule = kv.second;
30413049
if (molecule->valid) {
3042-
unsigned int imol = 0;
3043-
3044-
/* The number of potential molecules is heavily bounded so
3045-
* this O(N) operation should be safe since N is small */
3046-
for(imol = 0; imol < transitive_fanout_candidates.size(); imol++) {
3047-
if(molecule == transitive_fanout_candidates[imol]) {
3048-
break;
3049-
}
3050-
}
3051-
if(imol == transitive_fanout_candidates.size()) {
3052-
/* not in candidate list, add to list */
3053-
transitive_fanout_candidates.push_back(molecule);
3054-
}
3050+
transitive_fanout_candidates.insert({molecule->atom_block_ids[molecule->root], molecule});
30553051
}
30563052
}
30573053
}

vpr/src/pack/pack_types.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ struct t_pb_stats {
5959
this high fanout net to determine the
6060
next candidate atom */
6161
bool explore_transitive_fanout; /* If no marked candidate molecules and no high fanout nets to determine next candidate molecule then explore molecules on transitive fanout */
62-
std::vector<t_pack_molecule *> *transitive_fanout_candidates;
62+
std::unordered_map<AtomBlockId, t_pack_molecule *> transitive_fanout_candidates; // Holding trasitive fanout candidates key: root block id of the molecule, value: pointer to the molecule
6363

6464
/* How many pins of each atom net are contained in the *
6565
* currently open pb? */

vpr/src/util/vpr_utils.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1535,7 +1535,7 @@ void revalid_molecules(const t_pb* pb, const std::multimap<AtomBlockId,t_pack_mo
15351535
// that is part of a long chain. If so, check if this molecule
15361536
// have modified the chain_id value based on the stale packing
15371537
// then reset the chain id and the first packed molecule pointer
1538-
// this is packing is being reseted
1538+
// this is packing is being reset
15391539
if (cur_molecule->type == MOLECULE_FORCED_PACK &&
15401540
cur_molecule->pack_pattern->is_chain &&
15411541
cur_molecule->chain_info->is_long_chain &&
@@ -1567,9 +1567,9 @@ void free_pb_stats(t_pb *pb) {
15671567
if(pb->pb_stats->feasible_blocks) {
15681568
free(pb->pb_stats->feasible_blocks);
15691569
}
1570-
if(pb->pb_stats->transitive_fanout_candidates != nullptr) {
1571-
delete pb->pb_stats->transitive_fanout_candidates;
1572-
};
1570+
if(!pb->parent_pb) {
1571+
pb->pb_stats->transitive_fanout_candidates.clear();
1572+
}
15731573
delete pb->pb_stats;
15741574
pb->pb_stats = nullptr;
15751575
}

0 commit comments

Comments
 (0)