From de4ce3016af452d0e54a0c675c1cabbc14888046 Mon Sep 17 00:00:00 2001 From: RipperJ <1628079212@qq.com> Date: Thu, 18 Apr 2024 22:39:22 +0800 Subject: [PATCH] Pass counting node# crossing pblocks revised --- java/CrossingCRNodeCounter.java | 241 --------------- java/CrossingPBlockNodeCounter.java | 322 ++++++++++++++++++++ java/README.md | 8 +- poetry.lock | 111 ++++--- pyproject.toml | 1 + python/src/CrossingCRNodeCounter.py | 88 ------ python/src/README.md | 8 +- python/src/crossing_pblocks_node_counter.py | 71 +++++ 8 files changed, 483 insertions(+), 367 deletions(-) delete mode 100644 java/CrossingCRNodeCounter.java create mode 100644 java/CrossingPBlockNodeCounter.java delete mode 100644 python/src/CrossingCRNodeCounter.py create mode 100644 python/src/crossing_pblocks_node_counter.py diff --git a/java/CrossingCRNodeCounter.java b/java/CrossingCRNodeCounter.java deleted file mode 100644 index 1743340..0000000 --- a/java/CrossingCRNodeCounter.java +++ /dev/null @@ -1,241 +0,0 @@ -package com.xilinx.rapidwright.examples; - -import com.xilinx.rapidwright.design.blocks.PBlock; -import com.xilinx.rapidwright.design.Design; -import com.xilinx.rapidwright.device.Device; -import com.xilinx.rapidwright.device.IntentCode; -import com.xilinx.rapidwright.device.Node; -import com.xilinx.rapidwright.device.PIP; -import com.xilinx.rapidwright.device.Tile; - -import java.io.FileWriter; -import java.io.IOException; -import java.io.PrintWriter; -import java.util.Arrays; -import java.util.HashMap; -import java.util.Set; -import java.util.HashSet; - -public class CrossingCRNodeCounter { - private static Set intentCodesConsidered = new HashSet<>( - Arrays.asList( // color_index - IntentCode.INTENT_DEFAULT, // 1 - IntentCode.NODE_HLONG, // 2 - IntentCode.NODE_VLONG, // 3 - IntentCode.NODE_SINGLE, // 4 - IntentCode.NODE_DOUBLE, // 5 - IntentCode.NODE_HQUAD, // 6 - IntentCode.NODE_VQUAD, // 7 - IntentCode.NODE_LOCAL, // 8 - IntentCode.NODE_PINBOUNCE, // 9 - IntentCode.NODE_LAGUNA_DATA, // 10 - - IntentCode.NODE_GLOBAL_VDISTR, // ignored - IntentCode.NODE_GLOBAL_VROUTE, // ignored - IntentCode.NODE_GLOBAL_HDISTR, // ignored - IntentCode.NODE_GLOBAL_HROUTE // ignored - ) - ); - private static HashMap>> allPBlockDirectionToNodeCount = new HashMap<>(); - // Check whether a node has a IntentCode of our interest - // Exclude some IntentCodes including clock and control signals - private static boolean validNode(Node n) { - assert intentCodesConsidered.contains(n.getIntentCode()) : "Unexpected IntentCode: " + n.getIntentCode(); - // Exclude IntentCode.NODE_GLOBAL_VROUTE and IntentCode.NODE_GLOBAL_VDISTR - if (n.getIntentCode().toString().startsWith("NODE_GLOBAL")) { - assert n.getWireName().startsWith("CLK") : "This GLOBAL node is not a clock node: " + n; - return false; - } - // Filter out IntentCode.INTENT_DEFAULT Nodes - // ? referring to https://docs.amd.com/v/u/en-US/ug573-ultrascale-memory-resources - if (n.getIntentCode() == IntentCode.INTENT_DEFAULT) { - // Exclude CLKOUT_{NORTH\d+|SOUTH\d+} and cascade i/o of BRAMs - assert n.getWireName().matches("^(CLKOUT|BRAM|HPIO|GND|VCC).*$") : "Unexpected INTENT_DEFAULT node: " + n; - return false; - } - // DSP cascade not extracted by getIntersectingNodes - // ? referring to https://docs.amd.com/v/u/en-US/ug579-ultrascale-dsp - assert !n.getWireName().contains("DSP_") : "Unexpected DSP-related node: " + n; - return true; - } - - // Check whether a node in Set a also exists in Set b - // then, check whether the node has a valid IntentCode of our interest - // if both satisfied, add the node to the result set - public static Set getIntersectingNodes(Set a, Set b) { - Set nodesInA = getNodesInTiles(a); - Set nodesInB = getNodesInTiles(b); - - Set both = new HashSet<>(); - for (Node n : nodesInA) { - if (nodesInB.contains(n) && validNode(n)) { - both.add(n); - - // For debugging - // System.out.println(n + " " + n.getIntentCode()); // + " " + a + " " + b); - - // For highlight_objects in Vivado - // try { - // PrintWriter writer = new PrintWriter(new FileWriter("node_stats.txt", true)); - // writer.println(n + " " + n.getIntentCode());// + " " + a + " " + b); - // writer.close(); - // } catch (IOException e) { - // System.out.println("Error: " + e.getMessage()); - // e.printStackTrace(); - // } - } - } - return both; - } - - // Get the number of nodes crossing the boundary between the current pblock and the adjacent pblock(s) - // in at most 4 directions (N, S, E, W) - public static HashMap getSinglePBlockDirectionToNodeCount(Device device, int col, int row) { - // The current pblock (pCenter). - PBlock pCenter = new PBlock(device, "CLOCKREGION_X" + col + "Y" + row + ":CLOCKREGION_X" + col + "Y" + row); - // The direction (N, S, E, W) to the number of nodes crossing the boundary between the current pblock and the adjacent pblock(s). - HashMap directionToNodeCount = new HashMap(); - - // North - if (row < device.getNumOfClockRegionRows() - 1) { - PBlock pNorth = new PBlock(device, "CLOCKREGION_X" + col + "Y" + (row + 1) + ":CLOCKREGION_X" + col + "Y" + (row + 1)); - Set intersectingNodes = getIntersectingNodes(pCenter.getAllTiles(), pNorth.getAllTiles()); - int intersectingNodesCount = intersectingNodes.size(); - directionToNodeCount.put("N", intersectingNodesCount); - } - // South - if (row > 0) { - if (allPBlockDirectionToNodeCount.containsKey(col) && allPBlockDirectionToNodeCount.get(col).containsKey(row - 1)) { - directionToNodeCount.put("S", allPBlockDirectionToNodeCount.get(col).get(row - 1).get("N")); - } else { - assert false : "col " + col + "; row " + row; - PBlock pSouth = new PBlock(device, "CLOCKREGION_X" + col + "Y" + (row - 1) + ":CLOCKREGION_X" + col + "Y" + (row - 1)); - Set intersectingNodes = getIntersectingNodes(pCenter.getAllTiles(), pSouth.getAllTiles()); - int intersectingNodesCount = intersectingNodes.size(); - directionToNodeCount.put("S", intersectingNodesCount); - } - } - // East - if (col < device.getNumOfClockRegionsColumns() - 1) { - PBlock pEast = new PBlock(device, "CLOCKREGION_X" + (col + 1) + "Y" + row + ":CLOCKREGION_X" + (col + 1) + "Y" + row); - Set intersectingNodes = getIntersectingNodes(pCenter.getAllTiles(), pEast.getAllTiles()); - int intersectingNodesCount = intersectingNodes.size(); - directionToNodeCount.put("E", intersectingNodesCount); - } - // West - if (col > 0) { - if (allPBlockDirectionToNodeCount.containsKey(col - 1) && allPBlockDirectionToNodeCount.get(col - 1).containsKey(row)) { - directionToNodeCount.put("W", allPBlockDirectionToNodeCount.get(col - 1).get(row).get("E")); - } else { - assert false : "col " + col + "; row " + row; - PBlock pWest = new PBlock(device, "CLOCKREGION_X" + (col - 1) + "Y" + row + ":CLOCKREGION_X" + (col - 1) + "Y" + row); - Set intersectingNodes = getIntersectingNodes(pCenter.getAllTiles(), pWest.getAllTiles()); - int intersectingNodesCount = intersectingNodes.size(); - directionToNodeCount.put("W", intersectingNodesCount); - } - } - return directionToNodeCount; - } - - // Get a set of nodes in a set of tiles - public static Set getNodesInTiles(Set tiles) { - Set nodes = new HashSet<>(); - for (Tile t : tiles) { - for (PIP p : t.getPIPs()) { - Node start = p.getStartNode(); - Node end = p.getEndNode(); - nodes.add(start); - nodes.add(end); - } - } - nodes.remove(null); - return nodes; - } - - public static HashMap getSinglePBlockCrossingCRNodeCount(String dcp, int col, int row) { - Design design = null; - Device device = null; - try { - design = Design.readCheckpoint(dcp); - device = design.getDevice(); // TODO: directly get device bypassing design? - if (row < 0 || row >= device.getNumOfClockRegionRows() || col < 0 || col >= device.getNumOfClockRegionsColumns()) { - System.out.println("Invalid row or column number"); - return null; - } - else { - System.out.println("Device: " + device + "; col(X): " + col + "/" + device.getNumOfClockRegionsColumns() + "; row(Y): " + row + "/" + device.getNumOfClockRegionRows()); - // e.g., xcu250, col(X): 4/8, row(Y): 3/16 - } - } catch (Exception e) { - System.out.println("Error: " + e.getMessage()); - e.printStackTrace(); - } - assert design != null : "Design is null"; - assert device != null : "Device is null"; - - // Create the result map: - HashMap directionToNodeCount = getSinglePBlockDirectionToNodeCount(device, col, row); - return directionToNodeCount; - } - - public static HashMap>> getAllPBlockCrossingCRNodeCount(String dcp) { - Design design = null; - Device device = null; - try { - design = Design.readCheckpoint(dcp); - device = design.getDevice(); // TODO: directly get device bypassing design? - System.out.println("Device: " + device + "; col(X): " + device.getNumOfClockRegionsColumns() + "; row(Y): " + device.getNumOfClockRegionRows()); - } catch (Exception e) { - System.out.println("Error: " + e.getMessage()); - e.printStackTrace(); - } - assert design != null : "Design is null"; - assert device != null : "Device is null"; - - // Create the result map: - for (int col = 0; col < device.getNumOfClockRegionsColumns(); col++) { - for (int row = 0; row < device.getNumOfClockRegionRows(); row++) { - HashMap directionToNodeCount = getSinglePBlockDirectionToNodeCount(device, col, row); - HashMap> rowToDirectionToNodeCount = allPBlockDirectionToNodeCount.getOrDefault(col, new HashMap<>()); - rowToDirectionToNodeCount.put(row, directionToNodeCount); - allPBlockDirectionToNodeCount.put(col, rowToDirectionToNodeCount); - System.out.println("CLOCKREGION: X " + col + "/" + device.getNumOfClockRegionsColumns() + "; Y " + row + "/" + device.getNumOfClockRegionRows() + " done"); - } - } - return allPBlockDirectionToNodeCount; - } - - public static void main(String[] args) { - if(args.length != 3) { - System.out.println("USAGE: rapidwright MetricsExtractor <.dcp> "); - return; - } - Design design = null; - Device device = null; - int col = -1, row = -1; - try { - design = Design.readCheckpoint(args[0]); - col = Integer.parseInt(args[1]); - row = Integer.parseInt(args[2]); - device = design.getDevice(); // TODO: directly get device bypassing design? - if (row < 0 || row >= device.getNumOfClockRegionRows() || col < 0 || col >= device.getNumOfClockRegionsColumns()) { - System.out.println("Invalid row or column number"); - return; - } - else { - System.out.println("Device: " + device + "; col(X): " + col + "/" + device.getNumOfClockRegionsColumns() + "; row(Y): " + row + "/" + device.getNumOfClockRegionRows()); - // e.g., xcu250, col(X): 4/8, row(Y): 3/16 - } - } catch (Exception e) { - System.out.println("Error: " + e.getMessage()); - e.printStackTrace(); - } - assert design != null : "Design is null"; - assert device != null : "Device is null"; - - // Create the result map: - HashMap directionToNodeCount = getSinglePBlockDirectionToNodeCount(device, col, row); - // System.out.println("CLOCKREGION_X" + col + "Y" + row + ":CLOCKREGION_X" + col + "Y" + row); - System.out.println(directionToNodeCount); - } -} \ No newline at end of file diff --git a/java/CrossingPBlockNodeCounter.java b/java/CrossingPBlockNodeCounter.java new file mode 100644 index 0000000..e6e296a --- /dev/null +++ b/java/CrossingPBlockNodeCounter.java @@ -0,0 +1,322 @@ +/* +# Copyright (c) 2024 RapidStream Design Automation, Inc. and contributors. +# All rights reserved. The contributor(s) of this file has/have agreed to the +# RapidStream Contributor License Agreement. +*/ + +package com.xilinx.rapidwright.examples; + +import com.xilinx.rapidwright.design.blocks.PBlock; +import com.xilinx.rapidwright.design.blocks.PBlockRange; +import com.xilinx.rapidwright.design.ConstraintGroup; +import com.xilinx.rapidwright.design.Design; +import com.xilinx.rapidwright.device.Device; +import com.xilinx.rapidwright.device.IntentCode; +import com.xilinx.rapidwright.device.Node; +import com.xilinx.rapidwright.device.PIP; +import com.xilinx.rapidwright.device.Tile; + +import java.io.FileWriter; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.HashSet; +import java.util.Map; + +public class CrossingPBlockNodeCounter { + private static Set intentCodesConsidered = new HashSet<>( + Arrays.asList( // color_index + IntentCode.INTENT_DEFAULT, // 1 + IntentCode.NODE_HLONG, // 2 + IntentCode.NODE_VLONG, // 3 + IntentCode.NODE_SINGLE, // 4 + IntentCode.NODE_DOUBLE, // 5 + IntentCode.NODE_HQUAD, // 6 + IntentCode.NODE_VQUAD, // 7 + IntentCode.NODE_LOCAL, // 8 + IntentCode.NODE_PINBOUNCE, // 9 + IntentCode.NODE_LAGUNA_DATA, // 10 + + IntentCode.NODE_GLOBAL_VDISTR, // ignored + IntentCode.NODE_GLOBAL_VROUTE, // ignored + IntentCode.NODE_GLOBAL_HDISTR, // ignored + IntentCode.NODE_GLOBAL_HROUTE // ignored + ) + ); + private static HashMap>> allPBlockDirectionToNodeCount = new HashMap<>(); + // Check whether a node has a IntentCode of our interest + // Exclude some IntentCodes including clock and control signals + private static boolean validNode(Node n) { + assert intentCodesConsidered.contains(n.getIntentCode()) : "Unexpected IntentCode: " + n.getIntentCode(); + // Exclude IntentCode.NODE_GLOBAL_VROUTE and IntentCode.NODE_GLOBAL_VDISTR + if (n.getIntentCode().toString().startsWith("NODE_GLOBAL")) { + assert n.getWireName().startsWith("CLK") : "This GLOBAL node is not a clock node: " + n; + return false; + } + // Filter out IntentCode.INTENT_DEFAULT Nodes + // ? referring to https://docs.amd.com/v/u/en-US/ug573-ultrascale-memory-resources + if (n.getIntentCode() == IntentCode.INTENT_DEFAULT) { + // Exclude CLKOUT_{NORTH\d+|SOUTH\d+} and cascade i/o of BRAMs + assert n.getWireName().matches("^(CLKOUT|BRAM|HPIO|GND|VCC).*$") : "Unexpected INTENT_DEFAULT node: " + n; + return false; + } + // DSP cascade not extracted by getIntersectingNodes + // ? referring to https://docs.amd.com/v/u/en-US/ug579-ultrascale-dsp + assert !n.getWireName().contains("DSP_") : "Unexpected DSP-related node: " + n; + return true; + } + + // Check whether a node in Set a also exists in Set b + // then, check whether the node has a valid IntentCode of our interest + // if both satisfied, add the node to the result set + private static Set getIntersectingNodes(Set a, Set b) { + Set nodesInA = getNodesInTiles(a); + Set nodesInB = getNodesInTiles(b); + + Set both = new HashSet<>(); + for (Node n : nodesInA) { + if (nodesInB.contains(n) && validNode(n)) { + both.add(n); + + // For debugging + // System.out.println(n + " " + n.getIntentCode()); // + " " + a + " " + b); + + // For highlight_objects in Vivado + // try { + // PrintWriter writer = new PrintWriter(new FileWriter("node_stats.txt", true)); + // writer.println(n + " " + n.getIntentCode());// + " " + a + " " + b); + // writer.close(); + // } catch (IOException e) { + // System.out.println("Error: " + e.getMessage()); + // e.printStackTrace(); + // } + } + } + return both; + } + + private static String getPBlockNameFromColRow(Device device, int col, int row, int total_col, int total_row) { + int width = device.getNumOfClockRegionsColumns() / total_col; + int height = device.getNumOfClockRegionRows() / total_row; + return "X" + col * width + "Y" + row * height + "X" + ((col + 1) * width - 1) + "Y" + ((row + 1) * height - 1); + } + + private static String getPBlockNameFromDirection(Device device, int col, int row, int total_col, int total_row, String direction) { + int width = device.getNumOfClockRegionsColumns() / total_col; + int height = device.getNumOfClockRegionRows() / total_row; + String pBlockName = ""; + switch (direction) { + case "N": + pBlockName = "X" + col * width + "Y" + ((row + 1) * height) + "X" + ((col + 1) * width - 1) + "Y" + ((row + 2) * height - 1); + break; + case "S": + pBlockName = "X" + col * width + "Y" + ((row - 1) * height) + "X" + ((col + 1) * width - 1) + "Y" + ((row * height - 1)); + break; + case "E": + pBlockName = "X" + ((col + 1) * width) + "Y" + row * height + "X" + ((col + 2) * width - 1) + "Y" + ((row + 1) * height - 1); + break; + case "W": + pBlockName = "X" + ((col - 1) * width) + "Y" + row * height + "X" + ((col * width - 1)) + "Y" + ((row + 1) * height - 1); + break; + default: + assert false : "Invalid direction: " + direction; + } + return pBlockName; + } + + // Get the number of nodes crossing the boundary between the current pblock and the adjacent pblock(s) + // in at most 4 directions (N, S, E, W) + private static HashMap getSinglePBlockDirectionToNodeCount(Device device, Map pblockMap, int col, int row, int total_col, int total_row) { + // The current pblock (pCenter). + String pCenterName = getPBlockNameFromColRow(device, col, row, total_col, total_row); + assert pblockMap.containsKey(pCenterName) : "pCenterName " + pCenterName + " not found in pblockMap!"; + PBlock pCenter = pblockMap.get(pCenterName); + // The direction (N, S, E, W) to the number of nodes crossing the boundary between the current pblock and the adjacent pblock(s). + HashMap directionToNodeCount = new HashMap(); + + // North + if (row < total_row - 1) { + // PBlock pNorth = new PBlock(device, "CLOCKREGION_X" + col + "Y" + (row + 1) + ":CLOCKREGION_X" + col + "Y" + (row + 1)); + String pNorthName = getPBlockNameFromDirection(device, col, row, total_col, total_row, "N"); + assert pblockMap.containsKey(pNorthName) : "pNorthName " + pNorthName + " not found in pblockMap!"; + PBlock pNorth = pblockMap.get(pNorthName); + Set intersectingNodes = getIntersectingNodes(pCenter.getAllTiles(), pNorth.getAllTiles()); + int intersectingNodesCount = intersectingNodes.size(); + directionToNodeCount.put("N", intersectingNodesCount); + } + // South + if (row > 0) { + if (allPBlockDirectionToNodeCount.containsKey(col) && allPBlockDirectionToNodeCount.get(col).containsKey(row - 1)) { + directionToNodeCount.put("S", allPBlockDirectionToNodeCount.get(col).get(row - 1).get("N")); + } else { + System.err.println("South not found: col " + col + "; row " + row); + String pSouthName = getPBlockNameFromDirection(device, col, row, total_col, total_row, "S"); + assert pblockMap.containsKey(pSouthName) : "pSouthName " + pSouthName + " not found in pblockMap!"; + PBlock pSouth = pblockMap.get(pSouthName); + Set intersectingNodes = getIntersectingNodes(pCenter.getAllTiles(), pSouth.getAllTiles()); + int intersectingNodesCount = intersectingNodes.size(); + directionToNodeCount.put("S", intersectingNodesCount); + } + } + // East + if (col < total_col - 1) { + String pEastName = getPBlockNameFromDirection(device, col, row, total_col, total_row, "E"); + assert pblockMap.containsKey(pEastName) : "pEastName " + pEastName + " not found in pblockMap!"; + PBlock pEast = pblockMap.get(pEastName); + Set intersectingNodes = getIntersectingNodes(pCenter.getAllTiles(), pEast.getAllTiles()); + int intersectingNodesCount = intersectingNodes.size(); + directionToNodeCount.put("E", intersectingNodesCount); + } + // West + if (col > 0) { + if (allPBlockDirectionToNodeCount.containsKey(col - 1) && allPBlockDirectionToNodeCount.get(col - 1).containsKey(row)) { + directionToNodeCount.put("W", allPBlockDirectionToNodeCount.get(col - 1).get(row).get("E")); + } else { + System.err.println("South not found: col " + col + "; row " + row); + String pWestName = getPBlockNameFromDirection(device, col, row, total_col, total_row, "W"); + assert pblockMap.containsKey(pWestName) : "pWestName " + pWestName + " not found in pblockMap!"; + PBlock pWest = pblockMap.get(pWestName); + Set intersectingNodes = getIntersectingNodes(pCenter.getAllTiles(), pWest.getAllTiles()); + int intersectingNodesCount = intersectingNodes.size(); + directionToNodeCount.put("W", intersectingNodesCount); + } + } + return directionToNodeCount; + } + + // Get a set of nodes in a set of tiles + private static Set getNodesInTiles(Set tiles) { + Set nodes = new HashSet<>(); + for (Tile t : tiles) { + for (PIP p : t.getPIPs()) { + Node start = p.getStartNode(); + Node end = p.getEndNode(); + nodes.add(start); + nodes.add(end); + } + } + nodes.remove(null); + return nodes; + } + + private static ArrayList getXYsFromPBlockName(String pblockName) { + String pattern = "^.*X(\\d+)Y(\\d+).*X(\\d+)Y(\\d+).*$"; + Pattern r = Pattern.compile(pattern); + Matcher m = r.matcher(pblockName); + assert m.find() : "pblockName " + pblockName + " does not match the pattern '^.*X(\\d+)Y(\\d+).*X(\\d+)Y(\\d+).*$'!"; + ArrayList xyList = new ArrayList<>(); + for (int i = 1; i <= 4; i++) { + xyList.add(Integer.parseInt(m.group(i))); + } + System.out.println(pblockName + " " + xyList); + return xyList; + } + + private static String refinePBlockName(String pblockName) { + String pattern = "^.*X(\\d+)Y(\\d+).*X(\\d+)Y(\\d+).*$"; + Pattern r = Pattern.compile(pattern); + Matcher m = r.matcher(pblockName); + assert m.find() : "pblockName " + pblockName + " does not match the pattern '^.*X(\\d+)Y(\\d+).*X(\\d+)Y(\\d+).*$'!"; + ArrayList xyList = new ArrayList<>(); + String newPBlockName = "X" + m.group(1) + "Y" + m.group(2) + "X" + m.group(3) + "Y" + m.group(4); + return newPBlockName; + } + + private static Map getNameToPBlocksFromXDC(Design design){ + Device device = design.getDevice(); + Map pblockMap = new HashMap<>(); + for(ConstraintGroup cg : ConstraintGroup.values()) { + for(String line : design.getXDCConstraints(cg)) { + // rebuild island pblocks from create_clock and resize_pblock + if (line.trim().startsWith("create_pblock") && line.matches("^.*X\\d+Y\\d+.*X\\d+Y\\d+.*$")) { + String[] parts = line.split("\\s+"); + String pblockName = refinePBlockName(parts[1]); + PBlock pblock = new PBlock(); + pblockMap.put(pblockName, pblock); + } + if(line.trim().startsWith("resize_pblock") && line.matches("^.*X\\d+Y\\d+.*X\\d+Y\\d+.*-.*$")) { + String[] parts = line.split("\\s+"); + String pblockName = null; + String pblockRange = null; + boolean nextIsName = false; + boolean nextIsRange = false; + PBlock pblock = null; + for (String part : parts) { + if (part.contains("get_pblocks")) { + nextIsName = true; + } else if (nextIsName) { + nextIsName = false; + pblockName = refinePBlockName(part.replace("]", "").replace("}", "")); + assert pblockMap.containsKey(pblockName) : "pblockName " + pblockName + " not found in pblockMap!"; + pblock = pblockMap.get(pblockName); + } else if (part.contains("-add")) { + nextIsRange = true; + } else if (nextIsRange) { + pblockRange = part.replace("{", "").replace("}", "").replace("]", ""); + if (pblockRange.matches("^(RAMB|DSP|URAM).*$")) // BRAM/DSP/URAM cascade not relavant + continue; + pblock.add(new PBlockRange(device, pblockRange)); + } else if (part.contains("-remove")) { + // TODO: "resize_pblock [...] -remove {...}" not considered yet + // System.out.println("WARNING: Not considered yet!"); + break; + } + } + assert pblock != null && pblock.size() != 0; + pblockMap.put(pblockName, pblock); + } + } + } + return pblockMap; + } + + public static HashMap>> getAllPBlockCrossingNodeCount(String dcp, int total_col, int total_row) { + Design design = null; + Device device = null; + try { + design = Design.readCheckpoint(dcp); + device = design.getDevice(); + // Assume the atomic slot is at least clock-region-level, then they should not exceed CR# + assert total_col >= 0 && total_col < device.getNumOfClockRegionsColumns() : "Invalid column number"; + assert total_row >= 0 && total_row < device.getNumOfClockRegionRows() : "Invalid row number"; + System.out.println("Device: " + device + "; total_col(X): " + total_col + "; total_row(Y): " + total_row); + } catch (Exception e) { + System.err.println("Error: " + e.getMessage()); + e.printStackTrace(); + } + assert design != null : "Design is null"; + assert device != null : "Device is null"; + Map pblockMap = getNameToPBlocksFromXDC(design); + // System.out.println(" pMap: " + pblockMap + "\n"); + // example: "{X0Y12X3Y15=X0Y12:X3Y15, X4Y8X7Y11=SLICE_X144Y540:SLICE_X145Y719 X5Y9:X6Y11 X4Y8:X6Y8}" + + // Create the result map: + System.out.println("Extracting node counts for pblocks in different directions:"); + for (int c = 0; c < total_col; c++) { + for (int r = 0; r < total_row; r++) { + HashMap directionToNodeCount = getSinglePBlockDirectionToNodeCount(device, pblockMap, c, r, total_col, total_row); + HashMap> rowToDirectionToNodeCount = allPBlockDirectionToNodeCount.getOrDefault(c, new HashMap<>()); + rowToDirectionToNodeCount.put(r, directionToNodeCount); + allPBlockDirectionToNodeCount.put(c, rowToDirectionToNodeCount); + + String pCenterName = getPBlockNameFromColRow(device, c, r, total_col, total_row); + System.out.println(" PBlock " + pCenterName + "\tdone"); + } + } + return allPBlockDirectionToNodeCount; + } + + public static void main(String[] args) { + if(args.length != 3) { + System.out.println("USAGE: rapidwright MetricsExtractor <.dcp> "); + return; + } + HashMap>> allPBlockCrossingNodeCount = getAllPBlockCrossingNodeCount(args[0], Integer.parseInt(args[1]), Integer.parseInt(args[2])); + System.out.println(allPBlockCrossingNodeCount); + } +} diff --git a/java/README.md b/java/README.md index 8fad9d5..918364b 100644 --- a/java/README.md +++ b/java/README.md @@ -1,3 +1,9 @@ + + # RapidStream DSE Engine Java Source Code ## How to Compile @@ -10,4 +16,4 @@ ... } ``` -3. Recompile RapidWright with `./gradlew compileJava` \ No newline at end of file +3. Recompile RapidWright with `./gradlew compileJava` diff --git a/poetry.lock b/poetry.lock index cbc3d7c..4af7a4a 100644 --- a/poetry.lock +++ b/poetry.lock @@ -46,33 +46,33 @@ tests-no-zope = ["attrs[tests-mypy]", "cloudpickle", "hypothesis", "pympler", "p [[package]] name = "black" -version = "24.3.0" +version = "24.4.0" description = "The uncompromising code formatter." optional = false python-versions = ">=3.8" files = [ - {file = "black-24.3.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7d5e026f8da0322b5662fa7a8e752b3fa2dac1c1cbc213c3d7ff9bdd0ab12395"}, - {file = "black-24.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9f50ea1132e2189d8dff0115ab75b65590a3e97de1e143795adb4ce317934995"}, - {file = "black-24.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e2af80566f43c85f5797365077fb64a393861a3730bd110971ab7a0c94e873e7"}, - {file = "black-24.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:4be5bb28e090456adfc1255e03967fb67ca846a03be7aadf6249096100ee32d0"}, - {file = "black-24.3.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4f1373a7808a8f135b774039f61d59e4be7eb56b2513d3d2f02a8b9365b8a8a9"}, - {file = "black-24.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:aadf7a02d947936ee418777e0247ea114f78aff0d0959461057cae8a04f20597"}, - {file = "black-24.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:65c02e4ea2ae09d16314d30912a58ada9a5c4fdfedf9512d23326128ac08ac3d"}, - {file = "black-24.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:bf21b7b230718a5f08bd32d5e4f1db7fc8788345c8aea1d155fc17852b3410f5"}, - {file = "black-24.3.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:2818cf72dfd5d289e48f37ccfa08b460bf469e67fb7c4abb07edc2e9f16fb63f"}, - {file = "black-24.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4acf672def7eb1725f41f38bf6bf425c8237248bb0804faa3965c036f7672d11"}, - {file = "black-24.3.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c7ed6668cbbfcd231fa0dc1b137d3e40c04c7f786e626b405c62bcd5db5857e4"}, - {file = "black-24.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:56f52cfbd3dabe2798d76dbdd299faa046a901041faf2cf33288bc4e6dae57b5"}, - {file = "black-24.3.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:79dcf34b33e38ed1b17434693763301d7ccbd1c5860674a8f871bd15139e7837"}, - {file = "black-24.3.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:e19cb1c6365fd6dc38a6eae2dcb691d7d83935c10215aef8e6c38edee3f77abd"}, - {file = "black-24.3.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:65b76c275e4c1c5ce6e9870911384bff5ca31ab63d19c76811cb1fb162678213"}, - {file = "black-24.3.0-cp38-cp38-win_amd64.whl", hash = "sha256:b5991d523eee14756f3c8d5df5231550ae8993e2286b8014e2fdea7156ed0959"}, - {file = "black-24.3.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c45f8dff244b3c431b36e3224b6be4a127c6aca780853574c00faf99258041eb"}, - {file = "black-24.3.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:6905238a754ceb7788a73f02b45637d820b2f5478b20fec82ea865e4f5d4d9f7"}, - {file = "black-24.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d7de8d330763c66663661a1ffd432274a2f92f07feeddd89ffd085b5744f85e7"}, - {file = "black-24.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:7bb041dca0d784697af4646d3b62ba4a6b028276ae878e53f6b4f74ddd6db99f"}, - {file = "black-24.3.0-py3-none-any.whl", hash = "sha256:41622020d7120e01d377f74249e677039d20e6344ff5851de8a10f11f513bf93"}, - {file = "black-24.3.0.tar.gz", hash = "sha256:a0c9c4a0771afc6919578cec71ce82a3e31e054904e7197deacbc9382671c41f"}, + {file = "black-24.4.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6ad001a9ddd9b8dfd1b434d566be39b1cd502802c8d38bbb1ba612afda2ef436"}, + {file = "black-24.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e3a3a092b8b756c643fe45f4624dbd5a389f770a4ac294cf4d0fce6af86addaf"}, + {file = "black-24.4.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dae79397f367ac8d7adb6c779813328f6d690943f64b32983e896bcccd18cbad"}, + {file = "black-24.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:71d998b73c957444fb7c52096c3843875f4b6b47a54972598741fe9a7f737fcb"}, + {file = "black-24.4.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:8e5537f456a22cf5cfcb2707803431d2feeb82ab3748ade280d6ccd0b40ed2e8"}, + {file = "black-24.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:64e60a7edd71fd542a10a9643bf369bfd2644de95ec71e86790b063aa02ff745"}, + {file = "black-24.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5cd5b4f76056cecce3e69b0d4c228326d2595f506797f40b9233424e2524c070"}, + {file = "black-24.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:64578cf99b6b46a6301bc28bdb89f9d6f9b592b1c5837818a177c98525dbe397"}, + {file = "black-24.4.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:f95cece33329dc4aa3b0e1a771c41075812e46cf3d6e3f1dfe3d91ff09826ed2"}, + {file = "black-24.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4396ca365a4310beef84d446ca5016f671b10f07abdba3e4e4304218d2c71d33"}, + {file = "black-24.4.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:44d99dfdf37a2a00a6f7a8dcbd19edf361d056ee51093b2445de7ca09adac965"}, + {file = "black-24.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:21f9407063ec71c5580b8ad975653c66508d6a9f57bd008bb8691d273705adcd"}, + {file = "black-24.4.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:652e55bb722ca026299eb74e53880ee2315b181dfdd44dca98e43448620ddec1"}, + {file = "black-24.4.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7f2966b9b2b3b7104fca9d75b2ee856fe3fdd7ed9e47c753a4bb1a675f2caab8"}, + {file = "black-24.4.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1bb9ca06e556a09f7f7177bc7cb604e5ed2d2df1e9119e4f7d2f1f7071c32e5d"}, + {file = "black-24.4.0-cp38-cp38-win_amd64.whl", hash = "sha256:d4e71cdebdc8efeb6deaf5f2deb28325f8614d48426bed118ecc2dcaefb9ebf3"}, + {file = "black-24.4.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6644f97a7ef6f401a150cca551a1ff97e03c25d8519ee0bbc9b0058772882665"}, + {file = "black-24.4.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:75a2d0b4f5eb81f7eebc31f788f9830a6ce10a68c91fbe0fade34fff7a2836e6"}, + {file = "black-24.4.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eb949f56a63c5e134dfdca12091e98ffb5fd446293ebae123d10fc1abad00b9e"}, + {file = "black-24.4.0-cp39-cp39-win_amd64.whl", hash = "sha256:7852b05d02b5b9a8c893ab95863ef8986e4dda29af80bbbda94d7aee1abf8702"}, + {file = "black-24.4.0-py3-none-any.whl", hash = "sha256:74eb9b5420e26b42c00a3ff470dc0cd144b80a766128b1771d07643165e08d0e"}, + {file = "black-24.4.0.tar.gz", hash = "sha256:f07b69fda20578367eaebbd670ff8fc653ab181e1ff95d84497f9fa20e7d0641"}, ] [package.dependencies] @@ -154,13 +154,13 @@ files = [ [[package]] name = "filelock" -version = "3.13.3" +version = "3.13.4" description = "A platform independent file lock." optional = false python-versions = ">=3.8" files = [ - {file = "filelock-3.13.3-py3-none-any.whl", hash = "sha256:5ffa845303983e7a0b7ae17636509bc97997d58afeafa72fb141a17b152284cb"}, - {file = "filelock-3.13.3.tar.gz", hash = "sha256:a79895a25bbefdf55d1a2a0a80968f7dbb28edcd6d4234a0afb3f37ecde4b546"}, + {file = "filelock-3.13.4-py3-none-any.whl", hash = "sha256:404e5e9253aa60ad457cae1be07c0f0ca90a63931200a47d9b6a6af84fd7b45f"}, + {file = "filelock-3.13.4.tar.gz", hash = "sha256:d13f466618bfde72bd2c18255e269f72542c6e70e7bac83a0232d6b1cc5c8cf4"}, ] [package.extras] @@ -543,6 +543,45 @@ files = [ [package.extras] colors = ["colorama (>=0.4.6)"] +[[package]] +name = "jpype1" +version = "1.5.0" +description = "A Python to Java bridge." +optional = false +python-versions = ">=3.7" +files = [ + {file = "JPype1-1.5.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7b6b1af3f9e0033080e3532c2686a224cd14706f36c14ef36160a2a1db751a17"}, + {file = "JPype1-1.5.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0ed36803734b812c78ca9228dd3291128ac80b2a1d06c293d60b5c2f049040b4"}, + {file = "JPype1-1.5.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a02b2f05621c119d35f4acc501b4261eeb48a4af7cc13d9afc2e9eb316c4bd29"}, + {file = "JPype1-1.5.0-cp310-cp310-win_amd64.whl", hash = "sha256:0b40c76e075d4fed2c83340bb30b7b95bbc396fd370c564c6b608faab00ea4ef"}, + {file = "JPype1-1.5.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:85a31b30b482eaf788b21af421e0750aa0be7758307314178143a76632b0ad04"}, + {file = "JPype1-1.5.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:20f0229d7aaa04c480a7fa271cbd161ded58cecd838ba52a4e01bea21b60a058"}, + {file = "JPype1-1.5.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5ef976e0f3b2e9604469f449f30bb2031941a159a0637f4c16adb2c5076f3e81"}, + {file = "JPype1-1.5.0-cp311-cp311-win_amd64.whl", hash = "sha256:2bc987205ff8d2d8e36dfbef05430e0638e85d4fee1166ba58ebfa6f7a67cdf8"}, + {file = "JPype1-1.5.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:8714bfaf09d6877160bc7ac97812016ccb09f6d7ba5ea2a9f519178aefcca93f"}, + {file = "JPype1-1.5.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1696196a8b6ea2f8ad3280249014406de919088494b94a84581da01752d98dca"}, + {file = "JPype1-1.5.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8649b526eccb4047881ad60bdb1974eb71a09cdb7f8bda17c96fdc0f9a3f2d1e"}, + {file = "JPype1-1.5.0-cp312-cp312-win_amd64.whl", hash = "sha256:9aafc00b00bf8c1b624081e5d4ab87f7752e6c7ee6a141cfc332250b05c6d42f"}, + {file = "JPype1-1.5.0-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ccb9c786e9b709c6390c89e200036b2080bf668cce118561a0cfd74eae43903f"}, + {file = "JPype1-1.5.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa5a27cba59865f034259657fd322ca0a5cde82e691a1180c6a8040d2e0c0788"}, + {file = "JPype1-1.5.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:cff64ac1980d899841cbc561b097eeec8106b34d70c42342b211b83005562f88"}, + {file = "JPype1-1.5.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:439e006a3a74bd26e15ab6bca873e3572087667b5525cb82244a1945dd607d80"}, + {file = "JPype1-1.5.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b437ce6fadaf5562576b2b5919fa0a5174a92f70a7d903f0faf8dff6f34199fa"}, + {file = "JPype1-1.5.0-cp38-cp38-win_amd64.whl", hash = "sha256:a01eba1fdf5869e46dc7336a8ff2a97a66d209c8d5f23a64f7f23b70e55ffc0f"}, + {file = "JPype1-1.5.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:e8d9bdd137e7cecabebd46ce7d3539fd53745018974d0bc3ec0a3634c2e53af5"}, + {file = "JPype1-1.5.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c9f8f01474186bf69bf05dd9a5ef4d5b2159980cfc9d8da91e021d682cc32552"}, + {file = "JPype1-1.5.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f7aa1469d75f9b310f709b61bb2faa4cef4cbd4d670531ad1d1bb53e29cfda05"}, + {file = "JPype1-1.5.0-cp39-cp39-win_amd64.whl", hash = "sha256:6bfdc101c56cab0b6b16e974fd8cbb0b3f7f14178286b8b55413c5d82d5f2bea"}, + {file = "JPype1-1.5.0.tar.gz", hash = "sha256:425a6e1966afdd5848b60c2688bcaeb7e40ba504a686f1114589668e0631e878"}, +] + +[package.dependencies] +packaging = "*" + +[package.extras] +docs = ["readthedocs-sphinx-ext", "sphinx", "sphinx-rtd-theme"] +tests = ["pytest"] + [[package]] name = "mccabe" version = "0.7.0" @@ -811,18 +850,18 @@ files = [ [[package]] name = "setuptools" -version = "69.2.0" +version = "69.5.1" description = "Easily download, build, install, upgrade, and uninstall Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "setuptools-69.2.0-py3-none-any.whl", hash = "sha256:c21c49fb1042386df081cb5d86759792ab89efca84cf114889191cd09aacc80c"}, - {file = "setuptools-69.2.0.tar.gz", hash = "sha256:0ff4183f8f42cd8fa3acea16c45205521a4ef28f73c6391d8a25e92893134f2e"}, + {file = "setuptools-69.5.1-py3-none-any.whl", hash = "sha256:c636ac361bc47580504644275c9ad802c50415c7522212252c033bd15f301f32"}, + {file = "setuptools-69.5.1.tar.gz", hash = "sha256:6c1fccdac05a97e598fb0ae3bbed5904ccb317337a51139dcd51453611bbb987"}, ] [package.extras] -docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"] -testing = ["build[virtualenv]", "filelock (>=3.4.0)", "importlib-metadata", "ini2toml[lite] (>=0.9)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "mypy (==1.9)", "packaging (>=23.2)", "pip (>=19.1)", "pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-home (>=0.5)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff (>=0.2.1)", "pytest-timeout", "pytest-xdist (>=3)", "tomli", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] +docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"] +testing = ["build[virtualenv]", "filelock (>=3.4.0)", "importlib-metadata", "ini2toml[lite] (>=0.9)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "mypy (==1.9)", "packaging (>=23.2)", "pip (>=19.1)", "pytest (>=6,!=8.1.1)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-home (>=0.5)", "pytest-mypy", "pytest-perf", "pytest-ruff (>=0.2.1)", "pytest-timeout", "pytest-xdist (>=3)", "tomli", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] testing-integration = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "packaging (>=23.2)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] [[package]] @@ -871,13 +910,13 @@ files = [ [[package]] name = "virtualenv" -version = "20.25.1" +version = "20.25.3" description = "Virtual Python Environment builder" optional = false python-versions = ">=3.7" files = [ - {file = "virtualenv-20.25.1-py3-none-any.whl", hash = "sha256:961c026ac520bac5f69acb8ea063e8a4f071bcc9457b9c1f28f6b085c511583a"}, - {file = "virtualenv-20.25.1.tar.gz", hash = "sha256:e08e13ecdca7a0bd53798f356d5831434afa5b07b93f0abdf0797b7a06ffe197"}, + {file = "virtualenv-20.25.3-py3-none-any.whl", hash = "sha256:8aac4332f2ea6ef519c648d0bc48a5b1d324994753519919bddbb1aff25a104e"}, + {file = "virtualenv-20.25.3.tar.gz", hash = "sha256:7bb554bbdfeaacc3349fa614ea5bff6ac300fc7c335e9facf3a3bcfc703f45be"}, ] [package.dependencies] @@ -886,10 +925,10 @@ filelock = ">=3.12.2,<4" platformdirs = ">=3.9.1,<5" [package.extras] -docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.2)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"] +docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.2,!=7.3)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"] test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.4)", "pytest-env (>=0.8.2)", "pytest-freezer (>=0.4.8)", "pytest-mock (>=3.11.1)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=68)", "time-machine (>=2.10)"] [metadata] lock-version = "2.0" python-versions = "^3.10" -content-hash = "dcecf0a57b15089da5d84e9b7ade4b59af39a210387e0f69c98ca701cc31ff1a" +content-hash = "4a0832bb44a8f5cb2bfefad9dd7f78fc1a4e0c7609fc7183c95197ea5e01f11d" diff --git a/pyproject.toml b/pyproject.toml index c1128d9..c2168ac 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -25,6 +25,7 @@ authors = ["RapidStream Design Automation, Inc. "] [tool.poetry.dependencies] python = "^3.10" +jpype1 = "^1.5.0" [tool.poetry.group.dev] optional = true diff --git a/python/src/CrossingCRNodeCounter.py b/python/src/CrossingCRNodeCounter.py deleted file mode 100644 index ccd5628..0000000 --- a/python/src/CrossingCRNodeCounter.py +++ /dev/null @@ -1,88 +0,0 @@ -from pathlib import Path -from typing import Literal -import jpype -import jpype.imports -import sys - -def get_node_counts_between_CRs( - dcp_path: Path, - num_col: int, - num_row: int, -) -> dict[Literal["N", "S", "E", "W"], int]: - """Extract number of nodes between a **single** clock region and its adjacent - ones (at clock region level). - - Args: - dcp_path: Path to a checkpoint file which contains a grid of CRs. - num_col: Number of columns (X) of the pblock grid. - num_row: Number of rows (Y) of the pblock grid. - - Returns: - A dictionrary direction to the number of nodes. For example, for Alveo - U280, num_col: 0, num_row: 0, the output is {'E': 12480, 'N': 9200}. - - CR_X0Y0 should not have "SOUTH" or "WEST" keys because those slots - do not exist. - """ - jpype.startJVM(jpype.getDefaultJVMPath()) - from com.xilinx.rapidwright.examples import CrossingCRNodeCounter - node_count_java = CrossingCRNodeCounter.getSinglePBlockCrossingCRNodeCount(jpype.JString(str(dcp_path)), num_col, num_row) # - node_count = dict(node_count_java) # dict - ''' - # enabling assertions by "-ea" - process = jpype.java.lang.Runtime.getRuntime().exec_( - "java -ea com.xilinx.rapidwright.examples.CrossingCRNodeCounter {} {} {}".format(dcp_path, num_col, num_row)) - process.waitFor() - - # get stdout - input_stream = process.getInputStream() - reader = jpype.java.io.BufferedReader(jpype.java.io.InputStreamReader(input_stream)) - - # read commandline output - line = reader.readLine() - while line is not None: - print(line) - line = reader.readLine() - ''' - return node_count - -def get_node_counts_between_CRs( - dcp_path: Path -) -> dict[int, dict[int, dict[Literal["N", "S", "E", "W"], int]]]: - """Extract number of nodes between **all pairs of** pblocks (at clock region - level). - - Args: - dcp_path: Path to a checkpoint file which contains a grid of pblocks. It is - guaranteed that the pblock will be named in the format of f"x{x}y{y}". - - Returns: - A mapping from (col, row) to direction to the number of nodes. For example, - node_count[0][0]["N"] is the number of nodes between pblock (0, 0) and - (0, 1). - - node_count[0][0] should not have "SOUTH" or "WEST" keys because those slots - do not exist. - """ - jpype.startJVM(jpype.getDefaultJVMPath(), "-ea") # enabling assertions by "-ea" - from com.xilinx.rapidwright.examples import CrossingCRNodeCounter - node_count_java = CrossingCRNodeCounter.getAllPBlockCrossingCRNodeCount(jpype.JString(str(dcp_path))) # - node_count = {_:{__:dict(dict(node_count_java[_])[__]) for __ in dict(node_count_java[_]).keys()} for _ in node_count_java.keys()} # dict - return node_count - -if __name__ == "__main__": - if len(sys.argv) not in {2, 4}: - print("Usage: python CrossingCRNodeExtractor.py \n or python CrossingCRNodeExtractor.py ") - sys.exit(1) - - try: - dcp_path = Path(sys.argv[1]) - num_col = int(sys.argv[2]) if len(sys.argv) == 4 else -1 - num_row = int(sys.argv[3]) if len(sys.argv) == 4 else -1 - except Exception as e: - print("Error: Invalid arguments.") - sys.exit(1) - - # node_counts = get_node_counts_between_CRs(dcp_path, num_col, num_row) - node_counts = get_node_counts_between_CRs(dcp_path) - print(node_counts) \ No newline at end of file diff --git a/python/src/README.md b/python/src/README.md index caa36e0..b6caad2 100644 --- a/python/src/README.md +++ b/python/src/README.md @@ -1,3 +1,9 @@ + + # RapidStream DSE Engine Python Source Code -Please finish the "How to Compile" section in `/java/README.md` before running the script in `/python`. \ No newline at end of file +Please finish the "How to Compile" section in `/java/README.md` before running the script in `/python`. diff --git a/python/src/crossing_pblocks_node_counter.py b/python/src/crossing_pblocks_node_counter.py new file mode 100644 index 0000000..3cf3fc8 --- /dev/null +++ b/python/src/crossing_pblocks_node_counter.py @@ -0,0 +1,71 @@ +"""crossing_pblocks_node_counter.py: Extract node # between pblocks.""" + +__copyright__ = """ +Copyright (c) 2024 RapidStream Design Automation, Inc. and contributors. +All rights reserved. The contributor(s) of this file has/have agreed to the +RapidStream Contributor License Agreement. +""" + +import argparse +from pathlib import Path +from typing import Literal + +import jpype +import jpype.imports + +jpype.startJVM(jpype.getDefaultJVMPath(), "-ea") # enabling assertions +from com.xilinx.rapidwright.examples import ( # noqa: E402,E501 #pylint: disable=E0401,C0413 + CrossingPBlockNodeCounter, +) + + +def get_node_counts_between_pblocks( + dcp_path: Path, + num_col: int, + num_row: int, +) -> dict[int, dict[int, dict[Literal["N", "S", "E", "W"], int]]]: + """Extract number of wires between pblocks. + + Args: + dcp_path: Path to a checkpoint file which contains a grid of pblocks. + It is guaranteed that the pblock will be named in the format of + f"x{x}y{y}". + num_col: Number of columns of the pblock grid. + num_row: Number of rows of the pblock grid. + + Returns: + A mapping from (col, row) to direction to the number of wires. For + example, wire_count[0][0]["NORTH"] is the number of wires between + pblock (0, 0) and (0, 1). + + wire_count[0][0] should not have "SOUTH" or "WEST" keys because those + slots do not exist. + """ + node_count_java = CrossingPBlockNodeCounter.getAllPBlockCrossingNodeCount( + jpype.JString(str(dcp_path)), num_col, num_row + ) # + node_count = { + _: { + __: dict(dict(node_count_java[_])[__]) + for __ in dict(node_count_java[_]).keys() + } + for _ in node_count_java.keys() + } # dict + return node_count + + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument("dcp_path", type=str, help="Path to checkpoint") + parser.add_argument("num_col", type=int, help="Column# of the pblock grid") + parser.add_argument("num_row", type=int, help="Row# of the pblock grid") + args = parser.parse_args() + + dcp_path_input = Path(args.dcp_path) + num_col_input = args.num_col + num_row_input = args.num_row + + node_counts = get_node_counts_between_pblocks( + dcp_path_input, num_col_input, num_row_input + ) + print(node_counts)