-
Notifications
You must be signed in to change notification settings - Fork 415
Add PlacerSetupSlacks interface #1450
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
Changes from 15 commits
f4ea4a1
c024603
cb6e9a6
63db2e1
aa7b233
e8f73c6
d80de58
831df44
d329911
225870e
9056301
0e01ed7
2e212dc
96e65ba
112bde5
29b55a3
da55abf
92c416a
870eca6
a2685c7
cc4488e
38f25cc
74d279c
9f18666
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -14,8 +14,9 @@ | |
|
||
#include "timing_info.h" | ||
|
||
//Use an incremental approach to updaing criticalities? | ||
//Use an incremental approach to updating criticalities and setup slacks? | ||
constexpr bool INCR_UPDATE_CRITICALITIES = true; | ||
constexpr bool INCR_UPDATE_SETUP_SLACKS = true; | ||
|
||
/**************************************/ | ||
|
||
|
@@ -27,58 +28,29 @@ PlacerCriticalities::PlacerCriticalities(const ClusteredNetlist& clb_nlist, cons | |
, timing_place_crit_(make_net_pins_matrix(clb_nlist_, std::numeric_limits<float>::quiet_NaN())) { | ||
} | ||
|
||
/**************************************/ | ||
void PlacerCriticalities::update_criticalities(const SetupTimingInfo* timing_info, float crit_exponent) { | ||
/* Performs a 1-to-1 mapping from criticality to timing_place_crit_. | ||
* For every pin on every net (or, equivalently, for every tedge ending | ||
* in that pin), timing_place_crit_ = criticality^(criticality exponent) */ | ||
void PlacerCriticalities::update_criticalities(const SetupTimingInfo* timing_info, float crit_exponent, bool recompute) { | ||
//If the criticalities are not updated immediately after each time we call | ||
//timing_info->update(), then timing_info->pins_with_modified_setup_criticality() | ||
//cannot accurately account for all the pins that need to be updated. | ||
//In this case, we pass in recompute=true to update all criticalities from scratch. | ||
// | ||
//If the criticality exponent has changed, we also need to update from scratch. | ||
|
||
//Determine what pins need updating | ||
if (INCR_UPDATE_CRITICALITIES) { | ||
cluster_pins_with_modified_criticality_.clear(); | ||
if (crit_exponent != last_crit_exponent_) { | ||
//Criticality exponent changed, must re-calculate criticalities for *all* sink pins | ||
for (ClusterNetId net_id : clb_nlist_.nets()) { | ||
for (ClusterPinId pin_id : clb_nlist_.net_sinks(net_id)) { | ||
cluster_pins_with_modified_criticality_.insert(pin_id); | ||
} | ||
} | ||
|
||
//Record new criticality exponent | ||
last_crit_exponent_ = crit_exponent; | ||
} else { | ||
//Criticality exponent unchanged | ||
// | ||
//Collect the cluster pins which need to be updated based on the latest timing | ||
//analysis | ||
// | ||
//Note we use the set of pins reported by the *timing_info* as having modified | ||
//criticality, rather than those marked as modified by the timing analyzer. | ||
//Since timing_info uses shifted/relaxed criticality (which depends on max | ||
//required time and worst case slacks), additional nodes may be modified | ||
//when updating the atom pin criticalities. | ||
|
||
for (AtomPinId atom_pin : timing_info->pins_with_modified_setup_criticality()) { | ||
ClusterPinId clb_pin = pin_lookup_.connected_clb_pin(atom_pin); | ||
|
||
//Some atom pins correspond to connections which are completely | ||
//contained within a cluster, and hence have no corresponding | ||
//clustered pin. | ||
if (!clb_pin) continue; | ||
|
||
cluster_pins_with_modified_criticality_.insert(clb_pin); | ||
} | ||
} | ||
if (!recompute && crit_exponent == last_crit_exponent_ && INCR_UPDATE_CRITICALITIES) { | ||
incr_update_criticalities(timing_info); | ||
} else { | ||
//Non-incremental: all pins and nets need updating | ||
for (ClusterNetId net_id : clb_nlist_.nets()) { | ||
for (ClusterPinId pin_id : clb_nlist_.net_sinks(net_id)) { | ||
cluster_pins_with_modified_criticality_.insert(pin_id); | ||
} | ||
} | ||
recompute_criticalities(); | ||
|
||
//Record new criticality exponent | ||
last_crit_exponent_ = crit_exponent; | ||
} | ||
|
||
//Update the effected pins | ||
/* Performs a 1-to-1 mapping from criticality to timing_place_crit_. | ||
* For every pin on every net (or, equivalently, for every tedge ending | ||
* in that pin), timing_place_crit_ = criticality^(criticality exponent) */ | ||
|
||
// Update the effected pins | ||
for (ClusterPinId clb_pin : cluster_pins_with_modified_criticality_) { | ||
ClusterNetId clb_net = clb_nlist_.pin_net(clb_pin); | ||
int pin_index_in_net = clb_nlist_.pin_net_index(clb_pin); | ||
|
@@ -92,6 +64,41 @@ void PlacerCriticalities::update_criticalities(const SetupTimingInfo* timing_inf | |
} | ||
} | ||
|
||
void PlacerCriticalities::incr_update_criticalities(const SetupTimingInfo* timing_info) { | ||
cluster_pins_with_modified_criticality_.clear(); | ||
|
||
//Collect the cluster pins which need to be updated based on the latest timing | ||
//analysis | ||
// | ||
//Note we use the set of pins reported by the *timing_info* as having modified | ||
//criticality, rather than those marked as modified by the timing analyzer. | ||
//Since timing_info uses shifted/relaxed criticality (which depends on max | ||
//required time and worst case slacks), additional nodes may be modified | ||
//when updating the atom pin criticalities. | ||
|
||
for (AtomPinId atom_pin : timing_info->pins_with_modified_setup_criticality()) { | ||
ClusterPinId clb_pin = pin_lookup_.connected_clb_pin(atom_pin); | ||
|
||
//Some atom pins correspond to connections which are completely | ||
//contained within a cluster, and hence have no corresponding | ||
//clustered pin. | ||
if (!clb_pin) continue; | ||
|
||
cluster_pins_with_modified_criticality_.insert(clb_pin); | ||
} | ||
} | ||
|
||
void PlacerCriticalities::recompute_criticalities() { | ||
cluster_pins_with_modified_criticality_.clear(); | ||
|
||
//Non-incremental: all sink pins need updating | ||
for (ClusterNetId net_id : clb_nlist_.nets()) { | ||
for (ClusterPinId pin_id : clb_nlist_.net_sinks(net_id)) { | ||
cluster_pins_with_modified_criticality_.insert(pin_id); | ||
} | ||
} | ||
} | ||
|
||
void PlacerCriticalities::set_criticality(ClusterNetId net_id, int ipin, float val) { | ||
timing_place_crit_[net_id][ipin] = val; | ||
} | ||
|
@@ -100,6 +107,77 @@ PlacerCriticalities::pin_range PlacerCriticalities::pins_with_modified_criticali | |
return vtr::make_range(cluster_pins_with_modified_criticality_); | ||
} | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are some of these routines rewrites / replacements for routines in place.cpp? I haven't checked line by line but some seem similar. |
||
/**************************************/ | ||
|
||
/* Allocates space for the timing_place_setup_slacks_ data structure */ | ||
PlacerSetupSlacks::PlacerSetupSlacks(const ClusteredNetlist& clb_nlist, const ClusteredPinAtomPinsLookup& netlist_pin_lookup) | ||
: clb_nlist_(clb_nlist) | ||
, pin_lookup_(netlist_pin_lookup) | ||
, timing_place_setup_slacks_(make_net_pins_matrix(clb_nlist_, std::numeric_limits<float>::quiet_NaN())) { | ||
} | ||
|
||
void PlacerSetupSlacks::update_setup_slacks(const SetupTimingInfo* timing_info, bool recompute) { | ||
//If the setup slacks are not updated immediately after each time we call | ||
//timing_info->update(), then timing_info->pins_with_modified_setup_slack() | ||
//cannot accurately account for all the pins that need to be updated. | ||
//In this case, we pass in recompute=true to update all setup slacks from scratch. | ||
if (!recompute && INCR_UPDATE_SETUP_SLACKS) { | ||
incr_update_setup_slacks(timing_info); | ||
} else { | ||
recompute_setup_slacks(); | ||
} | ||
|
||
//Update the effected pins | ||
for (ClusterPinId clb_pin : cluster_pins_with_modified_setup_slack_) { | ||
ClusterNetId clb_net = clb_nlist_.pin_net(clb_pin); | ||
int pin_index_in_net = clb_nlist_.pin_net_index(clb_pin); | ||
|
||
float clb_pin_setup_slack = calculate_clb_net_pin_setup_slack(*timing_info, pin_lookup_, clb_pin); | ||
|
||
timing_place_setup_slacks_[clb_net][pin_index_in_net] = clb_pin_setup_slack; | ||
} | ||
} | ||
|
||
void PlacerSetupSlacks::incr_update_setup_slacks(const SetupTimingInfo* timing_info) { | ||
cluster_pins_with_modified_setup_slack_.clear(); | ||
|
||
//Collect the cluster pins which need to be updated based on the latest timing analysis | ||
// | ||
//Note we use the set of pins reported by the *timing_info* as having modified | ||
//setup slacks, rather than those marked as modified by the timing analyzer. | ||
for (AtomPinId atom_pin : timing_info->pins_with_modified_setup_slack()) { | ||
ClusterPinId clb_pin = pin_lookup_.connected_clb_pin(atom_pin); | ||
|
||
//Some atom pins correspond to connections which are completely | ||
//contained within a cluster, and hence have no corresponding | ||
//clustered pin. | ||
if (!clb_pin) continue; | ||
|
||
cluster_pins_with_modified_setup_slack_.insert(clb_pin); | ||
} | ||
} | ||
|
||
void PlacerSetupSlacks::recompute_setup_slacks() { | ||
cluster_pins_with_modified_setup_slack_.clear(); | ||
|
||
//Non-incremental: all sink pins need updating | ||
for (ClusterNetId net_id : clb_nlist_.nets()) { | ||
for (ClusterPinId pin_id : clb_nlist_.net_sinks(net_id)) { | ||
cluster_pins_with_modified_setup_slack_.insert(pin_id); | ||
} | ||
} | ||
} | ||
|
||
void PlacerSetupSlacks::set_setup_slack(ClusterNetId net_id, int ipin, float val) { | ||
timing_place_setup_slacks_[net_id][ipin] = val; | ||
} | ||
|
||
PlacerSetupSlacks::pin_range PlacerSetupSlacks::pins_with_modified_setup_slack() const { | ||
return vtr::make_range(cluster_pins_with_modified_setup_slack_); | ||
} | ||
|
||
/**************************************/ | ||
|
||
std::unique_ptr<PlaceDelayModel> alloc_lookups_and_criticalities(t_chan_width_dist chan_width_dist, | ||
const t_placer_opts& placer_opts, | ||
const t_router_opts& router_opts, | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -63,9 +63,9 @@ class PlacerCriticalities { | |
pin_range pins_with_modified_criticality() const; | ||
|
||
public: //Modifiers | ||
//Incrementally updates criticalities based on the atom netlist criticalitites provied by | ||
//Updates criticalities based on the atom netlist criticalitites provided by | ||
//timing_info and the provided criticality_exponent. | ||
void update_criticalities(const SetupTimingInfo* timing_info, float criticality_exponent); | ||
void update_criticalities(const SetupTimingInfo* timing_info, float criticality_exponent, bool recompute); | ||
|
||
//Override the criticality of a particular connection | ||
void set_criticality(ClusterNetId net, int ipin, float val); | ||
|
@@ -81,6 +81,70 @@ class PlacerCriticalities { | |
|
||
//Set of pins with criticaltites modified by last call to update_criticalities() | ||
vtr::vec_id_set<ClusterPinId> cluster_pins_with_modified_criticality_; | ||
|
||
//Updates criticalities: incremental V.S. from scratch | ||
void incr_update_criticalities(const SetupTimingInfo* timing_info); | ||
void recompute_criticalities(); | ||
}; | ||
|
||
/* Usage | ||
* ===== | ||
* PlacerSetupSlacks returns the clustered netlist connection setup slack used by | ||
* the placer. This also serves to map atom netlist level slack (i.e. on AtomPinIds) | ||
* to the clustered netlist (i.e. ClusterPinIds) used during placement. | ||
* | ||
* Setup slacks are calculated by calling update_setup_slacks(), which will | ||
* update setup slacks based on the atom netlist connection setup slacks provided by | ||
* the passed in SetupTimingInfo. This is done incrementally, based on the modified | ||
* connections/AtomPinIds returned by SetupTimingInfo. | ||
* | ||
* The setup slacks of individual connections can then be queried by calling the | ||
* setup_slack() member function. | ||
* | ||
* It also supports iterating via pins_with_modified_setup_slack() through the | ||
* clustered netlist pins/connections which have had their setup slacks modified by | ||
* the last call to update_setup_slacks(). | ||
*/ | ||
class PlacerSetupSlacks { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Explain that these are raw slacks (can be negative, based on the timing constraint specified by the user or the very difficult automatically set timing constraints if no user-specified one exists). |
||
public: //Types | ||
typedef vtr::vec_id_set<ClusterPinId>::iterator pin_iterator; | ||
typedef vtr::vec_id_set<ClusterNetId>::iterator net_iterator; | ||
|
||
typedef vtr::Range<pin_iterator> pin_range; | ||
typedef vtr::Range<net_iterator> net_range; | ||
|
||
public: //Lifetime | ||
PlacerSetupSlacks(const ClusteredNetlist& clb_nlist, const ClusteredPinAtomPinsLookup& netlist_pin_lookup); | ||
PlacerSetupSlacks(const PlacerSetupSlacks& clb_nlist) = delete; | ||
PlacerSetupSlacks& operator=(const PlacerSetupSlacks& clb_nlist) = delete; | ||
|
||
public: //Accessors | ||
//Returns the setup slack of the specified connection | ||
float setup_slack(ClusterNetId net, int ipin) const { return timing_place_setup_slacks_[net][ipin]; } | ||
|
||
//Returns the range of clustered netlist pins (i.e. ClusterPinIds) which were modified | ||
//by the last call to update_setup_slacks() | ||
pin_range pins_with_modified_setup_slack() const; | ||
|
||
public: //Modifiers | ||
//Updates setup slacks based on the atom netlist setup slacks provided by timing_info | ||
void update_setup_slacks(const SetupTimingInfo* timing_info, bool recompute); | ||
|
||
//Override the setup slack of a particular connection | ||
void set_setup_slack(ClusterNetId net, int ipin, float val); | ||
|
||
private: //Data | ||
const ClusteredNetlist& clb_nlist_; | ||
const ClusteredPinAtomPinsLookup& pin_lookup_; | ||
|
||
ClbNetPinsMatrix<float> timing_place_setup_slacks_; /* [0..cluster_ctx.clb_nlist.nets().size()-1][1..num_pins-1] */ | ||
|
||
//Set of pins with criticaltites modified by last call to update_criticalities() | ||
vtr::vec_id_set<ClusterPinId> cluster_pins_with_modified_setup_slack_; | ||
|
||
//Updates setup slacks: incremental V.S. from scratch | ||
void incr_update_setup_slacks(const SetupTimingInfo* timing_info); | ||
void recompute_setup_slacks(); | ||
}; | ||
|
||
/* Usage | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -579,6 +579,23 @@ float calculate_clb_net_pin_criticality(const SetupTimingInfo& timing_info, cons | |
return clb_pin_crit; | ||
} | ||
|
||
//Return the setup slack of a net's pin in the CLB netlist | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Explain that it assumes the timing analysis is up to date (has already been performed with an update call with the right delays). |
||
float calculate_clb_net_pin_setup_slack(const SetupTimingInfo& timing_info, const ClusteredPinAtomPinsLookup& pin_lookup, ClusterPinId clb_pin) { | ||
//There may be multiple atom netlist pins connected to this CLB pin | ||
float clb_pin_setup_slack = std::numeric_limits<float>::quiet_NaN(); | ||
|
||
for (const auto atom_pin : pin_lookup.connected_atom_pins(clb_pin)) { | ||
//Take the worst of the atom pin slacks as the CLB pin slack | ||
if (std::isnan(clb_pin_setup_slack)) { | ||
clb_pin_setup_slack = timing_info.setup_pin_slack(atom_pin); | ||
} else { | ||
clb_pin_setup_slack = std::min(clb_pin_setup_slack, timing_info.setup_pin_slack(atom_pin)); | ||
} | ||
} | ||
|
||
return clb_pin_setup_slack; | ||
} | ||
|
||
//Returns the worst (maximum) criticality of the set of slack tags specified. Requires the maximum | ||
//required time and worst slack for all domain pairs represent by the slack tags | ||
// | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Comment what each enum constant chooses.
I also think we should PATH_DRIVEN_TIMING_PLACE to CRITICALITY_TIMING_PLACE (would be more clear; PATH_DRIVEN is no longer very relevant as all our timing data comes from timing paths).