Skip to content

Commit

Permalink
P Metrics v1.0: CLB SLICE done, Reg ongoing; Fixing prior typos.
Browse files Browse the repository at this point in the history
  • Loading branch information
RipperJ committed Apr 26, 2024
1 parent de4ce30 commit 4411d8c
Show file tree
Hide file tree
Showing 3 changed files with 297 additions and 5 deletions.
2 changes: 1 addition & 1 deletion java/CrossingPBlockNodeCounter.java
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ private static HashMap<String, Integer> getSinglePBlockDirectionToNodeCount(Devi
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);
System.err.println("West 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);
Expand Down
292 changes: 292 additions & 0 deletions java/PlacementMetricExtractor.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,292 @@
/*
# 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.blocks.UtilizationType;
import com.xilinx.rapidwright.design.tools.LUTTools;
import com.xilinx.rapidwright.design.Cell;
import com.xilinx.rapidwright.design.ConstraintGroup;
import com.xilinx.rapidwright.design.Design;
import com.xilinx.rapidwright.design.DesignTools;
import com.xilinx.rapidwright.design.SiteInst;
import com.xilinx.rapidwright.device.Device;
import com.xilinx.rapidwright.device.Site;
import com.xilinx.rapidwright.device.SiteTypeEnum;
import com.xilinx.rapidwright.util.Utils;

import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.HashSet;
import java.util.List;
import java.util.Map;

public class PlacementMetricExtractor {

private static HashSet<String> stopElements;
private static HashSet<String> lutElements;
private static HashSet<String> regElements;
static {
stopElements = new HashSet<String>();
// CONFIG
stopElements.add("BSCAN1");
stopElements.add("BSCAN2");
stopElements.add("BSCAN3");
stopElements.add("BSCAN4");
stopElements.add("DCIRESET");
stopElements.add("DNAPORT");
stopElements.add("EFUSE_USR");
stopElements.add("FRAME_ECC");
stopElements.add("ICAP_BOT");
stopElements.add("ICAP_TOP");
stopElements.add("MASTER_JTAG");
stopElements.add("STARTUP");
stopElements.add("USR_ACCESS");

// BRAM
stopElements.add("RAMBFIFO36E2");

// IOB
stopElements.add("IBUFCTRL");
stopElements.add("INBUF");
stopElements.add("OUTBUF");
stopElements.add("PADOUT");

// MMCM
stopElements.add("MMCME3_ADV");

// DSP
stopElements.add("DSP_PREADD_DATA");
stopElements.add("DSP_A_B_DATA");
stopElements.add("DSP_C_DATA");
stopElements.add("DSP_OUTPUT");

lutElements = new HashSet<String>();
regElements = new HashSet<String>();

for (String letter : Arrays.asList("A", "B", "C", "D", "E", "F", "G", "H")) {
regElements.add(letter +"FF");
regElements.add(letter +"FF2");
for (String size : Arrays.asList("5", "6")) {
lutElements.add(letter + size + "LUT");
}
}
}


public static boolean isBELAReg(String elementName) {
return regElements.contains(elementName);
}

private static boolean isCellLutMemory(Cell c) {
if (c == null) return false;
if (c.getType().contains("SRL") || c.getType().contains("RAM")) return true;
return false;
}

private static void incrementUtilType(Map<UtilizationType, Integer> map, UtilizationType ut) {
Integer val = map.get(ut);
val++;
map.put(ut, val);
}

public static Map<UtilizationType, Integer> calculateUtilization(Design d, PBlock pblock) {
Set<Site> sites = pblock.getAllSites(null);
List<SiteInst> siteInsts = d.getSiteInsts().stream().filter(s -> sites.contains(s.getSite()))
.collect(Collectors.toList());
// System.out.println(sites);
for (SiteInst si : siteInsts) {
if (si.getCells().size() == 0)
System.out.println("SiteInst: " + si + "; Cell #: " + si.getCells().size());
}
return calculateUtilization(siteInsts);
}

public static Map<UtilizationType, Integer> calculateUtilization(Collection<SiteInst> siteInsts) {
Map<UtilizationType, Integer> map = new HashMap<UtilizationType, Integer>();

for (UtilizationType ut : UtilizationType.values()) {
map.put(ut, 0);
}
for (SiteInst si : siteInsts) {
SiteTypeEnum s = si.getSite().getSiteTypeEnum();
if (Utils.isSLICE(si)) { // done
incrementUtilType(map, UtilizationType.CLBS);
if (s == SiteTypeEnum.SLICEL) {
// corresponding TCL: get_sites -of_objects [get_pblocks CR_X0Y12_To_CR_X3Y15] -filter { IS_USED == "TRUE" && SITE_TYPE == "SLICEL" }
// ! Vivado failing to include one column (e.g., as tall as the height of a clock region in Alveo U250) of SLICELs beside the laguna column, reason unknown yet -- for example, `get_pblocks -of_objects [get_sites SLICE_X112Y741]` wouldn't show "CR_X0Y12_To_CR_X3Y15", which was created by "create_pblock CR_X0Y12_To_CR_X3Y15; resize_pblock CR_X0Y12_To_CR_X3Y15 -add CLOCKREGION_X0Y12:CLOCKREGION_X3Y15"
incrementUtilType(map, UtilizationType.CLBLS);
// System.out.println("mark_objects [get_sites " + si.getSite() + "]"); // debug
} else if (s == SiteTypeEnum.SLICEM) {
incrementUtilType(map, UtilizationType.CLBMS);
// corresponding TCL: get_sites -of_objects [get_pblocks CR_X0Y12_To_CR_X3Y15] -filter { IS_USED == "TRUE" && SITE_TYPE == "SLICEM" }
}
} else if (Utils.isDSP(si)) {
incrementUtilType(map, UtilizationType.DSPS);
} else if (Utils.isBRAM(si)) {
if (s == SiteTypeEnum.RAMBFIFO36) {
incrementUtilType(map, UtilizationType.RAMB36S_FIFOS);
} else if (s == SiteTypeEnum.RAMB181 || s == SiteTypeEnum.RAMBFIFO18) {
incrementUtilType(map, UtilizationType.RAMB18S);
}
} else if (Utils.isURAM(si)) {
incrementUtilType(map, UtilizationType.URAMS);
}
for (Cell c : si.getCells()) {
/* As in UtilizationType:
CLB_LUTS("CLB LUTs"),
LUTS_AS_LOGIC("LUTs as Logic"),
LUTS_AS_MEMORY("LUTs as Memory"),
CLB_REGS("CLB Regs"),
REGS_AS_FFS("Regs as FF"),
REGS_AS_LATCHES("Regs as Latch"),
CARRY8S("CARRY8s"),
//F7_MUXES("F7 Muxes"),
//F8_MUXES("F8 Muxes"),
//F9_MUXES("F9 Muxes"),
CLBS("CLBs"),
CLBLS("CLBLs"),
CLBMS("CLBMs"),
//LUT_FF_PAIRS("Lut/FF Pairs"),
RAMB36S_FIFOS("RAMB36s/FIFOs"),
RAMB18S("RAMB18s"),
URAMS("URAMs"),
DSPS("DSPs");
*/
if (c.getBELName() == null) {
// e.g., Alveo U250, DSP48E2_{X28|X29} cell: <LOCKED>(BEL: (unplaced)) -> c.getBELName() == null -> exception
// System.out.println("null Name! site: " + si.getName() + " cell: " + c); // debug
continue;
}
if (isBELAReg(c.getBELName())) {
incrementUtilType(map, UtilizationType.CLB_REGS);
incrementUtilType(map, UtilizationType.REGS_AS_FFS);
} else if (c.getBELName().contains("CARRY")) {
incrementUtilType(map, UtilizationType.CARRY8S);
}

}
for (char letter : LUTTools.lutLetters) {
Cell c5 = si.getCell(letter +"5LUT");
Cell c6 = si.getCell(letter +"6LUT");
if (c5 != null && c5.isRoutethru()) {
c5 = null;
} else if (c6 != null && c6.isRoutethru()) {
c6 = null;
}
if (c5 != null || c6 != null) {
incrementUtilType(map, UtilizationType.CLB_LUTS);

if (isCellLutMemory(c5) || isCellLutMemory(c6)) {
incrementUtilType(map, UtilizationType.LUTS_AS_MEMORY);
} else {
incrementUtilType(map, UtilizationType.LUTS_AS_LOGIC);
}
}
}
}
return map;
}

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+).*$'!";
String newPBlockName = "X" + m.group(1) + "Y" + m.group(2) + "X" + m.group(3) + "Y" + m.group(4);
return newPBlockName;
}

