Skip to content

Commit 931146f

Browse files
committed
add multithreading tests
1 parent 79575bb commit 931146f

File tree

5 files changed

+127
-22
lines changed

5 files changed

+127
-22
lines changed

CHANGES.rst

Lines changed: 21 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -79,26 +79,27 @@ transform improves multi-core utilization which may offset the performance loss
7979

8080
Added :code:`scipy.fft` backend, see #42. Fixed #46.
8181

82-
```
83-
Python 3.7.5 (default, Nov 23 2019, 04:02:01)
84-
Type 'copyright', 'credits' or 'license' for more information
85-
IPython 7.11.1 -- An enhanced Interactive Python. Type '?' for help.
86-
87-
In [1]: import numpy as np, mkl_fft, mkl_fft._scipy_fft_backend as mkl_be, scipy, scipy.fft, mkl
88-
89-
In [2]: mkl.verbose(1)
90-
Out[2]: True
91-
92-
In [3]: x = np.random.randn(8*7).reshape((7, 8))
93-
...: with scipy.fft.set_backend(mkl_be, only=True):
94-
...: ff = scipy.fft.fft2(x, workers=4)
95-
...: ff2 = scipy.fft.fft2(x)
96-
MKL_VERBOSE Intel(R) MKL 2020.0 Product build 20191102 for Intel(R) 64 architecture Intel(R) Advanced Vector Extensions 2 (Intel(R) AVX2) enabled processors, Lnx 2.40GHz intel_thread
97-
MKL_VERBOSE FFT(drfo7:8:8x8:1:1,bScale:0.0178571,tLim:1,desc:0x5629ad31b800) 24.85ms CNR:OFF Dyn:1 FastMM:1 TID:0 NThr:16,FFT:4
98-
99-
In [4]: np.allclose(ff, ff2)
100-
Out[4]: True
101-
```
82+
83+
.. code-block:: python
84+
85+
Python 3.7.5 (default, Nov 23 2019, 04:02:01)
86+
Type 'copyright', 'credits' or 'license' for more information
87+
IPython 7.11.1 -- An enhanced Interactive Python. Type '?' for help.
88+
89+
In [1]: import numpy as np, mkl_fft, mkl_fft._scipy_fft as mkl_be, scipy, scipy.fft, mkl
90+
91+
In [2]: mkl.verbose(1)
92+
Out[2]: True
93+
94+
In [3]: x = np.random.randn(8*7).reshape((7, 8))
95+
...: with scipy.fft.set_backend(mkl_be, only=True):
96+
...: ff = scipy.fft.fft2(x, workers=4)
97+
...: ff2 = scipy.fft.fft2(x)
98+
MKL_VERBOSE Intel(R) MKL 2020.0 Product build 20191102 for Intel(R) 64 architecture Intel(R) Advanced Vector Extensions 2 (Intel(R) AVX2) enabled processors, Lnx 2.40GHz intel_thread
99+
MKL_VERBOSE FFT(drfo7:8:8x8:1:1,bScale:0.0178571,tLim:1,desc:0x5629ad31b800) 24.85ms CNR:OFF Dyn:1 FastMM:1 TID:0 NThr:16,FFT:4
100+
101+
In [4]: np.allclose(ff, ff2)
102+
Out[4]: True
102103
103104
104105
1.0.15
Binary file not shown.

mkl_fft/tests/test_from_scipy.py renamed to mkl_fft/tests/from_scipy/test_basic.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# This file includes tests from scipy.fft module:
22
# https://github.com/scipy/scipy/blob/main/scipy/fft/tests/test_basic.py
33

4-
# TODO: remove when hfft functions are added
4+
# TODO: remove when hfft* functions are added
55
# pylint: disable=no-member
66

