212 lines
6.4 KiB
Text
212 lines
6.4 KiB
Text
Metadata-Version: 2.1
|
|
Name: threadpoolctl
|
|
Version: 2.1.0
|
|
Summary: threadpoolctl
|
|
Home-page: https://github.com/joblib/threadpoolctl
|
|
License: UNKNOWN
|
|
Author: Thomas Moreau
|
|
Author-email: thomas.moreau.2010@gmail.com
|
|
Requires-Python: >=3.5
|
|
Description-Content-Type: text/markdown
|
|
Classifier: Intended Audience :: Developers
|
|
Classifier: License :: OSI Approved :: BSD License
|
|
Classifier: Programming Language :: Python :: 3
|
|
Classifier: Programming Language :: Python :: 3.5
|
|
Classifier: Programming Language :: Python :: 3.6
|
|
Classifier: Programming Language :: Python :: 3.7
|
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
|
|
# Thread-pool Controls [![Build Status](https://dev.azure.com/joblib/threadpoolctl/_apis/build/status/joblib.threadpoolctl?branchName=master)](https://dev.azure.com/joblib/threadpoolctl/_build/latest?definitionId=1&branchName=master) [![codecov](https://codecov.io/gh/joblib/threadpoolctl/branch/master/graph/badge.svg)](https://codecov.io/gh/joblib/threadpoolctl)
|
|
|
|
Python helpers to limit the number of threads used in the
|
|
threadpool-backed of common native libraries used for scientific
|
|
computing and data science (e.g. BLAS and OpenMP).
|
|
|
|
Fine control of the underlying thread-pool size can be useful in
|
|
workloads that involve nested parallelism so as to mitigate
|
|
oversubscription issues.
|
|
|
|
## Installation
|
|
|
|
- For users, install the last published version from PyPI:
|
|
|
|
```bash
|
|
pip install threadpoolctl
|
|
```
|
|
|
|
- For contributors, install from the source repository in developer
|
|
mode:
|
|
|
|
```bash
|
|
pip install -r dev-requirements.txt
|
|
flit install --symlink
|
|
```
|
|
|
|
then you run the tests with pytest:
|
|
|
|
```bash
|
|
pytest
|
|
```
|
|
|
|
## Usage
|
|
|
|
### Command Line Interface
|
|
|
|
Get a JSON description of thread-pools initialized when importing python
|
|
packages such as numpy or scipy for instance:
|
|
|
|
```
|
|
python -m threadpoolctl -i numpy scipy.linalg
|
|
[
|
|
{
|
|
"filepath": "/home/ogrisel/miniconda3/envs/tmp/lib/libmkl_rt.so",
|
|
"prefix": "libmkl_rt",
|
|
"user_api": "blas",
|
|
"internal_api": "mkl",
|
|
"version": "2019.0.4",
|
|
"num_threads": 2,
|
|
"threading_layer": "intel"
|
|
},
|
|
{
|
|
"filepath": "/home/ogrisel/miniconda3/envs/tmp/lib/libiomp5.so",
|
|
"prefix": "libiomp",
|
|
"user_api": "openmp",
|
|
"internal_api": "openmp",
|
|
"version": null,
|
|
"num_threads": 4
|
|
}
|
|
]
|
|
```
|
|
|
|
The JSON information is written on STDOUT. If some of the packages are missing,
|
|
a warning message is displayed on STDERR.
|
|
|
|
### Python Runtime Programmatic Introspection
|
|
|
|
Introspect the current state of the threadpool-enabled runtime libraries
|
|
that are loaded when importing Python packages:
|
|
|
|
```python
|
|
>>> from threadpoolctl import threadpool_info
|
|
>>> from pprint import pprint
|
|
>>> pprint(threadpool_info())
|
|
[]
|
|
|
|
>>> import numpy
|
|
>>> pprint(threadpool_info())
|
|
[{'filepath': '/home/ogrisel/miniconda3/envs/tmp/lib/libmkl_rt.so',
|
|
'internal_api': 'mkl',
|
|
'num_threads': 2,
|
|
'prefix': 'libmkl_rt',
|
|
'threading_layer': 'intel',
|
|
'user_api': 'blas',
|
|
'version': '2019.0.4'},
|
|
{'filepath': '/home/ogrisel/miniconda3/envs/tmp/lib/libiomp5.so',
|
|
'internal_api': 'openmp',
|
|
'num_threads': 4,
|
|
'prefix': 'libiomp',
|
|
'user_api': 'openmp',
|
|
'version': None}]
|
|
|
|
>>> import xgboost
|
|
>>> pprint(threadpool_info())
|
|
[{'filepath': '/home/ogrisel/miniconda3/envs/tmp/lib/libmkl_rt.so',
|
|
'internal_api': 'mkl',
|
|
'num_threads': 2,
|
|
'prefix': 'libmkl_rt',
|
|
'threading_layer': 'intel',
|
|
'user_api': 'blas',
|
|
'version': '2019.0.4'},
|
|
{'filepath': '/home/ogrisel/miniconda3/envs/tmp/lib/libiomp5.so',
|
|
'internal_api': 'openmp',
|
|
'num_threads': 4,
|
|
'prefix': 'libiomp',
|
|
'user_api': 'openmp',
|
|
'version': None},
|
|
{'filepath': '/home/ogrisel/miniconda3/envs/tmp/lib/libgomp.so.1.0.0',
|
|
'internal_api': 'openmp',
|
|
'num_threads': 4,
|
|
'prefix': 'libgomp',
|
|
'user_api': 'openmp',
|
|
'version': None}]
|
|
```
|
|
|
|
In the above example, `numpy` was installed from the default anaconda channel and
|
|
comes with the MKL and its Intel OpenMP (`libiomp5`) implementation while
|
|
`xgboost` was installed from pypi.org and links against GNU OpenMP (`libgomp`)
|
|
so both OpenMP runtimes are loaded in the same Python program.
|
|
|
|
### Setting the Maximum Size of Thread-Pools
|
|
|
|
Control the number of threads used by the underlying runtime libraries
|
|
in specific sections of your Python program:
|
|
|
|
```python
|
|
from threadpoolctl import threadpool_limits
|
|
import numpy as np
|
|
|
|
|
|
with threadpool_limits(limits=1, user_api='blas'):
|
|
# In this block, calls to blas implementation (like openblas or MKL)
|
|
# will be limited to use only one thread. They can thus be used jointly
|
|
# with thread-parallelism.
|
|
a = np.random.randn(1000, 1000)
|
|
a_squared = a @ a
|
|
```
|
|
|
|
### Known Limitations
|
|
|
|
- `threadpool_limits` can fail to limit the number of inner threads when nesting
|
|
parallel loops managed by distinct OpenMP runtime implementations (for instance
|
|
libgomp from GCC and libomp from clang/llvm or libiomp from ICC).
|
|
|
|
See the `test_openmp_nesting` function in [tests/test_threadpoolctl.py](
|
|
https://github.com/joblib/threadpoolctl/blob/master/tests/test_threadpoolctl.py)
|
|
for an example. More information can be found at:
|
|
https://github.com/jeremiedbb/Nested_OpenMP
|
|
|
|
Note however that this problem does not happen when `threadpool_limits` is
|
|
used to limit the number of threads used internally by BLAS calls that are
|
|
themselves nested under OpenMP parallel loops. `threadpool_limits` works as
|
|
expected, even if the inner BLAS implementation relies on a distinct OpenMP
|
|
implementation.
|
|
|
|
- Using Intel OpenMP (ICC) and LLVM OpenMP (clang) in the same Python program
|
|
under Linux is known to cause problems. See the following guide for more details
|
|
and workarounds:
|
|
https://github.com/joblib/threadpoolctl/blob/master/multiple_openmp.md
|
|
|
|
|
|
## Maintainers
|
|
|
|
To make a release:
|
|
|
|
Bump the version number (`__version__`) in `threadpoolctl.py`.
|
|
|
|
Build the distribution archives:
|
|
|
|
```bash
|
|
pip install flit
|
|
flit build
|
|
```
|
|
|
|
Check the contents of `dist/`.
|
|
|
|
If everything is fine, make a commit for the release, tag it, push the
|
|
tag to github and then:
|
|
|
|
```bash
|
|
flit publish
|
|
```
|
|
|
|
### Credits
|
|
|
|
The initial dynamic library introspection code was written by @anton-malakhov
|
|
for the smp package available at https://github.com/IntelPython/smp .
|
|
|
|
threadpoolctl extends this for other operationg systems. Contrary to smp,
|
|
threadpoolctl does not attempt to limit the size of Python multiprocessing
|
|
pools (threads or processes) or set operating system-level CPU affinity
|
|
constraints: threadpoolctl only interacts with native libraries via their
|
|
public runtime APIs.
|
|
|