diff --git a/src/com/xilinx/rapidwright/rwroute/RWRoute.java b/src/com/xilinx/rapidwright/rwroute/RWRoute.java index 546aa9ede..d844f776f 100644 --- a/src/com/xilinx/rapidwright/rwroute/RWRoute.java +++ b/src/com/xilinx/rapidwright/rwroute/RWRoute.java @@ -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; @@ -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 */ @@ -252,6 +256,9 @@ protected void initialize() { nodesPopped = 0; overUsedRnodes = new HashSet<>(); + hus = config.isHus(); + husInitialCongested = false; + routerTimer.getRuntimeTracker("Initialization").stop(); } @@ -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; @@ -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(); @@ -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(); } @@ -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 + 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. */ diff --git a/src/com/xilinx/rapidwright/rwroute/RWRouteConfig.java b/src/com/xilinx/rapidwright/rwroute/RWRouteConfig.java index 1812030be..304895637 100644 --- a/src/com/xilinx/rapidwright/rwroute/RWRouteConfig.java +++ b/src/com/xilinx/rapidwright/rwroute/RWRouteConfig.java @@ -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) { @@ -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); } @@ -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."); } @@ -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(); @@ -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(); } diff --git a/test/src/com/xilinx/rapidwright/rwroute/TestRWRoute.java b/test/src/com/xilinx/rapidwright/rwroute/TestRWRoute.java index 5c8666565..40c743701 100644 --- a/test/src/com/xilinx/rapidwright/rwroute/TestRWRoute.java +++ b/test/src/com/xilinx/rapidwright/rwroute/TestRWRoute.java @@ -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.