Skip to content

Clusterer feasibility changes #1641

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 35 commits into from
Feb 27, 2021
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
918219f
Added a vpr floorplanning constraints context
sfkhalid Dec 16, 2020
1fdf881
Wrote code to set the PartitionRegion of the new cluster in start_new…
sfkhalid Jan 18, 2021
ca7b577
Added code to check for an empty PartitionRegion and code to check in…
sfkhalid Jan 21, 2021
ed6e7a8
Modified function for intersecting atom and cluster PartitionRegions
sfkhalid Jan 21, 2021
532a143
Fixed bug where cluster PartitionRegion was not updated soon enough i…
sfkhalid Jan 25, 2021
511a994
Ran make format
sfkhalid Jan 26, 2021
8008b2e
Added function to echo cluster contents
sfkhalid Jan 27, 2021
54f4995
Merge branch 'master' into clusterer_feasibility_changes
sfkhalid Jan 27, 2021
5845338
Added routine print_pack_status to print some cluster stats increment…
sfkhalid Jan 27, 2021
7b465fe
Printed end of clustering stats in table format
sfkhalid Jan 28, 2021
6fb45ff
Shortened and clarified some comments
sfkhalid Jan 28, 2021
3a606e8
Made formatting changes to cluster echo file
sfkhalid Jan 28, 2021
4fceb1e
Changed frequency of cluster progress messages
sfkhalid Feb 1, 2021
f00d55d
Need to merge changes to be able to push to remote branch. Merge bran…
sfkhalid Feb 1, 2021
f34a1d6
Changed data structure for holding cluster constraints from unordered…
sfkhalid Feb 3, 2021
e4b8257
Changed place where cluster's PartitionRegion is updated so that it d…
sfkhalid Feb 3, 2021
6e59e42
Added comments and removed unnecessary variables
sfkhalid Feb 4, 2021
ffa49a1
Merge branch 'master' into clusterer_feasibility_changes
sfkhalid Feb 4, 2021
83cfe2b
Made packing progress print every 4%
sfkhalid Feb 8, 2021
ed0cd07
Need to update local branchMerge branch 'clusterer_feasibility_change…
sfkhalid Feb 8, 2021
7e8f9d5
Print clustering progress in a table
sfkhalid Feb 8, 2021
c8b58b8
Added function level comments and table headers
sfkhalid Feb 8, 2021
f11da67
Modified build_device_grid function call in SetupGrid.cpp to get rid …
sfkhalid Feb 10, 2021
899a3da
Create the temporary cluster PartitionRegion earlier in the flow when…
sfkhalid Feb 10, 2021
afcb926
Merge branch 'master' into clusterer_feasibility_changes
sfkhalid Feb 11, 2021
ee4bf86
Moved print functions to be within their respective class. ex - print…
sfkhalid Feb 12, 2021
37ef5a7
Merge origin with local to be able to push changes to local 'clustere…
sfkhalid Feb 12, 2021
cfb812f
Comment update for print_constraints function
sfkhalid Feb 12, 2021
e2a7bfc
Updated comment for echo_constraints function
sfkhalid Feb 12, 2021
680cbdc
Merge branch 'master' into clusterer_feasibility_changes
sfkhalid Feb 15, 2021
40e9534
Merge branch 'master' into clusterer_feasibility_changes
sfkhalid Feb 26, 2021
d2d6fcb
Updated PartitionRegion class comment
sfkhalid Feb 26, 2021
bd217bf
Need to run make format on changes that were merged remotely 'cluster…
sfkhalid Feb 26, 2021
8c5bc25
Ran make format to fix formatting in vtr geometry file
sfkhalid Feb 26, 2021
b807f83
Merge branch 'master' into clusterer_feasibility_changes
sfkhalid Feb 26, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions vpr/src/base/partition_region.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,14 @@ std::vector<Region> PartitionRegion::get_partition_region() {
return partition_region;
}

bool PartitionRegion::empty() {
if (partition_region.size() == 0) {
return true;
} else {
return false;
}
}

