executorlib 0.0.8__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. executorlib/__init__.py +248 -0
  2. executorlib/_version.py +716 -0
  3. executorlib/backend/__init__.py +0 -0
  4. executorlib/backend/cache_parallel.py +57 -0
  5. executorlib/backend/cache_serial.py +6 -0
  6. executorlib/backend/interactive_parallel.py +99 -0
  7. executorlib/backend/interactive_serial.py +74 -0
  8. executorlib/base/__init__.py +0 -0
  9. executorlib/base/executor.py +167 -0
  10. executorlib/cache/__init__.py +0 -0
  11. executorlib/cache/backend.py +75 -0
  12. executorlib/cache/executor.py +121 -0
  13. executorlib/cache/queue_spawner.py +109 -0
  14. executorlib/cache/shared.py +249 -0
  15. executorlib/cache/subprocess_spawner.py +65 -0
  16. executorlib/interactive/__init__.py +0 -0
  17. executorlib/interactive/executor.py +329 -0
  18. executorlib/interactive/flux.py +135 -0
  19. executorlib/interactive/shared.py +657 -0
  20. executorlib/interactive/slurm.py +109 -0
  21. executorlib/standalone/__init__.py +21 -0
  22. executorlib/standalone/command.py +14 -0
  23. executorlib/standalone/hdf.py +116 -0
  24. executorlib/standalone/inputcheck.py +201 -0
  25. executorlib/standalone/interactive/__init__.py +0 -0
  26. executorlib/standalone/interactive/backend.py +98 -0
  27. executorlib/standalone/interactive/communication.py +213 -0
  28. executorlib/standalone/interactive/spawner.py +174 -0
  29. executorlib/standalone/plot.py +134 -0
  30. executorlib/standalone/queue.py +19 -0
  31. executorlib/standalone/serialize.py +82 -0
  32. executorlib/standalone/thread.py +42 -0
  33. executorlib-0.0.8.dist-info/LICENSE +29 -0
  34. executorlib-0.0.8.dist-info/METADATA +230 -0
  35. executorlib-0.0.8.dist-info/RECORD +37 -0
  36. executorlib-0.0.8.dist-info/WHEEL +5 -0
  37. executorlib-0.0.8.dist-info/top_level.txt +1 -0
@@ -0,0 +1,248 @@
1
+ from typing import Callable, Optional
2
+
3
+ from executorlib._version import get_versions as _get_versions
4
+ from executorlib.interactive.executor import (
5
+ ExecutorWithDependencies as _ExecutorWithDependencies,
6
+ )
7
+ from executorlib.interactive.executor import create_executor as _create_executor
8
+ from executorlib.standalone.inputcheck import (
9
+ check_plot_dependency_graph as _check_plot_dependency_graph,
10
+ )
11
+ from executorlib.standalone.inputcheck import (
12
+ check_pysqa_config_directory as _check_pysqa_config_directory,
13
+ )
14
+ from executorlib.standalone.inputcheck import (
15
+ check_refresh_rate as _check_refresh_rate,
16
+ )
17
+
18
+ __version__ = _get_versions()["version"]
19
+ __all__: list = []
20
+
21
+
22
+ class Executor:
23
+ """
24
+ The executorlib.Executor leverages either the message passing interface (MPI), the SLURM workload manager or
25
+ preferable the flux framework for distributing python functions within a given resource allocation. In contrast to
26
+ the mpi4py.futures.MPIPoolExecutor the executorlib.Executor can be executed in a serial python process and does not
27
+ require the python script to be executed with MPI. It is even possible to execute the executorlib.Executor directly
28
+ in an interactive Jupyter notebook.
29
+
30
+ Args:
31
+ max_workers (int): for backwards compatibility with the standard library, max_workers also defines the number of
32
+ cores which can be used in parallel - just like the max_cores parameter. Using max_cores is
33
+ recommended, as computers have a limited number of compute cores.
34
+ backend (str): Switch between the different backends "flux", "local" or "slurm". The default is "local".
35
+ cache_directory (str, optional): The directory to store cache files. Defaults to "cache".
36
+ max_cores (int): defines the number cores which can be used in parallel
37
+ resource_dict (dict): A dictionary of resources required by the task. With the following keys:
38
+ - cores (int): number of MPI cores to be used for each function call
39
+ - threads_per_core (int): number of OpenMP threads to be used for each function call
40
+ - gpus_per_core (int): number of GPUs per worker - defaults to 0
41
+ - cwd (str/None): current working directory where the parallel python task is executed
42
+ - openmpi_oversubscribe (bool): adds the `--oversubscribe` command line flag (OpenMPI and
43
+ SLURM only) - default False
44
+ - slurm_cmd_args (list): Additional command line arguments for the srun call (SLURM only)
45
+ flux_executor (flux.job.FluxExecutor): Flux Python interface to submit the workers to flux
46
+ flux_executor_pmi_mode (str): PMI interface to use (OpenMPI v5 requires pmix) default is None (Flux only)
47
+ flux_executor_nesting (bool): Provide hierarchically nested Flux job scheduler inside the submitted function.
48
+ flux_log_files (bool, optional): Write flux stdout and stderr files. Defaults to False.
49
+ pysqa_config_directory (str, optional): path to the pysqa config directory (only for pysqa based backend).
50
+ hostname_localhost (boolean): use localhost instead of the hostname to establish the zmq connection. In the
51
+ context of an HPC cluster this essential to be able to communicate to an
52
+ Executor running on a different compute node within the same allocation. And
53
+ in principle any computer should be able to resolve that their own hostname
54
+ points to the same address as localhost. Still MacOS >= 12 seems to disable
55
+ this look up for security reasons. So on MacOS it is required to set this
56
+ option to true
57
+ block_allocation (boolean): To accelerate the submission of a series of python functions with the same resource
58
+ requirements, executorlib supports block allocation. In this case all resources have
59
+ to be defined on the executor, rather than during the submission of the individual
60
+ function.
61
+ init_function (None): optional function to preset arguments for functions which are submitted later
62
+ disable_dependencies (boolean): Disable resolving future objects during the submission.
63
+ refresh_rate (float): Set the refresh rate in seconds, how frequently the input queue is checked.
64
+ plot_dependency_graph (bool): Plot the dependencies of multiple future objects without executing them. For
65
+ debugging purposes and to get an overview of the specified dependencies.
66
+ plot_dependency_graph_filename (str): Name of the file to store the plotted graph in.
67
+
68
+ Examples:
69
+ ```
70
+ >>> import numpy as np
71
+ >>> from executorlib import Executor
72
+ >>>
73
+ >>> def calc(i, j, k):
74
+ >>> from mpi4py import MPI
75
+ >>> size = MPI.COMM_WORLD.Get_size()
76
+ >>> rank = MPI.COMM_WORLD.Get_rank()
77
+ >>> return np.array([i, j, k]), size, rank
78
+ >>>
79
+ >>> def init_k():
80
+ >>> return {"k": 3}
81
+ >>>
82
+ >>> with Executor(cores=2, init_function=init_k) as p:
83
+ >>> fs = p.submit(calc, 2, j=4)
84
+ >>> print(fs.result())
85
+ [(array([2, 4, 3]), 2, 0), (array([2, 4, 3]), 2, 1)]
86
+ ```
87
+ """
88
+
89
+ def __init__(
90
+ self,
91
+ max_workers: Optional[int] = None,
92
+ backend: str = "local",
93
+ cache_directory: Optional[str] = None,
94
+ max_cores: Optional[int] = None,
95
+ resource_dict: Optional[dict] = None,
96
+ flux_executor=None,
97
+ flux_executor_pmi_mode: Optional[str] = None,
98
+ flux_executor_nesting: bool = False,
99
+ flux_log_files: bool = False,
100
+ pysqa_config_directory: Optional[str] = None,
101
+ hostname_localhost: Optional[bool] = None,
102
+ block_allocation: bool = False,
103
+ init_function: Optional[Callable] = None,
104
+ disable_dependencies: bool = False,
105
+ refresh_rate: float = 0.01,
106
+ plot_dependency_graph: bool = False,
107
+ plot_dependency_graph_filename: Optional[str] = None,
108
+ ):
109
+ # Use __new__() instead of __init__(). This function is only implemented to enable auto-completion.
110
+ pass
111
+
112
+ def __new__(
113
+ cls,
114
+ max_workers: Optional[int] = None,
115
+ backend: str = "local",
116
+ cache_directory: Optional[str] = None,
117
+ max_cores: Optional[int] = None,
118
+ resource_dict: Optional[dict] = None,
119
+ flux_executor=None,
120
+ flux_executor_pmi_mode: Optional[str] = None,
121
+ flux_executor_nesting: bool = False,
122
+ flux_log_files: bool = False,
123
+ pysqa_config_directory: Optional[str] = None,
124
+ hostname_localhost: Optional[bool] = None,
125
+ block_allocation: bool = False,
126
+ init_function: Optional[Callable] = None,
127
+ disable_dependencies: bool = False,
128
+ refresh_rate: float = 0.01,
129
+ plot_dependency_graph: bool = False,
130
+ plot_dependency_graph_filename: Optional[str] = None,
131
+ ):
132
+ """
133
+ Instead of returning a executorlib.Executor object this function returns either a executorlib.mpi.PyMPIExecutor,
134
+ executorlib.slurm.PySlurmExecutor or executorlib.flux.PyFluxExecutor depending on which backend is available. The
135
+ executorlib.flux.PyFluxExecutor is the preferred choice while the executorlib.mpi.PyMPIExecutor is primarily used
136
+ for development and testing. The executorlib.flux.PyFluxExecutor requires flux-core from the flux-framework to be
137
+ installed and in addition flux-sched to enable GPU scheduling. Finally, the executorlib.slurm.PySlurmExecutor
138
+ requires the SLURM workload manager to be installed on the system.
139
+
140
+ Args:
141
+ max_workers (int): for backwards compatibility with the standard library, max_workers also defines the
142
+ number of cores which can be used in parallel - just like the max_cores parameter. Using
143
+ max_cores is recommended, as computers have a limited number of compute cores.
144
+ backend (str): Switch between the different backends "flux", "local" or "slurm". The default is "local".
145
+ cache_directory (str, optional): The directory to store cache files. Defaults to "cache".
146
+ max_cores (int): defines the number cores which can be used in parallel
147
+ resource_dict (dict): A dictionary of resources required by the task. With the following keys:
148
+ - cores (int): number of MPI cores to be used for each function call
149
+ - threads_per_core (int): number of OpenMP threads to be used for each function call
150
+ - gpus_per_core (int): number of GPUs per worker - defaults to 0
151
+ - cwd (str/None): current working directory where the parallel python task is executed
152
+ - openmpi_oversubscribe (bool): adds the `--oversubscribe` command line flag (OpenMPI
153
+ and SLURM only) - default False
154
+ - slurm_cmd_args (list): Additional command line arguments for the srun call (SLURM
155
+ only)
156
+ flux_executor (flux.job.FluxExecutor): Flux Python interface to submit the workers to flux
157
+ flux_executor_pmi_mode (str): PMI interface to use (OpenMPI v5 requires pmix) default is None (Flux only)
158
+ flux_executor_nesting (bool): Provide hierarchically nested Flux job scheduler inside the submitted function.
159
+ flux_log_files (bool, optional): Write flux stdout and stderr files. Defaults to False.
160
+ pysqa_config_directory (str, optional): path to the pysqa config directory (only for pysqa based backend).
161
+ hostname_localhost (boolean): use localhost instead of the hostname to establish the zmq connection. In the
162
+ context of an HPC cluster this essential to be able to communicate to an
163
+ Executor running on a different compute node within the same allocation. And
164
+ in principle any computer should be able to resolve that their own hostname
165
+ points to the same address as localhost. Still MacOS >= 12 seems to disable
166
+ this look up for security reasons. So on MacOS it is required to set this
167
+ option to true
168
+ block_allocation (boolean): To accelerate the submission of a series of python functions with the same
169
+ resource requirements, executorlib supports block allocation. In this case all
170
+ resources have to be defined on the executor, rather than during the submission
171
+ of the individual function.
172
+ init_function (None): optional function to preset arguments for functions which are submitted later
173
+ disable_dependencies (boolean): Disable resolving future objects during the submission.
174
+ refresh_rate (float): Set the refresh rate in seconds, how frequently the input queue is checked.
175
+ plot_dependency_graph (bool): Plot the dependencies of multiple future objects without executing them. For
176
+ debugging purposes and to get an overview of the specified dependencies.
177
+ plot_dependency_graph_filename (str): Name of the file to store the plotted graph in.
178
+
179
+ """
180
+ default_resource_dict: dict = {
181
+ "cores": 1,
182
+ "threads_per_core": 1,
183
+ "gpus_per_core": 0,
184
+ "cwd": None,
185
+ "openmpi_oversubscribe": False,
186
+ "slurm_cmd_args": [],
187
+ }
188
+ if resource_dict is None:
189
+ resource_dict = {}
190
+ resource_dict.update(
191
+ {k: v for k, v in default_resource_dict.items() if k not in resource_dict}
192
+ )
193
+ if "_submission" in backend and not plot_dependency_graph:
194
+ from executorlib.cache.executor import create_file_executor
195
+
196
+ return create_file_executor(
197
+ max_workers=max_workers,
198
+ backend=backend,
199
+ max_cores=max_cores,
200
+ cache_directory=cache_directory,
201
+ resource_dict=resource_dict,
202
+ flux_executor=flux_executor,
203
+ flux_executor_pmi_mode=flux_executor_pmi_mode,
204
+ flux_executor_nesting=flux_executor_nesting,
205
+ flux_log_files=flux_log_files,
206
+ pysqa_config_directory=pysqa_config_directory,
207
+ hostname_localhost=hostname_localhost,
208
+ block_allocation=block_allocation,
209
+ init_function=init_function,
210
+ disable_dependencies=disable_dependencies,
211
+ )
212
+ elif not disable_dependencies:
213
+ _check_pysqa_config_directory(pysqa_config_directory=pysqa_config_directory)
214
+ return _ExecutorWithDependencies(
215
+ max_workers=max_workers,
216
+ backend=backend,
217
+ cache_directory=cache_directory,
218
+ max_cores=max_cores,
219
+ resource_dict=resource_dict,
220
+ flux_executor=flux_executor,
221
+ flux_executor_pmi_mode=flux_executor_pmi_mode,
222
+ flux_executor_nesting=flux_executor_nesting,
223
+ flux_log_files=flux_log_files,
224
+ hostname_localhost=hostname_localhost,
225
+ block_allocation=block_allocation,
226
+ init_function=init_function,
227
+ refresh_rate=refresh_rate,
228
+ plot_dependency_graph=plot_dependency_graph,
229
+ plot_dependency_graph_filename=plot_dependency_graph_filename,
230
+ )
231
+ else:
232
+ _check_pysqa_config_directory(pysqa_config_directory=pysqa_config_directory)
233
+ _check_plot_dependency_graph(plot_dependency_graph=plot_dependency_graph)
234
+ _check_refresh_rate(refresh_rate=refresh_rate)
235
+ return _create_executor(
236
+ max_workers=max_workers,
237
+ backend=backend,
238
+ cache_directory=cache_directory,
239
+ max_cores=max_cores,
240
+ resource_dict=resource_dict,
241
+ flux_executor=flux_executor,
242
+ flux_executor_pmi_mode=flux_executor_pmi_mode,
243
+ flux_executor_nesting=flux_executor_nesting,
244
+ flux_log_files=flux_log_files,
245
+ hostname_localhost=hostname_localhost,
246
+ block_allocation=block_allocation,
247
+ init_function=init_function,
248
+ )