1717
1818# pylint: disable=wrong-import-position, import-error
1919sys .path .insert (0 , str (Path (__file__ ).resolve ().parent / "../python_libs" ))
20- # sys.path.insert(0, str(Path(__file__).resolve().parent / "../"))
2120
2221from vtr import RawDefaultHelpFormatter
2322
2625FLOWS_FILE_EXT = ".flows"
2726CSV_FILE_EXT = ".csv"
2827NET_FILE_EXT = ".net"
28+ POST_ROUTING_EXT = ".post_routing"
2929CONSTRAINTS_FILE_EXT = ".xml"
3030
3131# informat parsed from the vpr output
3232PLACE_COST = "place_cost"
33- PLACE_TIME = "place_time "
34- PLACE_BB_COST = "bb_cost "
35- PLACE_CPD = "post_place_cpd "
36- NOC_AGGREGATE_BANDWIDTH_COST = "noc_aggregate_bandwidth_cost "
37- NOC_LATENCY_COST = "noc_latency_cost "
38- NOC_LATENCY_CONSTRAINT_COST = "noc_latency_constraint_cost "
33+ PLACE_TIME = "Place Time (s): "
34+ PLACE_BB_COST = "Post Place WL: "
35+ PLACE_CPD = "Post Place CPD (ns): "
36+ NOC_AGGREGATE_BANDWIDTH_COST = "NoC BW Cost: "
37+ NOC_LATENCY_COST = "NoC Latency Cost: "
38+ NOC_LATENCY_CONSTRAINT_COST = "# NoC Latency Constraints Met: "
3939NOC_PLACEMENT_WEIGHT = "noc_placement_weight"
40+ POST_ROUTED_WIRE_LENGTH_SEGMENTS = "Post Route WL (segments): "
41+ POST_ROUTED_FREQ = "Post Route Freq (MHz): "
42+ ROUTE_TIME = "Route Time (s): "
4043
4144# phrases to identify lines that contain palcement data
4245PLACEMENT_COST_PHRASE = "Placement cost:"
4346NOC_PLACEMENT_COST_PHRASE = "NoC Placement Costs."
4447PLACEMENT_TIME = "# Placement took"
4548POST_PLACE_CRITICAL_PATH_DELAY_PHRASE = "post-quench CPD"
4649
50+ # phrases to identify lines that contain routing data
51+ POST_ROUTED_WIRE_LENGTH_SEGMENTS_PHRASE = "Total wiring segments used:"
52+ POST_ROUTED_FREQ_PHRASE = "Final critical path delay (least slack):"
53+ ROUTE_TIME_PHRASE = "# Routing took"
54+
4755# regex match strings to extract placement info
4856PLACEMENT_COST_REGEX = "Placement cost: (.*), bb_cost: (.*), td_cost: (.*),"
4957NOC_PLACEMENT_COST_REGEX = (
5361)
5462PLACEMENT_TIME_REGEX = "# Placement took (.*) seconds.*"
5563POST_PLACE_CRITICAL_PATH_DELAY_REGEX = r"post-quench CPD = (.*) \(ns\)"
64+ POST_ROUTED_WIRE_LENGTH_SEGMENTS_REGEX = ".*Total wiring segments used: (.*), .*"
65+ POST_ROUTED_FREQ_REGEX = r"Final critical path delay \(least slack\): .* ns, Fmax: (.*) MHz.*"
66+ ROUTE_TIME_REGEX = "# Routing took (.*) seconds.*"
5667
5768MAX_SEED_VAL = 1000000
5869
@@ -187,6 +198,18 @@ def noc_test_command_line_parser(prog=None):
187198 "-number_of_threads" , default = 1 , type = int , help = "Number of concurrent VPR runs"
188199 )
189200
201+ parser .add_argument (
202+ "-route" ,
203+ action = "store_true" ,
204+ default = "store_false" ,
205+ dest = "route" ,
206+ help = "Run VPR routing on the test design" ,
207+ )
208+
209+ parser .add_argument (
210+ "-route_chan_width" , default = 300 , type = int , help = "Channel width used for routing"
211+ )
212+
190213 return parser
191214
192215
@@ -197,6 +220,7 @@ def find_all_circuit_files(
197220 Given a directory, recursively search and store '.blif' circuit files.
198221 Where each file represents a design that needs to be processed.
199222 """
223+
200224 # find all the circuit files located within the provided folder
201225 for single_design_file_path in Path (location_of_designs ).rglob ("*{0}" .format (CIRCUIT_FILE_EXT )):
202226 # store the design
@@ -213,6 +237,7 @@ def process_vpr_output(vpr_output_file):
213237 placement and routing information for a given run. Remove the
214238 log after after.
215239 """
240+
216241 open_file = open (vpr_output_file )
217242
218243 # datastrcuture below stors the palcement data in a disctionary
@@ -224,6 +249,7 @@ def process_vpr_output(vpr_output_file):
224249 # we only care about three lines where the
225250 # placement costs, noc costs and
226251 # placement times are located
252+ # and post route info
227253 # so identify those lines below
228254 if PLACEMENT_COST_PHRASE in line :
229255 process_placement_costs (placement_data , line )
@@ -237,6 +263,15 @@ def process_vpr_output(vpr_output_file):
237263 if PLACEMENT_TIME in line :
238264 process_placement_time (placement_data , line )
239265
266+ if POST_ROUTED_WIRE_LENGTH_SEGMENTS_PHRASE in line :
267+ process_post_route_wirelength (placement_data , line )
268+
269+ if POST_ROUTED_FREQ_PHRASE in line :
270+ process_post_route_freq (placement_data , line )
271+
272+ if ROUTE_TIME_PHRASE in line :
273+ process_route_time (placement_data , line )
274+
240275 # close and delete the output file
241276 open_file .close ()
242277 os .remove (vpr_output_file )
@@ -249,6 +284,7 @@ def process_placement_costs(placement_data, line_with_data):
249284 Given a string which contains palcement data. Extract the total
250285 placement cost and wirelength cost.
251286 """
287+
252288 # extract the placement costs from the line where they are located
253289 found_placement_metrics = regex .search (PLACEMENT_COST_REGEX , line_with_data )
254290
@@ -272,6 +308,7 @@ def process_placement_cpd(placement_data, line_with_data):
272308 Given a string which contains the CPD of a placed design, extract
273309 it from the string.
274310 """
311+
275312 # extract the placement time from the line where it is located
276313 found_placement_metrics = regex .search (POST_PLACE_CRITICAL_PATH_DELAY_REGEX , line_with_data )
277314
@@ -291,6 +328,7 @@ def process_noc_placement_costs(placement_data, line_with_data):
291328 - NoC latency cost
292329 - Number of latency constraints met (NoC latency constraints cost)
293330 """
331+
294332 # extract the noc placement costs from the line where they are located
295333 found_placement_metrics = regex .search (NOC_PLACEMENT_COST_REGEX , line_with_data )
296334
@@ -314,22 +352,75 @@ def process_placement_time(placement_data, line_with_data):
314352 Given a string which stores the placement time of a VPR run,
315353 extract it.
316354 """
355+
317356 # extract the placement time from the line where it is located
318357 found_placement_metrics = regex .search (PLACEMENT_TIME_REGEX , line_with_data )
319358
320359 # quick check that the regex worked properly
321- if found_placement_metrics .lastindex != 1 :
360+ if ( found_placement_metrics is None ) or ( found_placement_metrics .lastindex != 1 ) :
322361 raise Exception ("Placement time not written out correctly" )
323362
324363 # there should be only one element, since we are only grabbing the placement time
325364 placement_data [PLACE_TIME ] = float (found_placement_metrics .group (1 ))
326365
327366
367+ def process_post_route_wirelength (placement_data , line_with_data ):
368+ """
369+ Given a string which stores the wirelenth after routing,
370+ extract it.
371+ """
372+
373+ # extract wirelength from the line it is located in
374+ found_routing_metrics = regex .search (POST_ROUTED_WIRE_LENGTH_SEGMENTS_REGEX , line_with_data )
375+
376+ # check if regex worked correctly
377+ if (found_routing_metrics is None ) or (found_routing_metrics .lastindex != 1 ):
378+ raise Exception ("Routed wirelength not written out correctly" )
379+
380+ # there should be only one element, since we are only grabbing the routeed wirelength
381+ placement_data [POST_ROUTED_WIRE_LENGTH_SEGMENTS ] = float (found_routing_metrics .group (1 ))
382+
383+
384+ def process_post_route_freq (placement_data , line_with_data ):
385+ """
386+ Given a string which stores the frequency after routing,
387+ extract it.
388+ """
389+
390+ # extract freq from the line it is located in
391+ found_routing_metrics = regex .search (POST_ROUTED_FREQ_REGEX , line_with_data )
392+
393+ # check if regex worked correctly
394+ if (found_routing_metrics is None ) or (found_routing_metrics .lastindex != 1 ):
395+ raise Exception ("Routed frequency not written out correctly" )
396+
397+ # there should be only one element, since we are only grabbing the routed frequency
398+ placement_data [POST_ROUTED_FREQ ] = float (found_routing_metrics .group (1 ))
399+
400+
401+ def process_route_time (placement_data , line_with_data ):
402+ """
403+ Given a string which stores the total route time,
404+ extract it.
405+ """
406+
407+ # extract route time from the line it is located in
408+ found_routing_metrics = regex .search (ROUTE_TIME_REGEX , line_with_data )
409+
410+ # check if regex worked correctly
411+ if (found_routing_metrics is None ) or (found_routing_metrics .lastindex != 1 ):
412+ raise Exception ("Routing time not written out correctly" )
413+
414+ # there should be only one element, since we are only grabbing the route time
415+ placement_data [ROUTE_TIME ] = float (found_routing_metrics .group (1 ))
416+
417+
328418def check_for_constraints_file (design_file ):
329419 """
330420 Check if a given design has an accompanying constraints file which
331421 needs to be included within the VPR run.
332422 """
423+
333424 # build the constraint file path
334425 constraints_file = os .path .splitext (design_file )[0 ] + CONSTRAINTS_FILE_EXT
335426
@@ -352,6 +443,7 @@ def gen_vpr_run_command(design_file, design_flows_file, user_args):
352443 since a single net file caused failures when multiple concurrent
353444 VPR runs tried accessing the file during placement.
354445 """
446+
355447 # stores a list of VPR commands to execute for each seed
356448 vpr_run_commands = []
357449
@@ -370,6 +462,7 @@ def gen_vpr_run_command(design_file, design_flows_file, user_args):
370462 str (design_file ),
371463 "--noc" ,
372464 "on" ,
465+ "--noc_flows_file" ,
373466 design_flows_file ,
374467 "--noc_routing_algorithm" ,
375468 user_args .noc_routing_algorithm ,
@@ -408,6 +501,12 @@ def gen_vpr_run_command(design_file, design_flows_file, user_args):
408501 single_seed_vpr_command .append ("--read_placement_delay_lookup" )
409502 single_seed_vpr_command .append (user_args .placement_delay_lookahead_file )
410503
504+ if user_args .route is True :
505+ # user wanted to route design so add params to run router
506+ single_seed_vpr_command .append ("--route" )
507+ single_seed_vpr_command .append ("--route_chan_width" )
508+ single_seed_vpr_command .append (str (user_args .route_chan_width ))
509+
411510 # now add the newly created command to the list of all commands to execute
412511 vpr_run_commands .append (single_seed_vpr_command )
413512
@@ -419,6 +518,7 @@ def run_vpr_command_and_store_output(vpr_output_file, vpr_run_command):
419518 Execute a single VPR run using 1 thread and store the output to a
420519 newly created file.
421520 """
521+
422522 # create the file that will store the VPR output
423523 vpr_output = open (vpr_output_file , "w" )
424524 # run VPR. Will timeout after 10 hours (should be good for any design)
@@ -427,14 +527,15 @@ def run_vpr_command_and_store_output(vpr_output_file, vpr_run_command):
427527 vpr_output .close ()
428528
429529
430- def process_vpr_runs (run_args , num_of_seeds ):
530+ def process_vpr_runs (run_args , num_of_seeds , route ):
431531 """
432532 Goes through the log files for every VPR run for a single design
433533 and extracts relevant placement & routing metrics which is
434534 then stored internally. The placement metrics are averaged over
435535 all VPR runs. The ".net" and output log files for
436536 each VPR run is then removed.
437537 """
538+
438539 # stores the average of all results for the current test
439540 vpr_average_place_data = {}
440541 vpr_average_place_data [PLACE_BB_COST ] = 0.0
@@ -445,6 +546,11 @@ def process_vpr_runs(run_args, num_of_seeds):
445546 vpr_average_place_data [NOC_LATENCY_COST ] = 0.0
446547 vpr_average_place_data [NOC_LATENCY_CONSTRAINT_COST ] = 0.0
447548
549+ # add route metrics
550+ vpr_average_place_data [POST_ROUTED_WIRE_LENGTH_SEGMENTS ] = 0.0
551+ vpr_average_place_data [POST_ROUTED_FREQ ] = 0.0
552+ vpr_average_place_data [ROUTE_TIME ] = 0.0
553+
448554 for single_run_args in run_args :
449555
450556 # get the placement metrics for the current run
@@ -475,8 +581,22 @@ def process_vpr_runs(run_args, num_of_seeds):
475581 + curr_vpr_place_data [NOC_LATENCY_CONSTRAINT_COST ]
476582 )
477583
584+ if route is True :
585+ vpr_average_place_data [POST_ROUTED_WIRE_LENGTH_SEGMENTS ] = (
586+ vpr_average_place_data [POST_ROUTED_WIRE_LENGTH_SEGMENTS ]
587+ + curr_vpr_place_data [POST_ROUTED_WIRE_LENGTH_SEGMENTS ]
588+ )
589+ vpr_average_place_data [POST_ROUTED_FREQ ] = (
590+ vpr_average_place_data [POST_ROUTED_FREQ ] + curr_vpr_place_data [POST_ROUTED_FREQ ]
591+ )
592+ vpr_average_place_data [ROUTE_TIME ] = (
593+ vpr_average_place_data [ROUTE_TIME ] + curr_vpr_place_data [ROUTE_TIME ]
594+ )
595+
478596 # delete the net file associated with the current run
479597 os .remove (single_run_args [1 ][16 ])
598+ # delete net file after routing for current run
599+ os .remove (single_run_args [1 ][16 ] + POST_ROUTING_EXT )
480600
481601 # get the average palacement results after all the runs
482602 vpr_average_place_data = {
@@ -486,14 +606,15 @@ def process_vpr_runs(run_args, num_of_seeds):
486606 return vpr_average_place_data
487607
488608
489- def execute_vpr_and_process_output (vpr_command_list , num_of_seeds , num_of_threads ):
609+ def execute_vpr_and_process_output (vpr_command_list , num_of_seeds , num_of_threads , route ):
490610 """
491611 Given a number of VPR run commands, execute them over a number
492612 of available threads. A unique file name is created for each VPR
493613 run to store its output.
494614 Once all runs have executed, then process their output logs and store
495615 placement metrics.
496616 """
617+
497618 # stores arguments which will be used to run vpr
498619 run_args = []
499620
@@ -522,7 +643,7 @@ def execute_vpr_and_process_output(vpr_command_list, num_of_seeds, num_of_thread
522643 vpr_executor .shutdown (wait = True )
523644
524645 # process the output and return result
525- return process_vpr_runs (run_args = run_args , num_of_seeds = num_of_seeds )
646+ return process_vpr_runs (run_args = run_args , num_of_seeds = num_of_seeds , route = route )
526647
527648
528649if __name__ == "__main__" :
@@ -564,6 +685,7 @@ def execute_vpr_and_process_output(vpr_command_list, num_of_seeds, num_of_thread
564685 vpr_command_list = vpr_commands ,
565686 num_of_seeds = args .number_of_seeds ,
566687 num_of_threads = args .number_of_threads ,
688+ route = args .route ,
567689 )
568690
569691 print (vpr_placement_results )
0 commit comments