private static Map<String, PBlock> getNameToPBlocksFromXDC(Design design){
Device device = design.getDevice();
Map<String, PBlock> 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;
System.out.println(line.trim());
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 void getAllPBlockPlacementMetrics(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<String, PBlock> pblockMap = getNameToPBlocksFromXDC(design);
for (String pblockName : pblockMap.keySet()) {
PBlock pblock = pblockMap.get(pblockName);
Map<UtilizationType, Integer> utilizationMap = calculateUtilization(design, pblock);
System.out.println("PBlock: " + pblockName + "; Utilization: " + utilizationMap);
// break;
}
return;
}

public static void main(String[] args) {
if(args.length != 3) {
System.out.println("USAGE: rapidwright MetricsExtractor <.dcp> <col (X)> <row (Y)>");
return;
}
getAllPBlockPlacementMetrics(args[0], Integer.parseInt(args[1]), Integer.parseInt(args[2]));
}
}
8 changes: 4 additions & 4 deletions python/src/crossing_pblocks_node_counter.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ def get_node_counts_between_pblocks(
num_col: int,
num_row: int,
) -> dict[int, dict[int, dict[Literal["N", "S", "E", "W"], int]]]:
"""Extract number of wires between pblocks.
"""Extract number of nodes between pblocks.
Args:
dcp_path: Path to a checkpoint file which contains a grid of pblocks.
Expand All @@ -34,11 +34,11 @@ def get_node_counts_between_pblocks(
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
A mapping from (col, row) to direction to the number of nodes. For
example, node_count[0][0]["NORTH"] is the number of nodes between
pblock (0, 0) and (0, 1).
wire_count[0][0] should not have "SOUTH" or "WEST" keys because those
node_count[0][0] should not have "SOUTH" or "WEST" keys because those
slots do not exist.
"""
node_count_java = CrossingPBlockNodeCounter.getAllPBlockCrossingNodeCount(
Expand Down

0 comments on commit 4411d8c

Please sign in to comment.