PartitionRegion intersection(PartitionRegion& pr1, PartitionRegion& pr2) {
/**for N regions in part_region and M in the calling object you can get anywhere from
* 0 to M*N regions in the resulting vector. Only intersection regions with non-zero area rectangles and
Expand Down
5 changes: 5 additions & 0 deletions vpr/src/base/partition_region.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@ class PartitionRegion {
*/
std::vector<Region> get_partition_region();

/**
* @brief Check if the PartitionRegion is empty (ie. holds no regions in its vector)
*/
bool empty();

/**
* @brief Global friend function that returns the intersection of two PartitionRegions
*
Expand Down
14 changes: 14 additions & 0 deletions vpr/src/base/vpr_constraints.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,17 @@ std::vector<AtomBlockId> VprConstraints::get_part_atoms(PartitionId part_id) {

return part_atoms;
}

int VprConstraints::get_num_partitions() {
return num_partitions;
}

void VprConstraints::set_num_partitions(int num_parts) {
num_partitions = num_parts;
}

PartitionRegion VprConstraints::get_partition_pr(PartitionId part_id) {
PartitionRegion pr;
pr = partitions[part_id].get_part_region();
return pr;
}
27 changes: 26 additions & 1 deletion vpr/src/base/vpr_constraints.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ class VprConstraints {
/**
* @brief Return id of the partition the atom belongs to
*
* If an atom is not in a partition (unconstrained), PartitionId::Invalid() is returned.
* If an atom is not in a partition (unconstrained), PartitionId::INVALID() is returned.
*
* @param blk_id The atom for which the partition id is needed
*/
Expand All @@ -60,6 +60,25 @@ class VprConstraints {
*/
std::vector<AtomBlockId> get_part_atoms(PartitionId part_id);

/**
* @brief Returns the number of partitions in the object
*/
int get_num_partitions();

/**
* @brief Sets the number of partitions in the object
*
* @param num_parts The number of partitions in the partitions vector
*/
void set_num_partitions(int num_parts);

/**
* @brief Returns the PartitionRegion belonging to the specified Partition
*
* @param part_id The id of the partition whose PartitionRegion is needed
*/
PartitionRegion get_partition_pr(PartitionId part_id);

private:
/**
* Store all constrained atoms
Expand All @@ -70,6 +89,12 @@ class VprConstraints {
* Store all partitions
*/
vtr::vector<PartitionId, Partition> partitions;

/**
* Store number of partitions - the number of partitions in the partitions vector.
* Used when echoing VprConstraints objects.
*/
int num_partitions;
};

#endif /* VPR_CONSTRAINTS_H */
12 changes: 9 additions & 3 deletions vpr/src/base/vpr_constraints_reader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,16 @@ void load_vpr_constraints_file(const char* read_vpr_constraints_name) {
read_vpr_constraints_name);
}

VprConstraints constraints = reader.constraints_;
int num_parts = reader.num_partitions_;
//VprConstraints constraints = reader.constraints_;
//int num_parts = reader.num_partitions_;

//Update the floorplanning constraints in the floorplanning constraints context
auto& floorplanning_ctx = g_vpr_ctx.mutable_floorplanning();
floorplanning_ctx.constraints = reader.constraints_;

VprConstraints ctx_constraints = floorplanning_ctx.constraints;

if (getEchoEnabled() && isEchoFileEnabled(E_ECHO_VPR_CONSTRAINTS)) {
echo_constraints(getEchoFileName(E_ECHO_VPR_CONSTRAINTS), constraints, num_parts);
echo_constraints(getEchoFileName(E_ECHO_VPR_CONSTRAINTS), ctx_constraints, ctx_constraints.get_num_partitions());
}
}
3 changes: 3 additions & 0 deletions vpr/src/base/vpr_constraints_serializer.h
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,9 @@ class VprConstraintsSerializer final : public uxsd::VprConstraintsBase<VprConstr
}

virtual void finish_load() final {
//Pass the object the total number of partitions that were read in
//This number is used when echoing VprConstraints objects
constraints_.set_num_partitions(num_partitions_);
}

