Skip to content

Commit

Permalink
mfc.py: Fix argument passthrough & system()
Browse files Browse the repository at this point in the history
  • Loading branch information
henryleberre committed Jan 8, 2024
1 parent acd88d7 commit 15bd177
Show file tree
Hide file tree
Showing 5 changed files with 46 additions and 63 deletions.
43 changes: 23 additions & 20 deletions toolchain/mfc/args.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,6 @@ def add_common_arguments(p, mask = None):
test.add_argument("-f", "--from", default=test_cases[0].get_uuid(), type=str, help="First test UUID to run.")
test.add_argument("-t", "--to", default=test_cases[-1].get_uuid(), type=str, help="Last test UUID to run.")
test.add_argument("-o", "--only", nargs="+", type=str, default=[], metavar="L", help="Only run tests with UUIDs or hashes L.")
test.add_argument("-b", "--binary", choices=binaries, type=str, default=None, help="(Serial) Override MPI execution binary")
test.add_argument("-r", "--relentless", action="store_true", default=False, help="Run all tests, even if multiple fail.")
test.add_argument("-a", "--test-all", action="store_true", default=False, help="Run the Post Process Tests too.")
test.add_argument("-%", "--percent", type=int, default=100, help="Percentage of tests to run.")
Expand All @@ -98,29 +97,32 @@ def add_common_arguments(p, mask = None):
test_meg.add_argument("--add-new-variables", action="store_true", default=False, help="(Test Generation) If new variables are found in D/ when running tests, add them to the golden files.")
test_meg.add_argument("--remove-old-tests", action="store_true", default=False, help="(Test Generation) Delete tests directories that are no longer.")

test.add_argument(metavar="FORWARDED", default=[], dest="--", nargs="*", help="Arguments to forward to the ./mfc.sh run invocations.")

# === RUN ===
engines = [ e.slug for e in ENGINES ]

