Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add custom output directory for run_vtr_task and parse_vtr_task scripts #2153

Merged
merged 15 commits into from Nov 15, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
10 changes: 10 additions & 0 deletions doc/src/vtr/parse_vtr_task.rst
Expand Up @@ -47,6 +47,16 @@ Detailed Command-line Options
A file containing a list of tasks to parse.
Each task name should be on a separate line.

.. option:: -temp_dir <path>

Alternate directory containing task results to parse (see run_vtr_task).

**Default:** ``config/..`` for each task being parsed

Specifies the parent directory for the output of a set of tasks, which will contain ``<task_name>/run<#>`` directories, as well as any generated parse results.

A task folder or list with a config directory must still be specified when invoking the script.

.. option:: -create_golden

The results will be stored as golden results.
Expand Down
11 changes: 11 additions & 0 deletions doc/src/vtr/run_vtr_task.rst
Expand Up @@ -60,6 +60,17 @@ Detailed Command-line Options
<task_name3>
...

.. option:: -temp_dir <path>

Alternate directory for files generated by a set of tasks.
The script will automatically create this directory if necessary.

**Default:** ``config/..`` for each task being run

Specifies the parent directory for the output of this set of tasks, which will contain ``<task_name>/run<#>`` directories, as well as any generated parse results.

A task folder or list with a config directory must still be specified when invoking the script.

.. option:: -system {local | scripts}

Controls how the actions (e.g. invocations of :ref:`run_vtr_flow`) are called.
Expand Down
3 changes: 3 additions & 0 deletions requirements.txt
@@ -1,8 +1,11 @@
prettytable
lxml
psutil

# Python linter and formatter
click==8.0.2 # Our version of black needs an older version of click (https://stackoverflow.com/questions/71673404/importerror-cannot-import-name-unicodefun-from-click)
black==20.8b1
pylint==2.7.4

# Surelog
orderedmultidict
68 changes: 41 additions & 27 deletions vtr_flow/scripts/python_libs/vtr/parse_vtr_task.py
Expand Up @@ -94,6 +94,14 @@ def vtr_command_argparser(prog=None):
help="A file listing tasks to be run",
)

parser.add_argument(
"-temp_dir",
default=None,
metavar="TEMP_DIR",
dest="alt_tasks_dir",
help="Alternate directory to run the tasks in (will be created if non-existant)",
)

parser.add_argument(
"-parse_qor",
default=False,
Expand Down Expand Up @@ -148,16 +156,16 @@ def vtr_command_main(arg_list, prog=None):
num_failed = 0

jobs = create_jobs(args, configs, after_run=True)
parse_tasks(configs, jobs)
parse_tasks(configs, jobs, args.alt_tasks_dir)

if args.create_golden:
create_golden_results_for_tasks(configs)
create_golden_results_for_tasks(configs, args.alt_tasks_dir)

if args.check_golden:
num_failed += check_golden_results_for_tasks(configs)
num_failed += check_golden_results_for_tasks(configs, args.alt_tasks_dir)

if args.calc_geomean:
summarize_qor(configs)
summarize_qor(configs, args.alt_tasks_dir)
calc_geomean(args, configs)

except CommandError as error:
Expand All @@ -178,29 +186,29 @@ def vtr_command_main(arg_list, prog=None):
return num_failed


def parse_tasks(configs, jobs):
def parse_tasks(configs, jobs, alt_tasks_dir=None):
"""
Parse the selection of tasks specified in configs and associated jobs
"""
for config in configs:
config_jobs = [job for job in jobs if job.task_name() == config.task_name]
parse_task(config, config_jobs)
parse_task(config, config_jobs, alt_tasks_dir=alt_tasks_dir)


def parse_task(config, config_jobs, flow_metrics_basename=FIRST_PARSE_FILE):
def parse_task(config, config_jobs, flow_metrics_basename=FIRST_PARSE_FILE, alt_tasks_dir=None):
"""
Parse a single task run.

This generates a file parse_results.txt in the task's working directory,
which is an amalgam of the parse_rests.txt's produced by each job (flow invocation)
"""
run_dir = find_latest_run_dir(config)
run_dir = find_latest_run_dir(config, alt_tasks_dir)

# Record max widths for pretty printing
max_arch_len = len("architecture")
max_circuit_len = len("circuit")
for job in config_jobs:
work_dir = job.work_dir(get_latest_run_dir(find_task_dir(config)))
work_dir = job.work_dir(get_latest_run_dir(find_task_dir(config, alt_tasks_dir)))
if job.parse_command():
parse_filepath = str(PurePath(work_dir) / flow_metrics_basename)
with open(parse_filepath, "w+") as parse_file:
Expand Down Expand Up @@ -261,42 +269,42 @@ def parse_files(config_jobs, run_dir, flow_metrics_basename=FIRST_PARSE_FILE):
)


