Skip to content

Commit

Permalink
Merge pull request #2822 from AlexandreSinger/feature-packer-seed-sel…
Browse files Browse the repository at this point in the history
…ector

[Packer] Created GreedySeedSelector Class
  • Loading branch information
AlexandreSinger authored Nov 22, 2024
2 parents 33c131a + a05e5d5 commit bd4d839
Show file tree
Hide file tree
Showing 5 changed files with 353 additions and 214 deletions.
182 changes: 0 additions & 182 deletions vpr/src/pack/cluster_util.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1523,156 +1523,6 @@ t_molecule_stats calc_molecule_stats(const t_pack_molecule* molecule, const Atom
return molecule_stats;
}

std::vector<AtomBlockId> initialize_seed_atoms(const e_cluster_seed seed_type,
const t_molecule_stats& max_molecule_stats,
const Prepacker& prepacker,
const vtr::vector<AtomBlockId, float>& atom_criticality) {
const AtomNetlist& atom_nlist = g_vpr_ctx.atom().nlist;

//Put all atoms in seed list
std::vector<AtomBlockId> seed_atoms(atom_nlist.blocks().begin(), atom_nlist.blocks().end());

//Initially all gains are zero
vtr::vector<AtomBlockId, float> atom_gains(atom_nlist.blocks().size(), 0.);

if (seed_type == e_cluster_seed::TIMING) {
VTR_ASSERT(atom_gains.size() == atom_criticality.size());

//By criticality
atom_gains = atom_criticality;

} else if (seed_type == e_cluster_seed::MAX_INPUTS) {
//By number of used molecule input pins
for (auto blk : atom_nlist.blocks()) {
const t_pack_molecule* blk_mol = prepacker.get_atom_molecule(blk);
const t_molecule_stats molecule_stats = calc_molecule_stats(blk_mol, atom_nlist);
atom_gains[blk] = molecule_stats.num_used_ext_inputs;
}

} else if (seed_type == e_cluster_seed::BLEND) {
//By blended gain (criticality and inputs used)
for (auto blk : atom_nlist.blocks()) {
/* Score seed gain of each block as a weighted sum of timing criticality,
* number of tightly coupled blocks connected to it, and number of external inputs */
float seed_blend_fac = 0.5;

const t_pack_molecule* blk_mol = prepacker.get_atom_molecule(blk);
const t_molecule_stats molecule_stats = calc_molecule_stats(blk_mol, atom_nlist);
VTR_ASSERT(max_molecule_stats.num_used_ext_inputs > 0);

float blend_gain = (seed_blend_fac * atom_criticality[blk]
+ (1 - seed_blend_fac) * (molecule_stats.num_used_ext_inputs / max_molecule_stats.num_used_ext_inputs));
blend_gain *= (1 + 0.2 * (molecule_stats.num_blocks - 1));
atom_gains[blk] = blend_gain;
}

} else if (seed_type == e_cluster_seed::MAX_PINS || seed_type == e_cluster_seed::MAX_INPUT_PINS) {
//By pins per molecule (i.e. available pins on primitives, not pins in use)

for (auto blk : atom_nlist.blocks()) {
const t_pack_molecule* mol = prepacker.get_atom_molecule(blk);
const t_molecule_stats molecule_stats = calc_molecule_stats(mol, atom_nlist);

int molecule_pins = 0;
if (seed_type == e_cluster_seed::MAX_PINS) {
//All pins
molecule_pins = molecule_stats.num_pins;
} else {
VTR_ASSERT(seed_type == e_cluster_seed::MAX_INPUT_PINS);
//Input pins only
molecule_pins = molecule_stats.num_input_pins;
}

atom_gains[blk] = molecule_pins;
}

} else if (seed_type == e_cluster_seed::BLEND2) {
for (auto blk : atom_nlist.blocks()) {
const t_pack_molecule* mol = prepacker.get_atom_molecule(blk);
const t_molecule_stats molecule_stats = calc_molecule_stats(mol, atom_nlist);

float pin_ratio = vtr::safe_ratio<float>(molecule_stats.num_pins, max_molecule_stats.num_pins);
float input_pin_ratio = vtr::safe_ratio<float>(molecule_stats.num_input_pins, max_molecule_stats.num_input_pins);
float output_pin_ratio = vtr::safe_ratio<float>(molecule_stats.num_output_pins, max_molecule_stats.num_output_pins);
float used_ext_pin_ratio = vtr::safe_ratio<float>(molecule_stats.num_used_ext_pins, max_molecule_stats.num_used_ext_pins);
float used_ext_input_pin_ratio = vtr::safe_ratio<float>(molecule_stats.num_used_ext_inputs, max_molecule_stats.num_used_ext_inputs);
float used_ext_output_pin_ratio = vtr::safe_ratio<float>(molecule_stats.num_used_ext_outputs, max_molecule_stats.num_used_ext_outputs);
float num_blocks_ratio = vtr::safe_ratio<float>(molecule_stats.num_blocks, max_molecule_stats.num_blocks);
float criticality = atom_criticality[blk];

constexpr float PIN_WEIGHT = 0.;
constexpr float INPUT_PIN_WEIGHT = 0.5;
constexpr float OUTPUT_PIN_WEIGHT = 0.;
constexpr float USED_PIN_WEIGHT = 0.;
constexpr float USED_INPUT_PIN_WEIGHT = 0.2;
constexpr float USED_OUTPUT_PIN_WEIGHT = 0.;
constexpr float BLOCKS_WEIGHT = 0.2;
constexpr float CRITICALITY_WEIGHT = 0.1;

float gain = PIN_WEIGHT * pin_ratio
+ INPUT_PIN_WEIGHT * input_pin_ratio
+ OUTPUT_PIN_WEIGHT * output_pin_ratio

+ USED_PIN_WEIGHT * used_ext_pin_ratio
+ USED_INPUT_PIN_WEIGHT * used_ext_input_pin_ratio
+ USED_OUTPUT_PIN_WEIGHT * used_ext_output_pin_ratio

+ BLOCKS_WEIGHT * num_blocks_ratio
+ CRITICALITY_WEIGHT * criticality;

atom_gains[blk] = gain;
}

} else {
VPR_FATAL_ERROR(VPR_ERROR_PACK, "Unrecognized cluster seed type");
}

//Sort seeds in descending order of gain (i.e. highest gain first)
//
// Note that we use a *stable* sort here. It has been observed that different
// standard library implementations (e.g. gcc-4.9 vs gcc-5) use sorting algorithms
// which produce different orderings for seeds of equal gain (which is allowed with
// std::sort which does not specify how equal values are handled). Using a stable
// sort ensures that regardless of the underlying sorting algorithm the same seed
// order is produced regardless of compiler.
auto by_descending_gain = [&](const AtomBlockId lhs, const AtomBlockId rhs) {
return atom_gains[lhs] > atom_gains[rhs];
};
std::stable_sort(seed_atoms.begin(), seed_atoms.end(), by_descending_gain);

if (getEchoEnabled() && isEchoFileEnabled(E_ECHO_CLUSTERING_BLOCK_CRITICALITIES)) {
print_seed_gains(getEchoFileName(E_ECHO_CLUSTERING_BLOCK_CRITICALITIES), seed_atoms, atom_gains, atom_criticality);
}

return seed_atoms;
}

