Loading repository data…
Loading repository data…
eXascaleInfolab / repository
Python Multi-Process Execution Pool: concurrent asynchronous execution pool with custom resource constraints (memory, timeouts, affinity, CPU cores and caching), load balancing and profiling capabilities of the external apps on NUMA architecture
A Lightweight Multi-Process Execution Pool with load balancing and customizable resource consumption constraints.
\author: (c) Artem Lutov artem@exascale.info
\license: Apache License, Version 2.0
\organizations: eXascale Infolab, Lumais, ScienceWise
\date: 2015-07 v1, 2017-06 v2, 2018-05 v3
\grants: Swiss National Science Foundation grant number CRSII2_147609, European Commission grant Graphint 683253
BibTeX:
@misc{pyexpool,
author = {Artem Lutov and Philippe Cudré-Mauroux},
url = {https://github.com/eXascaleInfolab/PyExPool},
title = {PyExPool-v.3: A Lightweight Execution Pool with Constraint-aware Load-Balancer.},
year = {2018}
}
A Lightweight Multi-Process Execution Pool with load balancing to schedule Jobs execution with per-job timeout, optionally grouping them into Tasks and specifying optional execution parameters considering NUMA architecture peculiarities:
Automatic rescheduling of the workers on low memory condition for the in-RAM computations is an optional and the only feature that requires an external package, psutil.
All scheduling jobs share the same CPU affinity policy, which is convenient for the benchmarking, but not so suitable for scheduling both single and multi-threaded apps with distinct demands for the CPU cache.
All main functionality is implemented as a single-file module to be easily included into your project and customized as a part of your distribution (like in PyCaBeM to execute muliple apps in parralel on the dedicated CPU cores and avoiding their swapping from the main memory), also it can be installed as a library. An optional minimalistic Web interface is provided in the separate file to inspect and profile the load balancer and execution pool.
The main purpose of the main single-file module is the concurrent execution of modules and external executables with custom resource consumption constraints, cache / parallelization tuning and automatic balancing of the worker processes for the in memory computations on the single server. PyExPool is typically used as an application framework for benchmarking or heavy-loaded multi-process execution activities on constrained computational resources.
If the concurrent execution of Python functions is required, usage of external modules is not a problem and the automatic jobs scheduling for the in-RAM computations is not necessary, then a more handy and straightforward approach is to use Pebble library. A pretty convenient transparent parallel computations are provided by the Joblib. If a distributed task queue is required with advanced monitoring and reporting facilities then Celery might be a good choice. For the comprehensive parallel computing Dask is a good choice. For the parallel execution of only the shell scripts the GNU parallel might be a good option.
The only another existing open-source load balancer I'm aware about, which has wider functionality than PyExPool (but can not be integrated into your Python scripts so seamlessly) is Slurm Workload Manager.
The load balancing is enabled when the global variables _LIMIT_WORKERS_RAM and _CHAINED_CONSTRAINTS are set, jobs .category and relative .size (if known) specified. The balancing is performed to use as much RAM and CPU resources as possible performing in-RAM computations and meeting the specified timeout and memory constraints for each job and for the whole pool.
Large executing jobs can be postponed for the later execution with less number of worker processes after completion of the smaller jobs. The number of workers is reduced automatically (balanced) on the jobs queue processing to meet memory constraints. It is recommended to add jobs in the order of the increasing memory/time complexity if possible to reduce the number of worker processes terminations on jobs postponing (rescheduling).
Demo of the scheduling with memory constraints for the worker processes:
Demo of the scheduling with cache L1 maximization for single-threaded processes on the server with cross-node CPUs enumeration. Whole physical CPU core consisting of two hardware threads assigned to each worker process, so the L1 cache is dedicated (not shared), but the maximal loading over all CPUs is 50%:
Demo of the WebUI for the Jobs and Tasks tracing and profiling: Exactly the same fully functional interface is accessible from the console using w3m or other terminal browsers: To explore the WebUI demo execute the following testcase
$ MANUAL=1 python -m unittest mpetests.TestWebUI.test_failures
and open http://localhost:8081 (or :8080) in the browser.
Include the following modules:
These modules can be install either manually from GitHub or from the pypi repository:
$ pip install pyexpool
WebUI(
mpewuimodule) renders interface from the bottle html templates located in the.,./views/or any other folder from thebottle.TEMPLATE_PATHlist, where custom views can be placed to overwrite the default pages.
Additionally, hwloc / lstopo should be installed if customized CPU affinity masking and cache control are required, see Requirements section.
Multi-Process Execution Pool can be run without any external modules with automatically disabled load balancing.
The external modules / apps are required only for the extended functionality:
lstopo) is required to identify enumeration type of logical CPUs to perform correct CPU affinity masking. Required only for the automatic affinity masking with cache usage optimization and only if the CPU enumeration type is not specified manually.
$ sudo apt-get install -y hwloc
psutil is required for the dynamic jobs balancing to perform the in-RAM computations (_LIMIT_WORKERS_RAM = True) and limit memory consumption of the workers.
$ sudo pip install psutil
To perform in-memory computations dedicating almost all available RAM (specifying memlimit ~= physical memory), it is recommended to set swappiness to 1 .. 10:
$ sudo sysctl -w vm.swappiness=5or set it permanently in/etc/sysctl.conf:vm.swappiness = 5.
bottle is required for the minimalistic optional WebUI to monitor executing jobs.
$ sudo pip install bottle
WebUI(
mpewuimodule) renders interface from the bottle html templates located in the.,./views/or any other folder from thebottle.TEMPLATE_PATHlist, where custom views can be placed to overwrite the default pages.
mock is required exclusively for the unit testing under Python2, mock is included in the standard lib of Python3.
$ sudo pip install mock
All Python requirements are optional and installed automatically from the pip distribution ($ pip install pyexpool) or can be installed manually from the pyreqsopt.txt file:
$ sudo pip install -r pyreqsopt.txt
lstopoapp ofhwlocpackage is a system requirement and should be installed manually from the system-specific package repository or built from the sources.
Flexible API provides automatic CPU affinity management, maximization of the dedicated CPU cache, limitation of the minimal dedicated RAM per worker process, balancing of the worker processes and rescheduling of chains of the related jobs on low memory condition for the in-RAM computations, optional automatic restart of jobs on timeout, access to job's process, parent task, start and stop execution time and more...
ExecPool represents a pool of worker processes to execute Jobs that can be grouped into the hierarchy of Taskss for more flexible management.
# Global Parameters
# Limit the amount of memory (<= RAM) used by worker processes
# NOTE: requires import of psutils
_LIMIT_WORKERS_RAM = True
# Use chained constraints (timeout and memory limitation) in jobs to terminate
# also related worker processes and/or reschedule jobs, which have the same
# category and heavier than the origin violating the constraints
CHAINED_CONSTRAINTS = True
Job(name, workdir=None, args=(), timeout=0, rsrtonto=False, task=None #,*
, startdelay=0., onstart=None, ondone=None, onfinish=None, params=None, category=None, size=0, slowdown=1.
, omitafn=False, memkind=1, memlim=0., stdout=sys.stdout, stderr=sys.stderr, poutlog=None, perrlog=None):
"""Initialize job to be executed
Job is executed in a separate process via Popen or Process object and is
managed by the Process Pool Executor
Main parameters:
name: str - job name
workdir - working directory for the corresponding process, None means the dir of the benchmarking
args - execution arguments including the executable itself for the process
NOTE: can be None to make make a stub process and execute the callbacks
timeout - execution timeout in seconds. Default: 0, means infinity
rsrtonto - restart the job on timeout, Default: False. Can be used for
non-deterministic Jobs like generation of the synthetic networks to regenerate
the network on border cases overcoming getting stuck on specific values of the ra