Skip to content
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

Initial NoC Placement #2421

Merged
merged 41 commits into from
Jan 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
b77eecd
Simple annealer for NoC routers in initial placement.
soheilshahrouz Jun 19, 2023
f27c9dc
Clarify the description for propose_router_swap().
soheilshahrouz Jun 19, 2023
a4ef7a3
Look for an empty location in find_compatible_compressed_loc_in_range().
soheilshahrouz Jun 19, 2023
ade86b5
Add router swap proposal based on the flow centroid.
soheilshahrouz Jun 20, 2023
c11000e
Clean the code for initial router placement.
soheilshahrouz Jun 20, 2023
afc7e4e
Add RouterPlacementCheckpoint to store initial router placement check…
soheilshahrouz Jun 26, 2023
a91abe2
Solve non-decreasing NoC cost in initial placemennt
soheilshahrouz Jun 26, 2023
845e041
Re-initialize NoC-related costs when a checkpoint is restored.
soheilshahrouz Jun 27, 2023
f35b940
Place constrained routers in their region
soheilshahrouz Jun 27, 2023
da483b9
Moved RouterPlacementCheckpoint to a separate file. Used const refere…
soheilshahrouz Jun 27, 2023
aea8221
Call NoC-related functions only when NoC is enabled.
soheilshahrouz Jun 29, 2023
49ef3c3
Cherry-picked packing changes.
soheilshahrouz Jul 10, 2023
824b6b6
Add prototypes and comments for functions related to initial NoC plac…
soheilshahrouz Jul 10, 2023
1547c0c
Change the condition for restoring a placement checkpoint.
soheilshahrouz Jul 10, 2023
2597853
Avoid using constant and very high fanout (the same order as clock) n…
soheilshahrouz Jul 11, 2023
192151b
Disable high fanout connectivity in the first packing attempt.
soheilshahrouz Jul 14, 2023
a71ade5
Merge branch 'master' into init_noc_sa
soheilshahrouz Jul 30, 2023
cfe5151
Removed initial temperature boosting for NoC designs. Removed print_n…
soheilshahrouz Jul 30, 2023
c9cc32d
make format
soheilshahrouz Aug 7, 2023
634d852
Temporarily consider constant nets for clustering.
soheilshahrouz Aug 11, 2023
f715a53
cherry-picked some packing updates from noc congestion branch
soheilshahrouz Aug 18, 2023
7feda70
fixed out of range NoCRouterId bug in link removal test
soheilshahrouz Aug 23, 2023
3db9060
Merge branch 'master' into init_noc_sa
soheilshahrouz Aug 24, 2023
a31fe80
don't consider constant net candidates when NoC is enabled
soheilshahrouz Aug 24, 2023
ea9f5be
temporarily don't check emptiness
soheilshahrouz Aug 25, 2023
8f3b2fa
Revert "temporarily don't check emptiness"
soheilshahrouz Aug 30, 2023
355ba50
make format
soheilshahrouz Aug 30, 2023
7295447
weigh sink block locations in centroid calculation
soheilshahrouz Aug 30, 2023
a1188ce
Revert "weigh sink block locations in centroid calculation"
soheilshahrouz Oct 19, 2023
2b21f1c
Merge branch 'master' into init_noc_sa
soheilshahrouz Oct 21, 2023
e4ff934
Disable high fanout connectivity clustering for logic blocks
soheilshahrouz Oct 21, 2023
375db58
Reverted packing optimizations for NoC benchmarks
soheilshahrouz Nov 7, 2023
39c80f8
Reverted LOGIC_BLOCK_TYPE_HIGH_FANOUT_THRESHOLD value to 32.
soheilshahrouz Nov 9, 2023
d2d3904
Don't look for empty locs in init placement
soheilshahrouz Nov 10, 2023
81224e3
Applied the comments.
soheilshahrouz Nov 10, 2023
4439184
make format
soheilshahrouz Nov 11, 2023
67f55f0
set search_for_empty to false.
soheilshahrouz Nov 11, 2023
7e5ad48
Merge branch 'master' into init_noc_sa
soheilshahrouz Nov 13, 2023
12b681a
updated the default value for --noc_swap_percentage option
soheilshahrouz Nov 13, 2023
0617bae
Merge branch 'master' into init_noc_sa
vaughnbetz Dec 4, 2023
4357180
Merge branch 'master' into init_noc_sa
soheilshahrouz Dec 6, 2023
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
2 changes: 1 addition & 1 deletion vpr/src/base/read_options.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2823,7 +2823,7 @@ argparse::ArgumentParser create_arg_parser(std::string prog_name, t_options& arg
.help(
"Sets the minimum fraction of swaps attempted by the placer that are NoC blocks."
"This value is an integer ranging from 0-100. 0 means NoC blocks will be moved at the same rate as other blocks. 100 means all swaps attempted by the placer are NoC router blocks.")
.default_value("40")
.default_value("0")
.show_in(argparse::ShowIn::HELP_ONLY);

noc_grp.add_argument<std::string>(args.noc_placement_file_name, "--noc_placement_file_name")
Expand Down
5 changes: 5 additions & 0 deletions vpr/src/base/vpr_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,11 @@ struct ClusteringHelperContext : public Context {
// the utilization of external input/output pins during packing (between 0 and 1)
t_ext_pin_util_targets target_external_pin_util;

// During clustering, a block is related to un-clustered primitives with nets.
// This relation has three types: low fanout, high fanout, and trasitive
// high_fanout_thresholds stores the threshold for nets to a block type to be considered high fanout
t_pack_high_fanout_thresholds high_fanout_thresholds;

// A vector of unordered_sets of AtomBlockIds that are inside each clustered block [0 .. num_clustered_blocks-1]
// unordered_set for faster insertion/deletion during the iterative improvement process of packing
vtr::vector<ClusterBlockId, std::unordered_set<AtomBlockId>> atoms_lookup;
Expand Down
245 changes: 241 additions & 4 deletions vpr/src/base/vpr_types.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,154 @@ t_ext_pin_util_targets::t_ext_pin_util_targets(float default_in_util, float defa
defaults_.output_pin_util = default_out_util;
}

t_ext_pin_util t_ext_pin_util_targets::get_pin_util(std::string block_type_name) const {
t_ext_pin_util_targets::t_ext_pin_util_targets(const std::vector<std::string>& specs)
: t_ext_pin_util_targets(1., 1.) {
if (specs.size() == 1 && specs[0] == "auto") {
//No user-specified pin utilizations, infer them automatically.
//
//We set a pin utilization target based on the block type, with
//the logic block having a lower utilization target and other blocks
//(e.g. hard blocks) having no limit.

auto& device_ctx = g_vpr_ctx.device();
auto& grid = device_ctx.grid;
t_logical_block_type_ptr logic_block_type = infer_logic_block_type(grid);

//Allowing 100% pin utilization of the logic block type can harm
//routability, since it may allow a few (typically outlier) clusters to
//use a very large number of pins -- causing routability issues. These
//clusters can cause failed routings where only a handful of routing
//resource nodes remain overused (and do not resolve) These can be
//avoided by putting a (soft) limit on the number of input pins which
//can be used, effectively clipping off the most egregeous outliers.
//
//Experiments show that limiting input utilization produces better quality
//than limiting output utilization (limiting input utilization implicitly
//also limits output utilization).
//
//For relatively high pin utilizations (e.g. > 70%) this has little-to-no
//impact on the number of clusters required. As a result we set a default
//input pin utilization target which is high, but less than 100%.
if (logic_block_type != nullptr) {
constexpr float LOGIC_BLOCK_TYPE_AUTO_INPUT_UTIL = 0.8;
constexpr float LOGIC_BLOCK_TYPE_AUTO_OUTPUT_UTIL = 1.0;

t_ext_pin_util logic_block_ext_pin_util(LOGIC_BLOCK_TYPE_AUTO_INPUT_UTIL, LOGIC_BLOCK_TYPE_AUTO_OUTPUT_UTIL);

set_block_pin_util(logic_block_type->name, logic_block_ext_pin_util);
} else {
VTR_LOG_WARN("Unable to identify logic block type to apply default pin utilization targets to; this may result in denser packing than desired\n");
}

} else {
//Process user specified overrides

bool default_set = false;
std::set<std::string> seen_block_types;

for (const auto& spec : specs) {
t_ext_pin_util target_ext_pin_util(1., 1.);

auto block_values = vtr::split(spec, ":");
std::string block_type;
std::string values;
if (block_values.size() == 2) {
block_type = block_values[0];
values = block_values[1];
} else if (block_values.size() == 1) {
values = block_values[0];
} else {
std::stringstream msg;
msg << "In valid block pin utilization specification '" << spec << "' (expected at most one ':' between block name and values";
VPR_FATAL_ERROR(VPR_ERROR_PACK, msg.str().c_str());
}

auto elements = vtr::split(values, ",");
if (elements.size() == 1) {
target_ext_pin_util.input_pin_util = vtr::atof(elements[0]);
} else if (elements.size() == 2) {
target_ext_pin_util.input_pin_util = vtr::atof(elements[0]);
target_ext_pin_util.output_pin_util = vtr::atof(elements[1]);
} else {
std::stringstream msg;
msg << "Invalid conversion from '" << spec << "' to external pin util (expected either a single float value, or two float values separted by a comma)";
VPR_FATAL_ERROR(VPR_ERROR_PACK, msg.str().c_str());
}

if (target_ext_pin_util.input_pin_util < 0. || target_ext_pin_util.input_pin_util > 1.) {
std::stringstream msg;
msg << "Out of range target input pin utilization '" << target_ext_pin_util.input_pin_util << "' (expected within range [0.0, 1.0])";
VPR_FATAL_ERROR(VPR_ERROR_PACK, msg.str().c_str());
}
if (target_ext_pin_util.output_pin_util < 0. || target_ext_pin_util.output_pin_util > 1.) {
std::stringstream msg;
msg << "Out of range target output pin utilization '" << target_ext_pin_util.output_pin_util << "' (expected within range [0.0, 1.0])";
VPR_FATAL_ERROR(VPR_ERROR_PACK, msg.str().c_str());
}

if (block_type.empty()) {
//Default value
if (default_set) {
std::stringstream msg;
msg << "Only one default pin utilization should be specified";
VPR_FATAL_ERROR(VPR_ERROR_PACK, msg.str().c_str());
}
set_default_pin_util(target_ext_pin_util);
default_set = true;
} else {
if (seen_block_types.count(block_type)) {
std::stringstream msg;
msg << "Only one pin utilization should be specified for block type '" << block_type << "'";
VPR_FATAL_ERROR(VPR_ERROR_PACK, msg.str().c_str());
}

set_block_pin_util(block_type, target_ext_pin_util);
seen_block_types.insert(block_type);
}
}
}
}

t_ext_pin_util_targets& t_ext_pin_util_targets::operator=(t_ext_pin_util_targets&& other) noexcept {
if (this != &other) {
defaults_ = std::move(other.defaults_);
overrides_ = std::move(other.overrides_);
}
return *this;
}

t_ext_pin_util t_ext_pin_util_targets::get_pin_util(const std::string& block_type_name) const {
auto itr = overrides_.find(block_type_name);
if (itr != overrides_.end()) {
return itr->second;
}
return defaults_;
}

void t_ext_pin_util_targets::set_block_pin_util(std::string block_type_name, t_ext_pin_util target) {
std::string t_ext_pin_util_targets::to_string() const {
std::stringstream ss;

auto& device_ctx = g_vpr_ctx.device();

for (unsigned int itype = 0; itype < device_ctx.physical_tile_types.size(); ++itype) {
if (is_empty_type(&device_ctx.physical_tile_types[itype])) continue;

auto blk_name = device_ctx.physical_tile_types[itype].name;

ss << blk_name << ":";

auto pin_util = get_pin_util(blk_name);
ss << pin_util.input_pin_util << ',' << pin_util.output_pin_util;

if (itype != device_ctx.physical_tile_types.size() - 1) {
ss << " ";
}
}

return ss.str();
}

void t_ext_pin_util_targets::set_block_pin_util(const std::string& block_type_name, t_ext_pin_util target) {
overrides_[block_type_name] = target;
}

Expand All @@ -26,22 +165,120 @@ void t_ext_pin_util_targets::set_default_pin_util(t_ext_pin_util default_target)
t_pack_high_fanout_thresholds::t_pack_high_fanout_thresholds(int threshold)
: default_(threshold) {}

t_pack_high_fanout_thresholds::t_pack_high_fanout_thresholds(const std::vector<std::string>& specs)
: t_pack_high_fanout_thresholds(128) {
if (specs.size() == 1 && specs[0] == "auto") {
//No user-specified high fanout thresholds, infer them automatically.
//
//We set the high fanout threshold a based on the block type, with
//the logic block having a lower threshold than other blocks.
//(Since logic blocks are the ones which tend to be too densely
//clustered.)

auto& device_ctx = g_vpr_ctx.device();
auto& grid = device_ctx.grid;
t_logical_block_type_ptr logic_block_type = infer_logic_block_type(grid);

if (logic_block_type != nullptr) {
constexpr float LOGIC_BLOCK_TYPE_HIGH_FANOUT_THRESHOLD = 32;

set(logic_block_type->name, LOGIC_BLOCK_TYPE_HIGH_FANOUT_THRESHOLD);
} else {
VTR_LOG_WARN("Unable to identify logic block type to apply default packer high fanout thresholds; this may result in denser packing than desired\n");
}
} else {
//Process user specified overrides

bool default_set = false;
std::set<std::string> seen_block_types;

for (const auto& spec : specs) {
auto block_values = vtr::split(spec, ":");
std::string block_type;
std::string value;
if (block_values.size() == 1) {
value = block_values[0];
} else if (block_values.size() == 2) {
block_type = block_values[0];
value = block_values[1];
} else {
std::stringstream msg;
msg << "In valid block high fanout threshold specification '" << spec << "' (expected at most one ':' between block name and value";
VPR_FATAL_ERROR(VPR_ERROR_PACK, msg.str().c_str());
}

int threshold = vtr::atoi(value);

if (block_type.empty()) {
//Default value
if (default_set) {
std::stringstream msg;
msg << "Only one default high fanout threshold should be specified";
VPR_FATAL_ERROR(VPR_ERROR_PACK, msg.str().c_str());
}
set_default(threshold);
default_set = true;
} else {
if (seen_block_types.count(block_type)) {
std::stringstream msg;
msg << "Only one high fanout threshold should be specified for block type '" << block_type << "'";
VPR_FATAL_ERROR(VPR_ERROR_PACK, msg.str().c_str());
}

set(block_type, threshold);
seen_block_types.insert(block_type);
}
}
}
}

t_pack_high_fanout_thresholds& t_pack_high_fanout_thresholds::operator=(t_pack_high_fanout_thresholds&& other) noexcept {
if (this != &other) {
default_ = std::move(other.default_);
overrides_ = std::move(other.overrides_);
}
return *this;
}

void t_pack_high_fanout_thresholds::set_default(int threshold) {
default_ = threshold;
}

void t_pack_high_fanout_thresholds::set(std::string block_type_name, int threshold) {
void t_pack_high_fanout_thresholds::set(const std::string& block_type_name, int threshold) {
overrides_[block_type_name] = threshold;
}

int t_pack_high_fanout_thresholds::get_threshold(std::string block_type_name) const {
int t_pack_high_fanout_thresholds::get_threshold(const std::string& block_type_name) const {
auto itr = overrides_.find(block_type_name);
if (itr != overrides_.end()) {
return itr->second;
}
return default_;
}

std::string t_pack_high_fanout_thresholds::to_string() const {
std::stringstream ss;

auto& device_ctx = g_vpr_ctx.device();

for (unsigned int itype = 0; itype < device_ctx.physical_tile_types.size(); ++itype) {
if (is_empty_type(&device_ctx.physical_tile_types[itype])) continue;

auto blk_name = device_ctx.physical_tile_types[itype].name;

ss << blk_name << ":";

auto threshold = get_threshold(blk_name);
ss << threshold;

if (itype != device_ctx.physical_tile_types.size() - 1) {
ss << " ";
}
}

return ss.str();
}

/*
* t_pb structure function definitions
*/
Expand Down
26 changes: 21 additions & 5 deletions vpr/src/base/vpr_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -194,16 +194,21 @@ class t_ext_pin_util_targets {
public:
t_ext_pin_util_targets() = default;
t_ext_pin_util_targets(float default_in_util, float default_out_util);
t_ext_pin_util_targets(const std::vector<std::string>& specs);
t_ext_pin_util_targets& operator=(t_ext_pin_util_targets&& other) noexcept;

///@brief Returns the input pin util of the specified block (or default if unspecified)
t_ext_pin_util get_pin_util(std::string block_type_name) const;
t_ext_pin_util get_pin_util(const std::string& block_type_name) const;

///@brief Returns a string describing input/output pin utilization targets
std::string to_string() const;

public:
/**
* @brief Sets the pin util for the specified block type
* @return true if non-default was previously set
*/
void set_block_pin_util(std::string block_type_name, t_ext_pin_util target);
void set_block_pin_util(const std::string& block_type_name, t_ext_pin_util target);

/**
* @brief Sets the default pin util
Expand All @@ -219,16 +224,22 @@ class t_ext_pin_util_targets {
class t_pack_high_fanout_thresholds {
public:
t_pack_high_fanout_thresholds() = default;
t_pack_high_fanout_thresholds(int threshold);
explicit t_pack_high_fanout_thresholds(int threshold);
explicit t_pack_high_fanout_thresholds(const std::vector<std::string>& specs);
t_pack_high_fanout_thresholds& operator=(t_pack_high_fanout_thresholds&& other) noexcept;

///@brief Returns the high fanout threshold of the specifi ed block
int get_threshold(const std::string& block_type_name) const;
Copy link
Contributor

Choose a reason for hiding this comment

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

Think about whether you should have these two packing classes in vpr_types.h, or if you should move them into a packing header (could be a new one).

Copy link
Contributor

Choose a reason for hiding this comment

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

It sounds like these should go in an existing or a new packing_utility.h or some such.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Both high fanout threshold and target pin utilization are commang line arguements that impact the packing stage. I think if we move these two classes two a separate file, we also need to move other packing data types like e_balance_block_type_util and e_unrelated_clustering to the same file. What is your view on this?


int get_threshold(std::string block_type_name) const;
///@brief Returns a string describing high fanout thresholds for different block types
std::string to_string() const;

public:
/**
* @brief Sets the pin util for the specified block type
* @return true if non-default was previously set
*/
void set(std::string block_type_name, int threshold);
void set(const std::string& block_type_name, int threshold);

/**
* @brief Sets the default pin util
Expand Down Expand Up @@ -723,6 +734,11 @@ struct t_pl_loc {
, y(yloc)
, sub_tile(sub_tile_loc)
, layer(layer_num) {}
t_pl_loc(const t_physical_tile_loc& phy_loc, int sub_tile_loc)
Copy link
Contributor

Choose a reason for hiding this comment

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

Add a brief comment for the constructors (can just say various constructors)

: x(phy_loc.x)
, y(phy_loc.y)
, sub_tile(sub_tile_loc)
, layer(phy_loc.layer_num) {}

int x = OPEN;
int y = OPEN;
Expand Down
9 changes: 9 additions & 0 deletions vpr/src/noc/noc_router.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,15 @@ int NocRouter::get_router_layer_position(void) const {
return router_layer_position;
}

t_physical_tile_loc NocRouter::get_router_physical_location(void) const {
const int x = get_router_grid_position_x();
const int y = get_router_grid_position_y();
const int layer = get_router_layer_position();
t_physical_tile_loc phy_loc{x, y, layer};

return phy_loc;
}

ClusterBlockId NocRouter::get_router_block_ref(void) const {
return router_block_ref;
}
Expand Down
6 changes: 6 additions & 0 deletions vpr/src/noc/noc_router.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,12 @@ class NocRouter {
*/
int get_router_layer_position(void) const;

/**
* @brief Gets the physical location where the the physical router is located
* @return t_physical_tile_loc that contains x-y coordinates and the layer number
*/
t_physical_tile_loc get_router_physical_location(void) const;

/**
* @brief Gets the unique id of the router block that is current placed on the physical router
* @return A ClusterBlockId that identifies a router block in the clustered netlist
Expand Down
Loading
Loading