@@ -184,6 +184,174 @@ def __init__(
184184 )
185185
186186
187+ class TestClusterExecutor (BaseExecutor ):
188+ """
189+ The executorlib.api.TestClusterExecutor is designed to test the file based communication used in the
190+ SlurmClusterExecutor and the FluxClusterExecutor locally. It is not recommended for production use, rather use the
191+ SingleNodeExecutor.
192+
193+ Args:
194+ max_workers (int): for backwards compatibility with the standard library, max_workers also defines the number of
195+ cores which can be used in parallel - just like the max_cores parameter. Using max_cores is
196+ recommended, as computers have a limited number of compute cores.
197+ cache_directory (str, optional): The directory to store cache files. Defaults to "executorlib_cache".
198+ max_cores (int): defines the number cores which can be used in parallel
199+ resource_dict (dict): A dictionary of resources required by the task. With the following keys:
200+ - cores (int): number of MPI cores to be used for each function call
201+ - threads_per_core (int): number of OpenMP threads to be used for each function call
202+ - gpus_per_core (int): number of GPUs per worker - defaults to 0
203+ - cwd (str/None): current working directory where the parallel python task is executed
204+ hostname_localhost (boolean): use localhost instead of the hostname to establish the zmq connection. In the
205+ context of an HPC cluster this essential to be able to communicate to an
206+ Executor running on a different compute node within the same allocation. And
207+ in principle any computer should be able to resolve that their own hostname
208+ points to the same address as localhost. Still MacOS >= 12 seems to disable
209+ this look up for security reasons. So on MacOS it is required to set this
210+ option to true
211+ block_allocation (boolean): To accelerate the submission of a series of python functions with the same resource
212+ requirements, executorlib supports block allocation. In this case all resources have
213+ to be defined on the executor, rather than during the submission of the individual
214+ function.
215+ init_function (None): optional function to preset arguments for functions which are submitted later
216+ disable_dependencies (boolean): Disable resolving future objects during the submission.
217+ refresh_rate (float): Set the refresh rate in seconds, how frequently the input queue is checked.
218+ plot_dependency_graph (bool): Plot the dependencies of multiple future objects without executing them. For
219+ debugging purposes and to get an overview of the specified dependencies.
220+ plot_dependency_graph_filename (str): Name of the file to store the plotted graph in.
221+ log_obj_size (bool): Enable debug mode which reports the size of the communicated objects.
222+
223+ Examples:
224+ ```
225+ >>> import numpy as np
226+ >>> from executorlib.api import TestClusterExecutor
227+ >>>
228+ >>> def calc(i, j, k):
229+ >>> from mpi4py import MPI
230+ >>> size = MPI.COMM_WORLD.Get_size()
231+ >>> rank = MPI.COMM_WORLD.Get_rank()
232+ >>> return np.array([i, j, k]), size, rank
233+ >>>
234+ >>> def init_k():
235+ >>> return {"k": 3}
236+ >>>
237+ >>> with TestClusterExecutor(max_workers=2, init_function=init_k) as p:
238+ >>> fs = p.submit(calc, 2, j=4)
239+ >>> print(fs.result())
240+ [(array([2, 4, 3]), 2, 0), (array([2, 4, 3]), 2, 1)]
241+ ```
242+ """
243+
244+ def __init__ (
245+ self ,
246+ max_workers : Optional [int ] = None ,
247+ cache_directory : Optional [str ] = None ,
248+ max_cores : Optional [int ] = None ,
249+ resource_dict : Optional [dict ] = None ,
250+ hostname_localhost : Optional [bool ] = None ,
251+ block_allocation : bool = False ,
252+ init_function : Optional [Callable ] = None ,
253+ disable_dependencies : bool = False ,
254+ refresh_rate : float = 0.01 ,
255+ plot_dependency_graph : bool = False ,
256+ plot_dependency_graph_filename : Optional [str ] = None ,
257+ log_obj_size : bool = False ,
258+ ):
259+ """
260+ The executorlib.api.TestClusterExecutor is designed to test the file based communication used in the
261+ SlurmClusterExecutor and the FluxClusterExecutor locally. It is not recommended for production use, rather use
262+ the SingleNodeExecutor.
263+
264+ Args:
265+ max_workers (int): for backwards compatibility with the standard library, max_workers also defines the
266+ number of cores which can be used in parallel - just like the max_cores parameter. Using
267+ max_cores is recommended, as computers have a limited number of compute cores.
268+ cache_directory (str, optional): The directory to store cache files. Defaults to "executorlib_cache".
269+ max_cores (int): defines the number cores which can be used in parallel
270+ resource_dict (dict): A dictionary of resources required by the task. With the following keys:
271+ - cores (int): number of MPI cores to be used for each function call
272+ - threads_per_core (int): number of OpenMP threads to be used for each function call
273+ - gpus_per_core (int): number of GPUs per worker - defaults to 0
274+ - cwd (str/None): current working directory where the parallel python task is executed
275+ hostname_localhost (boolean): use localhost instead of the hostname to establish the zmq connection. In the
276+ context of an HPC cluster this essential to be able to communicate to an
277+ Executor running on a different compute node within the same allocation. And
278+ in principle any computer should be able to resolve that their own hostname
279+ points to the same address as localhost. Still MacOS >= 12 seems to disable
280+ this look up for security reasons. So on MacOS it is required to set this
281+ option to true
282+ block_allocation (boolean): To accelerate the submission of a series of python functions with the same
283+ resource requirements, executorlib supports block allocation. In this case all
284+ resources have to be defined on the executor, rather than during the submission
285+ of the individual function.
286+ init_function (None): optional function to preset arguments for functions which are submitted later
287+ disable_dependencies (boolean): Disable resolving future objects during the submission.
288+ refresh_rate (float): Set the refresh rate in seconds, how frequently the input queue is checked.
289+ plot_dependency_graph (bool): Plot the dependencies of multiple future objects without executing them. For
290+ debugging purposes and to get an overview of the specified dependencies.
291+ plot_dependency_graph_filename (str): Name of the file to store the plotted graph in.
292+ log_obj_size (bool): Enable debug mode which reports the size of the communicated objects.
293+
294+ """
295+ default_resource_dict : dict = {
296+ "cores" : 1 ,
297+ "threads_per_core" : 1 ,
298+ "gpus_per_core" : 0 ,
299+ "cwd" : None ,
300+ "openmpi_oversubscribe" : False ,
301+ }
302+ if resource_dict is None :
303+ resource_dict = {}
304+ resource_dict .update (
305+ {k : v for k , v in default_resource_dict .items () if k not in resource_dict }
306+ )
307+ if not plot_dependency_graph :
308+ from executorlib .task_scheduler .file .subprocess_spawner import (
309+ execute_in_subprocess ,
310+ )
311+ from executorlib .task_scheduler .file .task_scheduler import (
312+ create_file_executor ,
313+ )
314+
315+ super ().__init__ (
316+ executor = create_file_executor (
317+ max_workers = max_workers ,
318+ backend = None ,
319+ max_cores = max_cores ,
320+ cache_directory = cache_directory ,
321+ resource_dict = resource_dict ,
322+ flux_executor = None ,
323+ flux_executor_pmi_mode = None ,
324+ flux_executor_nesting = False ,
325+ flux_log_files = False ,
326+ pysqa_config_directory = None ,
327+ hostname_localhost = hostname_localhost ,
328+ block_allocation = block_allocation ,
329+ init_function = init_function ,
330+ disable_dependencies = disable_dependencies ,
331+ execute_function = execute_in_subprocess ,
332+ )
333+ )
334+ else :
335+ super ().__init__ (
336+ executor = DependencyTaskScheduler (
337+ executor = create_single_node_executor (
338+ max_workers = max_workers ,
339+ cache_directory = cache_directory ,
340+ max_cores = max_cores ,
341+ resource_dict = resource_dict ,
342+ hostname_localhost = hostname_localhost ,
343+ block_allocation = block_allocation ,
344+ init_function = init_function ,
345+ log_obj_size = log_obj_size ,
346+ ),
347+ max_cores = max_cores ,
348+ refresh_rate = refresh_rate ,
349+ plot_dependency_graph = plot_dependency_graph ,
350+ plot_dependency_graph_filename = plot_dependency_graph_filename ,
351+ )
352+ )
353+
354+
187355def create_single_node_executor (
188356 max_workers : Optional [int ] = None ,
189357 max_cores : Optional [int ] = None ,
0 commit comments