Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions flow/designs/asap7/gcd/autotuner-sweep.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"PLACE_DENSITY_LB_ADDON": {
"type": "float",
"minmax": [
0.0,
0.2
],
"step": 0.05
}
}
6 changes: 6 additions & 0 deletions tools/AutoTuner/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# syntax=docker/dockerfile:1
FROM openroad/orfs:latest
WORKDIR /OpenROAD-flow-scripts/tools/AutoTuner
RUN pip install --no-cache-dir --upgrade pip && \
pip install --no-cache-dir -r requirements.txt && \
pip install --no-cache-dir --no-deps .
55 changes: 35 additions & 20 deletions tools/AutoTuner/src/autotuner/distributed.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@
from uuid import uuid4 as uuid
from collections import namedtuple
from multiprocessing import cpu_count
import time

import numpy as np
import torch
Expand All @@ -91,7 +92,6 @@
parse_config,
read_config,
read_metrics,
prepare_ray_server,
CONSTRAINTS_SDC,
FASTROUTE_TCL,
)
Expand All @@ -101,9 +101,18 @@
# The worst of optimized metric
ERROR_METRIC = 9e99
# Path to the FLOW_HOME directory
ORFS_FLOW_DIR = os.path.abspath(
os.path.join(os.path.dirname(__file__), "../../../../flow")
)
if "ORFS_FLOW_DIR" in os.environ:
ORFS_FLOW_DIR = os.environ["ORFS_FLOW_DIR"]
else:
ORFS_FLOW_DIR = os.path.abspath(
os.path.join(os.path.dirname(__file__), "../../../../flow")
)
if "INSTALL_PATH" in os.environ:
INSTALL_PATH = os.environ["INSTALL_PATH"]
else:
INSTALL_PATH = os.path.abspath(os.path.join(ORFS_FLOW_DIR, "../tools/install"))
LOCAL_DIR = ""

# Global variable for args
args = None

Expand Down Expand Up @@ -448,7 +457,7 @@ def parse_arguments():

# If the experiment name is the default, add a UUID to the end.
if args.experiment == "test":
id = str(uuid())[:8]
id = time.strftime("%Y%m%d-%H%M%S") + "-" + str(uuid())[:4]
args.experiment = f"{args.mode}-{id}"
else:
args.experiment += f"-{args.mode}"
Expand Down Expand Up @@ -558,31 +567,38 @@ def save_best(results):

def sweep():
"""Run sweep of parameters"""
if args.server is not None:
# For remote sweep we create the following directory structure:
# 1/ 2/ 3/ 4/
# <repo>/<logs>/<platform>/<design>/
repo_dir = os.path.abspath(LOCAL_DIR + "/../" * 4)
else:
repo_dir = os.path.abspath(os.path.join(ORFS_FLOW_DIR, ".."))
repo_dir = os.path.abspath(os.path.join(ORFS_FLOW_DIR, ".."))
print(f"[INFO TUN-0012] Log folder {LOCAL_DIR}.")
queue = Queue()
parameter_list = list()
total_combinations = 1
for name, content in config_dict.items():
print(f"[INFO TUN-0013] Sweeping {name} over {content}.")
if not isinstance(content, list):
print(f"[ERROR TUN-0015] {name} sweep is not supported.")
sys.exit(1)
if content[-1] == 0:
print("[ERROR TUN-0014] Sweep does not support step value zero.")
sys.exit(1)
parameter_list.append([{name: i} for i in np.arange(*content)])
parameter_list.append([{name: i} for i in np.round(np.arange(*content), 4).tolist()])
total_combinations *= len(parameter_list[-1])
print(f"[INFO TUN-0017] Total of {total_combinations} combinations.")
if total_combinations > 1000:
print(
"[WARN TUN-0033] The total number of combinations is very large."
" Do you wish to continue? (y/n)"
)
if input().lower() != "y":
sys.exit(1)
parameter_list = list(product(*parameter_list))
queue = Queue()
for parameter in parameter_list:
temp = dict()
params_to_sweep = dict()
for value in parameter:
temp.update(value)
queue.put([args, repo_dir, temp, SDC_ORIGINAL, FR_ORIGINAL, INSTALL_PATH])
workers = [consumer.remote(queue) for _ in range(args.jobs)]
params_to_sweep.update(value)
queue.put([args, repo_dir, params_to_sweep, SDC_ORIGINAL, FR_ORIGINAL, INSTALL_PATH])
max_jobs = min(args.jobs, queue.qsize())
print(f"[INFO TUN-0008] Starting sweep with {max_jobs} workers.")
workers = [consumer.remote(queue) for _ in range(max_jobs)]
print("[INFO TUN-0009] Waiting for results.")
ray.get(workers)
print("[INFO TUN-0010] Sweep complete.")
Expand All @@ -592,14 +608,13 @@ def main():
global args, SDC_ORIGINAL, FR_ORIGINAL, LOCAL_DIR, INSTALL_PATH, ORFS_FLOW_DIR, config_dict, reference, best_params
args = parse_arguments()

