plc_client_os_test.py 18.6 KB
Newer Older
Dinple committed
1 2 3 4
import numpy as np
import sys,os,traceback
import argparse
import math
Dinple committed
5
from absl import flags
Dinple committed
6
from absl.flags import argparse_flags
Dinple committed
7
from absl import app
Dinple committed
8
from Plc_client import plc_client_os as plc_client_os
Dinple committed
9 10 11 12 13 14
try:
    from Plc_client import plc_client as plc_client
except ImportError:
    print("[PLC CLIENT MISSING] Downloading Google's API for testing!")
    os.system("curl 'https://raw.githubusercontent.com/google-research/circuit_training/main/circuit_training/environment/plc_client.py' > ./Plc_client/plc_client.py")
    from Plc_client import plc_client as plc_client
Dinple committed
15
np.set_printoptions(threshold=sys.maxsize)
Dinple committed
16
# FLAGS = flags.FLAGS
Dinple committed
17

Dinple committed
18 19 20 21 22 23 24
"""plc_client_os_test docstrings

Test Utility Class for Google's API plc_wrapper_main with plc_client.py and plc_client_os.py

Example:
    At ./MacroPlacement/CodeElement, run the following command:

Dinple committed
25 26 27 28 29 30 31 32 33 34 35
        $ python3 -m Plc_client.plc_client_os_test --netlist ./Plc_client/test/ariane/netlist.pb.txt\
            --plc ./Plc_client/test/ariane/initial.plc\
            --width 356.592\
            --height 356.640\
            --col 35\
            --row 33\
            --rpmh 10\
            --rpmv 10\
            --marh 5\
            --marv 5\
            --smooth 2
Dinple committed
36 37 38 39 40 41 42 43 44 45 46 47
        
        $ python3 -m Plc_client.plc_client_os_test --netlist ./Plc_client/test/ariane133/netlist.pb.txt\
            --plc ./Plc_client/test/ariane133/initial.plc\
            --width 1599\
            --height 1600.06\
            --col 24\
            --row 21\
            --rpmh 10\
            --rpmv 10\
            --marh 5\
            --marv 5\
            --smooth 2
Dinple committed
48 49 50 51 52 53 54 55 56

Todo:
    * Clean up code
    * Extract argument from command line
    * Report index for each mismatch array entry 

"""

class PlacementCostTest():
Dinple committed
57

Dinple committed
58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
    """ Canvas Setting Reference Table
        ++ Google's Ariane ++
        - CANVAS_WIDTH = 356.592
        - CANVAS_HEIGHT = 356.640
        - GRID_COL = 35
        - GRID_ROW = 33

        ++ Ariane133 ++
        - CANVAS_WIDTH = 1599.99
        - CANVAS_HEIGHT = 1600.06
        - GRID_COL = 24
        - GRID_ROW = 21

        ++ Sample clustered ++
        - CANVAS_WIDTH = 400
        - CANVAS_HEIGHT = 400
        - GRID_COL = 4
        - GRID_ROW = 4

        ++ PMm ++
        - CANVAS_WIDTH = 100
        - CANVAS_HEIGHT = 100
        - GRID_COL = 5
        - GRID_ROW = 5
    """


    def __init__(self, NETLIST_PATH, PLC_PATH=None,
                width=0, height=0,
                column=0, row=0, rpmv=10, rpmh=10,
                marh=10, marv=10, smooth=1) -> None:
Dinple committed
89
        self.NETLIST_PATH = NETLIST_PATH
Dinple committed
90 91 92 93 94 95 96 97 98 99 100 101
        self.PLC_PATH = PLC_PATH
        self.CANVAS_WIDTH = width
        self.CANVAS_HEIGHT = height
        self.GRID_COL = column
        self.GRID_ROW = row

        # for congestion computation
        self.RPMV = rpmv
        self.RPMH = rpmh
        self.MARH = marh
        self.MARV = marv
        self.SMOOTH = smooth
Dinple committed
102

Dinple committed
103 104 105 106
    
    def test_metadata(self):
        print("############################ TEST METADATA ############################")
        # Google's Binary Executable
Dinple committed
107
        self.plc = plc_client.PlacementCost(self.NETLIST_PATH)
