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

Add Hybrid Updating Strategy (HUS) #1043

Merged
merged 10 commits into from
Aug 14, 2024
62 changes: 61 additions & 1 deletion src/com/xilinx/rapidwright/rwroute/RWRoute.java
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@
import java.util.PriorityQueue;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;

import com.xilinx.rapidwright.design.Cell;
import com.xilinx.rapidwright.design.Design;
Expand Down Expand Up @@ -122,6 +121,11 @@ public class RWRoute{
/** Flag for whether LUT routethrus are to be considered */
protected boolean lutRoutethru;

/** Flag for use of Hybrid Updating Strategy (HUS) */
private boolean hus;
/** Flag (computed at end of iteration 1) to indicate design is congested enough to consider HUS */
private boolean husInitialCongested;

/** The current routing iteration */
protected int routeIteration;
/** Timers to store runtime of different phases */
Expand Down Expand Up @@ -252,6 +256,9 @@ protected void initialize() {
nodesPopped = 0;
overUsedRnodes = new HashSet<>();

hus = config.isHus();
husInitialCongested = false;

routerTimer.getRuntimeTracker("Initialization").stop();
}

Expand Down Expand Up @@ -853,6 +860,7 @@ public void routeIndirectConnections() {
long lastIterationRnodeCount = 0;
long lastIterationRnodeTime = 0;

boolean initialHus = this.hus;
while (routeIteration < config.getMaxIterations()) {
long startIteration = System.nanoTime();
connectionsRoutedIteration = 0;
Expand Down Expand Up @@ -900,6 +908,11 @@ public void routeIndirectConnections() {
}
}

if (initialHus && !hus) {
System.out.println("INFO: Hybrid Updating Strategy (HUS) activated");
initialHus = false;
}

routeIteration++;
lastIterationRnodeCount = routingGraph.numNodes();
lastIterationRnodeTime = rnodesTimer.getTime();
Expand Down Expand Up @@ -1236,9 +1249,15 @@ private void printRoutingIterationStatisticsInfo(float iterationRuntime, float r
*/
private void updateCostFactors() {
updateCongestionCosts.start();

checkHus();

// Inflate the present congestion factor
presentCongestionFactor *= config.getPresentCongestionMultiplier();
presentCongestionFactor = Math.min(presentCongestionFactor, config.getMaxPresentCongestionFactor());

updateCost();

updateCongestionCosts.stop();
}

Expand All @@ -1262,6 +1281,47 @@ private void updateCost() {
}
}

/**
* Check whether to activate Hybrid Updating Strategy (HUS)
*/
private void checkHus() {
if (!hus) {
return;
}

if (routeIteration == 1) {
// Count the number of overused nodes
long overUseCnt = 0;
for (RouteNode rnode : routingGraph.getRnodes()) {
if (rnode.isOverUsed()) {
overUseCnt++;
}
}
husInitialCongested = (float) overUseCnt / sortedIndirectConnections.size() > config.getHusInitialCongestedThreshold();
}

if (husInitialCongested) {
float congestedConnRatio = (float) connectionsRoutedIteration / sortedIndirectConnections.size();
if (congestedConnRatio < config.getHusActivateThreshold()) {
// Activate HUS: slow down the present cost growth and increase historical cost growth instead
eddieh-xlnx marked this conversation as resolved.
Show resolved Hide resolved
float husAlpha = config.getHusAlpha();
if (husAlpha >= config.getPresentCongestionMultiplier()) {
System.out.println("WARNING: HUS alpha is not less than the current present congestion multiplier.");
}
config.setPresentCongestionMultiplier(husAlpha);

float husBeta = config.getHusBeta();
if (husBeta <= historicalCongestionFactor) {
System.out.println("WARNING: HUS beta is not greater than the current historical congestion factor.");
}
historicalCongestionFactor = husBeta;

// Disable HUS from being activated again
hus = false;
}
}
}

/**
* Computes node usage of each type and the total wirelength of the design.
*/
Expand Down
133 changes: 133 additions & 0 deletions src/com/xilinx/rapidwright/rwroute/RWRouteConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,16 @@ public class RWRouteConfig {
private boolean lutRoutethru;
/* true to enable GND -> VCC optimization for LUT inputs */
private boolean invertGndToVccForLutInputs;
/* true to use HUS */
private boolean hus;
/* The value of alpha in HUS*/
private float husAlpha;
/* The value of Beta in HUS*/
private float husBeta;
/* The threshold for determining whether a case is a congested design in HUS */
private float husInitialCongestedThreshold;
/* The threshold for determining whether to start using historical-centric updating in HUS */
private float husActivateThreshold;

/** Constructs a Configuration Object */
public RWRouteConfig(String[] arguments) {
Expand Down Expand Up @@ -125,6 +135,11 @@ public RWRouteConfig(String[] arguments) {
lutPinSwapping = false;
lutRoutethru = false;
invertGndToVccForLutInputs = true;
hus = false;
husAlpha = 1.1f;
husBeta = 2f;
husInitialCongestedThreshold = 0.5f;
husActivateThreshold = 0.4f;
if (arguments != null) {
parseArguments(arguments);
}
Expand Down Expand Up @@ -233,6 +248,21 @@ private void parseArguments(String[] arguments) {
case "--noInvertGndToVccForLutInputs":
setInvertGndToVccForLutInputs(false);
break;
case "--hus":
setHus(true);
break;
case "--husAlpha":
setHusAlpha(Float.parseFloat(arguments[++i]));
break;
case "--husBeta":
setHusBeta(Float.parseFloat(arguments[++i]));
break;
case "--husInitialCongestedThreshold":
setHusInitialCongestedThreshold(Float.parseFloat(arguments[++i]));
break;
case "--husActivateThreshold":
setHusActivateThreshold(Float.parseFloat(arguments[++i]));
break;
default:
throw new IllegalArgumentException("ERROR: RWRoute argument '" + arg + "' not recognized.");
}
Expand Down Expand Up @@ -886,6 +916,102 @@ public void setVerbose(boolean verbose) {
this.verbose = verbose;
}

/** Checks if the hybrid updating strategy (HUS) is enabled.
* HUS will, once its user-configurable thresholds are met, slow down the growth of present costs of used nodes and
* instead increases the growth of overused nodes' historical costs.
* Default: false.
*/
public boolean isHus() {
return hus;
}

/**
* Sets whether hybrid updating strategy (HUS) is enabled.
* HUS will, once its user-configurable thresholds are met, slow down the growth of present costs of used nodes and
* instead increases the growth of overused nodes' historical costs.
* Default: false.
* @param hus true to enable the hybrid updating strategy (HUS)
*/
public void setHus(boolean hus) {
this.hus = hus;
}

/**
* Gets the value of alpha in the hybrid updating strategy (HUS)
* Default: 1.1
* @return the value of alpha in the hybrid updating strategy (HUS)
*/
public float getHusAlpha() {
return husAlpha;
}

/**
* Sets the value of alpha in the hybrid updating strategy (HUS)
* Default: 1.1
* @param husAlpha the value of alpha in the hybrid updating strategy (HUS)
*/
public void setHusAlpha(float husAlpha) {
this.husAlpha = husAlpha;
}

/**
* Gets the value of beta in the hybrid updating strategy (HUS)
* Default: 2.0
* @return the value of beta in the hybrid updating strategy (HUS)
*/
public float getHusBeta() {
return husBeta;
}

/**
* Sets the value of beta in the hybrid updating strategy (HUS)
* Default: 2.0
* @param husBeta the value of beta in the hybrid updating strategy (HUS)
*/
public void setHusBeta(float husBeta) {
this.husBeta = husBeta;
}

/**
* Gets the threshold (number of overused nodes at the end of routing iteration 1 divided by
* total number of connections to be routed) above which a design is congested enough to consider HUS
* Default: 0.5
* @return the threshold for determining whether a design is congested enough to consider HUS
*/
public float getHusInitialCongestedThreshold() {
return husInitialCongestedThreshold;
}

/**
* Sets the threshold (number of overused nodes at the end of routing iteration 1 divided by
* total number of connections to be routed) above which a design is congested enough to consider HUS
* Default: 0.5
* @param husInitialCongestedThreshold the threshold for determining whether a design is congested enough to consider HUS
*/
public void setHusInitialCongestedThreshold(float husInitialCongestedThreshold) {
this.husInitialCongestedThreshold = husInitialCongestedThreshold;
}

/**
* Gets the threshold (number of congested connections at the end of the routing iteration divided by
* total number of connections to be routed) below which HUS will be activated
* Default: 0.4
* @return the threshold for determining whether to activate HUS
*/
public float getHusActivateThreshold() {
return husActivateThreshold;
}

/**
* Sets the threshold (number of congested connections at the end of the routing iteration divided by
* total number of connections to be routed) below which HUS will be activated
* Default: 0.4
* @param husActivateThreshold the threshold for determining whether to activate HUS
*/
public void setHusActivateThreshold(float husActivateThreshold) {
this.husActivateThreshold = husActivateThreshold;
}

@Override
public String toString() {
StringBuilder s = new StringBuilder();
Expand Down Expand Up @@ -922,6 +1048,13 @@ public String toString() {
s.append(MessageGenerator.formatString("Historical congestion factor: ", historicalCongestionFactor));
s.append(MessageGenerator.formatString("LUT pin swapping: ", isLutPinSwapping()));
s.append(MessageGenerator.formatString("LUT routethrus: ", isLutRoutethru()));
s.append(MessageGenerator.formatString("Use Hybrid Updating Strategy: ", isHus()));
if (isHus()) {
s.append(MessageGenerator.formatString("HUS alpha: ", husAlpha));
s.append(MessageGenerator.formatString("HUS beta: ", husBeta));
s.append(MessageGenerator.formatString("HUS initial congested threshold: ", husInitialCongestedThreshold));
s.append(MessageGenerator.formatString("HUS activate threshold: ", husActivateThreshold));
}

return s.toString();
}
Expand Down
14 changes: 14 additions & 0 deletions test/src/com/xilinx/rapidwright/rwroute/TestRWRoute.java
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,20 @@ public void testNonTimingDrivenFullRoutingWithLutRoutethru(String path) {
VivadoToolsHelper.assertFullyRouted(design);
}

@ParameterizedTest
@ValueSource(strings = {
"bnn.dcp", // does not activate HUS
"optical-flow.dcp" // activates HUS
})
@LargeTest(max_memory_gb = 8)
public void testNonTimingDrivenFullRoutingWithHUS(String path) {
Design design = RapidWrightDCP.loadDCP(path);
RWRoute.routeDesignWithUserDefinedArguments(design, new String[] {"--nonTimingDriven", "--hus"});
assertAllSourcesRoutedFlagSet(design);
assertAllPinsRouted(design);
VivadoToolsHelper.assertFullyRouted(design);
}

/**
* Tests the timing driven full routing, i.e., RWRoute running in timing-driven mode.
* The bnn design from Rosetta benchmarks is used.
Expand Down
Loading