Skip to content

Commit 5f18f70

Browse files
cursoragentogrisel
andcommitted
Derive native pool spawn expectations from threadpool_info
Warm up BLAS/OpenMP pools in the parent process, then use threadpool_info (or get_threadpool_limits on older releases) to set the minimum expected ETW thread spawn count instead of hard-coded guesses. Co-authored-by: Olivier Grisel <olivier.grisel@ensta.org>
1 parent 6829160 commit 5f18f70

1 file changed

Lines changed: 54 additions & 3 deletions

File tree

threadpoolctl/tests/test_windows_thread_tracer_integration.py

Lines changed: 54 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,44 @@
2828
TRACER_ATTACH_DELAY_SECONDS = 0.5
2929
TRACER_FLUSH_DELAY_SECONDS = 0.3
3030
SUBPROCESS_TIMEOUT_SECONDS = 60
31+
BLAS_THREAD_ENV_VARS = {
32+
"OMP_NUM_THREADS": "1",
33+
"OPENBLAS_NUM_THREADS": "4",
34+
"MKL_NUM_THREADS": "4",
35+
}
36+
37+
38+
def _threadpool_info():
39+
try:
40+
from threadpoolctl import threadpool_info
41+
42+
return threadpool_info()
43+
except ImportError:
44+
from threadpoolctl import get_threadpool_limits
45+
46+
return get_threadpool_limits()
47+
48+
49+
def _module_num_threads(module):
50+
if "num_threads" in module:
51+
return module["num_threads"]
52+
return module.get("n_thread")
53+
54+
55+
def _expected_pool_thread_count(user_api):
56+
thread_counts = [
57+
_module_num_threads(module)
58+
for module in _threadpool_info()
59+
if module.get("user_api") == user_api and _module_num_threads(module)
60+
]
61+
if not thread_counts:
62+
pytest.skip("No {0} thread pool detected".format(user_api))
63+
return max(thread_counts)
64+
65+
66+
def _configure_blas_thread_env():
67+
for name, value in BLAS_THREAD_ENV_VARS.items():
68+
os.environ[name] = value
3169

3270

3371
def _child_script(body):
@@ -110,10 +148,14 @@ def work():
110148

111149
def test_tracer_counts_openmp_thread_spawns():
112150
try:
113-
from threadpoolctl.tests._openmp_test_helper import check_openmp_n_threads # noqa: F401
151+
from threadpoolctl.tests._openmp_test_helper import check_openmp_n_threads
114152
except ImportError:
115153
pytest.skip("OpenMP test helper is not built")
116154

155+
os.environ["OMP_NUM_THREADS"] = "4"
156+
check_openmp_n_threads(10)
157+
expected_spawn_count = _expected_pool_thread_count("openmp")
158+
117159
body = """
118160
import os
119161
@@ -123,11 +165,20 @@ def test_tracer_counts_openmp_thread_spawns():
123165
used = check_openmp_n_threads(1000)
124166
assert used >= 1
125167
"""
126-
_run_traced_child(body, minimum_spawn_count=4)
168+
_run_traced_child(body, minimum_spawn_count=expected_spawn_count)
127169

128170

129171
def test_tracer_counts_blas_thread_spawns():
130172
pytest.importorskip("numpy")
173+
_configure_blas_thread_env()
174+
175+
import numpy as np
176+
177+
rng = np.random.RandomState(0)
178+
warmup = rng.rand(100, 100)
179+
np.dot(warmup, warmup)
180+
expected_spawn_count = _expected_pool_thread_count("blas")
181+
131182
body = """
132183
import os
133184
@@ -141,4 +192,4 @@ def test_tracer_counts_blas_thread_spawns():
141192
a = rng.rand(2000, 2000)
142193
np.dot(a, a)
143194
"""
144-
_run_traced_child(body, minimum_spawn_count=2)
195+
_run_traced_child(body, minimum_spawn_count=expected_spawn_count)

0 commit comments

Comments
 (0)