Skip to content

Commit 813e42b

Browse files
committed
Modified NoC placement script to support routing and parse routing information
1 parent a0ee531 commit 813e42b

File tree

1 file changed

+133
-11
lines changed

1 file changed

+133
-11
lines changed

vtr_flow/scripts/noc/noc_benchmark_test.py

Lines changed: 133 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717

1818
# pylint: disable=wrong-import-position, import-error
1919
sys.path.insert(0, str(Path(__file__).resolve().parent / "../python_libs"))
20-
# sys.path.insert(0, str(Path(__file__).resolve().parent / "../"))
2120

2221
from vtr import RawDefaultHelpFormatter
2322

@@ -26,24 +25,33 @@
2625
FLOWS_FILE_EXT = ".flows"
2726
CSV_FILE_EXT = ".csv"
2827
NET_FILE_EXT = ".net"
28+
POST_ROUTING_EXT = ".post_routing"
2929
CONSTRAINTS_FILE_EXT = ".xml"
3030

3131
# informat parsed from the vpr output
3232
PLACE_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: "
3939
NOC_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
4245
PLACEMENT_COST_PHRASE = "Placement cost:"
4346
NOC_PLACEMENT_COST_PHRASE = "NoC Placement Costs."
4447
PLACEMENT_TIME = "# Placement took"
4548
POST_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
4856
PLACEMENT_COST_REGEX = "Placement cost: (.*), bb_cost: (.*), td_cost: (.*),"
4957
NOC_PLACEMENT_COST_REGEX = (
@@ -53,6 +61,9 @@
5361
)
5462
PLACEMENT_TIME_REGEX = "# Placement took (.*) seconds.*"
5563
POST_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

5768
MAX_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+
328418
def 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

528649
if __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

Comments
 (0)