t_pack_molecule* get_highest_gain_seed_molecule(int& seed_index,
const std::vector<AtomBlockId>& seed_atoms,
const Prepacker& prepacker,
const ClusterLegalizer& cluster_legalizer) {
while (seed_index < static_cast<int>(seed_atoms.size())) {
AtomBlockId blk_id = seed_atoms[seed_index++];

// Check if the atom has already been assigned to a cluster
if (!cluster_legalizer.is_atom_clustered(blk_id)) {
t_pack_molecule* best = nullptr;

t_pack_molecule* molecule = prepacker.get_atom_molecule(blk_id);
if (!cluster_legalizer.is_mol_clustered(molecule)) {
if (best == nullptr || (best->base_gain) < (molecule->base_gain)) {
best = molecule;
}
}
VTR_ASSERT(best != nullptr);
return best;
}
}

/*if it makes it to here , there are no more blocks available*/
return nullptr;
}

float get_molecule_gain(t_pack_molecule* molecule, std::map<AtomBlockId, float>& blk_gain, AttractGroupId cluster_attraction_group_id, AttractionInfo& attraction_groups, int num_molecule_failures) {
float gain;
int i;
Expand Down Expand Up @@ -1804,38 +1654,6 @@ std::map<const t_model*, std::vector<t_logical_block_type_ptr>> identify_primiti
return model_candidates;
}