def create_golden_results_for_tasks(configs):
def create_golden_results_for_tasks(configs, alt_tasks_dir=None):
"""Runs create_golden_results_for_task on all of the give configuration"""

for config in configs:
create_golden_results_for_task(config)
create_golden_results_for_task(config, alt_tasks_dir)


def create_golden_results_for_task(config):
def create_golden_results_for_task(config, alt_tasks_dir=None):
"""
Copies the latest task run's parse_results.txt into the config directory as golden_results.txt
"""
run_dir = find_latest_run_dir(config)
run_dir = find_latest_run_dir(config, alt_tasks_dir)

task_results = str(PurePath(run_dir).joinpath(FIRST_PARSE_FILE))
golden_results_filepath = str(PurePath(config.config_dir).joinpath("golden_results.txt"))

shutil.copy(task_results, golden_results_filepath)


def check_golden_results_for_tasks(configs):
def check_golden_results_for_tasks(configs, alt_tasks_dir=None):
"""runs check_golden_results_for_task on all the input configurations"""
num_qor_failures = 0

print("\nCalculating QoR results...")
for config in configs:
num_qor_failures += check_golden_results_for_task(config)
num_qor_failures += check_golden_results_for_task(config, alt_tasks_dir)

return num_qor_failures


def check_golden_results_for_task(config):
def check_golden_results_for_task(config, alt_tasks_dir=None):
"""
Copies the latest task run's parse_results.txt into the config directory as golden_results.txt
"""
num_qor_failures = 0
run_dir = find_latest_run_dir(config)
run_dir = find_latest_run_dir(config, alt_tasks_dir)