Dinple committed
108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210
        # Open-sourced Implementation
        self.plc_os = plc_client_os.PlacementCost(netlist_file=self.NETLIST_PATH,
                                                macro_macro_x_spacing = 50,
                                                macro_macro_y_spacing = 50)

        # NOTE: must set canvas before restoring placement, otherwise OOB error
        self.plc.set_canvas_size(self.CANVAS_WIDTH, self.CANVAS_HEIGHT)
        self.plc.set_placement_grid(self.GRID_COL, self.GRID_ROW)
        self.plc_os.set_canvas_size(self.CANVAS_WIDTH, self.CANVAS_HEIGHT)
        self.plc_os.set_placement_grid(self.GRID_COL, self.GRID_ROW)

        if self.PLC_PATH:
            print("[PLC FILE FOUND] Loading info from .plc file")
            self.plc_os.set_canvas_boundary_check(False)
            self.plc_os.restore_placement(self.PLC_PATH,
                                            ifInital=True,
                                            ifValidate=True,
                                            ifReadComment=False)
            self.plc.set_canvas_boundary_check(False)
            self.plc.restore_placement(self.PLC_PATH)
        else:
            print("[PLC FILE MISSING] Using only netlist info")

        try:
            assert int(self.plc_os.get_area()) == int(self.plc.get_area())
            
            self.plc.set_routes_per_micron(1.0, 2.0)
            self.plc_os.set_routes_per_micron(1.0, 2.0)
            assert self.plc.get_routes_per_micron() == self.plc_os.get_routes_per_micron()

            self.plc.set_overlap_threshold(2.0)
            self.plc_os.set_overlap_threshold(2.0)
            assert self.plc.get_overlap_threshold() == self.plc_os.get_overlap_threshold()

            self.plc.set_congestion_smooth_range(2.0)
            self.plc_os.set_congestion_smooth_range(2.0)
            assert self.plc.get_congestion_smooth_range() == self.plc_os.get_congestion_smooth_range()

            self.plc.set_macro_routing_allocation(3.0, 4.0)
            self.plc_os.set_macro_routing_allocation(3.0, 4.0)
            assert self.plc.get_macro_routing_allocation() == self.plc_os.get_macro_routing_allocation()
        except Exception as e:
            _, _, tb = sys.exc_info()
            traceback.print_tb(tb)
            tb_info = traceback.extract_tb(tb)
            _, line, _, text = tb_info[-1]
            print('[METADATA ERROR] at line {} in statement {}'\
                .format(line, text))
            exit(1)
        
        # test get_macro_adjacency
        plc_macroadj = self.plc.get_macro_adjacency()
        plc_macroadj = np.array(plc_macroadj).reshape(int(math.sqrt(len(plc_macroadj))),\
             int(math.sqrt(len(plc_macroadj))))

        plcos_macroadj = self.plc_os.get_macro_adjacency()
        plcos_macroadj = np.array(plcos_macroadj).reshape(int(math.sqrt(len(plcos_macroadj))),\
             int(math.sqrt(len(plcos_macroadj))))

        try:
            assert(np.sum(np.nonzero(plc_macroadj - plcos_macroadj)) == 0)
        except Exception as e:
            print("[MACRO ADJ ERROR] Mismatched found -- {}".format(str(e)))
            exit(1)
        
        # test get_macro_and_clustered_port_adjacency
        plc_clusteradj, plc_cell = self.plc.get_macro_and_clustered_port_adjacency()
        plc_clusteradj = np.array(plc_clusteradj).reshape(int(math.sqrt(len(plc_clusteradj))),\
             int(math.sqrt(len(plc_clusteradj))))

        plcos_clusteradj, plcos_cell = self.plc_os.get_macro_and_clustered_port_adjacency()
        plcos_clusteradj = np.array(plcos_clusteradj).reshape(int(math.sqrt(len(plcos_clusteradj))),\
             int(math.sqrt(len(plcos_clusteradj))))

        try:
            for plc_adj, plcos_adj in zip(plc_clusteradj, plcos_clusteradj):
                assert(np.sum(np.nonzero(plc_adj - plcos_adj)) == 0)
        except Exception as e:
            print("[MACRO AND CLUSTERED PORT ADJ ERROR] Mismatched found -- {}".format(str(e)))
            exit(1)
        
        print("                  +++++++++++++++++++++++++++")
        print("                  +++ TEST METADATA: PASS +++")
        print("                  +++++++++++++++++++++++++++")
    
    def view_canvas(self):
        print("############################ VIEW CANVAS ############################")
        self.plc_os = plc_client_os.PlacementCost(netlist_file=self.NETLIST_PATH,
                                                macro_macro_x_spacing = 50,
                                                macro_macro_y_spacing = 50)
        self.plc.set_canvas_size(self.CANVAS_WIDTH, self.CANVAS_HEIGHT)
        self.plc.set_placement_grid(self.GRID_COL, self.GRID_ROW)
        self.plc_os.set_canvas_size(self.CANVAS_WIDTH, self.CANVAS_HEIGHT)
        self.plc_os.set_placement_grid(self.GRID_COL, self.GRID_ROW)
        # show canvas
        self.plc_os.display_canvas()

    def test_proxy_cost(self):
        print("############################ TEST PROXY COST ############################")
        # Google's Binary Executable
        self.plc = plc_client.PlacementCost(self.NETLIST_PATH)
        
        # Open-sourced Implementation
