Mercurial > repos > rliterman > csp2
comparison CSP2/CSP2_env/env-d9b9114564458d9d-741b3de822f2aaca6c6caa4325c4afce/lib/python3.8/site-packages/threadpoolctl-3.5.0.dist-info/METADATA @ 69:33d812a61356
planemo upload commit 2e9511a184a1ca667c7be0c6321a36dc4e3d116d
author | jpayne |
---|---|
date | Tue, 18 Mar 2025 17:55:14 -0400 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
67:0e9998148a16 | 69:33d812a61356 |
---|---|
1 Metadata-Version: 2.1 | |
2 Name: threadpoolctl | |
3 Version: 3.5.0 | |
4 Summary: threadpoolctl | |
5 Home-page: https://github.com/joblib/threadpoolctl | |
6 License: BSD-3-Clause | |
7 Author: Thomas Moreau | |
8 Author-email: thomas.moreau.2010@gmail.com | |
9 Requires-Python: >=3.8 | |
10 Description-Content-Type: text/markdown | |
11 Classifier: Intended Audience :: Developers | |
12 Classifier: License :: OSI Approved :: BSD License | |
13 Classifier: Programming Language :: Python :: 3 | |
14 Classifier: Programming Language :: Python :: 3.8 | |
15 Classifier: Programming Language :: Python :: 3.9 | |
16 Classifier: Programming Language :: Python :: 3.10 | |
17 Classifier: Programming Language :: Python :: 3.11 | |
18 Classifier: Programming Language :: Python :: 3.12 | |
19 Classifier: Topic :: Software Development :: Libraries :: Python Modules | |
20 | |
21 # Thread-pool Controls [](https://dev.azure.com/joblib/threadpoolctl/_build/latest?definitionId=1&branchName=master) [](https://codecov.io/gh/joblib/threadpoolctl) | |
22 | |
23 Python helpers to limit the number of threads used in the | |
24 threadpool-backed of common native libraries used for scientific | |
25 computing and data science (e.g. BLAS and OpenMP). | |
26 | |
27 Fine control of the underlying thread-pool size can be useful in | |
28 workloads that involve nested parallelism so as to mitigate | |
29 oversubscription issues. | |
30 | |
31 ## Installation | |
32 | |
33 - For users, install the last published version from PyPI: | |
34 | |
35 ```bash | |
36 pip install threadpoolctl | |
37 ``` | |
38 | |
39 - For contributors, install from the source repository in developer | |
40 mode: | |
41 | |
42 ```bash | |
43 pip install -r dev-requirements.txt | |
44 flit install --symlink | |
45 ``` | |
46 | |
47 then you run the tests with pytest: | |
48 | |
49 ```bash | |
50 pytest | |
51 ``` | |
52 | |
53 ## Usage | |
54 | |
55 ### Command Line Interface | |
56 | |
57 Get a JSON description of thread-pools initialized when importing python | |
58 packages such as numpy or scipy for instance: | |
59 | |
60 ``` | |
61 python -m threadpoolctl -i numpy scipy.linalg | |
62 [ | |
63 { | |
64 "filepath": "/home/ogrisel/miniconda3/envs/tmp/lib/libmkl_rt.so", | |
65 "prefix": "libmkl_rt", | |
66 "user_api": "blas", | |
67 "internal_api": "mkl", | |
68 "version": "2019.0.4", | |
69 "num_threads": 2, | |
70 "threading_layer": "intel" | |
71 }, | |
72 { | |
73 "filepath": "/home/ogrisel/miniconda3/envs/tmp/lib/libiomp5.so", | |
74 "prefix": "libiomp", | |
75 "user_api": "openmp", | |
76 "internal_api": "openmp", | |
77 "version": null, | |
78 "num_threads": 4 | |
79 } | |
80 ] | |
81 ``` | |
82 | |
83 The JSON information is written on STDOUT. If some of the packages are missing, | |
84 a warning message is displayed on STDERR. | |
85 | |
86 ### Python Runtime Programmatic Introspection | |
87 | |
88 Introspect the current state of the threadpool-enabled runtime libraries | |
89 that are loaded when importing Python packages: | |
90 | |
91 ```python | |
92 >>> from threadpoolctl import threadpool_info | |
93 >>> from pprint import pprint | |
94 >>> pprint(threadpool_info()) | |
95 [] | |
96 | |
97 >>> import numpy | |
98 >>> pprint(threadpool_info()) | |
99 [{'filepath': '/home/ogrisel/miniconda3/envs/tmp/lib/libmkl_rt.so', | |
100 'internal_api': 'mkl', | |
101 'num_threads': 2, | |
102 'prefix': 'libmkl_rt', | |
103 'threading_layer': 'intel', | |
104 'user_api': 'blas', | |
105 'version': '2019.0.4'}, | |
106 {'filepath': '/home/ogrisel/miniconda3/envs/tmp/lib/libiomp5.so', | |
107 'internal_api': 'openmp', | |
108 'num_threads': 4, | |
109 'prefix': 'libiomp', | |
110 'user_api': 'openmp', | |
111 'version': None}] | |
112 | |
113 >>> import xgboost | |
114 >>> pprint(threadpool_info()) | |
115 [{'filepath': '/home/ogrisel/miniconda3/envs/tmp/lib/libmkl_rt.so', | |
116 'internal_api': 'mkl', | |
117 'num_threads': 2, | |
118 'prefix': 'libmkl_rt', | |
119 'threading_layer': 'intel', | |
120 'user_api': 'blas', | |
121 'version': '2019.0.4'}, | |
122 {'filepath': '/home/ogrisel/miniconda3/envs/tmp/lib/libiomp5.so', | |
123 'internal_api': 'openmp', | |
124 'num_threads': 4, | |
125 'prefix': 'libiomp', | |
126 'user_api': 'openmp', | |
127 'version': None}, | |
128 {'filepath': '/home/ogrisel/miniconda3/envs/tmp/lib/libgomp.so.1.0.0', | |
129 'internal_api': 'openmp', | |
130 'num_threads': 4, | |
131 'prefix': 'libgomp', | |
132 'user_api': 'openmp', | |
133 'version': None}] | |
134 ``` | |
135 | |
136 In the above example, `numpy` was installed from the default anaconda channel and comes | |
137 with MKL and its Intel OpenMP (`libiomp5`) implementation while `xgboost` was installed | |
138 from pypi.org and links against GNU OpenMP (`libgomp`) so both OpenMP runtimes are | |
139 loaded in the same Python program. | |
140 | |
141 The state of these libraries is also accessible through the object oriented API: | |
142 | |
143 ```python | |
144 >>> from threadpoolctl import ThreadpoolController, threadpool_info | |
145 >>> from pprint import pprint | |
146 >>> import numpy | |
147 >>> controller = ThreadpoolController() | |
148 >>> pprint(controller.info()) | |
149 [{'architecture': 'Haswell', | |
150 'filepath': '/home/jeremie/miniconda/envs/dev/lib/libopenblasp-r0.3.17.so', | |
151 'internal_api': 'openblas', | |
152 'num_threads': 4, | |
153 'prefix': 'libopenblas', | |
154 'threading_layer': 'pthreads', | |
155 'user_api': 'blas', | |
156 'version': '0.3.17'}] | |
157 | |
158 >>> controller.info() == threadpool_info() | |
159 True | |
160 ``` | |
161 | |
162 ### Setting the Maximum Size of Thread-Pools | |
163 | |
164 Control the number of threads used by the underlying runtime libraries | |
165 in specific sections of your Python program: | |
166 | |
167 ```python | |
168 >>> from threadpoolctl import threadpool_limits | |
169 >>> import numpy as np | |
170 | |
171 >>> with threadpool_limits(limits=1, user_api='blas'): | |
172 ... # In this block, calls to blas implementation (like openblas or MKL) | |
173 ... # will be limited to use only one thread. They can thus be used jointly | |
174 ... # with thread-parallelism. | |
175 ... a = np.random.randn(1000, 1000) | |
176 ... a_squared = a @ a | |
177 ``` | |
178 | |
179 The threadpools can also be controlled via the object oriented API, which is especially | |
180 useful to avoid searching through all the loaded shared libraries each time. It will | |
181 however not act on libraries loaded after the instantiation of the | |
182 `ThreadpoolController`: | |
183 | |
184 ```python | |
185 >>> from threadpoolctl import ThreadpoolController | |
186 >>> import numpy as np | |
187 >>> controller = ThreadpoolController() | |
188 | |
189 >>> with controller.limit(limits=1, user_api='blas'): | |
190 ... a = np.random.randn(1000, 1000) | |
191 ... a_squared = a @ a | |
192 ``` | |
193 | |
194 ### Restricting the limits to the scope of a function | |
195 | |
196 `threadpool_limits` and `ThreadpoolController` can also be used as decorators to set | |
197 the maximum number of threads used by the supported libraries at a function level. The | |
198 decorators are accessible through their `wrap` method: | |
199 | |
200 ```python | |
201 >>> from threadpoolctl import ThreadpoolController, threadpool_limits | |
202 >>> import numpy as np | |
203 >>> controller = ThreadpoolController() | |
204 | |
205 >>> @controller.wrap(limits=1, user_api='blas') | |
206 ... # or @threadpool_limits.wrap(limits=1, user_api='blas') | |
207 ... def my_func(): | |
208 ... # Inside this function, calls to blas implementation (like openblas or MKL) | |
209 ... # will be limited to use only one thread. | |
210 ... a = np.random.randn(1000, 1000) | |
211 ... a_squared = a @ a | |
212 ... | |
213 ``` | |
214 | |
215 ### Switching the FlexiBLAS backend | |
216 | |
217 `FlexiBLAS` is a BLAS wrapper for which the BLAS backend can be switched at runtime. | |
218 `threadpoolctl` exposes python bindings for this feature. Here's an example but note | |
219 that this part of the API is experimental and subject to change without deprecation: | |
220 | |
221 ```python | |
222 >>> from threadpoolctl import ThreadpoolController | |
223 >>> import numpy as np | |
224 >>> controller = ThreadpoolController() | |
225 | |
226 >>> controller.info() | |
227 [{'user_api': 'blas', | |
228 'internal_api': 'flexiblas', | |
229 'num_threads': 1, | |
230 'prefix': 'libflexiblas', | |
231 'filepath': '/usr/local/lib/libflexiblas.so.3.3', | |
232 'version': '3.3.1', | |
233 'available_backends': ['NETLIB', 'OPENBLASPTHREAD', 'ATLAS'], | |
234 'loaded_backends': ['NETLIB'], | |
235 'current_backend': 'NETLIB'}] | |
236 | |
237 # Retrieve the flexiblas controller | |
238 >>> flexiblas_ct = controller.select(internal_api="flexiblas").lib_controllers[0] | |
239 | |
240 # Switch the backend with one predefined at build time (listed in "available_backends") | |
241 >>> flexiblas_ct.switch_backend("OPENBLASPTHREAD") | |
242 >>> controller.info() | |
243 [{'user_api': 'blas', | |
244 'internal_api': 'flexiblas', | |
245 'num_threads': 4, | |
246 'prefix': 'libflexiblas', | |
247 'filepath': '/usr/local/lib/libflexiblas.so.3.3', | |
248 'version': '3.3.1', | |
249 'available_backends': ['NETLIB', 'OPENBLASPTHREAD', 'ATLAS'], | |
250 'loaded_backends': ['NETLIB', 'OPENBLASPTHREAD'], | |
251 'current_backend': 'OPENBLASPTHREAD'}, | |
252 {'user_api': 'blas', | |
253 'internal_api': 'openblas', | |
254 'num_threads': 4, | |
255 'prefix': 'libopenblas', | |
256 'filepath': '/usr/lib/x86_64-linux-gnu/openblas-pthread/libopenblasp-r0.3.8.so', | |
257 'version': '0.3.8', | |
258 'threading_layer': 'pthreads', | |
259 'architecture': 'Haswell'}] | |
260 | |
261 # It's also possible to directly give the path to a shared library | |
262 >>> flexiblas_controller.switch_backend("/home/jeremie/miniforge/envs/flexiblas_threadpoolctl/lib/libmkl_rt.so") | |
263 >>> controller.info() | |
264 [{'user_api': 'blas', | |
265 'internal_api': 'flexiblas', | |
266 'num_threads': 2, | |
267 'prefix': 'libflexiblas', | |
268 'filepath': '/usr/local/lib/libflexiblas.so.3.3', | |
269 'version': '3.3.1', | |
270 'available_backends': ['NETLIB', 'OPENBLASPTHREAD', 'ATLAS'], | |
271 'loaded_backends': ['NETLIB', | |
272 'OPENBLASPTHREAD', | |
273 '/home/jeremie/miniforge/envs/flexiblas_threadpoolctl/lib/libmkl_rt.so'], | |
274 'current_backend': '/home/jeremie/miniforge/envs/flexiblas_threadpoolctl/lib/libmkl_rt.so'}, | |
275 {'user_api': 'openmp', | |
276 'internal_api': 'openmp', | |
277 'num_threads': 4, | |
278 'prefix': 'libomp', | |
279 'filepath': '/home/jeremie/miniforge/envs/flexiblas_threadpoolctl/lib/libomp.so', | |
280 'version': None}, | |
281 {'user_api': 'blas', | |
282 'internal_api': 'openblas', | |
283 'num_threads': 4, | |
284 'prefix': 'libopenblas', | |
285 'filepath': '/usr/lib/x86_64-linux-gnu/openblas-pthread/libopenblasp-r0.3.8.so', | |
286 'version': '0.3.8', | |
287 'threading_layer': 'pthreads', | |
288 'architecture': 'Haswell'}, | |
289 {'user_api': 'blas', | |
290 'internal_api': 'mkl', | |
291 'num_threads': 2, | |
292 'prefix': 'libmkl_rt', | |
293 'filepath': '/home/jeremie/miniforge/envs/flexiblas_threadpoolctl/lib/libmkl_rt.so.2', | |
294 'version': '2024.0-Product', | |
295 'threading_layer': 'gnu'}] | |
296 ``` | |
297 | |
298 You can observe that the previously linked OpenBLAS shared object stays loaded by | |
299 the Python program indefinitely, but FlexiBLAS itself no longer delegates BLAS calls | |
300 to OpenBLAS as indicated by the `current_backend` attribute. | |
301 ### Writing a custom library controller | |
302 | |
303 Currently, `threadpoolctl` has support for `OpenMP` and the main `BLAS` libraries. | |
304 However it can also be used to control the threadpool of other native libraries, | |
305 provided that they expose an API to get and set the limit on the number of threads. | |
306 For that, one must implement a controller for this library and register it to | |
307 `threadpoolctl`. | |
308 | |
309 A custom controller must be a subclass of the `LibController` class and implement | |
310 the attributes and methods described in the docstring of `LibController`. Then this | |
311 new controller class must be registered using the `threadpoolctl.register` function. | |
312 An complete example can be found [here]( | |
313 https://github.com/joblib/threadpoolctl/blob/master/tests/_pyMylib/__init__.py). | |
314 | |
315 ### Sequential BLAS within OpenMP parallel region | |
316 | |
317 When one wants to have sequential BLAS calls within an OpenMP parallel region, it's | |
318 safer to set `limits="sequential_blas_under_openmp"` since setting `limits=1` and | |
319 `user_api="blas"` might not lead to the expected behavior in some configurations | |
320 (e.g. OpenBLAS with the OpenMP threading layer | |
321 https://github.com/xianyi/OpenBLAS/issues/2985). | |
322 | |
323 ### Known Limitations | |
324 | |
325 - `threadpool_limits` can fail to limit the number of inner threads when nesting | |
326 parallel loops managed by distinct OpenMP runtime implementations (for instance | |
327 libgomp from GCC and libomp from clang/llvm or libiomp from ICC). | |
328 | |
329 See the `test_openmp_nesting` function in [tests/test_threadpoolctl.py]( | |
330 https://github.com/joblib/threadpoolctl/blob/master/tests/test_threadpoolctl.py) | |
331 for an example. More information can be found at: | |
332 https://github.com/jeremiedbb/Nested_OpenMP | |
333 | |
334 Note however that this problem does not happen when `threadpool_limits` is | |
335 used to limit the number of threads used internally by BLAS calls that are | |
336 themselves nested under OpenMP parallel loops. `threadpool_limits` works as | |
337 expected, even if the inner BLAS implementation relies on a distinct OpenMP | |
338 implementation. | |
339 | |
340 - Using Intel OpenMP (ICC) and LLVM OpenMP (clang) in the same Python program | |
341 under Linux is known to cause problems. See the following guide for more details | |
342 and workarounds: | |
343 https://github.com/joblib/threadpoolctl/blob/master/multiple_openmp.md | |
344 | |
345 - Setting the maximum number of threads of the OpenMP and BLAS libraries has a global | |
346 effect and impacts the whole Python process. There is no thread level isolation as | |
347 these libraries do not offer thread-local APIs to configure the number of threads to | |
348 use in nested parallel calls. | |
349 | |
350 | |
351 ## Maintainers | |
352 | |
353 To make a release: | |
354 | |
355 - Bump the version number (`__version__`) in `threadpoolctl.py` and update the | |
356 release date in `CHANGES.md`. | |
357 | |
358 - Build the distribution archives: | |
359 | |
360 ```bash | |
361 pip install flit | |
362 flit build | |
363 ``` | |
364 | |
365 and check the contents of `dist/`. | |
366 | |
367 - If everything is fine, make a commit for the release, tag it and push the | |
368 tag to github: | |
369 | |
370 ```bash | |
371 git tag -a X.Y.Z | |
372 git push git@github.com:joblib/threadpoolctl.git X.Y.Z | |
373 ``` | |
374 | |
375 - Upload the wheels and source distribution to PyPI using flit. Since PyPI doesn't | |
376 allow password authentication anymore, the username needs to be changed to the | |
377 generic name `__token__`: | |
378 | |
379 ```bash | |
380 FLIT_USERNAME=__token__ flit publish | |
381 ``` | |
382 | |
383 and a PyPI token has to be passed in place of the password. | |
384 | |
385 - Create a PR for the release on the [conda-forge feedstock](https://github.com/conda-forge/threadpoolctl-feedstock) (or wait for the bot to make it). | |
386 | |
387 - Publish the release on github. | |
388 | |
389 ### Credits | |
390 | |
391 The initial dynamic library introspection code was written by @anton-malakhov | |
392 for the smp package available at https://github.com/IntelPython/smp . | |
393 | |
394 threadpoolctl extends this for other operating systems. Contrary to smp, | |
395 threadpoolctl does not attempt to limit the size of Python multiprocessing | |
396 pools (threads or processes) or set operating system-level CPU affinity | |
397 constraints: threadpoolctl only interacts with native libraries via their | |
398 public runtime APIs. | |
399 |