void print_seed_gains(const char* fname, const std::vector<AtomBlockId>& seed_atoms, const vtr::vector<AtomBlockId, float>& atom_gain, const vtr::vector<AtomBlockId, float>& atom_criticality) {
FILE* fp = vtr::fopen(fname, "w");

const AtomContext& atom_ctx = g_vpr_ctx.atom();

//For prett formatting determine the maximum name length
int max_name_len = strlen("atom_block_name");
int max_type_len = strlen("atom_block_type");
for (auto blk_id : atom_ctx.nlist.blocks()) {
max_name_len = std::max(max_name_len, (int)atom_ctx.nlist.block_name(blk_id).size());

const t_model* model = atom_ctx.nlist.block_model(blk_id);
max_type_len = std::max(max_type_len, (int)strlen(model->name));
}

fprintf(fp, "%-*s %-*s %8s %8s\n", max_name_len, "atom_block_name", max_type_len, "atom_block_type", "gain", "criticality");
fprintf(fp, "\n");
for (auto blk_id : seed_atoms) {
std::string name = atom_ctx.nlist.block_name(blk_id);
fprintf(fp, "%-*s ", max_name_len, name.c_str());

const t_model* model = atom_ctx.nlist.block_model(blk_id);
fprintf(fp, "%-*s ", max_type_len, model->name);

fprintf(fp, "%*f ", std::max((int)strlen("gain"), 8), atom_gain[blk_id]);
fprintf(fp, "%*f ", std::max((int)strlen("criticality"), 8), atom_criticality[blk_id]);
fprintf(fp, "\n");
}

fclose(fp);
}