Dinple committed
211 212 213 214 215
        self.plc_os = plc_client_os.PlacementCost(netlist_file=self.NETLIST_PATH,
                                                macro_macro_x_spacing = 50,
                                                macro_macro_y_spacing = 50)
        
        if self.PLC_PATH:
Dinple committed
216 217
            print("[PLC FILE FOUND] Loading info from .plc file")
            self.plc_os.set_canvas_boundary_check(False)
Dinple committed
218
            self.plc_os.restore_placement(self.PLC_PATH,
Dinple committed
219 220 221 222
                                            ifInital=True,
                                            ifValidate=True,
                                            ifReadComment=False)
            self.plc.set_canvas_boundary_check(False)
Dinple committed
223
            # self.plc.restore_placement(self.PLC_PATH)
Dinple committed
224 225 226 227 228 229 230 231
        else:
            print("[PLC FILE MISSING] Using only netlist info")

        self.plc.set_routes_per_micron(self.RPMH, self.RPMV)
        self.plc_os.set_routes_per_micron(self.RPMH, self.RPMV)

        self.plc.set_macro_routing_allocation(self.MARH, self.MARV)
        self.plc_os.set_macro_routing_allocation(self.MARH, self.MARV)
Dinple committed
232

Dinple committed
233 234 235 236 237 238 239 240
        self.plc.set_congestion_smooth_range(self.SMOOTH)
        self.plc_os.set_congestion_smooth_range(self.SMOOTH)

        self.plc.set_canvas_size(self.CANVAS_WIDTH, self.CANVAS_HEIGHT)
        self.plc.set_placement_grid(self.GRID_COL, self.GRID_ROW)
        self.plc_os.set_canvas_size(self.CANVAS_WIDTH, self.CANVAS_HEIGHT)
        self.plc_os.set_placement_grid(self.GRID_COL, self.GRID_ROW)

241 242 243 244 245 246 247 248
        # TODO: [IGNORE] Setting blockage has no effect on proxy cost computation
        if False:
            self.plc.create_blockage(0, 0, 400, 400, 1)
            self.plc.create_blockage(0, 0, 200, 200, 1)
            print(self.plc.get_blockages())
            print(self.plc.make_soft_macros_square())
            print(self.plc.set_use_incremental_cost(True))
            print(self.plc_os.get_soft_macros_count())
Dinple committed
249

Dinple committed
250 251
        # HPWL
        try:
Dinple committed
252
            assert int(self.plc_os.get_wirelength()) == int(self.plc.get_wirelength())
Dinple committed
253 254
            assert abs(self.plc.get_cost() - self.plc_os.get_cost()) <= 1e-3
        except Exception as e:
Dinple committed
255
            print("[WIRELENGTH ERROR] Discrepancies found when computing wirelength -- {}, {}".format(str(self.plc.get_cost()), self.plc_os.get_cost()))
Dinple committed
256 257 258 259 260 261 262
            exit(1)

        # Density
        try:
            assert int(sum(self.plc_os.get_grid_cells_density())) == int(sum(self.plc.get_grid_cells_density()))
            assert int(self.plc_os.get_density_cost()) == int(self.plc.get_density_cost())
        except Exception as e:
Dinple committed
263
            print("[DENSITY ERROR] Discrepancies found when computing density -- {}, {}".format(str(self.plc.get_density_cost()), self.plc_os.get_density_cost()))
