-
Notifications
You must be signed in to change notification settings - Fork 36
Use thread-local limiting APIs when possible, and fix deadlock #228
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
dfcda95
d4c0060
9f51d12
a987c0a
2b713e0
7f8ff37
46825f7
cb219e4
83e4474
c78474f
c670e4d
d8b2d0e
bbfb797
751cffa
deec01c
eebbcdd
3028da7
60a7be6
1c4d49e
0c79887
9522d11
8eb782d
d683a51
fdcb084
39067b4
c46a1d1
76b2ee0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1 +1 @@ | ||
| collect_ignore = ["tests/_openmp_test_helper"] | ||
| collect_ignore = ["tests/_openmp_test_helper", "tests/_limit_blas"] |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| # Used by test_setting_limit_on_thread_local_blas_api_is_actually_thread_local() | ||
|
|
||
| from concurrent.futures import ThreadPoolExecutor | ||
| from time import sleep | ||
| import sys | ||
|
|
||
| import numpy as np | ||
| import threadpoolctl | ||
|
|
||
| ARR = np.ones((1500, 1500)) | ||
|
|
||
|
|
||
| def in_thread(_): | ||
| with threadpoolctl.threadpool_limits(limits=int(sys.argv[1]), user_api="blas"): | ||
| ARR.dot(ARR) | ||
| # Make sure jobs are evenly distributed and don't end up in one thread. | ||
| sleep(0.01) | ||
|
|
||
|
|
||
| if __name__ == "__main__": | ||
| with ThreadPoolExecutor(2) as pool: | ||
| list(pool.map(in_thread, range(2))) |
| Original file line number | Diff line number | Diff line change | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -60,9 +60,6 @@ def test_determine_thread_limit_scope_processwide(default: int) -> None: | |||||||||||||
| assert _determine_thread_limit_scope(api.get, api.set) == "process" | ||||||||||||||
|
|
||||||||||||||
|
|
||||||||||||||
| @pytest.mark.skipif( | ||||||||||||||
| sys.platform != "linux", reason="Non-Linux OpenMP might be different" | ||||||||||||||
| ) | ||||||||||||||
| @pytest.mark.parametrize( | ||||||||||||||
| ["select_filter", "expected_thread_limit_scope", "extra_check"], | ||||||||||||||
| [ | ||||||||||||||
|
|
@@ -77,7 +74,12 @@ def test_determine_thread_limit_scope_processwide(default: int) -> None: | |||||||||||||
| # pthreads here. | ||||||||||||||
| lambda lib: lib.threading_layer == "pthreads", | ||||||||||||||
| ), | ||||||||||||||
| ({"user_api": "openmp"}, "current_thread", lambda _lib: True), | ||||||||||||||
| ( | ||||||||||||||
| {"user_api": "openmp"}, | ||||||||||||||
| "current_thread", | ||||||||||||||
| # Windows OpenMP is process-wide: | ||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I asked an LLM to know if this was a bug or not. Apparently, this is not a bug but a consequence of a being an implementation of an older version of the spec:
Suggested change
For information, recent MSVC can be configured to build with the I don't know if there is an easy way to snif libomp specific symbols on such MSVC generated binary files.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I imagine there's no reason not to use omp_set_num_threads on Windows, it might just not be thread-local (but it won't be worse than openblas_set_num_threads). So as a first pass I will:
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah, sounds like that VS flag is experimental for now, so maybe I won't suggest it.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it's still worth expanding the inline comment to explain that the current windows OpenMP runtime implement semantics from an older version of the OpenMP spec but that it is hopefully expected to change in the future, at which point we might want to update this test to make sure it passes on all platforms. |
||||||||||||||
| lambda _lib: sys.platform in ("linux", "darwin"), | ||||||||||||||
| ), | ||||||||||||||
| ], | ||||||||||||||
| ) | ||||||||||||||
| def test_api_scope( | ||||||||||||||
|
|
@@ -94,9 +96,11 @@ def test_api_scope( | |||||||||||||
| if not controller.lib_controllers: | ||||||||||||||
| pytest.skip(f"{select_filter} controller not found") | ||||||||||||||
|
|
||||||||||||||
| for lib in controller.lib_controllers: | ||||||||||||||
| if not extra_check(lib): | ||||||||||||||
| pytest.skip("extra check returned false") | ||||||||||||||
| libs = [lib for lib in controller.lib_controllers if extra_check(lib)] | ||||||||||||||
| if not libs: | ||||||||||||||
| pytest.skip("No libraries matched the requirements") | ||||||||||||||
|
|
||||||||||||||
| for lib in libs: | ||||||||||||||
| assert ( | ||||||||||||||
| _determine_thread_limit_scope(lib.get_num_threads, lib.set_num_threads) | ||||||||||||||
| == expected_thread_limit_scope | ||||||||||||||
|
|
||||||||||||||
Uh oh!
There was an error while loading. Please reload this page.