Commit d26a3ff8 authored by Jaime Arias's avatar Jaime Arias
Browse files

fix oar generation script

parent 4d74498e
...@@ -30,6 +30,7 @@ __pycache__/ ...@@ -30,6 +30,7 @@ __pycache__/
# slurm batch # slurm batch
slurm slurm
oar
# editor # editor
.vscode .vscode
...@@ -41,4 +42,3 @@ slurm-*.out ...@@ -41,4 +42,3 @@ slurm-*.out
# git rm -r .ipynb_checkpoints/ # git rm -r .ipynb_checkpoints/
# End of https://www.gitignore.io/api/jupyternotebooks # End of https://www.gitignore.io/api/jupyternotebooks
...@@ -3,9 +3,10 @@ ...@@ -3,9 +3,10 @@
import os import os
import stat import stat
import sys import sys
from itertools import product
from functools import reduce
from collections import ChainMap from collections import ChainMap
from functools import reduce
from itertools import product
from time import time
sbatch_header = """\ sbatch_header = """\
#!/bin/bash #!/bin/bash
...@@ -24,7 +25,7 @@ module load gcc/8.3.0/openmpi/3.1.4 ...@@ -24,7 +25,7 @@ module load gcc/8.3.0/openmpi/3.1.4
oar_header = """\ oar_header = """\
#!/bin/bash #!/bin/bash
# #
#OAR --name {experiment_name}_{model_instance}_n{nodes}-th{threads} #OAR --name {experiment_name}
#OAR --resource /nodes={nodes}/cpu=1/core={threads},walltime={timeout} #OAR --resource /nodes={nodes}/cpu=1/core={threads},walltime={timeout}
#OAR --stderr {error_file} #OAR --stderr {error_file}
#OAR --stdout {output_file} #OAR --stdout {output_file}
...@@ -75,8 +76,7 @@ def generate_model_instance_path(model_name, model_instance, extension, paths): ...@@ -75,8 +76,7 @@ def generate_model_instance_path(model_name, model_instance, extension, paths):
return model_path return model_path
def generate_formula_path(identifier, extension, model_name, model_instance, def generate_formula_path(identifier, extension, model_name, model_instance, paths):
paths):
"""Generates the absolute path of a formula """Generates the absolute path of a formula
Parameters Parameters
...@@ -98,13 +98,11 @@ def generate_formula_path(identifier, extension, model_name, model_instance, ...@@ -98,13 +98,11 @@ def generate_formula_path(identifier, extension, model_name, model_instance,
Formula path Formula path
""" """
name = f"{model_instance}-{identifier}.{extension}" name = f"{model_instance}-{identifier}.{extension}"
formula_path = os.path.join(paths["formulas"], model_name, model_instance, formula_path = os.path.join(paths["formulas"], model_name, model_instance, name)
name)
return formula_path return formula_path
def pmcsog_run(parameters, threads, model_name, model_instance, formula, def pmcsog_run(parameters, threads, model_name, model_instance, formula, paths):
paths):
"""Generates the string with the command to execute pmc-sog """Generates the string with the command to execute pmc-sog
Parameters Parameters
...@@ -127,21 +125,20 @@ def pmcsog_run(parameters, threads, model_name, model_instance, formula, ...@@ -127,21 +125,20 @@ def pmcsog_run(parameters, threads, model_name, model_instance, formula,
str str
Command to execute pmc-sog Command to execute pmc-sog
""" """
formula = generate_formula_path(formula, 'ltl.reduced', model_name, formula = generate_formula_path(
model_instance, paths) formula, "ltl.reduced", model_name, model_instance, paths
model = generate_model_instance_path(model_name, model_instance, 'net', )
paths) model = generate_model_instance_path(model_name, model_instance, "net", paths)
tool = os.path.join(paths['tools'], 'pmc-sog') tool = os.path.join(paths["tools"], "pmc-sog")
parallelisation = parameters['parallelisation'] parallelisation = parameters["parallelisation"]
algorithm = parameters['strategy'].strip() algorithm = parameters["strategy"].strip()
algorithm = '"{}"'.format(algorithm) if algorithm != "default" else '' algorithm = '"{}"'.format(algorithm) if algorithm != "default" else ""
return f"{tool} {parallelisation} {threads} {model} {formula} {algorithm}" return f"{tool} {parallelisation} {threads} {model} {formula} {algorithm}"
def ltsmin_run(parameters, threads, model_name, model_instance, formula, def ltsmin_run(parameters, threads, model_name, model_instance, formula, paths):
paths):
"""Generates the string with the command to execute pnml2lts-mc """Generates the string with the command to execute pnml2lts-mc
Parameters Parameters
...@@ -164,11 +161,9 @@ def ltsmin_run(parameters, threads, model_name, model_instance, formula, ...@@ -164,11 +161,9 @@ def ltsmin_run(parameters, threads, model_name, model_instance, formula,
str str
Command to execute pnml2lts-mc Command to execute pnml2lts-mc
""" """
tool = os.path.join(paths['tools'], 'pnml2lts-mc') tool = os.path.join(paths["tools"], "pnml2lts-mc")
formula = generate_formula_path(formula, 'ltl', model_name, model_instance, formula = generate_formula_path(formula, "ltl", model_name, model_instance, paths)
paths) model = generate_model_instance_path(model_name, model_instance, "pnml", paths)
model = generate_model_instance_path(model_name, model_instance, 'pnml',
paths)
strategy = parameters["strategy"] strategy = parameters["strategy"]
size = parameters["size"] size = parameters["size"]
...@@ -176,8 +171,7 @@ def ltsmin_run(parameters, threads, model_name, model_instance, formula, ...@@ -176,8 +171,7 @@ def ltsmin_run(parameters, threads, model_name, model_instance, formula,
return f"{tool} --strategy={strategy} --size={size} --threads={threads} --ltl={formula} {model}" return f"{tool} --strategy={strategy} --size={size} --threads={threads} --ltl={formula} {model}"
def tool_command(tool_dict, threads, model_name, model_instance, formula, def tool_command(tool_dict, threads, model_name, model_instance, formula, paths):
paths):
"""Factory method that returns the correct command depending on the tool """Factory method that returns the correct command depending on the tool
Parameters Parameters
...@@ -200,16 +194,18 @@ def tool_command(tool_dict, threads, model_name, model_instance, formula, ...@@ -200,16 +194,18 @@ def tool_command(tool_dict, threads, model_name, model_instance, formula,
str str
Command of the tool Command of the tool
""" """
tool_name = tool_dict['name'] tool_name = tool_dict["name"]
tool_parameters = tool_dict['parameters'] tool_parameters = tool_dict["parameters"]
command = "" command = ""
if (tool_name == "pmc-sog"): if tool_name == "pmc-sog":
command = pmcsog_run(tool_parameters, threads, model_name, command = pmcsog_run(
model_instance, formula, paths) tool_parameters, threads, model_name, model_instance, formula, paths
elif (tool_name == "pnml2lts-mc"): )
command = ltsmin_run(tool_parameters, threads, model_name, elif tool_name == "pnml2lts-mc":
model_instance, formula, paths) command = ltsmin_run(
tool_parameters, threads, model_name, model_instance, formula, paths
)
else: else:
sys.exit("{} is not handled yet".format(tool_name)) sys.exit("{} is not handled yet".format(tool_name))
...@@ -242,24 +238,43 @@ def srun(command, nodes, threads, timeout, job_name, output_folder): ...@@ -242,24 +238,43 @@ def srun(command, nodes, threads, timeout, job_name, output_folder):
return f"srun -n {nodes} --resv-ports --cpus-per-task={threads} --time={timeout} --output={output_file} --error={error_file} --job-name={job_name} {command}" return f"srun -n {nodes} --resv-ports --cpus-per-task={threads} --time={timeout} --output={output_file} --error={error_file} --job-name={job_name} {command}"
def mpi_run(command, nodes, threads, timeout_minutes, job_name, output_folder):
error_file = f"{output_folder}/{job_name}.err"
output_file = f"{output_folder}/{job_name}.out"
timeout = timeout_minutes * 60
return f"mpirun -machinefile $OAR_NODEFILE --npernode {nodes} -cpus-per-proc {threads} --timeout {timeout} {command} > {output_file} 2>{error_file}"
def generate_experiment_name(tool_dict): def generate_experiment_name(tool_dict):
"""Generate the name of the experiment""" """Generate the name of the experiment"""
tool_name = tool_dict["name"] tool_name = tool_dict["name"]
tool_params_dict = tool_dict["parameters"] tool_params_dict = tool_dict["parameters"]
tool_parameters = tool_dict["parameters"][ tool_parameters = (
"parallelisation"] + "_" if tool_name == "pmc-sog" else '' tool_dict["parameters"]["parallelisation"] + "_"
if tool_name == "pmc-sog"
else ""
)
tool_parameters += tool_params_dict["strategy"] tool_parameters += tool_params_dict["strategy"]
tool_parameters = reduce( tool_parameters = reduce(
(lambda s, v: s.replace(*v)), (lambda s, v: s.replace(*v)),
[['(poprem)', '-default'], ['(poprem shy)', '-shy'], ['Cou', 'couv']], [["(poprem)", "-default"], ["(poprem shy)", "-shy"], ["Cou", "couv"]],
tool_parameters) tool_parameters,
)
return f"{tool_name}_{tool_parameters}" return f"{tool_name}_{tool_parameters}"
def generate_oar(tool_dict, nodes, threads, model_dict, formulas_ids, def generate_oar(
timeout, paths): tool_dict,
nodes,
threads,
model_dict,
formulas_ids,
timeout,
paths,
oar_timeout="2:00:00",
):
"""Generates a slurm batch of a experiment to be executed on the cluster """Generates a slurm batch of a experiment to be executed on the cluster
Parameters Parameters
...@@ -280,45 +295,56 @@ def generate_oar(tool_dict, nodes, threads, model_dict, formulas_ids, ...@@ -280,45 +295,56 @@ def generate_oar(tool_dict, nodes, threads, model_dict, formulas_ids,
Dictionary with the paths of the project Dictionary with the paths of the project
""" """
tool_name = tool_dict["name"] tool_name = tool_dict["name"]
model_name = model_dict['name'] model_name = model_dict["name"]
model_instances = model_dict['instances'] model_instances = model_dict["instances"]
experiment_name = generate_experiment_name(tool_dict) experiment_name = generate_experiment_name(tool_dict)
# folder where oar scripts will be saved # folder where oar scripts will be saved
oar_folder = os.path.join(paths['oar'], 'experiments', tool_name, experiment_name, model_name) oar_folder = os.path.join(
paths["oar"], "experiments", tool_name, experiment_name, model_name
)
create_folder(oar_folder) create_folder(oar_folder)
# print srun command for each model_instance # print srun command for each model_instance
for model_instance in model_instances: for model_instance in model_instances:
oar_name = f"{model_instance}-n{nodes}-th{threads}.oar" oar_job = f"{experiment_name}_{model_instance}_n{nodes}-th{threads}"
oar_file = os.path.join(oar_folder, oar_name) oar_file = os.path.join(oar_folder, f"{oar_job}.oar")
# folder where the outputs will be saved # folder where the outputs will be saved
output_folder = os.path.join(paths['results'], tool_name, output_folder = os.path.join(
experiment_name, model_name, paths["results"], tool_name, experiment_name, model_name, model_instance
model_instance) )
create_folder(output_folder) create_folder(output_folder)
error_file = f"{output_folder}/{experiment_name}.err" error_file = f"{output_folder}/{oar_job}.err"
output_file = f"{output_folder}/{experiment_name}.out" output_file = f"{output_folder}/{oar_job}.out"
header = oar_header.format(experiment_name=experiment_name, header = oar_header.format(
model_instance=model_instance, experiment_name=oar_job,
nodes=nodes, model_instance=model_instance,
threads=threads, nodes=nodes,
timeout="2:00:00", threads=threads,
error_file=error_file, timeout=oar_timeout,
output_file=output_file) error_file=error_file,
output_file=output_file,
)
with open(oar_file, 'w') as f: with open(oar_file, "w") as f:
f.write(header) f.write(header)
for formula in formulas_ids: for formula in formulas_ids:
command = tool_command(tool_dict, threads, model_name, command = tool_command(
model_instance, formula, paths) tool_dict, threads, model_name, model_instance, formula, paths
)
job_name = f"{oar_job}-f{formula}"
f.write(command) mpi_command = mpi_run(
command, nodes, threads, timeout, job_name, output_folder
)
f.write(mpi_command)
f.write("\n\n") f.write("\n\n")
# give oar script the exec right # give oar script the exec right
...@@ -326,8 +352,9 @@ def generate_oar(tool_dict, nodes, threads, model_dict, formulas_ids, ...@@ -326,8 +352,9 @@ def generate_oar(tool_dict, nodes, threads, model_dict, formulas_ids,
os.chmod(oar_file, st.st_mode | stat.S_IEXEC) os.chmod(oar_file, st.st_mode | stat.S_IEXEC)
def generate_sbatch(tool_dict, nodes, threads, model_dict, formulas_ids, def generate_sbatch(
timeout, paths): tool_dict, nodes, threads, model_dict, formulas_ids, timeout, paths
):
"""Generates a slurm batch of a experiment to be executed on the cluster """Generates a slurm batch of a experiment to be executed on the cluster
Parameters Parameters
...@@ -348,40 +375,47 @@ def generate_sbatch(tool_dict, nodes, threads, model_dict, formulas_ids, ...@@ -348,40 +375,47 @@ def generate_sbatch(tool_dict, nodes, threads, model_dict, formulas_ids,
Dictionary with the paths of the project Dictionary with the paths of the project
""" """
tool_name = tool_dict["name"] tool_name = tool_dict["name"]
model_name = model_dict['name'] model_name = model_dict["name"]
model_instances = model_dict['instances'] model_instances = model_dict["instances"]
experiment_name = generate_experiment_name(tool_dict) experiment_name = generate_experiment_name(tool_dict)
header = sbatch_header.format(experiment_name=experiment_name, header = sbatch_header.format(
model_name=model_name, experiment_name=experiment_name,
nodes=nodes, model_name=model_name,
threads=threads) nodes=nodes,
threads=threads,
)
sbatch_folder = os.path.join(paths['slurm'], 'experiments', tool_name, sbatch_folder = os.path.join(
experiment_name, model_name) paths["slurm"], "experiments", tool_name, experiment_name, model_name
)
create_folder(sbatch_folder) create_folder(sbatch_folder)
sbatch_name = f"n{nodes}-th{threads}.sbatch" sbatch_name = f"n{nodes}-th{threads}.sbatch"
sbatch_file = os.path.join(sbatch_folder, sbatch_name) sbatch_file = os.path.join(sbatch_folder, sbatch_name)
with open(sbatch_file, 'w') as sbatch_file: with open(sbatch_file, "w") as sbatch_file:
sbatch_file.write(header) sbatch_file.write(header)
# print srun command for each model_instance # print srun command for each model_instance
for model_instance in model_instances: for model_instance in model_instances:
output_folder = os.path.join(paths['results'], tool_name, output_folder = os.path.join(
experiment_name, model_name, paths["results"], tool_name, experiment_name, model_name, model_instance
model_instance) )
create_folder(output_folder) create_folder(output_folder)
for formula in formulas_ids: for formula in formulas_ids:
command = tool_command(tool_dict, threads, model_name, command = tool_command(
model_instance, formula, paths) tool_dict, threads, model_name, model_instance, formula, paths
)
job_name = f"{tool_name}_{model_instance}-n{nodes}-th{threads}-f{formula}" job_name = (
f"{tool_name}_{model_instance}-n{nodes}-th{threads}-f{formula}"
)
srun_command = srun(command, nodes, threads, timeout, job_name, srun_command = srun(
output_folder) command, nodes, threads, timeout, job_name, output_folder
)
sbatch_file.write(srun_command) sbatch_file.write(srun_command)
sbatch_file.write("\n\n") sbatch_file.write("\n\n")
...@@ -390,23 +424,24 @@ def generate_sbatch(tool_dict, nodes, threads, model_dict, formulas_ids, ...@@ -390,23 +424,24 @@ def generate_sbatch(tool_dict, nodes, threads, model_dict, formulas_ids,
def create_default_paths(): def create_default_paths():
"""Create the default path for the project""" """Create the default path for the project"""
base_folder = os.path.abspath( base_folder = os.path.abspath(
os.path.join(os.path.dirname(os.path.realpath(__file__)), os.pardir)) os.path.join(os.path.dirname(os.path.realpath(__file__)), os.pardir)
)
paths = { paths = {
# Absolute path where are stored the formulas, models, and scripts # Absolute path where are stored the formulas, models, and scripts
'project': base_folder, "project": base_folder,
# Folder where the formulas are saved # Folder where the formulas are saved
'formulas': os.path.join(base_folder, "formulas"), "formulas": os.path.join(base_folder, "formulas"),
# Folder where the models are saved # Folder where the models are saved
'models': os.path.join(base_folder, "models"), "models": os.path.join(base_folder, "models"),
# Folder where the results will be saved # Folder where the results will be saved
'results': os.path.join(base_folder, "results"), "results": os.path.join(base_folder, "results"),
# Folder where the slurm batches will be saved # Folder where the slurm batches will be saved
'slurm': os.path.join(base_folder, "slurm"), "slurm": os.path.join(base_folder, "slurm"),
# Folder where the oar batches will be saved # Folder where the oar batches will be saved
'oar': os.path.join(base_folder, "oar"), "oar": os.path.join(base_folder, "oar"),
# Folder where the tool are saved # Folder where the tool are saved
'tools': os.path.join(base_folder, "tools") "tools": os.path.join(base_folder, "tools"),
} }
# Create paths if they don't exist # Create paths if they don't exist
...@@ -418,21 +453,23 @@ def create_default_paths(): ...@@ -418,21 +453,23 @@ def create_default_paths():
def explode_tool(tool): def explode_tool(tool):
"""Generates a tool dictionary for each parameter""" """Generates a tool dictionary for each parameter"""
parameters = [[{ parameters = [
name: value [{name: value} for value in values]
} for value in values] for name, values in tool["parameters"].items()] for name, values in tool["parameters"].items()
]
parameters = product(*parameters) parameters = product(*parameters)
result = [{ result = [
"name": tool["name"], {"name": tool["name"], "parameters": dict(ChainMap(*parameter))}
"parameters": dict(ChainMap(*parameter)) for parameter in parameters
} for parameter in parameters] ]
return result return result
def generate_multiple_batchs(tools, models, formulas, nodes_list, def generate_multiple_batchs(
threads_list, timeout, paths, launcher): tools, models, formulas, nodes_list, threads_list, timeout, paths, launcher
):
"""Generates the slurm batch for several experiments """Generates the slurm batch for several experiments
Parameters Parameters
...@@ -462,22 +499,24 @@ def generate_multiple_batchs(tools, models, formulas, nodes_list, ...@@ -462,22 +499,24 @@ def generate_multiple_batchs(tools, models, formulas, nodes_list,
for nodes in nodes_list: for nodes in nodes_list:
for threads in threads_list: for threads in threads_list:
if launcher == "slurm": if launcher == "slurm":
generate_sbatch(tool, nodes, threads, model, formulas, generate_sbatch(
timeout, paths) tool, nodes, threads, model, formulas, timeout, paths
)
elif launcher == "oar": elif launcher == "oar":
generate_oar(tool, nodes, threads, model, formulas, generate_oar(
timeout, paths) tool, nodes, threads, model, formulas, timeout, paths
)
else: else:
print(f"{launcher} is not supported") print(f"{launcher} is not supported")
sys.exit(0) sys.exit(0)
if __name__ == '__main__': if __name__ == "__main__":
# Default paths # Default paths
paths = create_default_paths() paths = create_default_paths()
# slurm or oar # slurm or oar
launcher="oar" launcher = "oar"
# Timeout: 20 minutes # Timeout: 20 minutes
timeout = 20 timeout = 20
...@@ -493,38 +532,46 @@ if __name__ == '__main__': ...@@ -493,38 +532,46 @@ if __name__ == '__main__':
formulas = [n for n in range(1, nb_formulas + 1)] formulas = [n for n in range(1, nb_formulas + 1)]
# Models to be run # Models to be run
models = [{ models = [
# "name": "philo", {
# "instances": ["philo5", "philo10", "philo20"] # "name": "philo",
# }, { # "instances": ["philo5", "philo10", "philo20"]
# "name": "train", # }, {
# "instances": ["train12", "train24", "train48", "train96"] # "name": "train",
# }, { # "instances": ["train12", "train24", "train48", "train96"]
"name": "tring", # }, {
"instances": [ "tring10" ] # "tring5", "tring20" "name": "tring",
# }, { "instances": ["tring10"] # "tring5", "tring20"
# "name": # }, {
# "robot", # "name":
# "instances": ["robot20"] #"robot20", "robot50", "robot2", "robot5", "robot10"] # "robot",
# }, { # "instances": ["robot20"] #"robot20", "robot50", "robot2", "robot5", "robot10"]
# "name": "spool", # }, {
# "instances": ["spool4", "spool5"] #, "spool1", "spool2", "spool3"] # "name": "spool",
}] # "instances": ["spool4", "spool5"] #, "spool1", "spool2", "spool3"]
}
]
# Tools to be compared