add_common_arguments(run)
run.add_argument("input", metavar="INPUT", type=str, help="Input file to run.")
run.add_argument("arguments", metavar="ARGUMENTS", nargs='*', type=str, default=[], help="Additional arguments to pass to the case file.")
run.add_argument("-e", "--engine", choices=engines, type=str, default=engines[0], help="Job execution/submission engine choice.")
run.add_argument("-p", "--partition", metavar="PARTITION", type=str, default="", help="(Batch) Partition for job submission.")
run.add_argument("-N", "--nodes", metavar="NODES", type=int, default=1, help="(Batch) Number of nodes.")
run.add_argument("-n", "--tasks-per-node", metavar="TASKS", type=int, default=1, help="Number of tasks per node.")
run.add_argument("-w", "--walltime", metavar="WALLTIME", type=str, default="01:00:00", help="(Batch) Walltime.")
run.add_argument("-a", "--account", metavar="ACCOUNT", type=str, default="", help="(Batch) Account to charge.")
run.add_argument("-@", "--email", metavar="EMAIL", type=str, default="", help="(Batch) Email for job notification.")
run.add_argument("-#", "--name", metavar="NAME", type=str, default="MFC", help="(Batch) Job name.")
run.add_argument("-f", "--flags", metavar="FLAGS", nargs='+', type=str, default=[], help="(Batch) Additional batch options.")
run.add_argument("-b", "--binary", choices=binaries, type=str, default=None, help="(Interactive) Override MPI execution binary")
run.add_argument("-s", "--scratch", action="store_true", default=False, help="Build from scratch.")
run.add_argument("--ncu", nargs=argparse.REMAINDER, type=str, help="Profile with NVIDIA Nsight Compute.")
run.add_argument("--nsys", nargs=argparse.REMAINDER, type=str, help="Profile with NVIDIA Nsight Systems.")
run.add_argument( "--dry-run", action="store_true", default=False, help="(Batch) Run without submitting batch file.")
run.add_argument("--case-optimization", action="store_true", default=False, help="(GPU Optimization) Compile MFC targets with some case parameters hard-coded.")
run.add_argument( "--no-build", action="store_true", default=False, help="(Testing) Do not rebuild MFC.")
run.add_argument("--wait", action="store_true", default=False, help="(Batch) Wait for the job to finish.")
run.add_argument("input", metavar="INPUT", type=str, help="Input file to run.")
run.add_argument("arguments", metavar="ARGUMENTS", nargs="*", type=str, default=[], help="Additional arguments to pass to the case file.")
run.add_argument("-e", "--engine", choices=engines, type=str, default=engines[0], help="Job execution/submission engine choice.")
run.add_argument("--output-summary", type=str, default=None, help="(Interactive) Output a YAML summary file.")
run.add_argument("-p", "--partition", metavar="PARTITION", type=str, default="", help="(Batch) Partition for job submission.")
run.add_argument("-N", "--nodes", metavar="NODES", type=int, default=1, help="(Batch) Number of nodes.")
run.add_argument("-n", "--tasks-per-node", metavar="TASKS", type=int, default=1, help="Number of tasks per node.")
run.add_argument("-w", "--walltime", metavar="WALLTIME", type=str, default="01:00:00", help="(Batch) Walltime.")
run.add_argument("-a", "--account", metavar="ACCOUNT", type=str, default="", help="(Batch) Account to charge.")
run.add_argument("-@", "--email", metavar="EMAIL", type=str, default="", help="(Batch) Email for job notification.")
run.add_argument("-#", "--name", metavar="NAME", type=str, default="MFC", help="(Batch) Job name.")
run.add_argument("-b", "--binary", choices=binaries, type=str, default=None, help="(Interactive) Override MPI execution binary")
run.add_argument("-s", "--scratch", action="store_true", default=False, help="Build from scratch.")
run.add_argument("--ncu", nargs=argparse.REMAINDER, type=str, help="Profile with NVIDIA Nsight Compute.")
run.add_argument("--nsys", nargs=argparse.REMAINDER, type=str, help="Profile with NVIDIA Nsight Systems.")
run.add_argument( "--dry-run", action="store_true", default=False, help="(Batch) Run without submitting batch file.")
run.add_argument("--case-optimization", action="store_true", default=False, help="(GPU Optimization) Compile MFC targets with some case parameters hard-coded.")
run.add_argument( "--no-build", action="store_true", default=False, help="(Testing) Do not rebuild MFC.")
run.add_argument("--wait", action="store_true", default=False, help="(Batch) Wait for the job to finish.")
run.add_argument("-f", "--flags", metavar="FLAGS", dest="--", nargs=argparse.REMAINDER, type=str, default=[], help="(Interactive) Arguments to forward to the MPI invocation.")

# === BENCH ===
add_common_arguments(bench, "t")
Expand All @@ -129,6 +131,7 @@ def add_common_arguments(p, mask = None):
add_common_arguments(count, "g")

args: dict = vars(parser.parse_args())
args["--"] = args.get("--", [])