Dinple committed
264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304
            exit(1)

        # Congestion
        try:
            assert abs(sum(self.plc_os.get_horizontal_routing_congestion()) - sum(self.plc.get_horizontal_routing_congestion())) < 1e-3
            assert abs(sum(self.plc_os.get_vertical_routing_congestion()) - sum(self.plc.get_vertical_routing_congestion())) < 1e-3
            assert abs(self.plc.get_congestion_cost() - self.plc_os.get_congestion_cost()) < 1e-3
        except Exception as e:
            print("[CONGESTION ERROR] Discrepancies found when computing congestion -- {}".format(str(e)))
            exit(1)

        print("                  +++++++++++++++++++++++++++++")
        print("                  +++ TEST PROXY COST: PASS +++")
        print("                  +++++++++++++++++++++++++++++")

    def test_miscellaneous(self):
        # Google's Binary Executable
        self.plc = plc_client.PlacementCost(self.NETLIST_PATH)
        self.plc_os = plc_client_os.PlacementCost(netlist_file=self.NETLIST_PATH,
                                                macro_macro_x_spacing = 50,
                                                macro_macro_y_spacing = 50)
        print("****************** miscellaneous ******************")
        self.plc.set_canvas_size(self.CANVAS_WIDTH, self.CANVAS_HEIGHT)
        self.plc.set_placement_grid(self.GRID_COL, self.GRID_ROW)
        self.plc_os.set_canvas_size(self.CANVAS_WIDTH, self.CANVAS_HEIGHT)
        self.plc_os.set_placement_grid(self.GRID_COL, self.GRID_ROW)
        NODE_IDX = 0
        print("get_macro_indices", self.plc.get_macro_indices(), self.plc_os.get_macro_indices())
        print("get_node_name", self.plc.get_node_name(NODE_IDX))
        print("get_node_location", self.plc.get_node_location(NODE_IDX))
        print("get_grid_cell_of_node", self.plc.get_grid_cell_of_node(NODE_IDX))
        print("get_node_location", self.plc.get_node_location(NODE_IDX))
        print("get_macro_orientation", self.plc.get_macro_orientation(NODE_IDX))
        print("is_node_placed", self.plc.is_node_placed(NODE_IDX))
        print("get_source_filename", self.plc.get_source_filename())
        print("get_blockages", self.plc.get_blockages())
        print("get_ref_node_id", self.plc.get_ref_node_id(NODE_IDX), self.plc.get_ref_node_id(NODE_IDX))
        print("get_node_mask\n", np.array(self.plc.get_node_mask(NODE_IDX)).reshape((4,4)))
        print("can_place_node", self.plc.can_place_node(0, 1))
        print("***************************************************")
    
Dinple committed
305
    def test_proxy_congestion(self):
Dinple committed
306
        # Google's API
Dinple committed
307
        self.plc = plc_client.PlacementCost(self.NETLIST_PATH)
Dinple committed
308 309 310 311 312 313
        self.plc_os = plc_client_os.PlacementCost(self.NETLIST_PATH)

        # set rpm
        self.plc.set_routes_per_micron(10, 10)
        self.plc_os.set_routes_per_micron(10, 10)

Dinple committed
314 315
        self.plc.set_macro_routing_allocation(10, 10)
        self.plc_os.set_macro_routing_allocation(10, 10)
Dinple committed
316

Dinple committed
317 318
        self.plc.set_congestion_smooth_range(0.0)
        self.plc_os.set_congestion_smooth_range(0.0)
Dinple committed
319

Dinple committed
320 321
        self.plc.set_canvas_size(self.CANVAS_WIDTH, self.CANVAS_HEIGHT)
        self.plc.set_placement_grid(self.GRID_COL, self.GRID_ROW)
Dinple committed
322 323 324 325
        self.plc_os.set_canvas_size(self.CANVAS_WIDTH, self.CANVAS_HEIGHT)
        self.plc_os.set_placement_grid(self.GRID_COL, self.GRID_ROW)


Yucheng Wang committed
326 327 328 329
        temp_gl_h = np.array(self.plc.get_horizontal_routing_congestion())
        temp_os_h =  np.array(self.plc_os.get_horizontal_routing_congestion())
        print(temp_gl_h.reshape(self.GRID_COL, self.GRID_ROW))
        print(temp_os_h.reshape(self.GRID_COL, self.GRID_ROW))
Dinple committed
330

Dinple committed
331 332
        print("GL H Congestion: ", self.plc.get_horizontal_routing_congestion())
        print("OS H Congestion: ", self.plc_os.get_horizontal_routing_congestion())
Dinple committed
333

Yucheng Wang committed
334 335
        temp_gl_v = np.array(self.plc.get_vertical_routing_congestion())
        temp_os_v = np.array(self.plc_os.get_vertical_routing_congestion())
Dinple committed
336
        
Yucheng Wang committed
337 338
        print(temp_gl_v.reshape(self.GRID_COL, self.GRID_ROW))
        print(temp_os_v.reshape(self.GRID_COL, self.GRID_ROW))