LOCAL_DIR = os.path.join(ORFS_FLOW_DIR, f"logs/{args.platform}/{args.design}")
# Read config and original files before handling where to run in case we
# need to upload the files.
config_dict, SDC_ORIGINAL, FR_ORIGINAL = read_config(
os.path.abspath(args.config), args.mode, getattr(args, "algorithm", None)
)

LOCAL_DIR, ORFS_FLOW_DIR, INSTALL_PATH = prepare_ray_server(args)

if args.mode == "tune":
best_params = set_best_params(args.platform, args.design)
search_algo = set_algorithm(
Expand Down
37 changes: 8 additions & 29 deletions tools/AutoTuner/src/autotuner/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,8 @@
import yaml
import subprocess
import sys
import uuid
from uuid import uuid4 as uuid
import time
from multiprocessing import cpu_count
from datetime import datetime

import numpy as np
Expand Down Expand Up @@ -319,9 +318,8 @@ def openroad(
if install_path is None:
install_path = os.path.join(base_dir, "tools/install")

export_command = f"export PATH={install_path}/OpenROAD/bin"
export_command += f":{install_path}/yosys/bin:$PATH"
export_command += " && "
export_command = f"export OPENROAD_EXE={install_path}/OpenROAD/bin/openroad &&"
export_command += f" export YOSYS_EXE={install_path}/yosys/bin/yosys &&"

make_command = export_command
if args.memory_limit is not None:
Expand Down Expand Up @@ -610,28 +608,6 @@ def read_tune_pbt(name, this):
return config, sdc_file, fr_file


def prepare_ray_server(args):
"""
Prepares Ray server and returns basic directories.
"""
# Connect to remote Ray server if any, otherwise will run locally
if args.server is not None:
# Connect to ray server before first remote execution.
ray.init(f"ray://{args.server}:{args.port}")
print("[INFO TUN-0001] Connected to Ray server.")
# Common variables used for local and remote runs.
orfs_dir = getattr(args, "orfs", None)
orfs_flow_dir = os.path.abspath(
os.path.join(orfs_dir, "flow")
if orfs_dir
else os.path.join(os.path.dirname(__file__), "../../../../flow")
)
local_dir = f"logs/{args.platform}/{args.design}"
local_dir = os.path.join(orfs_flow_dir, local_dir)
install_path = os.path.abspath(os.path.join(orfs_flow_dir, "../tools/install"))
return local_dir, orfs_flow_dir, install_path


@ray.remote
def openroad_distributed(
args,
Expand All @@ -643,6 +619,8 @@ def openroad_distributed(
variant=None,
):
"""Simple wrapper to run openroad distributed with Ray."""
if variant is None and len(config) != 1:
variant = "multiple-params"
config = parse_config(
config=config,
base_dir=repo_dir,
Expand All @@ -655,11 +633,12 @@ def openroad_distributed(
if variant is None:
variant = config.replace(" ", "_").replace("=", "_")
t = time.time()
id = time.strftime("%Y%m%d-%H%M%S") + "-" + str(uuid())[:4]
metric_file = openroad(
args=args,
base_dir=repo_dir,
parameters=config,
flow_variant=f"{uuid.uuid4()}-{variant}" if variant else f"{uuid.uuid4()}",
flow_variant=f"{id}-{variant}" if variant else id,
install_path=install_path,
)
duration = time.time() - t
Expand All @@ -671,7 +650,7 @@ def consumer(queue):
"""consumer"""
while not queue.empty():
next_item = queue.get()
name = next_item[1]
name = next_item[2]
print(f"[INFO TUN-0007] Scheduling run for parameter {name}.")
ray.get(openroad_distributed.remote(*next_item))
print(f"[INFO TUN-0008] Finished run for parameter {name}.")
Loading