# Add default arguments of other subparsers
for name, parser in [("run", run), ("test", test), ("build", build),
Expand Down
11 changes: 7 additions & 4 deletions toolchain/mfc/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ def configure(self):
delete_directory(build_dirpath)
create_directory(build_dirpath)

if system(command, no_exception=True) != 0:
if system(command).returncode != 0:
raise MFCException(f"Failed to configure the [bold magenta]{self.name}[/bold magenta] target.")

cons.print(no_indent=True)
Expand All @@ -159,14 +159,16 @@ def build(self):
if ARG('verbose'):
command.append("--verbose")

system(command, exception_text=f"Failed to build the [bold magenta]{self.name}[/bold magenta] target.")
if system(command).returncode != 0:
raise MFCException(f"Failed to build the [bold magenta]{self.name}[/bold magenta] target.")

cons.print(no_indent=True)

def install(self):
command = ["cmake", "--install", self.get_build_dirpath()]

system(command, exception_text=f"Failed to install the [bold magenta]{self.name}[/bold magenta] target.")
if system(command).returncode != 0:
raise MFCException(f"Failed to install the [bold magenta]{self.name}[/bold magenta] target.")

cons.print(no_indent=True)

Expand All @@ -182,7 +184,8 @@ def clean(self):
if ARG("verbose"):
command.append("--verbose")

system(command, exception_text=f"Failed to clean the [bold magenta]{self.name}[/bold magenta] target.")
if system(command).returncode != 0:
raise MFCException(f"Failed to clean the [bold magenta]{self.name}[/bold magenta] target.")


FFTW = MFCTarget('fftw', ['-DMFC_FFTW=ON'], True, False, False, MFCTarget.Dependencies([], [], []), -1)
Expand Down
27 changes: 4 additions & 23 deletions toolchain/mfc/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,33 +28,14 @@ class MFCException(Exception):
pass


# pylint: disable=too-many-arguments
def system(command: typing.List[str], no_exception: bool = False, exception_text=None, on_error=lambda: None, cwd=None, stdout=None, stderr=None, env: dict = None) -> int:
def system(command: typing.List[str], print_cmd = None, **kwargs) -> subprocess.CompletedProcess:
cmd = [ str(x) for x in command if not isspace(str(x)) ]

if env is None:
env = os.environ.copy()

if stdout != subprocess.DEVNULL:
cons.print(no_indent=True)

cons.print(f"$ {' '.join(cmd)}")

if stdout != subprocess.DEVNULL:
if print_cmd in [True, None]:
cons.print(f"$ {' '.join(cmd)}")
cons.print(no_indent=True)

r = subprocess.run(cmd, cwd=cwd, stdout=stdout, stderr=stderr, env=env, check=False)

if r.returncode != 0:
on_error()

if not no_exception:
if exception_text is None:
exception_text = f'Failed to execute command "{command}".'

raise MFCException(exception_text)

return r.returncode
return subprocess.run(cmd, **kwargs, check=False)


def file_write(filepath: str, content: str):
Expand Down
2 changes: 1 addition & 1 deletion toolchain/mfc/run/engines.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ def get_args(self) -> str:
def __get_exec_cmd(self, target: MFCTarget) -> typing.List[str]:
cmd = []
if ARG("mpi"):
cmd += [self.mpibin.bin] + self.mpibin.gen_params() + ARG("flags")[:]
cmd += [self.mpibin.bin] + self.mpibin.gen_params() + ARG("--")[:]

cmd += profiler_prepend()

Expand Down
26 changes: 11 additions & 15 deletions toolchain/mfc/test/case.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,29 +106,25 @@ def __init__(self, trace: str, mods: dict, ppn: int = None, opt: bool = None) ->

def run(self, targets: typing.List[typing.Union[str, MFCTarget]], gpus: typing.Set[int]) -> subprocess.CompletedProcess:
if gpus is not None and len(gpus) != 0:
gpus_select = f"--gpus {' '.join([str(_) for _ in gpus])}"
gpus_select = ["--gpus"] + [str(_) for _ in gpus]
else:
gpus_select = ""
gpus_select = []

filepath = f'"{self.get_dirpath()}/case.py"'
tasks = f"-n {self.ppn}"
jobs = f"-j {ARG('jobs')}" if ARG("case_optimization") else ""
binary_option = f"-b {ARG('binary')}" if ARG("binary") is not None else ""
case_optimization = "--case-optimization" if ARG("case_optimization") or self.opt else "--no-build"
filepath = f'{self.get_dirpath()}/case.py'
tasks = ["-n", str(self.ppn)]
jobs = ["-j", str(ARG("jobs"))] if ARG("case_optimization") else []
case_optimization = ["--case-optimization"] if ARG("case_optimization") or self.opt else ["--no-build"]

mfc_script = ".\\mfc.bat" if os.name == 'nt' else "./mfc.sh"

target_names = [ get_target(t).name for t in targets ]

command: str = f'''\
{mfc_script} run {filepath} {tasks} {binary_option} \
{case_optimization} {jobs} -t {' '.join(target_names)} \
{gpus_select} 2>&1\
'''
command = [
mfc_script, "run", filepath, *tasks, *case_optimization,
*jobs, "-t", *target_names, *gpus_select, *ARG("--")
]

return subprocess.run(command, stdout=subprocess.PIPE,
stderr=subprocess.PIPE, universal_newlines=True,
shell=True, check=False)
return common.system(command, print_cmd=False, text=True, capture_output=True)

def get_uuid(self) -> str:
return hex(binascii.crc32(hashlib.sha1(str(self.trace).encode()).digest())).upper()[2:].zfill(8)
Expand Down

0 comments on commit 15bd177

Please sign in to comment.