size_t update_pb_type_count(const t_pb* pb, std::map<t_pb_type*, int>& pb_type_count, size_t depth) {
size_t max_depth = depth;

Expand Down
12 changes: 0 additions & 12 deletions vpr/src/pack/cluster_util.h
Original file line number Diff line number Diff line change
Expand Up @@ -428,16 +428,6 @@ t_pack_molecule* get_molecule_for_cluster(t_pb* cur_pb,
*/
t_molecule_stats calc_molecule_stats(const t_pack_molecule* molecule, const AtomNetlist& atom_nlist);

std::vector<AtomBlockId> initialize_seed_atoms(const e_cluster_seed seed_type,
const t_molecule_stats& max_molecule_stats,
const Prepacker& prepacker,
const vtr::vector<AtomBlockId, float>& atom_criticality);

t_pack_molecule* get_highest_gain_seed_molecule(int& seed_index,
const std::vector<AtomBlockId>& seed_atoms,
const Prepacker& prepacker,
const ClusterLegalizer& cluster_legalizer);

/*
* @brief Get gain of packing molecule into current cluster.
*
Expand All @@ -448,8 +438,6 @@ t_pack_molecule* get_highest_gain_seed_molecule(int& seed_index,
*/
float get_molecule_gain(t_pack_molecule* molecule, std::map<AtomBlockId, float>& blk_gain, AttractGroupId cluster_attraction_group_id, AttractionInfo& attraction_groups, int num_molecule_failures);

void print_seed_gains(const char* fname, const std::vector<AtomBlockId>& seed_atoms, const vtr::vector<AtomBlockId, float>& atom_gain, const vtr::vector<AtomBlockId, float>& atom_criticality);

/**
* @brief Score unclustered atoms that are two hops away from current cluster
*
Expand Down
35 changes: 15 additions & 20 deletions vpr/src/pack/greedy_clusterer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,16 @@

#include "greedy_clusterer.h"
#include <map>
#include <vector>
#include "atom_netlist.h"
#include "attraction_groups.h"
#include "cluster_legalizer.h"
#include "cluster_util.h"
#include "constraints_report.h"
#include "greedy_seed_selector.h"
#include "physical_types.h"
#include "prepack.h"
#include "vtr_vector.h"

GreedyClusterer::GreedyClusterer(const t_packer_opts& packer_opts,
const t_analysis_opts& analysis_opts,
Expand Down Expand Up @@ -106,7 +109,7 @@ GreedyClusterer::do_clustering(ClusterLegalizer& cluster_legalizer,

enum e_block_pack_status block_pack_status;

t_pack_molecule *istart, *next_molecule, *prev_molecule;
t_pack_molecule *next_molecule, *prev_molecule;

auto& device_ctx = g_vpr_ctx.mutable_device();

Expand All @@ -130,8 +133,6 @@ GreedyClusterer::do_clustering(ClusterLegalizer& cluster_legalizer,
* (eg. [A1, A2, ..]->[B1, B2, ..]->C implies cluster [A1, A2, ...] and C have a weak link) */
vtr::vector<LegalizationClusterId, std::vector<AtomNetId>> clb_inter_blk_nets(atom_netlist_.blocks().size());

istart = nullptr;

const t_molecule_stats max_molecule_stats = prepacker.calc_max_molecule_stats(atom_netlist_);

cluster_stats.num_molecules = prepacker.get_num_molecules();
Expand Down Expand Up @@ -170,18 +171,16 @@ GreedyClusterer::do_clustering(ClusterLegalizer& cluster_legalizer,
clustering_delay_calc, timing_info, atom_criticality);
}

// Assign gain scores to atoms and sort them based on the scores.
auto seed_atoms = initialize_seed_atoms(packer_opts_.cluster_seed_type,
max_molecule_stats,
prepacker,
atom_criticality);
// Create the greedy seed selector.
GreedySeedSelector seed_selector(atom_netlist_,
prepacker,
packer_opts_.cluster_seed_type,
max_molecule_stats,
atom_criticality);

/* index of next most timing critical block */
int seed_index = 0;
istart = get_highest_gain_seed_molecule(seed_index,
seed_atoms,
prepacker,
cluster_legalizer);
// Pick the first seed molecule.
t_pack_molecule* istart = seed_selector.get_next_seed(prepacker,
cluster_legalizer);

print_pack_status_header();

Expand All @@ -191,7 +190,6 @@ GreedyClusterer::do_clustering(ClusterLegalizer& cluster_legalizer,

while (istart != nullptr) {
bool is_cluster_legal = false;
int saved_seed_index = seed_index;
// The basic algorithm:
// 1) Try to put all the molecules in that you can without doing the
// full intra-lb route. Then do full legalization at the end.
Expand Down Expand Up @@ -333,10 +331,8 @@ GreedyClusterer::do_clustering(ClusterLegalizer& cluster_legalizer,

if (is_cluster_legal) {
// Pick new seed.
istart = get_highest_gain_seed_molecule(seed_index,
seed_atoms,
prepacker,
cluster_legalizer);
istart = seed_selector.get_next_seed(prepacker,
cluster_legalizer);
// Update cluster stats.
if (packer_opts_.timing_driven && num_blocks_hill_added > 0)
cluster_stats.blocks_since_last_analysis += num_blocks_hill_added;
Expand All @@ -350,7 +346,6 @@ GreedyClusterer::do_clustering(ClusterLegalizer& cluster_legalizer,
// If the cluster is not legal, requeue used mols.
num_used_type_instances[cluster_legalizer.get_cluster_type(legalization_cluster_id)]--;
total_clb_num--;
seed_index = saved_seed_index;
// Destroy the illegal cluster.
cluster_legalizer.destroy_cluster(legalization_cluster_id);
cluster_legalizer.compress();
Expand Down
Loading

0 comments on commit bd4d839

Please sign in to comment.