Commit b3306464 by Dinple

update + bug fixies

parent b5fadf19
......@@ -487,7 +487,7 @@ class PlacementCost(object):
elif all(it in line_item for it in ['MACROs'])\
and len(line_item) == 2:
_macros_cnt = int(line_item[1])
elif all(re.match(r'[0-9NEWS\.\-]+', it) for it in line_item)\
elif all(re.match(r'[0-9FNEWS\.\-]+', it) for it in line_item)\
and len(line_item) == 5:
# [node_index] [x] [y] [orientation] [fixed]
_node_plc[int(line_item[0])] = line_item[1:]
......@@ -561,6 +561,7 @@ class PlacementCost(object):
# restore placement for each module
try:
# print(sorted(list(info_dict['node_plc'].keys())))
assert sorted(self.port_indices +\
self.hard_macro_indices +\
self.soft_macro_indices) == sorted(list(info_dict['node_plc'].keys()))
......@@ -2378,6 +2379,216 @@ class PlacementCost(object):
plt.show()
plt.close('all')
'''
FD Placement below shares the same functionality as the FDPlacement/fd_placement.py
'''
def __repulsive_force(self, repel_factor, node_i, node_j):
'''
Calculate repulsive force between two nodes node_i, node_j
'''
if repel_factor == 0.0:
return 0.0, 0.0
# retrieve module instance
mod_i = self.modules_w_pins[node_i]
mod_j = self.modules_w_pins[node_j]
# retrieve module position
x_i, y_i = mod_i.get_pos()
x_j, y_j = mod_j.get_pos()
# get dist between x and y
x_dist = x_i - x_j
y_dist = y_i - y_j
# get dist of hypotenuse
hypo_dist = math.sqrt(x_dist**2 + y_dist**2)
# compute force in x and y direction
if hypo_dist <= 1e-5:
return 1e5, 1e5
else:
f_x = repel_factor * x_dist / hypo_dist
f_y = repel_factor * y_dist / hypo_dist
return f_x, f_y
def __attractive_force(self, io_factor, attract_factor, node_i, node_j, io_flag = True, attract_exponent = 1):
'''
Calculate repulsive force between two nodes node_i, node_j
'''
# retrieve module instance
mod_i = self.modules_w_pins[node_i]
mod_j = self.modules_w_pins[node_j]
# retrieve module position
x_i, y_i = mod_i.get_pos()
x_j, y_j = mod_j.get_pos()
# get dist between x and y
x_dist = x_i - x_j
y_dist = y_i - y_j
# get dist of hypotenuse
hypo_dist = math.sqrt(x_dist**2 + y_dist**2)
# compute force in x and y direction
if hypo_dist <= 0.0:
return 0.0, 0.0
else:
if io_flag:
temp_f = io_factor * (hypo_dist ** attract_exponent)
else:
temp_f = attract_factor * (hypo_dist ** attract_exponent)
f_x = x_dist / hypo_dist * temp_f
f_y = y_dist / hypo_dist * temp_f
return f_x, f_y
def __centralize(self, mod_id):
'''
Pull the modules to the nearest center of the gridcell
'''
mod = self.modules_w_pins[mod_id]
mod_x, mod_y = mod.get_pos()
# compute grid cell col
# why / 2.0?
col = round((mod_x - self.grid_width / 2.0) / self.grid_width)
if (col < 0):
col = 0
elif col > self.grid_col - 1:
col = self.grid_col - 1
row = round((mod_y - self.grid_height / 2.0) / self.grid_height)
if (row < 0):
row = 0
elif row > self.grid_row - 1:
row = self.grid_row - 1
mod.set_pos((col + 0.5) * self.grid_width, (row + 0.5) * self.grid_height)
def __boundary_check(self, mod_id):
'''
Make sure all the clusters are placed within the canvas
'''
mod = self.modules_w_pins[mod_id]
mod_x, mod_y = mod.get_pos()
if mod_x < 0.0:
mod_x = 0.0
if mod_x > self.width:
mod_x = self.width
if mod_y < 0.0:
mod_y = 0.0
if mod_y > self.height:
mod_y = self.height
mod.set_pos(mod_x, mod_y)
def __fd_placement(self, io_factor, max_displacement, attract_factor, repel_factor):
'''
Force-directed Placement for standard-cell clusters
'''
# store x/y displacement for all soft macro disp
soft_macro_disp = {}
for mod_idx in self.soft_macro_indices:
soft_macro_disp[mod_idx] = [0.0, 0.0]
def add_displace(mod_id, x_disp, y_disp):
soft_macro_disp[mod_id][0] += x_disp
soft_macro_disp[mod_id][1] += y_disp
# limit the displacement. max_displace is the threshold
def limit_displace(max_displace, mod_id):
if max_displace <= 0.0:
soft_macro_disp[mod_id][0] = 0.0
soft_macro_disp[mod_id][1] = 0.0
# get dist of hypotenuse
hypo_dist = math.sqrt(soft_macro_disp[mod_id][0]**2 + soft_macro_disp[mod_id][1]**2)
if hypo_dist > max_displace:
soft_macro_disp[mod_id][0] = soft_macro_disp[mod_id][0] / hypo_dist * max_displace
soft_macro_disp[mod_id][1] = soft_macro_disp[mod_id][1] / hypo_dist * max_displace
def update_location(mod_id, x_disp, y_disp):
x_pos, y_pos = self.modules_w_pins[mod_id].get_pos()
# logging.info("{} {} {} {}".format(x_pos, y_pos, x_disp, y_disp))
self.modules_w_pins[mod_id].set_pos(x_pos + x_disp, y_pos + y_disp)
# calculate the repulsive forces
# repulsive forces between stdcell clusters
for mod_i in self.soft_macro_indices:
for mod_j in self.soft_macro_indices:
if (mod_i <= mod_j):
continue
repul_x, repul_y = self.__repulsive_force(repel_factor=repel_factor,
node_i=mod_i, node_j=mod_j)
add_displace(mod_i, repul_x, repul_y)
add_displace(mod_j, -1.0 * repul_x, -1.0 * repul_y)
# repulsive forces between stdcell clusters and macros
for mod_i in self.soft_macro_indices:
for mod_j in self.hard_macro_indices:
repul_x, repul_y = self.__repulsive_force(repel_factor=repel_factor,
node_i=mod_i, node_j=mod_j)
add_displace(mod_i, repul_x, repul_y)
# calculate the attractive force
# traverse each edge
# the adj_matrix is a symmetric matrix
for driver_pin_idx, driver_pin in enumerate(self.modules_w_pins):
# only for soft macro
if driver_pin_idx in self.soft_macro_pin_indices and driver_pin.get_sink():
driver_mod_idx = self.get_ref_node_id(driver_pin_idx)
for sink_pin_name in driver_pin.get_sink().keys():
sink_mod_idx = self.mod_name_to_indices[sink_pin_name]
# print(self.modules_w_pins[sink_mod_idx].get_type())
attrac_x, attrac_y = self.__attractive_force(io_factor=io_factor,
attract_factor=attract_factor,
node_i=driver_mod_idx,
node_j=sink_mod_idx
)
add_displace(driver_mod_idx, -1.0 * attrac_x, -1.0 * attrac_y)
for mod_idx in soft_macro_disp.keys():
# limit max displacement to threshold : max_displacement
limit_displace(max_displace=max_displacement, mod_id=mod_idx)
# push all the macros to the nearest center of gridcell
update_location(mod_idx, *soft_macro_disp[mod_idx])
# Moved to here to save a for loop
# Based on our understanding, the stdcell clusters can be placed
# at any place in the canvas instead of the center of gridcells
self.__boundary_check(mod_idx)
def optimize_stdcells(self, use_current_loc, move_stdcells, move_macros,
log_scale_conns, use_sizes, io_factor, num_steps,
max_move_distance, attract_factor, repel_factor):
# initialize the position for all the macros and stdcell clusters
# YW: here I will ignore centering Macros since CT placement does that
for mod_idx in self.soft_macro_indices:
self.__centralize(mod_id = mod_idx)
for epoch_id, iterations in enumerate(num_steps):
logging.info("#[OPTIMIZING STDCELs] at num_step {}:".format(str(epoch_id)))
print("[INFO] max_displaccment = ", max_move_distance[epoch_id])
print("[INFO] attractive_factor = ", attract_factor[epoch_id])
print("[INFO] repulsive_factor = ", repel_factor[epoch_id])
print("[INFO] io_factor = ", io_factor)
print("[INFO] number of iteration = ", iterations)
for iter in range(iterations):
logging.info("# iteration {}:".format(str(iter)))
self.__fd_placement(io_factor=io_factor,
max_displacement=max_move_distance[epoch_id],
attract_factor=attract_factor[epoch_id],
repel_factor=repel_factor[epoch_id])
self.save_placement('epoch_{}.plc'.format(str(epoch_id)))
# Board Entity Definition
class Port:
......
......@@ -741,18 +741,6 @@ class PlacementCostTest():
init_placement=self.PLC_PATH
)
if self.PLC_PATH:
print("#[PLC FILE FOUND] Loading info from .plc file")
self.plc_util_os.set_canvas_boundary_check(False)
self.plc_util_os.restore_placement(self.PLC_PATH,
ifInital=True,
ifValidate=True,
ifReadComment=False)
self.plc_util.set_canvas_boundary_check(False)
self.plc_util.restore_placement(self.PLC_PATH)
else:
print("#[PLC FILE MISSING] Using only netlist info")
self.extractor = observation_extractor.ObservationExtractor(
plc=self.plc_util, observation_config=self._observation_config
)
......@@ -935,6 +923,24 @@ class PlacementCostTest():
print(" +++ TEST ENVIRONMENT: PASS +++")
print(" ++++++++++++++++++++++++++++++")
def test_fd_placement(self):
print("############################ TEST FDPLACEMENT ############################")
self.plc_util_os = placement_util.create_placement_cost(
plc_client=plc_client_os,
netlist_file=self.NETLIST_PATH,
init_placement=self.PLC_PATH
)
# placement util is incapable of setting routing resources
self.plc_util_os.set_routes_per_micron(self.RPMH, self.RPMV)
self.plc_util_os.set_macro_routing_allocation(self.MARH, self.MARV)
self.plc_util_os.set_congestion_smooth_range(self.SMOOTH)
self.plc_util_os.set_canvas_size(self.CANVAS_WIDTH, self.CANVAS_HEIGHT)
self.plc_util_os.set_placement_grid(self.GRID_COL, self.GRID_ROW)
placement_util.fd_placement_schedule(self.plc_util_os)
def parse_flags(argv):
parser = argparse_flags.ArgumentParser(
......@@ -1003,6 +1009,7 @@ def main(args):
# PCT.test_observation_extractor()
PCT.view_canvas()
# PCT.test_environment()
# PCT.test_fd_placement()
if __name__ == '__main__':
......
import re
import os, sys
import math
import numpy as np
import logging
import matplotlib.pyplot as plt
import pandas as pd
from torch import argmax
# disable scientific notation
np.set_printoptions(suppress=True)
# print full array
np.set_printoptions(threshold=sys.maxsize)
'''
META INFO
'''
# Directory that stores all plc file (must come from the same netlist)
PLC_DIR = "Plc_client/test/ariane"
assert os.path.isdir(PLC_DIR)
# Top X% of largest movement range
TOP_X = 1
# List to store every plc coordinate
PLC_COORD = []
# scan through every .plc file
for __, __, files in os.walk(PLC_DIR):
for plc_file in files:
if plc_file.endswith((".plc")):
plc_pth = os.path.join(PLC_DIR, plc_file)
print("[INFO] Reading plc file {}".format(plc_pth))
# store in numpy array for ease of computation
temp_coord = np.empty((1,2), float)
for cnt, line in enumerate(open(plc_pth, 'r')):
line_item = re.findall(r'[0-9A-Za-z\.\-]+', line)
# skip empty lines
if len(line_item) == 0:
continue
if all(re.match(r'[0-9FNEWS\.\-]+', it) for it in line_item)\
and len(line_item) == 5:
# extract pos
temp_coord = np.append(temp_coord, np.array([[float(line_item[1]),float(line_item[2])]]), axis=0)
# remove header row
temp_coord = temp_coord[1:, :]
# make sure every plc is aligned
if PLC_COORD:
assert PLC_COORD[-1].shape == temp_coord.shape
PLC_COORD.append(temp_coord)
print(temp_coord)
del temp_coord
# store all pair-wise distance
abs_dist_plc = np.empty((PLC_COORD[-1].shape[0],1), float)
# pair-wise distance of all plc files
for i in range(len(PLC_COORD)):
for j in range(len(PLC_COORD)):
if i == j:
continue
# find x/y position diff
diff_coord = PLC_COORD[i] - PLC_COORD[j]
# x_diff^2, y_diff^2
diff_coord = np.power(diff_coord, 2)
# sqrt(x_diff^2 + y_diff^2)
abs_dist_coord = np.sqrt(diff_coord[:, 0] + diff_coord[:, 1])
abs_dist_plc = np.append(abs_dist_plc, abs_dist_coord.reshape((-1, 1)), axis=1)
# remove header col
abs_dist_plc = abs_dist_plc[:, 1:]
TOP_N = int(math.floor(abs_dist_plc.shape[0] * (TOP_X/100.0)))
print(TOP_N)
'''
MACRO placement maximum distance + visual
'''
# across all the plc diff, the max distance [row wise]
max_dist = np.amax(abs_dist_plc, axis=1)
# top-n max distance
topn_max_dist_idx = np.argpartition(max_dist, -TOP_N)[-TOP_N:]
topn_max_dist_val = np.take(max_dist, topn_max_dist_idx)
x = range(topn_max_dist_val.shape[0])
y = topn_max_dist_val
n = topn_max_dist_idx
fig, ax = plt.subplots()
ax.set_title("Top {}% Maximum Placement Range".format(TOP_X))
ax.scatter(x, y, c = 'b')
ax.set_xlabel("module index")
ax.set_ylabel("distance")
for i, txt in enumerate(n):
ax.annotate(txt, (x[i], y[i]))
plt.show()
'''
MACRO placement box plot visual
'''
abs_dist_plc_df = pd.DataFrame(data=abs_dist_plc)
topn_max_dist_df = abs_dist_plc_df.iloc[topn_max_dist_idx, :]
topn_max_dist_df.T.boxplot()
plt.title("Top {}% Placement Range".format(TOP_X))
plt.xlabel("module index")
plt.ylabel("distance")
plt.show()
'''
MACRO placement variane test
'''
'''
MACRO placement std dev test
'''
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment