Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
M
macroplacement
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
lvzhengyang
macroplacement
Commits
b3306464
Commit
b3306464
authored
Nov 01, 2022
by
Dinple
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
update + bug fixies
parent
b5fadf19
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
353 additions
and
13 deletions
+353
-13
CodeElements/Plc_client/plc_client_os.py
+212
-1
CodeElements/Plc_client/plc_client_os_test.py
+19
-12
CodeElements/Plc_client/stat_test.py
+122
-0
No files found.
CodeElements/Plc_client/plc_client_os.py
View file @
b3306464
...
...
@@ -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-9
F
NEWS\.\-]+'
,
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
:
...
...
CodeElements/Plc_client/plc_client_os_test.py
View file @
b3306464
...
...
@@ -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__'
:
...
...
CodeElements/Plc_client/stat_test.py
0 → 100644
View file @
b3306464
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
'''
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment