executorlib 0.0.1__tar.gz
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.
- executorlib-0.0.1/LICENSE +29 -0
- executorlib-0.0.1/MANIFEST.in +1 -0
- executorlib-0.0.1/PKG-INFO +193 -0
- executorlib-0.0.1/README.md +127 -0
- executorlib-0.0.1/executorlib/__init__.py +225 -0
- executorlib-0.0.1/executorlib/_version.py +21 -0
- executorlib-0.0.1/executorlib/backend/__init__.py +0 -0
- executorlib-0.0.1/executorlib/backend/cache_parallel.py +40 -0
- executorlib-0.0.1/executorlib/backend/cache_serial.py +6 -0
- executorlib-0.0.1/executorlib/backend/interactive_parallel.py +91 -0
- executorlib-0.0.1/executorlib/backend/interactive_serial.py +65 -0
- executorlib-0.0.1/executorlib/cache/__init__.py +0 -0
- executorlib-0.0.1/executorlib/cache/executor.py +28 -0
- executorlib-0.0.1/executorlib/cache/hdf.py +83 -0
- executorlib-0.0.1/executorlib/cache/shared.py +217 -0
- executorlib-0.0.1/executorlib/interactive/__init__.py +168 -0
- executorlib-0.0.1/executorlib/interactive/backend.py +76 -0
- executorlib-0.0.1/executorlib/interactive/dependencies.py +67 -0
- executorlib-0.0.1/executorlib/interactive/executor.py +112 -0
- executorlib-0.0.1/executorlib/interactive/flux.py +79 -0
- executorlib-0.0.1/executorlib/shared/__init__.py +24 -0
- executorlib-0.0.1/executorlib/shared/communication.py +195 -0
- executorlib-0.0.1/executorlib/shared/executor.py +635 -0
- executorlib-0.0.1/executorlib/shared/inputcheck.py +121 -0
- executorlib-0.0.1/executorlib/shared/interface.py +154 -0
- executorlib-0.0.1/executorlib/shared/plot.py +82 -0
- executorlib-0.0.1/executorlib/shared/thread.py +31 -0
- executorlib-0.0.1/executorlib/shell/__init__.py +7 -0
- executorlib-0.0.1/executorlib/shell/executor.py +114 -0
- executorlib-0.0.1/executorlib/shell/interactive.py +181 -0
- executorlib-0.0.1/executorlib.egg-info/PKG-INFO +193 -0
- executorlib-0.0.1/executorlib.egg-info/SOURCES.txt +57 -0
- executorlib-0.0.1/executorlib.egg-info/dependency_links.txt +1 -0
- executorlib-0.0.1/executorlib.egg-info/requires.txt +18 -0
- executorlib-0.0.1/executorlib.egg-info/top_level.txt +1 -0
- executorlib-0.0.1/pyproject.toml +62 -0
- executorlib-0.0.1/setup.cfg +4 -0
- executorlib-0.0.1/setup.py +8 -0
- executorlib-0.0.1/tests/test_backend_serial.py +85 -0
- executorlib-0.0.1/tests/test_cache_executor_mpi.py +41 -0
- executorlib-0.0.1/tests/test_cache_executor_serial.py +110 -0
- executorlib-0.0.1/tests/test_cache_hdf.py +66 -0
- executorlib-0.0.1/tests/test_cache_shared.py +100 -0
- executorlib-0.0.1/tests/test_dependencies_executor.py +203 -0
- executorlib-0.0.1/tests/test_executor_backend_flux.py +115 -0
- executorlib-0.0.1/tests/test_executor_backend_mpi.py +80 -0
- executorlib-0.0.1/tests/test_executor_backend_mpi_noblock.py +78 -0
- executorlib-0.0.1/tests/test_executor_conda.py +76 -0
- executorlib-0.0.1/tests/test_flux_executor.py +154 -0
- executorlib-0.0.1/tests/test_integration_pyiron_workflow.py +236 -0
- executorlib-0.0.1/tests/test_local_executor.py +483 -0
- executorlib-0.0.1/tests/test_local_executor_future.py +141 -0
- executorlib-0.0.1/tests/test_shared_backend.py +114 -0
- executorlib-0.0.1/tests/test_shared_communication.py +100 -0
- executorlib-0.0.1/tests/test_shared_executorbase.py +23 -0
- executorlib-0.0.1/tests/test_shared_input_check.py +61 -0
- executorlib-0.0.1/tests/test_shared_thread.py +15 -0
- executorlib-0.0.1/tests/test_shell_executor.py +86 -0
- executorlib-0.0.1/tests/test_shell_interactive.py +70 -0
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
BSD 3-Clause License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2022, Jan Janssen
|
|
4
|
+
All rights reserved.
|
|
5
|
+
|
|
6
|
+
Redistribution and use in source and binary forms, with or without
|
|
7
|
+
modification, are permitted provided that the following conditions are met:
|
|
8
|
+
|
|
9
|
+
* Redistributions of source code must retain the above copyright notice, this
|
|
10
|
+
list of conditions and the following disclaimer.
|
|
11
|
+
|
|
12
|
+
* Redistributions in binary form must reproduce the above copyright notice,
|
|
13
|
+
this list of conditions and the following disclaimer in the documentation
|
|
14
|
+
and/or other materials provided with the distribution.
|
|
15
|
+
|
|
16
|
+
* Neither the name of the copyright holder nor the names of its
|
|
17
|
+
contributors may be used to endorse or promote products derived from
|
|
18
|
+
this software without specific prior written permission.
|
|
19
|
+
|
|
20
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
21
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
22
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
23
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
24
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
25
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
26
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
27
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
28
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
29
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
include LICENSE
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: executorlib
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: Scale serial and MPI-parallel python functions over hundreds of compute nodes all from within a jupyter notebook or serial python process.
|
|
5
|
+
Author-email: Jan Janssen <janssen@lanl.gov>
|
|
6
|
+
License: BSD 3-Clause License
|
|
7
|
+
|
|
8
|
+
Copyright (c) 2022, Jan Janssen
|
|
9
|
+
All rights reserved.
|
|
10
|
+
|
|
11
|
+
Redistribution and use in source and binary forms, with or without
|
|
12
|
+
modification, are permitted provided that the following conditions are met:
|
|
13
|
+
|
|
14
|
+
* Redistributions of source code must retain the above copyright notice, this
|
|
15
|
+
list of conditions and the following disclaimer.
|
|
16
|
+
|
|
17
|
+
* Redistributions in binary form must reproduce the above copyright notice,
|
|
18
|
+
this list of conditions and the following disclaimer in the documentation
|
|
19
|
+
and/or other materials provided with the distribution.
|
|
20
|
+
|
|
21
|
+
* Neither the name of the copyright holder nor the names of its
|
|
22
|
+
contributors may be used to endorse or promote products derived from
|
|
23
|
+
this software without specific prior written permission.
|
|
24
|
+
|
|
25
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
26
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
27
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
28
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
29
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
30
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
31
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
32
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
33
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
34
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
35
|
+
|
|
36
|
+
Project-URL: Homepage, https://github.com/pyiron/executorlib
|
|
37
|
+
Project-URL: Documentation, https://executorlib.readthedocs.io
|
|
38
|
+
Project-URL: Repository, https://github.com/pyiron/executorlib
|
|
39
|
+
Keywords: pyiron
|
|
40
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
41
|
+
Classifier: Topic :: Scientific/Engineering :: Physics
|
|
42
|
+
Classifier: License :: OSI Approved :: BSD License
|
|
43
|
+
Classifier: Intended Audience :: Science/Research
|
|
44
|
+
Classifier: Operating System :: OS Independent
|
|
45
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
46
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
47
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
48
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
49
|
+
Requires-Python: <3.13,>=3.9
|
|
50
|
+
Description-Content-Type: text/markdown
|
|
51
|
+
License-File: LICENSE
|
|
52
|
+
Requires-Dist: cloudpickle<=3.0.0,>=2.0.0
|
|
53
|
+
Requires-Dist: pyzmq<=26.0.3,>=25.0.0
|
|
54
|
+
Provides-Extra: conda
|
|
55
|
+
Requires-Dist: conda_subprocess<=0.0.4,>=0.0.3; extra == "conda"
|
|
56
|
+
Provides-Extra: mpi
|
|
57
|
+
Requires-Dist: mpi4py<=3.1.6,>=3.1.4; extra == "mpi"
|
|
58
|
+
Provides-Extra: hdf
|
|
59
|
+
Requires-Dist: h5py<=3.11.0,>=3.6.0; extra == "hdf"
|
|
60
|
+
Requires-Dist: h5io<=0.2.3,>=0.2.1; extra == "hdf"
|
|
61
|
+
Provides-Extra: graph
|
|
62
|
+
Requires-Dist: pygraphviz<=1.13,>=1.10; extra == "graph"
|
|
63
|
+
Requires-Dist: matplotlib<=3.9.1,>=3.5.3; extra == "graph"
|
|
64
|
+
Requires-Dist: networkx<=3.3,>=2.8.8; extra == "graph"
|
|
65
|
+
Requires-Dist: ipython<=8.26.0,>=7.33.0; extra == "graph"
|
|
66
|
+
|
|
67
|
+
# executorlib
|
|
68
|
+
[](https://github.com/pyiron/executorlib/actions/workflows/unittest-openmpi.yml)
|
|
69
|
+
[](https://coveralls.io/github/pyiron/executorlib?branch=main)
|
|
70
|
+
[](https://mybinder.org/v2/gh/pyiron/executorlib/HEAD?labpath=notebooks%2Fexamples.ipynb)
|
|
71
|
+
|
|
72
|
+
## Challenges
|
|
73
|
+
In high performance computing (HPC) the Python programming language is commonly used as high-level language to
|
|
74
|
+
orchestrate the coupling of scientific applications. Still the efficient usage of highly parallel HPC clusters remains
|
|
75
|
+
challenging, in primarily three aspects:
|
|
76
|
+
|
|
77
|
+
* **Communication**: Distributing python function calls over hundreds of compute node and gathering the results on a
|
|
78
|
+
shared file system is technically possible, but highly inefficient. A socket-based communication approach is
|
|
79
|
+
preferable.
|
|
80
|
+
* **Resource Management**: Assigning Python functions to GPUs or executing Python functions on multiple CPUs using the
|
|
81
|
+
message passing interface (MPI) requires major modifications to the python workflow.
|
|
82
|
+
* **Integration**: Existing workflow libraries implement a secondary the job management on the Python level rather than
|
|
83
|
+
leveraging the existing infrastructure provided by the job scheduler of the HPC.
|
|
84
|
+
|
|
85
|
+
### executorlib is ...
|
|
86
|
+
In a given HPC allocation the `executorlib` library addresses these challenges by extending the Executor interface
|
|
87
|
+
of the standard Python library to support the resource assignment in the HPC context. Computing resources can either be
|
|
88
|
+
assigned on a per function call basis or as a block allocation on a per Executor basis. The `executorlib` library
|
|
89
|
+
is built on top of the [flux-framework](https://flux-framework.org) to enable fine-grained resource assignment. In
|
|
90
|
+
addition, [Simple Linux Utility for Resource Management (SLURM)](https://slurm.schedmd.com) is supported as alternative
|
|
91
|
+
queuing system and for workstation installations `executorlib` can be installed without a job scheduler.
|
|
92
|
+
|
|
93
|
+
### executorlib is not ...
|
|
94
|
+
The executorlib library is not designed to request an allocation from the job scheduler of an HPC. Instead within a given
|
|
95
|
+
allocation from the job scheduler the `executorlib` library can be employed to distribute a series of python
|
|
96
|
+
function calls over the available computing resources to achieve maximum computing resource utilization.
|
|
97
|
+
|
|
98
|
+
## Example
|
|
99
|
+
The following examples illustrates how `executorlib` can be used to distribute a series of MPI parallel function calls
|
|
100
|
+
within a queuing system allocation. `example.py`:
|
|
101
|
+
```python
|
|
102
|
+
import flux.job
|
|
103
|
+
from executorlib import Executor
|
|
104
|
+
|
|
105
|
+
def calc(i):
|
|
106
|
+
from mpi4py import MPI
|
|
107
|
+
size = MPI.COMM_WORLD.Get_size()
|
|
108
|
+
rank = MPI.COMM_WORLD.Get_rank()
|
|
109
|
+
return i, size, rank
|
|
110
|
+
|
|
111
|
+
with flux.job.FluxExecutor() as flux_exe:
|
|
112
|
+
with Executor(max_cores=2, cores_per_worker=2, executor=flux_exe) as exe:
|
|
113
|
+
fs = exe.submit(calc, 3)
|
|
114
|
+
print(fs.result())
|
|
115
|
+
```
|
|
116
|
+
This example can be executed using:
|
|
117
|
+
```
|
|
118
|
+
python example.py
|
|
119
|
+
```
|
|
120
|
+
Which returns:
|
|
121
|
+
```
|
|
122
|
+
>>> [(0, 2, 0), (0, 2, 1)], [(1, 2, 0), (1, 2, 1)]
|
|
123
|
+
```
|
|
124
|
+
The important part in this example is that [mpi4py](https://mpi4py.readthedocs.io) is only used in the `calc()`
|
|
125
|
+
function, not in the python script, consequently it is not necessary to call the script with `mpiexec` but instead
|
|
126
|
+
a call with the regular python interpreter is sufficient. This highlights how `executorlib` allows the users to
|
|
127
|
+
parallelize one function at a time and not having to convert their whole workflow to use [mpi4py](https://mpi4py.readthedocs.io).
|
|
128
|
+
The same code can also be executed inside a jupyter notebook directly which enables an interactive development process.
|
|
129
|
+
|
|
130
|
+
The interface of the standard [concurrent.futures.Executor](https://docs.python.org/3/library/concurrent.futures.html#module-concurrent.futures)
|
|
131
|
+
is extended by adding the option `cores_per_worker=2` to assign multiple MPI ranks to each function call. To create two
|
|
132
|
+
workers the maximum number of cores can be increased to `max_cores=4`. In this case each worker receives two cores
|
|
133
|
+
resulting in a total of four CPU cores being utilized.
|
|
134
|
+
|
|
135
|
+
After submitting the function `calc()` with the corresponding parameter to the executor `exe.submit(calc, 0)`
|
|
136
|
+
a python [`concurrent.futures.Future`](https://docs.python.org/3/library/concurrent.futures.html#future-objects) is
|
|
137
|
+
returned. Consequently, the `executorlib.Executor` can be used as a drop-in replacement for the
|
|
138
|
+
[`concurrent.futures.Executor`](https://docs.python.org/3/library/concurrent.futures.html#module-concurrent.futures)
|
|
139
|
+
which allows the user to add parallelism to their workflow one function at a time.
|
|
140
|
+
|
|
141
|
+
## Disclaimer
|
|
142
|
+
While we try to develop a stable and reliable software library, the development remains a opensource project under the
|
|
143
|
+
BSD 3-Clause License without any warranties::
|
|
144
|
+
```
|
|
145
|
+
BSD 3-Clause License
|
|
146
|
+
|
|
147
|
+
Copyright (c) 2022, Jan Janssen
|
|
148
|
+
All rights reserved.
|
|
149
|
+
|
|
150
|
+
Redistribution and use in source and binary forms, with or without
|
|
151
|
+
modification, are permitted provided that the following conditions are met:
|
|
152
|
+
|
|
153
|
+
* Redistributions of source code must retain the above copyright notice, this
|
|
154
|
+
list of conditions and the following disclaimer.
|
|
155
|
+
|
|
156
|
+
* Redistributions in binary form must reproduce the above copyright notice,
|
|
157
|
+
this list of conditions and the following disclaimer in the documentation
|
|
158
|
+
and/or other materials provided with the distribution.
|
|
159
|
+
|
|
160
|
+
* Neither the name of the copyright holder nor the names of its
|
|
161
|
+
contributors may be used to endorse or promote products derived from
|
|
162
|
+
this software without specific prior written permission.
|
|
163
|
+
|
|
164
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
165
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
166
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
167
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
168
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
169
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
170
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
171
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
172
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
173
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
# Documentation
|
|
177
|
+
* [Installation](https://executorlib.readthedocs.io/en/latest/installation.html)
|
|
178
|
+
* [Compatible Job Schedulers](https://executorlib.readthedocs.io/en/latest/installation.html#compatible-job-schedulers)
|
|
179
|
+
* [executorlib with Flux Framework](https://executorlib.readthedocs.io/en/latest/installation.html#executorlib-with-flux-framework)
|
|
180
|
+
* [Test Flux Framework](https://executorlib.readthedocs.io/en/latest/installation.html#test-flux-framework)
|
|
181
|
+
* [Without Flux Framework](https://executorlib.readthedocs.io/en/latest/installation.html#without-flux-framework)
|
|
182
|
+
* [Examples](https://executorlib.readthedocs.io/en/latest/examples.html)
|
|
183
|
+
* [Compatibility](https://executorlib.readthedocs.io/en/latest/examples.html#compatibility)
|
|
184
|
+
* [Resource Assignment](https://executorlib.readthedocs.io/en/latest/examples.html#resource-assignment)
|
|
185
|
+
* [Data Handling](https://executorlib.readthedocs.io/en/latest/examples.html#data-handling)
|
|
186
|
+
* [Up-Scaling](https://executorlib.readthedocs.io/en/latest/examples.html#up-scaling)
|
|
187
|
+
* [Coupled Functions](https://executorlib.readthedocs.io/en/latest/examples.html#coupled-functions)
|
|
188
|
+
* [SLURM Job Scheduler](https://executorlib.readthedocs.io/en/latest/examples.html#slurm-job-scheduler)
|
|
189
|
+
* [Workstation Support](https://executorlib.readthedocs.io/en/latest/examples.html#workstation-support)
|
|
190
|
+
* [Development](https://executorlib.readthedocs.io/en/latest/development.html)
|
|
191
|
+
* [Contributions](https://executorlib.readthedocs.io/en/latest/development.html#contributions)
|
|
192
|
+
* [License](https://executorlib.readthedocs.io/en/latest/development.html#license)
|
|
193
|
+
* [Integration](https://executorlib.readthedocs.io/en/latest/development.html#integration)
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
# executorlib
|
|
2
|
+
[](https://github.com/pyiron/executorlib/actions/workflows/unittest-openmpi.yml)
|
|
3
|
+
[](https://coveralls.io/github/pyiron/executorlib?branch=main)
|
|
4
|
+
[](https://mybinder.org/v2/gh/pyiron/executorlib/HEAD?labpath=notebooks%2Fexamples.ipynb)
|
|
5
|
+
|
|
6
|
+
## Challenges
|
|
7
|
+
In high performance computing (HPC) the Python programming language is commonly used as high-level language to
|
|
8
|
+
orchestrate the coupling of scientific applications. Still the efficient usage of highly parallel HPC clusters remains
|
|
9
|
+
challenging, in primarily three aspects:
|
|
10
|
+
|
|
11
|
+
* **Communication**: Distributing python function calls over hundreds of compute node and gathering the results on a
|
|
12
|
+
shared file system is technically possible, but highly inefficient. A socket-based communication approach is
|
|
13
|
+
preferable.
|
|
14
|
+
* **Resource Management**: Assigning Python functions to GPUs or executing Python functions on multiple CPUs using the
|
|
15
|
+
message passing interface (MPI) requires major modifications to the python workflow.
|
|
16
|
+
* **Integration**: Existing workflow libraries implement a secondary the job management on the Python level rather than
|
|
17
|
+
leveraging the existing infrastructure provided by the job scheduler of the HPC.
|
|
18
|
+
|
|
19
|
+
### executorlib is ...
|
|
20
|
+
In a given HPC allocation the `executorlib` library addresses these challenges by extending the Executor interface
|
|
21
|
+
of the standard Python library to support the resource assignment in the HPC context. Computing resources can either be
|
|
22
|
+
assigned on a per function call basis or as a block allocation on a per Executor basis. The `executorlib` library
|
|
23
|
+
is built on top of the [flux-framework](https://flux-framework.org) to enable fine-grained resource assignment. In
|
|
24
|
+
addition, [Simple Linux Utility for Resource Management (SLURM)](https://slurm.schedmd.com) is supported as alternative
|
|
25
|
+
queuing system and for workstation installations `executorlib` can be installed without a job scheduler.
|
|
26
|
+
|
|
27
|
+
### executorlib is not ...
|
|
28
|
+
The executorlib library is not designed to request an allocation from the job scheduler of an HPC. Instead within a given
|
|
29
|
+
allocation from the job scheduler the `executorlib` library can be employed to distribute a series of python
|
|
30
|
+
function calls over the available computing resources to achieve maximum computing resource utilization.
|
|
31
|
+
|
|
32
|
+
## Example
|
|
33
|
+
The following examples illustrates how `executorlib` can be used to distribute a series of MPI parallel function calls
|
|
34
|
+
within a queuing system allocation. `example.py`:
|
|
35
|
+
```python
|
|
36
|
+
import flux.job
|
|
37
|
+
from executorlib import Executor
|
|
38
|
+
|
|
39
|
+
def calc(i):
|
|
40
|
+
from mpi4py import MPI
|
|
41
|
+
size = MPI.COMM_WORLD.Get_size()
|
|
42
|
+
rank = MPI.COMM_WORLD.Get_rank()
|
|
43
|
+
return i, size, rank
|
|
44
|
+
|
|
45
|
+
with flux.job.FluxExecutor() as flux_exe:
|
|
46
|
+
with Executor(max_cores=2, cores_per_worker=2, executor=flux_exe) as exe:
|
|
47
|
+
fs = exe.submit(calc, 3)
|
|
48
|
+
print(fs.result())
|
|
49
|
+
```
|
|
50
|
+
This example can be executed using:
|
|
51
|
+
```
|
|
52
|
+
python example.py
|
|
53
|
+
```
|
|
54
|
+
Which returns:
|
|
55
|
+
```
|
|
56
|
+
>>> [(0, 2, 0), (0, 2, 1)], [(1, 2, 0), (1, 2, 1)]
|
|
57
|
+
```
|
|
58
|
+
The important part in this example is that [mpi4py](https://mpi4py.readthedocs.io) is only used in the `calc()`
|
|
59
|
+
function, not in the python script, consequently it is not necessary to call the script with `mpiexec` but instead
|
|
60
|
+
a call with the regular python interpreter is sufficient. This highlights how `executorlib` allows the users to
|
|
61
|
+
parallelize one function at a time and not having to convert their whole workflow to use [mpi4py](https://mpi4py.readthedocs.io).
|
|
62
|
+
The same code can also be executed inside a jupyter notebook directly which enables an interactive development process.
|
|
63
|
+
|
|
64
|
+
The interface of the standard [concurrent.futures.Executor](https://docs.python.org/3/library/concurrent.futures.html#module-concurrent.futures)
|
|
65
|
+
is extended by adding the option `cores_per_worker=2` to assign multiple MPI ranks to each function call. To create two
|
|
66
|
+
workers the maximum number of cores can be increased to `max_cores=4`. In this case each worker receives two cores
|
|
67
|
+
resulting in a total of four CPU cores being utilized.
|
|
68
|
+
|
|
69
|
+
After submitting the function `calc()` with the corresponding parameter to the executor `exe.submit(calc, 0)`
|
|
70
|
+
a python [`concurrent.futures.Future`](https://docs.python.org/3/library/concurrent.futures.html#future-objects) is
|
|
71
|
+
returned. Consequently, the `executorlib.Executor` can be used as a drop-in replacement for the
|
|
72
|
+
[`concurrent.futures.Executor`](https://docs.python.org/3/library/concurrent.futures.html#module-concurrent.futures)
|
|
73
|
+
which allows the user to add parallelism to their workflow one function at a time.
|
|
74
|
+
|
|
75
|
+
## Disclaimer
|
|
76
|
+
While we try to develop a stable and reliable software library, the development remains a opensource project under the
|
|
77
|
+
BSD 3-Clause License without any warranties::
|
|
78
|
+
```
|
|
79
|
+
BSD 3-Clause License
|
|
80
|
+
|
|
81
|
+
Copyright (c) 2022, Jan Janssen
|
|
82
|
+
All rights reserved.
|
|
83
|
+
|
|
84
|
+
Redistribution and use in source and binary forms, with or without
|
|
85
|
+
modification, are permitted provided that the following conditions are met:
|
|
86
|
+
|
|
87
|
+
* Redistributions of source code must retain the above copyright notice, this
|
|
88
|
+
list of conditions and the following disclaimer.
|
|
89
|
+
|
|
90
|
+
* Redistributions in binary form must reproduce the above copyright notice,
|
|
91
|
+
this list of conditions and the following disclaimer in the documentation
|
|
92
|
+
and/or other materials provided with the distribution.
|
|
93
|
+
|
|
94
|
+
* Neither the name of the copyright holder nor the names of its
|
|
95
|
+
contributors may be used to endorse or promote products derived from
|
|
96
|
+
this software without specific prior written permission.
|
|
97
|
+
|
|
98
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
99
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
100
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
101
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
102
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
103
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
104
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
105
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
106
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
107
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
# Documentation
|
|
111
|
+
* [Installation](https://executorlib.readthedocs.io/en/latest/installation.html)
|
|
112
|
+
* [Compatible Job Schedulers](https://executorlib.readthedocs.io/en/latest/installation.html#compatible-job-schedulers)
|
|
113
|
+
* [executorlib with Flux Framework](https://executorlib.readthedocs.io/en/latest/installation.html#executorlib-with-flux-framework)
|
|
114
|
+
* [Test Flux Framework](https://executorlib.readthedocs.io/en/latest/installation.html#test-flux-framework)
|
|
115
|
+
* [Without Flux Framework](https://executorlib.readthedocs.io/en/latest/installation.html#without-flux-framework)
|
|
116
|
+
* [Examples](https://executorlib.readthedocs.io/en/latest/examples.html)
|
|
117
|
+
* [Compatibility](https://executorlib.readthedocs.io/en/latest/examples.html#compatibility)
|
|
118
|
+
* [Resource Assignment](https://executorlib.readthedocs.io/en/latest/examples.html#resource-assignment)
|
|
119
|
+
* [Data Handling](https://executorlib.readthedocs.io/en/latest/examples.html#data-handling)
|
|
120
|
+
* [Up-Scaling](https://executorlib.readthedocs.io/en/latest/examples.html#up-scaling)
|
|
121
|
+
* [Coupled Functions](https://executorlib.readthedocs.io/en/latest/examples.html#coupled-functions)
|
|
122
|
+
* [SLURM Job Scheduler](https://executorlib.readthedocs.io/en/latest/examples.html#slurm-job-scheduler)
|
|
123
|
+
* [Workstation Support](https://executorlib.readthedocs.io/en/latest/examples.html#workstation-support)
|
|
124
|
+
* [Development](https://executorlib.readthedocs.io/en/latest/development.html)
|
|
125
|
+
* [Contributions](https://executorlib.readthedocs.io/en/latest/development.html#contributions)
|
|
126
|
+
* [License](https://executorlib.readthedocs.io/en/latest/development.html#license)
|
|
127
|
+
* [Integration](https://executorlib.readthedocs.io/en/latest/development.html#integration)
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
from typing import Optional
|
|
2
|
+
|
|
3
|
+
from executorlib.interactive import create_executor
|
|
4
|
+
from executorlib.interactive.dependencies import ExecutorWithDependencies
|
|
5
|
+
from executorlib.shared.inputcheck import (
|
|
6
|
+
check_plot_dependency_graph as _check_plot_dependency_graph,
|
|
7
|
+
)
|
|
8
|
+
from executorlib.shared.inputcheck import (
|
|
9
|
+
check_refresh_rate as _check_refresh_rate,
|
|
10
|
+
)
|
|
11
|
+
from executorlib.shell.executor import SubprocessExecutor
|
|
12
|
+
from executorlib.shell.interactive import ShellExecutor
|
|
13
|
+
|
|
14
|
+
from ._version import get_versions
|
|
15
|
+
|
|
16
|
+
__version__ = get_versions()["version"]
|
|
17
|
+
__all__ = [
|
|
18
|
+
SubprocessExecutor,
|
|
19
|
+
ShellExecutor,
|
|
20
|
+
]
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
try:
|
|
24
|
+
from executorlib.cache.executor import FileExecutor
|
|
25
|
+
|
|
26
|
+
__all__ += [FileExecutor]
|
|
27
|
+
except ImportError:
|
|
28
|
+
pass
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class Executor:
|
|
32
|
+
"""
|
|
33
|
+
The executorlib.Executor leverages either the message passing interface (MPI), the SLURM workload manager or
|
|
34
|
+
preferable the flux framework for distributing python functions within a given resource allocation. In contrast to
|
|
35
|
+
the mpi4py.futures.MPIPoolExecutor the executorlib.Executor can be executed in a serial python process and does not
|
|
36
|
+
require the python script to be executed with MPI. It is even possible to execute the executorlib.Executor directly
|
|
37
|
+
in an interactive Jupyter notebook.
|
|
38
|
+
|
|
39
|
+
Args:
|
|
40
|
+
max_workers (int): for backwards compatibility with the standard library, max_workers also defines the number of
|
|
41
|
+
cores which can be used in parallel - just like the max_cores parameter. Using max_cores is
|
|
42
|
+
recommended, as computers have a limited number of compute cores.
|
|
43
|
+
max_cores (int): defines the number cores which can be used in parallel
|
|
44
|
+
cores_per_worker (int): number of MPI cores to be used for each function call
|
|
45
|
+
threads_per_core (int): number of OpenMP threads to be used for each function call
|
|
46
|
+
gpus_per_worker (int): number of GPUs per worker - defaults to 0
|
|
47
|
+
oversubscribe (bool): adds the `--oversubscribe` command line flag (OpenMPI and SLURM only) - default False
|
|
48
|
+
cwd (str/None): current working directory where the parallel python task is executed
|
|
49
|
+
conda_environment_name (str): name of the conda environment to initialize
|
|
50
|
+
conda_environment_path (str): path of the conda environment to initialize
|
|
51
|
+
executor (flux.job.FluxExecutor): Flux Python interface to submit the workers to flux
|
|
52
|
+
hostname_localhost (boolean): use localhost instead of the hostname to establish the zmq connection. In the
|
|
53
|
+
context of an HPC cluster this essential to be able to communicate to an
|
|
54
|
+
Executor running on a different compute node within the same allocation. And
|
|
55
|
+
in principle any computer should be able to resolve that their own hostname
|
|
56
|
+
points to the same address as localhost. Still MacOS >= 12 seems to disable
|
|
57
|
+
this look up for security reasons. So on MacOS it is required to set this
|
|
58
|
+
option to true
|
|
59
|
+
backend (str): Switch between the different backends "flux", "local" or "slurm". Alternatively, when "auto"
|
|
60
|
+
is selected (the default) the available backend is determined automatically.
|
|
61
|
+
block_allocation (boolean): To accelerate the submission of a series of python functions with the same resource
|
|
62
|
+
requirements, executorlib supports block allocation. In this case all resources have
|
|
63
|
+
to be defined on the executor, rather than during the submission of the individual
|
|
64
|
+
function.
|
|
65
|
+
init_function (None): optional function to preset arguments for functions which are submitted later
|
|
66
|
+
command_line_argument_lst (list): Additional command line arguments for the srun call (SLURM only)
|
|
67
|
+
pmi (str): PMI interface to use (OpenMPI v5 requires pmix) default is None (Flux only)
|
|
68
|
+
disable_dependencies (boolean): Disable resolving future objects during the submission.
|
|
69
|
+
refresh_rate (float): Set the refresh rate in seconds, how frequently the input queue is checked.
|
|
70
|
+
plot_dependency_graph (bool): Plot the dependencies of multiple future objects without executing them. For
|
|
71
|
+
debugging purposes and to get an overview of the specified dependencies.
|
|
72
|
+
|
|
73
|
+
Examples:
|
|
74
|
+
```
|
|
75
|
+
>>> import numpy as np
|
|
76
|
+
>>> from executorlib import Executor
|
|
77
|
+
>>>
|
|
78
|
+
>>> def calc(i, j, k):
|
|
79
|
+
>>> from mpi4py import MPI
|
|
80
|
+
>>> size = MPI.COMM_WORLD.Get_size()
|
|
81
|
+
>>> rank = MPI.COMM_WORLD.Get_rank()
|
|
82
|
+
>>> return np.array([i, j, k]), size, rank
|
|
83
|
+
>>>
|
|
84
|
+
>>> def init_k():
|
|
85
|
+
>>> return {"k": 3}
|
|
86
|
+
>>>
|
|
87
|
+
>>> with Executor(cores=2, init_function=init_k) as p:
|
|
88
|
+
>>> fs = p.submit(calc, 2, j=4)
|
|
89
|
+
>>> print(fs.result())
|
|
90
|
+
[(array([2, 4, 3]), 2, 0), (array([2, 4, 3]), 2, 1)]
|
|
91
|
+
```
|
|
92
|
+
"""
|
|
93
|
+
|
|
94
|
+
def __init__(
|
|
95
|
+
self,
|
|
96
|
+
max_workers: int = 1,
|
|
97
|
+
max_cores: int = 1,
|
|
98
|
+
cores_per_worker: int = 1,
|
|
99
|
+
threads_per_core: int = 1,
|
|
100
|
+
gpus_per_worker: int = 0,
|
|
101
|
+
oversubscribe: bool = False,
|
|
102
|
+
cwd: Optional[str] = None,
|
|
103
|
+
conda_environment_name: Optional[str] = None,
|
|
104
|
+
conda_environment_path: Optional[str] = None,
|
|
105
|
+
executor=None,
|
|
106
|
+
hostname_localhost: bool = False,
|
|
107
|
+
backend: str = "auto",
|
|
108
|
+
block_allocation: bool = True,
|
|
109
|
+
init_function: Optional[callable] = None,
|
|
110
|
+
command_line_argument_lst: list[str] = [],
|
|
111
|
+
pmi: Optional[str] = None,
|
|
112
|
+
disable_dependencies: bool = False,
|
|
113
|
+
refresh_rate: float = 0.01,
|
|
114
|
+
plot_dependency_graph: bool = False,
|
|
115
|
+
):
|
|
116
|
+
# Use __new__() instead of __init__(). This function is only implemented to enable auto-completion.
|
|
117
|
+
pass
|
|
118
|
+
|
|
119
|
+
def __new__(
|
|
120
|
+
cls,
|
|
121
|
+
max_workers: int = 1,
|
|
122
|
+
max_cores: int = 1,
|
|
123
|
+
cores_per_worker: int = 1,
|
|
124
|
+
threads_per_core: int = 1,
|
|
125
|
+
gpus_per_worker: int = 0,
|
|
126
|
+
oversubscribe: bool = False,
|
|
127
|
+
cwd: Optional[str] = None,
|
|
128
|
+
conda_environment_name: Optional[str] = None,
|
|
129
|
+
conda_environment_path: Optional[str] = None,
|
|
130
|
+
executor=None,
|
|
131
|
+
hostname_localhost: bool = False,
|
|
132
|
+
backend: str = "auto",
|
|
133
|
+
block_allocation: bool = False,
|
|
134
|
+
init_function: Optional[callable] = None,
|
|
135
|
+
command_line_argument_lst: list[str] = [],
|
|
136
|
+
pmi: Optional[str] = None,
|
|
137
|
+
disable_dependencies: bool = False,
|
|
138
|
+
refresh_rate: float = 0.01,
|
|
139
|
+
plot_dependency_graph: bool = False,
|
|
140
|
+
):
|
|
141
|
+
"""
|
|
142
|
+
Instead of returning a executorlib.Executor object this function returns either a executorlib.mpi.PyMPIExecutor,
|
|
143
|
+
executorlib.slurm.PySlurmExecutor or executorlib.flux.PyFluxExecutor depending on which backend is available. The
|
|
144
|
+
executorlib.flux.PyFluxExecutor is the preferred choice while the executorlib.mpi.PyMPIExecutor is primarily used
|
|
145
|
+
for development and testing. The executorlib.flux.PyFluxExecutor requires flux-core from the flux-framework to be
|
|
146
|
+
installed and in addition flux-sched to enable GPU scheduling. Finally, the executorlib.slurm.PySlurmExecutor
|
|
147
|
+
requires the SLURM workload manager to be installed on the system.
|
|
148
|
+
|
|
149
|
+
Args:
|
|
150
|
+
max_workers (int): for backwards compatibility with the standard library, max_workers also defines the
|
|
151
|
+
number of cores which can be used in parallel - just like the max_cores parameter. Using
|
|
152
|
+
max_cores is recommended, as computers have a limited number of compute cores.
|
|
153
|
+
max_cores (int): defines the number cores which can be used in parallel
|
|
154
|
+
cores_per_worker (int): number of MPI cores to be used for each function call
|
|
155
|
+
threads_per_core (int): number of OpenMP threads to be used for each function call
|
|
156
|
+
gpus_per_worker (int): number of GPUs per worker - defaults to 0
|
|
157
|
+
oversubscribe (bool): adds the `--oversubscribe` command line flag (OpenMPI and SLURM only) - default False
|
|
158
|
+
cwd (str/None): current working directory where the parallel python task is executed
|
|
159
|
+
conda_environment_name (str): name of the conda environment to initialize
|
|
160
|
+
conda_environment_path (str): path of the conda environment to initialize
|
|
161
|
+
executor (flux.job.FluxExecutor): Flux Python interface to submit the workers to flux
|
|
162
|
+
hostname_localhost (boolean): use localhost instead of the hostname to establish the zmq connection. In the
|
|
163
|
+
context of an HPC cluster this essential to be able to communicate to an
|
|
164
|
+
Executor running on a different compute node within the same allocation. And
|
|
165
|
+
in principle any computer should be able to resolve that their own hostname
|
|
166
|
+
points to the same address as localhost. Still MacOS >= 12 seems to disable
|
|
167
|
+
this look up for security reasons. So on MacOS it is required to set this
|
|
168
|
+
option to true
|
|
169
|
+
backend (str): Switch between the different backends "flux", "local" or "slurm". Alternatively, when "auto"
|
|
170
|
+
is selected (the default) the available backend is determined automatically.
|
|
171
|
+
block_allocation (boolean): To accelerate the submission of a series of python functions with the same
|
|
172
|
+
resource requirements, executorlib supports block allocation. In this case all
|
|
173
|
+
resources have to be defined on the executor, rather than during the submission
|
|
174
|
+
of the individual function.
|
|
175
|
+
init_function (None): optional function to preset arguments for functions which are submitted later
|
|
176
|
+
command_line_argument_lst (list): Additional command line arguments for the srun call (SLURM only)
|
|
177
|
+
pmi (str): PMI interface to use (OpenMPI v5 requires pmix) default is None (Flux only)
|
|
178
|
+
disable_dependencies (boolean): Disable resolving future objects during the submission.
|
|
179
|
+
refresh_rate (float): Set the refresh rate in seconds, how frequently the input queue is checked.
|
|
180
|
+
plot_dependency_graph (bool): Plot the dependencies of multiple future objects without executing them. For
|
|
181
|
+
debugging purposes and to get an overview of the specified dependencies.
|
|
182
|
+
|
|
183
|
+
"""
|
|
184
|
+
if not disable_dependencies:
|
|
185
|
+
return ExecutorWithDependencies(
|
|
186
|
+
max_workers=max_workers,
|
|
187
|
+
max_cores=max_cores,
|
|
188
|
+
cores_per_worker=cores_per_worker,
|
|
189
|
+
threads_per_core=threads_per_core,
|
|
190
|
+
gpus_per_worker=gpus_per_worker,
|
|
191
|
+
oversubscribe=oversubscribe,
|
|
192
|
+
cwd=cwd,
|
|
193
|
+
conda_environment_name=conda_environment_name,
|
|
194
|
+
conda_environment_path=conda_environment_path,
|
|
195
|
+
executor=executor,
|
|
196
|
+
hostname_localhost=hostname_localhost,
|
|
197
|
+
backend=backend,
|
|
198
|
+
block_allocation=block_allocation,
|
|
199
|
+
init_function=init_function,
|
|
200
|
+
command_line_argument_lst=command_line_argument_lst,
|
|
201
|
+
pmi=pmi,
|
|
202
|
+
refresh_rate=refresh_rate,
|
|
203
|
+
plot_dependency_graph=plot_dependency_graph,
|
|
204
|
+
)
|
|
205
|
+
else:
|
|
206
|
+
_check_plot_dependency_graph(plot_dependency_graph=plot_dependency_graph)
|
|
207
|
+
_check_refresh_rate(refresh_rate=refresh_rate)
|
|
208
|
+
return create_executor(
|
|
209
|
+
max_workers=max_workers,
|
|
210
|
+
max_cores=max_cores,
|
|
211
|
+
cores_per_worker=cores_per_worker,
|
|
212
|
+
threads_per_core=threads_per_core,
|
|
213
|
+
gpus_per_worker=gpus_per_worker,
|
|
214
|
+
oversubscribe=oversubscribe,
|
|
215
|
+
cwd=cwd,
|
|
216
|
+
conda_environment_name=conda_environment_name,
|
|
217
|
+
conda_environment_path=conda_environment_path,
|
|
218
|
+
executor=executor,
|
|
219
|
+
hostname_localhost=hostname_localhost,
|
|
220
|
+
backend=backend,
|
|
221
|
+
block_allocation=block_allocation,
|
|
222
|
+
init_function=init_function,
|
|
223
|
+
command_line_argument_lst=command_line_argument_lst,
|
|
224
|
+
pmi=pmi,
|
|
225
|
+
)
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
|
|
2
|
+
# This file was generated by 'versioneer.py' (0.29) from
|
|
3
|
+
# revision-control system data, or from the parent directory name of an
|
|
4
|
+
# unpacked source archive. Distribution tarballs contain a pre-generated copy
|
|
5
|
+
# of this file.
|
|
6
|
+
|
|
7
|
+
import json
|
|
8
|
+
|
|
9
|
+
version_json = '''
|
|
10
|
+
{
|
|
11
|
+
"date": "2024-07-14T21:06:50+0200",
|
|
12
|
+
"dirty": true,
|
|
13
|
+
"error": null,
|
|
14
|
+
"full-revisionid": "0a84450d76b7081b62a9d948bac56f905d013b5d",
|
|
15
|
+
"version": "0.0.1"
|
|
16
|
+
}
|
|
17
|
+
''' # END VERSION_JSON
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def get_versions():
|
|
21
|
+
return json.loads(version_json)
|
|
File without changes
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import pickle
|
|
2
|
+
import sys
|
|
3
|
+
|
|
4
|
+
import cloudpickle
|
|
5
|
+
|
|
6
|
+
from executorlib.cache.shared import backend_load_file, backend_write_file
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def main():
|
|
10
|
+
from mpi4py import MPI
|
|
11
|
+
|
|
12
|
+
MPI.pickle.__init__(
|
|
13
|
+
cloudpickle.dumps,
|
|
14
|
+
cloudpickle.loads,
|
|
15
|
+
pickle.HIGHEST_PROTOCOL,
|
|
16
|
+
)
|
|
17
|
+
mpi_rank_zero = MPI.COMM_WORLD.Get_rank() == 0
|
|
18
|
+
mpi_size_larger_one = MPI.COMM_WORLD.Get_size() > 1
|
|
19
|
+
file_name = sys.argv[1]
|
|
20
|
+
|
|
21
|
+
if mpi_rank_zero:
|
|
22
|
+
apply_dict = backend_load_file(file_name=file_name)
|
|
23
|
+
else:
|
|
24
|
+
apply_dict = None
|
|
25
|
+
apply_dict = MPI.COMM_WORLD.bcast(apply_dict, root=0)
|
|
26
|
+
output = apply_dict["fn"].__call__(*apply_dict["args"], **apply_dict["kwargs"])
|
|
27
|
+
if mpi_size_larger_one:
|
|
28
|
+
result = MPI.COMM_WORLD.gather(output, root=0)
|
|
29
|
+
else:
|
|
30
|
+
result = output
|
|
31
|
+
if mpi_rank_zero:
|
|
32
|
+
backend_write_file(
|
|
33
|
+
file_name=file_name,
|
|
34
|
+
output=result,
|
|
35
|
+
)
|
|
36
|
+
MPI.COMM_WORLD.Barrier()
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
if __name__ == "__main__":
|
|
40
|
+
main()
|