if not config.pass_requirements_file:
print(
Expand Down Expand Up @@ -460,32 +468,38 @@ def check_two_files(
# pylint: enable=too-many-branches,too-many-locals


def summarize_qor(configs):
def summarize_qor(configs, alt_tasks_dir=None):
"""Summarize the Qor results"""

first = True
task_path = Path(configs[0].config_dir).parent
task_path = Path(find_task_dir(configs[0], alt_tasks_dir))
if len(configs) > 1 or (task_path.parent / "task_list.txt").is_file():
task_path = task_path.parent
task_path = task_path / "task_summary"
task_path.mkdir(exist_ok=True)
out_file = task_path / (str(Path(find_latest_run_dir(configs[0])).stem) + "_summary.txt")
out_file = task_path / (
str(Path(find_latest_run_dir(configs[0], alt_tasks_dir)).stem) + "_summary.txt"
)
with out_file.open("w+") as out:
for config in configs:
with (Path(find_latest_run_dir(config)) / QOR_PARSE_FILE).open("r") as in_file:
with (Path(find_latest_run_dir(config, alt_tasks_dir)) / QOR_PARSE_FILE).open(
"r"
) as in_file:
headers = in_file.readline()
if first:
print("task_name \t{}".format(headers), file=out, end="")
first = False
for line in in_file:
print("{}\t{}".format(config.task_name, line), file=out, end="")
pretty_print_table(str(Path(find_latest_run_dir(config)) / QOR_PARSE_FILE))
pretty_print_table(
str(Path(find_latest_run_dir(config, alt_tasks_dir)) / QOR_PARSE_FILE)
)


def calc_geomean(args, configs):
"""caclulate and ouput the geomean values to the geomean file"""
first = False
task_path = Path(configs[0].config_dir).parent
task_path = Path(find_task_dir(configs[0], args.alt_tasks_dir))
if len(configs) > 1 or (task_path.parent / "task_list.txt").is_file():
task_path = task_path.parent
out_file = task_path / "qor_geomean.txt"
Expand All @@ -494,7 +508,7 @@ def calc_geomean(args, configs):
summary_file = (
task_path
/ "task_summary"
/ (str(Path(find_latest_run_dir(configs[0])).stem) + "_summary.txt")
/ (str(Path(find_latest_run_dir(configs[0], args.alt_tasks_dir)).stem) + "_summary.txt")
)

with out_file.open("w" if first else "a") as out:
Expand All @@ -508,7 +522,7 @@ def calc_geomean(args, configs):
first = False
lines = summary.readlines()
print(
get_latest_run_number(str(Path(configs[0].config_dir).parent)),
get_latest_run_number(find_task_dir(configs[0], args.alt_tasks_dir)),
file=out,
end="\t",
)
Expand Down Expand Up @@ -550,9 +564,9 @@ def calculate_individual_geo_mean(lines, index, geo_mean, num):
return geo_mean, num, previous_value


def find_latest_run_dir(config):
def find_latest_run_dir(config, alt_tasks_dir=None):
"""Find the latest run directory for given configuration"""
task_dir = find_task_dir(config)
task_dir = find_task_dir(config, alt_tasks_dir)

run_dir = get_latest_run_dir(task_dir)

Expand Down
6 changes: 4 additions & 2 deletions vtr_flow/scripts/python_libs/vtr/task.py
Expand Up @@ -336,9 +336,11 @@ def create_jobs(args, configs, after_run=False):
work_dir = str(PurePath(arch).joinpath(circuit))

run_dir = (
str(Path(get_latest_run_dir(find_task_dir(config))) / work_dir)
str(Path(get_latest_run_dir(find_task_dir(config, args.alt_tasks_dir))) / work_dir)
if after_run
else str(Path(get_next_run_dir(find_task_dir(config))) / work_dir)
else str(
Path(get_next_run_dir(find_task_dir(config, args.alt_tasks_dir))) / work_dir
)
)

# Collect any extra script params from the config file
Expand Down
15 changes: 11 additions & 4 deletions vtr_flow/scripts/python_libs/vtr/util.py
Expand Up @@ -450,13 +450,20 @@ def get_next_run_dir(base_dir):
return str(PurePath(base_dir) / run_dir_name(get_next_run_number(base_dir)))


def find_task_dir(config):
def find_task_dir(config, alt_tasks_dir=None):
"""
find the task directory
Finds the task directory.

Returns the parent of the config directory, or if specified,
a directory with the task's name in an alternate location
"""
task_dir = None
# Task dir is just above the config directory
task_dir = Path(config.config_dir).parent

if alt_tasks_dir is None:
task_dir = Path(config.config_dir).parent
else:
task_dir = Path(alt_tasks_dir) / config.task_name
task_dir.mkdir(parents=True, exist_ok=True)
assert task_dir.is_dir

return str(task_dir)
Expand Down
18 changes: 13 additions & 5 deletions vtr_flow/scripts/run_vtr_task.py
Expand Up @@ -97,6 +97,14 @@ def vtr_command_argparser(prog=None):
help="A file listing tasks to be run",
)

parser.add_argument(
"-temp_dir",
default=None,
metavar="TEMP_DIR",
dest="alt_tasks_dir",
help="Alternate directory to run the tasks in (will be created if non-existant)",
)

parser.add_argument(
"-parse",
default=False,
Expand Down Expand Up @@ -272,7 +280,7 @@ def run_tasks(

run_dirs = {}
for config in configs:
task_dir = find_task_dir(config)
task_dir = find_task_dir(config, args.alt_tasks_dir)
task_run_dir = get_next_run_dir(task_dir)
run_dirs[config.task_name] = task_run_dir

Expand All @@ -290,17 +298,17 @@ def run_tasks(
print("\nParsing test results...")
if len(args.list_file) > 0:
print("scripts/parse_vtr_task.py -l {}".format(args.list_file[0]))
parse_tasks(configs, jobs)
parse_tasks(configs, jobs, args.alt_tasks_dir)
print("Elapsed time: {}".format(format_elapsed_time(datetime.now() - start)))

if args.create_golden:
create_golden_results_for_tasks(configs)
create_golden_results_for_tasks(configs, args.alt_tasks_dir)

if args.check_golden:
num_failed += check_golden_results_for_tasks(configs)
num_failed += check_golden_results_for_tasks(configs, args.alt_tasks_dir)

if args.calc_geomean:
summarize_qor(configs)
summarize_qor(configs, args.alt_tasks_dir)
calc_geomean(args, configs)
# This option generates a shell script (vtr_flow.sh) for each architecture,
# circuit, script_params
Expand Down