Dinple committed
339

Dinple committed
340 341
        print("GL V Congestion: ", self.plc.get_vertical_routing_congestion())
        print("OS V Congestion: ", self.plc_os.get_vertical_routing_congestion())
Yucheng Wang committed
342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377

        print("congestion GL: ", self.plc.get_congestion_cost())
        print("congestion OS: ", self.plc_os.get_congestion_cost())
        if abs(self.plc.get_congestion_cost() - self.plc_os.get_congestion_cost()) > 1e-3:
            print("MISMATCH FOUND!!!****************")
        else:
            print("MATCHED!!! **********************")

        ###################################################################### EXTRACT ROUTING CONGESTION
        self.plc.set_macro_routing_allocation(0, 0)
        self.plc_os.set_macro_routing_allocation(0, 0)

        temp_gl_h_rt = np.array(self.plc.get_horizontal_routing_congestion())
        temp_os_h_rt =  np.array(self.plc_os.get_horizontal_routing_congestion())

        temp_gl_v_rt = np.array(self.plc.get_vertical_routing_congestion())
        temp_os_v_rt = np.array(self.plc_os.get_vertical_routing_congestion())

        temp_gl_h_mc = (temp_gl_h - temp_gl_h_rt).reshape(self.GRID_COL, self.GRID_ROW)
        temp_os_h_mc = (temp_os_h - temp_os_h_rt).reshape(self.GRID_COL, self.GRID_ROW)

        temp_gl_v_mc = (temp_gl_v - temp_gl_v_rt).reshape(self.GRID_COL, self.GRID_ROW)
        temp_os_v_mc = (temp_os_v - temp_os_v_rt).reshape(self.GRID_COL, self.GRID_ROW)

        # print("GL H MACRO Congestion", (temp_gl_h_mc).reshape(self.GRID_COL, self.GRID_ROW))
        # print("OS H MACRO Congestion", (temp_os_h_mc).reshape(self.GRID_COL, self.GRID_ROW))
        print("H MACRO Congestion DIFF", np.where(abs(temp_gl_h_mc - temp_os_h_mc) > 1e-5))

        # print("GL V MACRO Congestion", (temp_gl_v_mc).reshape(self.GRID_COL, self.GRID_ROW))
        # print("OS V MACRO Congestion", (temp_os_v_mc).reshape(self.GRID_COL, self.GRID_ROW))
        print("V MACRO Congestion DIFF", np.where(abs(temp_gl_v_mc - temp_os_v_mc) > 1e-5))

        ####################################################################### BY ENTRY
        print("**************BY ENTRY DIFF")
        print(temp_gl_h_mc[0][6], temp_os_h_mc[0][6])

Dinple committed
378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408
def parse_flags(argv):
    parser = argparse_flags.ArgumentParser(description='An argparse + app.run example')
    parser.add_argument("--netlist", required=True,
        help="Path to netlist in pb.txt")
    parser.add_argument("--plc", required=False,
        help="Path to plc in .plc")
    parser.add_argument("--width", type=float, required=True,
        help="Canvas width")
    parser.add_argument("--height", type=float, required=True,
        help="Canvas height")
    parser.add_argument("--col", type=int, required=True,
        help="Grid column")
    parser.add_argument("--row", type=int, required=True,
        help="Grid row")
    parser.add_argument("--rpmh", type=float, default=10, required=False,
        help="Grid row")
    parser.add_argument("--rpmv", type=float, default=10, required=False,
        help="Grid row")
    parser.add_argument("--marh", type=float, default=10, required=False,
        help="Grid row")
    parser.add_argument("--marv", type=float, default=10, required=False,
        help="Grid row")
    parser.add_argument("--smooth", type=float, default=1, required=False,
        help="Grid row")
    return parser.parse_args(argv[1:])

def main(args):
    if args.plc:
        PCT = PlacementCostTest(args.netlist, args.plc, args.width, args.height,
                                args.col, args.row, args.rpmv, args.rpmv,
                                args.marh, args.marv, args.smooth)
Dinple committed
409
    else:
Dinple committed
410 411 412 413 414 415 416 417
        PCT = PlacementCostTest(args.netlist, args.width, args.height,
                                args.col, args.row, args.rpmv, args.rpmv,
                                args.marh, args.marv, args.smooth)
    PCT.test_metadata()
    PCT.test_proxy_cost()

if __name__ == '__main__':
    app.run(main, flags_parser=parse_flags)