Skip to content

Commit 550d6de

Browse files
[AP][IP] Split Initial Placement Into Stages
In the AP flow, the initial placement stage will try to create a minimum displacement placement based on the flat placement and the clustering. It does this by iteratively trying to place clusters farther and farther from where they want to be placed (according to the flat placement). I found that this flow was having issues with macros that contained multiple clusters. If this blocks are placed too late, they may not find a hole big enough for them to fit into. To resolve this issue, split the initial placer into stages such that all fixed blocks are placed first (this blocks must be placed first to ensure other blocks don't take their spots), then all large macros are placed, then all remaining clusters are placed. I expected to make this a backup flow, which only turned on if the first flow failed; however, I found that this actually outperformed my original implementation. I think that placing these larger macros early (i.e. placing them closer to their flat placement position) allows more blocks to be placed closer to where they want to be placed. For most circuits this had a very minor improvement, but for other circuits (such as MCML from the VTR benchmarks) they improved massively.
1 parent b7581d1 commit 550d6de

File tree

1 file changed

+145
-15
lines changed

1 file changed

+145
-15
lines changed

vpr/src/place/initial_placement.cpp

Lines changed: 145 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#include <limits>
3030
#include <optional>
3131
#include <queue>
32+
#include <vector>
3233

3334
#ifdef VERBOSE
3435
void print_clb_placement(const char* fname);
@@ -1628,27 +1629,20 @@ static void print_ap_initial_placer_status(unsigned iteration,
16281629
}
16291630

16301631
/**
1631-
* @brief Places all blocks in the clustered netlist as close to the global
1632-
* placement produced by the AP flow.
1633-
*
1634-
* This function will place clusters in passes. In the first pass, it will try
1635-
* to place clusters exactly where their global placement is (according to the
1636-
* atoms contained in the cluster). In the second pass, all unplaced clusters
1637-
* will try to be placed within 1 tile of where they wanted to be placed.
1638-
* Subsequent passes will then try to place clusters at exponentially farther
1639-
* distances.
1632+
* @brief Collects unplaced clusters and sorts such that clusters which should
1633+
* be placed first appear early in the list.
16401634
*
16411635
* The clusters are sorted based on how many clusters are in the macro that
16421636
* contains this cluster and the standard deviation of the placement of atoms
16431637
* within the cluster. Large macros with low standard deviation will be placed
16441638
* first.
16451639
*/
1646-
static inline void place_all_blocks_ap(enum e_pad_loc_type pad_loc_type,
1647-
BlkLocRegistry& blk_loc_registry,
1648-
const PlaceMacros& place_macros,
1649-
const FlatPlacementInfo& flat_placement_info) {
1650-
const ClusteredNetlist& cluster_netlist = g_vpr_ctx.clustering().clb_nlist;
1651-
const DeviceGrid& device_grid = g_vpr_ctx.device().grid;
1640+
static inline std::vector<ClusterBlockId> get_sorted_clusters_to_place(
1641+
BlkLocRegistry& blk_loc_registry,
1642+
const PlaceMacros& place_macros,
1643+
const ClusteredNetlist& cluster_netlist,
1644+
const FlatPlacementInfo& flat_placement_info) {
1645+
16521646
const auto& cluster_constraints = g_vpr_ctx.floorplanning().cluster_constraints;
16531647

16541648
// Create a list of clusters to place.
@@ -1728,6 +1722,29 @@ static inline void place_all_blocks_ap(enum e_pad_loc_type pad_loc_type,
17281722
return cluster_score[lhs] > cluster_score[rhs];
17291723
});
17301724

1725+
return clusters_to_place;
1726+
}
1727+
1728+
/**
1729+
* @brief Tries to place all of the given clusters as closed to their flat
1730+
* placement as possible (minimum displacement from flat placement).
1731+
*
1732+
* This function will place clusters in passes. In the first pass, it will try
1733+
* to place clusters exactly where their global placement is (according to the
1734+
* atoms contained in the cluster). In the second pass, all unplaced clusters
1735+
* will try to be placed within 1 tile of where they wanted to be placed.
1736+
* Subsequent passes will then try to place clusters at exponentially farther
1737+
* distances.
1738+
*/
1739+
static inline void place_blocks_min_displacement(std::vector<ClusterBlockId>& clusters_to_place,
1740+
enum e_pad_loc_type pad_loc_type,
1741+
BlkLocRegistry& blk_loc_registry,
1742+
const PlaceMacros& place_macros,
1743+
const ClusteredNetlist& cluster_netlist,
1744+
const FlatPlacementInfo& flat_placement_info) {
1745+
1746+
const DeviceGrid& device_grid = g_vpr_ctx.device().grid;
1747+
17311748
// Compute the max L1 distance on the device. If we cannot find a location
17321749
// to place a cluster within this distance, then no legal location exists.
17331750
float max_distance_on_device = device_grid.width() + device_grid.height();
@@ -1844,13 +1861,126 @@ static inline void place_all_blocks_ap(enum e_pad_loc_type pad_loc_type,
18441861
iter++;
18451862
}
18461863

1864+
if (clusters_to_place.size() > 0) {
1865+
VTR_LOG("Unable to place all clusters.\n");
1866+
VTR_LOG("Clusters left unplaced:\n");
1867+
for (ClusterBlockId blk_id : clusters_to_place) {
1868+
VTR_LOG("\t%s\n", cluster_netlist.block_name(blk_id).c_str());
1869+
}
1870+
}
1871+
18471872
// Check if anything has not been placed, if so just crash for now.
18481873
// TODO: Should fall back on the original initial placer. Unless there is a
18491874
// bug in the code above, it could be that it is challenging to place
18501875
// for this circuit.
18511876
VTR_ASSERT(clusters_to_place.size() == 0);
18521877
}
18531878

1879+
/**
1880+
* @brief Places all blocks in the clustered netlist as close to the global
1881+
* placement produced by the AP flow.
1882+
*
1883+
* This function places the blocks in stages. The goal of this stage-based
1884+
* approach is to place clusters which are challenging to place first. Within
1885+
* each stage, the clusters are ordered based on heuristics such that the most
1886+
* impactful clusters get first dibs on placement.
1887+
*/
1888+
static inline void place_all_blocks_ap(enum e_pad_loc_type pad_loc_type,
1889+
BlkLocRegistry& blk_loc_registry,
1890+
const PlaceMacros& place_macros,
1891+
const FlatPlacementInfo& flat_placement_info) {
1892+
1893+
const ClusteredNetlist& cluster_netlist = g_vpr_ctx.clustering().clb_nlist;
1894+
1895+
// Get a list of clusters to place, sorted based on different heuristics
1896+
// to try to give more important clusters first dibs on the placement.
1897+
std::vector<ClusterBlockId> sorted_cluster_list = get_sorted_clusters_to_place(blk_loc_registry,
1898+
place_macros,
1899+
cluster_netlist,
1900+
flat_placement_info);
1901+
1902+
// 1: Get the constrained clusters and place them first. For now, we place
1903+
// constrained clusters first to prevent other clusters from taking their
1904+
// spot if they are constrained to one and only one site.
1905+
// TODO: This gives clusters with region constraints VIP access to the
1906+
// placement. This may not give the best results. This should be
1907+
// investigated more once region constraints are more supported in the
1908+
// AP flow.
1909+
std::vector<ClusterBlockId> constrained_clusters;
1910+
constrained_clusters.reserve(sorted_cluster_list.size());
1911+
for (ClusterBlockId blk_id : sorted_cluster_list) {
1912+
if (is_cluster_constrained(blk_id))
1913+
constrained_clusters.push_back(blk_id);
1914+
}
1915+
1916+
if (constrained_clusters.size() > 0) {
1917+
VTR_LOG("Placing constrained clusters...\n");
1918+
place_blocks_min_displacement(constrained_clusters,
1919+
pad_loc_type,
1920+
blk_loc_registry,
1921+
place_macros,
1922+
cluster_netlist,
1923+
flat_placement_info);
1924+
VTR_LOG("\n");
1925+
}
1926+
1927+
// 2. Get all of the large macros and place them next. Large macros have a
1928+
// hard time finding a place to go since they take up so much space. They
1929+
// also can have a larger impact on the quality of the placement, so we
1930+
// give them dibs on placement early.
1931+
std::vector<ClusterBlockId> large_macro_clusters;
1932+
large_macro_clusters.reserve(sorted_cluster_list.size());
1933+
for (ClusterBlockId blk_id : sorted_cluster_list) {
1934+
// If this block has been placed, skip it.
1935+
if (is_block_placed(blk_id, blk_loc_registry.block_locs()))
1936+
continue;
1937+
1938+
// Get the size of the macro this block is a part of.
1939+
t_pl_macro pl_macro = get_or_create_macro(blk_id, place_macros);
1940+
size_t macro_size = pl_macro.members.size();
1941+
if (macro_size > 1) {
1942+
// If the size of the macro is larger than 1 (there is more than
1943+
// one cluster in this macro) add to the list.
1944+
large_macro_clusters.push_back(blk_id);
1945+
}
1946+
}
1947+
1948+
if (large_macro_clusters.size() > 0) {
1949+
VTR_LOG("Placing clusters that are part of larger macros...\n");
1950+
place_blocks_min_displacement(large_macro_clusters,
1951+
pad_loc_type,
1952+
blk_loc_registry,
1953+
place_macros,
1954+
cluster_netlist,
1955+
flat_placement_info);
1956+
VTR_LOG("\n");
1957+
}
1958+
1959+
// 3. Place the rest of the clusters. These clusters will be unconstrained
1960+
// and be of small size; so they are more free to fill in the gaps left
1961+
// behind.
1962+
std::vector<ClusterBlockId> clusters_to_place;
1963+
clusters_to_place.reserve(sorted_cluster_list.size());
1964+
for (ClusterBlockId blk_id : sorted_cluster_list) {
1965+
// If this block has been placed, skip it.
1966+
if (is_block_placed(blk_id, blk_loc_registry.block_locs()))
1967+
continue;
1968+
1969+
clusters_to_place.push_back(blk_id);
1970+
}
1971+
1972+
if (clusters_to_place.size() > 0) {
1973+
VTR_LOG("Placing general clusters...\n");
1974+
place_blocks_min_displacement(clusters_to_place,
1975+
pad_loc_type,
1976+
blk_loc_registry,
1977+
place_macros,
1978+
cluster_netlist,
1979+
flat_placement_info);
1980+
VTR_LOG("\n");
1981+
}
1982+
}
1983+
18541984
void initial_placement(const t_placer_opts& placer_opts,
18551985
const char* constraints_file,
18561986
const t_noc_opts& noc_opts,

0 commit comments

Comments
 (0)