//temp data for loads
Expand Down
16 changes: 16 additions & 0 deletions vpr/src/base/vpr_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include "place_macro.h"
#include "compressed_grid.h"
#include "metadata_storage.h"
#include "vpr_constraints.h"

/**
* @brief A Context is collection of state relating to a particular part of VPR
Expand Down Expand Up @@ -369,6 +370,17 @@ struct RoutingContext : public Context {
cached_router_lookahead_;
};

/**
* @brief State relating to VPR's floorplanning constraints
*
* This should contain only data structures related to constraining blocks
* to certain regions on the chip.
*/
struct FloorplanningContext : public Context {
VprConstraints constraints;
std::unordered_map<ClusterBlockId, PartitionRegion> clb_constraints;
};

/**
* @brief This object encapsulates VPR's state.
*
Expand Down Expand Up @@ -440,6 +452,9 @@ class VprContext : public Context {
const RoutingContext& routing() const { return routing_; }
RoutingContext& mutable_routing() { return routing_; }

const FloorplanningContext& floorplanning() const { return constraints_; }
FloorplanningContext& mutable_floorplanning() { return constraints_; }

private:
DeviceContext device_;

Expand All @@ -451,6 +466,7 @@ class VprContext : public Context {
ClusteringContext clustering_;
PlacementContext placement_;
RoutingContext routing_;
FloorplanningContext constraints_;
};

#endif
1 change: 1 addition & 0 deletions vpr/src/base/vpr_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ enum e_block_pack_status {
BLK_PASSED,
BLK_FAILED_FEASIBLE,
BLK_FAILED_ROUTE,
BLK_FAILED_FLOORPLANNING,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

think about whether this enum can be in a lower header file. If it's only used in the clusterer, can have a cluster_utilities header file and put this enum in there. This can be a cleanup on a separate pull request

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in pack subdirectory - is there a cluster utilities type header file? check, could possibly put there

BLK_STATUS_UNDEFINED
};

Expand Down
145 changes: 145 additions & 0 deletions vpr/src/pack/cluster.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@
#include "tatum/report/graphviz_dot_writer.hpp"
#include "tatum/TimingReporter.hpp"

#include "constraints_load.h"

#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 packer_opts.feasible_block_array_size */
#define AAPACK_MAX_TRANSITIVE_EXPLORE 40 /* When investigating transitive fanout connections in packing, consider a maximum of this many molecules, must be less than packer_opts.feasible_block_array_size */

Expand Down Expand Up @@ -216,6 +218,10 @@ static enum e_block_pack_status try_place_atom_block_rec(const t_pb_graph_node*
int verbosity,
const int feasible_block_array_size);

static enum e_block_pack_status intersect_atom_cluster_part_regions(const AtomBlockId blk_id,
const ClusterBlockId clb_index,
int verbosity);

static void revert_place_atom_block(const AtomBlockId blk_id, t_lb_router_data* router_data, const std::multimap<AtomBlockId, t_pack_molecule*>& atom_molecules);

