From 0b6cfad9675d3e2b12d1b379f750610ab6a61d74 Mon Sep 17 00:00:00 2001 From: Csaba Kiraly Date: Fri, 3 Mar 2023 11:02:07 +0100 Subject: [PATCH 1/4] factorize study code Signed-off-by: Csaba Kiraly --- study.py | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/study.py b/study.py index 52433c5..2823fa1 100644 --- a/study.py +++ b/study.py @@ -4,6 +4,16 @@ import time, sys, random, copy import importlib from DAS import * +def runOnce(sim, config, shape): + if not config.deterministic: + random.seed(datetime.now()) + + sim.resetShape(shape) + sim.initValidators() + sim.initNetwork() + result = sim.run() + sim.logger.info("Shape: %s ... Block Available: %d in %d steps" % (str(sim.shape.__dict__), result.blockAvailable, len(result.missingVector)), extra=sim.format) + return result def study(): if len(sys.argv) < 2: @@ -24,7 +34,6 @@ def study(): sim = Simulator(shape, config) sim.initLogger() results = [] - simCnt = 0 now = datetime.now() execID = now.strftime("%Y-%m-%d_%H-%M-%S_")+str(random.randint(100,999)) @@ -33,19 +42,11 @@ def study(): start = time.time() for shape in config.nextShape(): - if not config.deterministic: - random.seed(datetime.now()) - - sim.resetShape(shape) - sim.initValidators() - sim.initNetwork() - result = sim.run() - sim.logger.info("Shape: %s ... Block Available: %d in %d steps" % (str(sim.shape.__dict__), result.blockAvailable, len(result.missingVector)), extra=sim.format) + result = runOnce(sim, config, shape) results.append(copy.deepcopy(result)) - simCnt += 1 end = time.time() - sim.logger.info("A total of %d simulations ran in %d seconds" % (simCnt, end-start), extra=sim.format) + sim.logger.info("A total of %d simulations ran in %d seconds" % (len(results), end-start), extra=sim.format) if config.dumpXML: for res in results: From f5ffb0a07b0ac0bece35e0b701ae7a5f9e851a68 Mon Sep 17 00:00:00 2001 From: Csaba Kiraly Date: Fri, 3 Mar 2023 11:15:55 +0100 Subject: [PATCH 2/4] use joblib to run in parallel Signed-off-by: Csaba Kiraly --- study.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/study.py b/study.py index 2823fa1..4cd4b53 100644 --- a/study.py +++ b/study.py @@ -2,8 +2,13 @@ import time, sys, random, copy import importlib +from joblib import Parallel, delayed from DAS import * +# Parallel execution: +# The code currently uses 'joblib' to execute on multiple cores. For other options such as 'ray', see +# https://stackoverflow.com/questions/9786102/how-do-i-parallelize-a-simple-python-loop + def runOnce(sim, config, shape): if not config.deterministic: random.seed(datetime.now()) @@ -41,9 +46,7 @@ def study(): sim.logger.info("Starting simulations:", extra=sim.format) start = time.time() - for shape in config.nextShape(): - result = runOnce(sim, config, shape) - results.append(copy.deepcopy(result)) + results = Parallel(-1)(delayed(runOnce)(sim, config, shape) for shape in config.nextShape()) end = time.time() sim.logger.info("A total of %d simulations ran in %d seconds" % (len(results), end-start), extra=sim.format) From 16b670e9165d824dd0c3ac970585957d6a53bfff Mon Sep 17 00:00:00 2001 From: Csaba Kiraly Date: Fri, 3 Mar 2023 11:26:00 +0100 Subject: [PATCH 3/4] fix issues with logging in parallel execution For fixing logging issues see https://stackoverflow.com/questions/58026381/logging-nested-functions-using-joblib-parallel-and-delayed-calls and https://github.com/joblib/joblib/issues/1017 Signed-off-by: Csaba Kiraly --- DAS/simulator.py | 11 ++++++----- study.py | 4 ++++ 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/DAS/simulator.py b/DAS/simulator.py index dbd1b37..8b79e2c 100644 --- a/DAS/simulator.py +++ b/DAS/simulator.py @@ -104,11 +104,12 @@ class Simulator: def initLogger(self): """It initializes the logger.""" logger = logging.getLogger("DAS") - logger.setLevel(self.logLevel) - ch = logging.StreamHandler() - ch.setLevel(self.logLevel) - ch.setFormatter(CustomFormatter()) - logger.addHandler(ch) + if len(logger.handlers) == 0: + logger.setLevel(self.logLevel) + ch = logging.StreamHandler() + ch.setLevel(self.logLevel) + ch.setFormatter(CustomFormatter()) + logger.addHandler(ch) self.logger = logger diff --git a/study.py b/study.py index 4cd4b53..914acfe 100644 --- a/study.py +++ b/study.py @@ -8,11 +8,15 @@ from DAS import * # Parallel execution: # The code currently uses 'joblib' to execute on multiple cores. For other options such as 'ray', see # https://stackoverflow.com/questions/9786102/how-do-i-parallelize-a-simple-python-loop +# For fixing logging issues in parallel execution, see +# https://stackoverflow.com/questions/58026381/logging-nested-functions-using-joblib-parallel-and-delayed-calls +# and https://github.com/joblib/joblib/issues/1017 def runOnce(sim, config, shape): if not config.deterministic: random.seed(datetime.now()) + sim.initLogger() sim.resetShape(shape) sim.initValidators() sim.initNetwork() From 567d13e37083ba7bc7f8ebf4c64ffb2cbff1d1cb Mon Sep 17 00:00:00 2001 From: Csaba Kiraly Date: Mon, 13 Mar 2023 14:22:14 +0100 Subject: [PATCH 4/4] add numJobs parameter to config Signed-off-by: Csaba Kiraly --- config_example.py | 4 ++++ study.py | 3 ++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/config_example.py b/config_example.py index 0ac65ad..c2f7fcf 100644 --- a/config_example.py +++ b/config_example.py @@ -20,6 +20,10 @@ dumpXML = 1 visualization = 1 logLevel = logging.INFO +# number of parallel workers. -1: all cores; 1: sequential +# for more details, see joblib.Parallel +numJobs = 3 + # Number of simulation runs with the same parameters for statistical relevance runs = range(10) diff --git a/study.py b/study.py index 914acfe..f557fc2 100644 --- a/study.py +++ b/study.py @@ -50,7 +50,8 @@ def study(): sim.logger.info("Starting simulations:", extra=sim.format) start = time.time() - results = Parallel(-1)(delayed(runOnce)(sim, config, shape) for shape in config.nextShape()) + results = Parallel(config.numJobs)(delayed(runOnce)(sim, config, shape) for shape in config.nextShape()) + end = time.time() sim.logger.info("A total of %d simulations ran in %d seconds" % (len(results), end-start), extra=sim.format)