77
import multiprocessing
@@ -426,7 +426,7 @@ def test_dtypes_real(self, dtype, xp):
426426
res_rfft = fft.irfft(fft.rfft(x))
427427
# TODO: res_hfft = fft.hfft(fft.ihfft(x), x.shape[0])
428428
# Check both numerical results and exact dtype matches
429-
xp_assert_close(res_rfft, x, rtol=1e-06)
429+
xp_assert_close(res_rfft, x, rtol=1e-06, atol=1e-06)
430430
# TODO: xp_assert_close(res_hfft, x)
431431

432432
@pytest.mark.parametrize("dtype", ["complex64", "complex128"])
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
# This file includes tests from scipy.fft module:
2+
# https://github.com/scipy/scipy/blob/main/scipy/fft/tests/test_multithreading.py.py
3+
4+
import multiprocessing
5+
import os
6+
7+
import numpy as np
8+
import pytest
9+
from numpy.testing import assert_allclose
10+
11+
import mkl_fft.interfaces.scipy_fft as fft
12+
13+
14+
@pytest.fixture(scope="module")
15+
def x():
16+
return np.random.randn(512, 128) # Must be large enough to qualify for mt
17+
18+
19+
@pytest.mark.parametrize(
20+
"func",
21+
[
22+
fft.fft,
23+
fft.ifft,
24+
fft.fft2,
25+
fft.ifft2,
26+
fft.fftn,
27+
fft.ifftn,
28+
fft.rfft,
29+
fft.irfft,
30+
fft.rfft2,
31+
fft.irfft2,
32+
fft.rfftn,
33+
fft.irfftn,
34+
# TODO: fft.hfft, fft.ihfft, fft.hfft2, fft.ihfft2, fft.hfftn, fft.ihfftn,
35+
# TODO: fft.dct, fft.idct, fft.dctn, fft.idctn,
36+
# TODO: fft.dst, fft.idst, fft.dstn, fft.idstn,
37+
],
38+
)
39+
@pytest.mark.parametrize("workers", [2, -1])
40+
def test_threaded_same(x, func, workers):
41+
expected = func(x, workers=1)
42+
actual = func(x, workers=workers)
43+
assert_allclose(actual, expected)
44+
45+
46+
def _mt_fft(x):
47+
return fft.fft(x, workers=2)
48+
49+
50+
@pytest.mark.slow
51+
def test_mixed_threads_processes(x):
52+
# Test that the fft threadpool is safe to use before & after fork
53+
54+
expect = fft.fft(x, workers=2)
55+
56+
with multiprocessing.Pool(2) as p:
57+
res = p.map(_mt_fft, [x for _ in range(4)])
58+
59+
for r in res:
60+
assert_allclose(r, expect)
61+
62+
fft.fft(x, workers=2)
63+
64+
65+
def test_invalid_workers(x):
66+
cpus = os.cpu_count()
67+
68+
fft.ifft([1], workers=-cpus)
69+
70+
with pytest.raises(ValueError, match="workers must not be zero"):
71+
fft.fft(x, workers=0)
72+
73+
with pytest.raises(ValueError, match="workers value out of range"):
74+
fft.ifft(x, workers=-cpus - 1)
75+
76+
77+
@pytest.mark.skip()
78+
def test_set_get_workers():
79+
cpus = os.cpu_count()
80+
assert fft.get_workers() == 1
81+
with fft.set_workers(4):
82+
assert fft.get_workers() == 4
83+
84+
with fft.set_workers(-1):
85+
assert fft.get_workers() == cpus
86+
87+
assert fft.get_workers() == 4
88+
89+
assert fft.get_workers() == 1
90+
91+
with fft.set_workers(-cpus):
92+
assert fft.get_workers() == 1
93+
94+
95+
@pytest.mark.skip("mkl_fft does not validate workers")
96+
def test_set_workers_invalid():
97+
98+
with pytest.raises(ValueError, match="workers must not be zero"):
99+
with fft.set_workers(0):
100+
pass
101+
102+
with pytest.raises(ValueError, match="workers value out of range"):
103+
with fft.set_workers(-os.cpu_count() - 1):
104+
pass

0 commit comments

Comments
 (0)