static void update_connection_gain_values(const AtomNetId net_id, const AtomBlockId clustered_blk_id, t_pb* cur_pb, enum e_net_relation_to_clustered_block net_relation_to_clustered_block);
Expand Down Expand Up @@ -633,6 +639,9 @@ std::map<t_logical_block_type_ptr, size_t> do_clustering(const t_packer_opts& pa
next_molecule->pack_pattern->name, next_molecule->atom_block_ids.size());
VTR_LOG("\n");
fflush(stdout);
} else if (block_pack_status == BLK_FAILED_FLOORPLANNING) {
VTR_LOG("\tFloorplanning constraints not met: '%s' (%s)", blk_name.c_str(), blk_model->name);
VTR_LOG("\n");
} else {
VTR_LOG("\tFAILED_FEASIBILITY_CHECK: '%s' (%s)", blk_name.c_str(), blk_model->name, block_pack_status);
VTR_LOGV(next_molecule->pack_pattern, " molecule %s molecule_size %zu",
Expand Down Expand Up @@ -1198,6 +1207,7 @@ static enum e_block_pack_status try_pack_molecule(t_cluster_placement_stats* clu
t_ext_pin_util max_external_pin_util) {
int molecule_size, failed_location;
int i;
int j;
enum e_block_pack_status block_pack_status;
t_pb* parent;
t_pb* cur_pb;
Expand Down Expand Up @@ -1233,6 +1243,24 @@ static enum e_block_pack_status try_pack_molecule(t_cluster_placement_stats* clu
return BLK_FAILED_FEASIBLE;
}

//for loop to check if cluster PartitionRegion intersects with atom PartitionRegion
for (j = 0; j < molecule_size; j++) {
//try to intersect with atom PartitionRegion if atom exists
if (molecule->atom_block_ids[j]) {
block_pack_status = intersect_atom_cluster_part_regions(molecule->atom_block_ids[j], clb_index, verbosity);

if (block_pack_status == BLK_FAILED_FLOORPLANNING) {
VTR_LOG("\t\t\t From intersect: block failed floorplanning check \n");
return block_pack_status;
} else if (block_pack_status == BLK_PASSED) {
VTR_LOG("\t\t\t From intersect: block passed \n");
}
}
}

//change status back to undefined before the while loop in case in was changed to BLK_PASSED in the above for loop
block_pack_status = BLK_STATUS_UNDEFINED;

while (block_pack_status != BLK_PASSED) {
if (get_next_primitive_list(cluster_placement_stats_ptr, molecule,
primitives_list)) {
Expand All @@ -1243,13 +1271,26 @@ static enum e_block_pack_status try_pack_molecule(t_cluster_placement_stats* clu
failed_location = i + 1;
// try place atom block if it exists
if (molecule->atom_block_ids[i]) {
//VTR_LOG("\t\t\t Inner for loop, molecule size is %d, i is %d \n", molecule_size, i);
block_pack_status = try_place_atom_block_rec(primitives_list[i],
molecule->atom_block_ids[i], pb, &parent,
max_models, max_cluster_size, clb_index,
cluster_placement_stats_ptr, molecule, router_data,
verbosity, feasible_block_array_size);
}
}

//for loop to check if cluster PartitionRegion intersects with atom PartitionRegion
/*for (j = 0; j < molecule_size && block_pack_status == BLK_PASSED; j++) {
* //VTR_ASSERT((primitives_list[i] == nullptr) == (!molecule->atom_block_ids[i]));
* //failed_location = i + 1;
* //try to intersect with atom PartitionRegion if atom exists
* if (molecule->atom_block_ids[j]) {
* VTR_LOG("\t\t\t In the second for loop in try_pack_molecule, j is %d \n", j);
* block_pack_status = intersect_atom_cluster_part_regions(molecule->atom_block_ids[j], clb_index, verbosity);
* }
* }*/

if (enable_pin_feasibility_filter && block_pack_status == BLK_PASSED) {
/* Check if pin usage is feasible for the current packing assignment */
reset_lookahead_pins_used(pb);
Expand Down Expand Up @@ -1503,6 +1544,75 @@ static enum e_block_pack_status try_place_atom_block_rec(const t_pb_graph_node*
return block_pack_status;
}

/*try and see if floorplanning constraints match*/
static enum e_block_pack_status intersect_atom_cluster_part_regions(const AtomBlockId blk_id,
const ClusterBlockId clb_index,
int verbosity) {
auto& floorplanning_ctx = g_vpr_ctx.mutable_floorplanning();
VprConstraints ctx_constraints = floorplanning_ctx.constraints;

/*check if the atom can go in the cluster by checking if the atom and cluster have intersecting PartitionRegions*/

//get partition that atom belongs to
PartitionId partid;
partid = ctx_constraints.get_atom_partition(blk_id);

PartitionRegion atom_pr;
PartitionRegion cluster_pr;
PartitionRegion intersect_pr;

//if the atom does not belong to a partition, it can be put in the cluster
//regardless of what the cluster's PartitionRegion is because it has no constraints
if (partid == PartitionId::INVALID()) {
if (verbosity > 3) {
VTR_LOG("\t\t\t Intersect: Atom block %d passed cluster %d \n", blk_id, clb_index);
}
return BLK_PASSED;
} else {
//get pr of that partition
atom_pr = ctx_constraints.get_partition_pr(partid);

//intersect it with the pr of the current cluster
auto got = floorplanning_ctx.clb_constraints.find(clb_index);
//cluster_pr = got->second;

if (got == floorplanning_ctx.clb_constraints.end()) {
VTR_LOG("\t\t\t Did not find PR of cluster");
} else {
cluster_pr = got->second;
//intersect_pr = intersection(atom_pr, cluster_pr);
}

if (cluster_pr.empty() == true) {
//what if the atom passes here but then doesn't pass somewhere else
//the cluster PR will have been updated for no reason
//probably better to have another function at the end of the try_pack_molecule function that
//takes care of updating cluster PR
got->second = atom_pr;
if (verbosity > 3) {
VTR_LOG("\t\t\t Intersect: Atom block %d passed cluster %d \n", blk_id, clb_index);
}
return BLK_PASSED;
} else {
intersect_pr = intersection(cluster_pr, atom_pr);
}

if (intersect_pr.empty() == true) {
if (verbosity > 3) {
VTR_LOG("\t\t\t Intersect: Atom block %d failed floorplanning check for cluster %d \n", blk_id, clb_index);
}
return BLK_FAILED_FLOORPLANNING;
} else {
//update the cluster's PartitionRegion
got->second = intersect_pr;
if (verbosity > 3) {
VTR_LOG("\t\t\t Intersect: Atom block %d passed cluster %d \n", blk_id, clb_index);
}
return BLK_PASSED;
}
}
}

/* Revert trial atom block iblock and free up memory space accordingly
*/
static void revert_place_atom_block(const AtomBlockId blk_id, t_lb_router_data* router_data, const std::multimap<AtomBlockId, t_pack_molecule*>& atom_molecules) {
Expand Down Expand Up @@ -1948,6 +2058,19 @@ static void start_new_cluster(t_cluster_placement_stats* cluster_placement_stats
auto& atom_ctx = g_vpr_ctx.atom();
auto& device_ctx = g_vpr_ctx.mutable_device();

/*
* Get floorplanning information
*/
auto& floorplanning_ctx = g_vpr_ctx.mutable_floorplanning();

VprConstraints ctx_constraints = floorplanning_ctx.constraints;

/*
* Set an empty PR for the cluster
*/
PartitionRegion empty_pr;
floorplanning_ctx.clb_constraints.insert({clb_index, empty_pr});

/* Allocate a dummy initial cluster and load a atom block as a seed and check if it is legal */
AtomBlockId root_atom = molecule->atom_block_ids[molecule->root];
const std::string& root_atom_name = atom_ctx.nlist.block_name(root_atom);
Expand Down Expand Up @@ -2065,6 +2188,28 @@ static void start_new_cluster(t_cluster_placement_stats* cluster_placement_stats
auto block_type = clb_nlist->block_type(clb_index);
num_used_type_instances[block_type]++;

/*determine whether seed atom belongs to a partition*/
PartitionId partid;
partid = ctx_constraints.get_atom_partition(root_atom);

/*if the seed atom does not belong to a partition, it is unconstrained, so the cluster will have an empty PartitionRegion
*if there is a constraint,set cluster PartitionRegion to same in the vector map of the clusters in the constraints context
*/
/*if (partid == PartitionId::INVALID()) {
* PartitionRegion empty_pr;
* floorplanning_ctx.clb_constraints.insert({clb_index, empty_pr});
* } else {
* PartitionRegion pr = ctx_constraints.get_partition_pr(partid);
* floorplanning_ctx.clb_constraints.insert({clb_index, pr});
* }*/

//if seed atom belongs to a partition, update cluster_pr
if (partid != PartitionId::INVALID()) {
PartitionRegion pr = ctx_constraints.get_partition_pr(partid);
floorplanning_ctx.clb_constraints[clb_index] = pr;
VTR_LOG("Cluster's partition region was updated to match seed atom\n");
}

/* Expand FPGA size if needed */
// Check used type instances against the possible equivalent physical locations
unsigned int num_instances = 0;
Expand Down