Skip to content

Commit 4c16550

Browse files
committed
add manual patching to mkl_fft
1 parent 142b483 commit 4c16550

File tree

2 files changed

+131
-0
lines changed

2 files changed

+131
-0
lines changed

mkl_fft/__init__.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,18 @@
3939
rfft2,
4040
rfftn,
4141
)
42+
from ._patch_numpy import (
43+
is_patched,
44+
mkl_fft,
45+
patch_numpy_fft,
46+
restore_numpy_fft,
47+
)
4248
from ._pydfti import irfftpack, rfftpack # pylint: disable=no-name-in-module
4349
from ._version import __version__
4450

4551
import mkl_fft.interfaces # isort: skip
4652

53+
4754
__all__ = [
4855
"fft",
4956
"ifft",
@@ -60,6 +67,10 @@
6067
"rfftn",
6168
"irfftn",
6269
"interfaces",
70+
"mkl_fft",
71+
"patch_numpy_fft"
72+
"restore_numpy_fft",
73+
"is_patched",
6374
]
6475

6576
del _init_helper

mkl_fft/_patch_numpy.py

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
#!/usr/bin/env python
2+
# Copyright (c) 2017, Intel Corporation
3+
#
4+
# Redistribution and use in source and binary forms, with or without
5+
# modification, are permitted provided that the following conditions are met:
6+
#
7+
# * Redistributions of source code must retain the above copyright notice,
8+
# this list of conditions and the following disclaimer.
9+
# * Redistributions in binary form must reproduce the above copyright
10+
# notice, this list of conditions and the following disclaimer in the
11+
# documentation and/or other materials provided with the distribution.
12+
# * Neither the name of Intel Corporation nor the names of its contributors
13+
# may be used to endorse or promote products derived from this software
14+
# without specific prior written permission.
15+
#
16+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19+
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
20+
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21+
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22+
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
23+
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24+
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25+
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26+
27+
"""Define functions for patching NumPy with MKL-based NumPy interface."""
28+
29+
from contextlib import ContextDecorator
30+
from threading import local as threading_local
31+
32+
import numpy as np
33+
34+
import mkl_fft.interfaces.numpy_fft as _nfft
35+
36+
_tls = threading_local()
37+
38+
39+
class _Patch():
40+
"""Internal object for patching NumPy with mkl_fft interfaces."""
41+
42+
_is_patched = False
43+
__patched_functions__ = _nfft.__all__
44+
_restore_dict = {}
45+
46+
def _register_func(self, name, func):
47+
if name not in self.__patched_functions__:
48+
raise ValueError("%s not an mkl_fft function." % name)
49+
f = getattr(np.fft, name)
50+
self._restore_dict[name] = f
51+
setattr(np.fft, name, func)
52+
53+
def _restore_func(self, name):
54+
if name not in self.__patched_functions__:
55+
raise ValueError("%s not an mkl_fft function." % name)
56+
try:
57+
val = self._restore_dict[name]
58+
except KeyError:
59+
print("failed to restore")
60+
return
61+
else:
62+
print("found and restoring...")
63+
setattr(np.fft, name, val)
64+
65+
def restore(self):
66+
for name in self._restore_dict.keys():
67+
self._restore_func(name)
68+
self._is_patched = False
69+
70+
def do_patch(self):
71+
for f in self.__patched_functions__:
72+
self._register_func(f, getattr(_nfft, f))
73+
self._is_patched = True
74+
75+
def is_patched(self):
76+
return self._is_patched
77+
78+
79+
def _initialize_tls():
80+
_tls.patch = _Patch()
81+
_tls.initialized = True
82+
83+
84+
def _is_tls_initialized():
85+
return (getattr(_tls, "initialized", None) is not None) and (_tls.initialized is True)
86+
87+
88+
def patch_numpy_fft(verbose=False):
89+
if verbose:
90+
print(
91+
"Now patching NumPy FFT submodule with mkl_fft NumPy interface. "
92+
"Please direct bug reports to https://github.com/IntelPython/mkl_fft"
93+
)
94+
if not _is_tls_initialized():
95+
_initialize_tls()
96+
_tls.patch.do_patch()
97+
98+
99+
def restore_numpy_fft(verbose=False):
100+
if verbose:
101+
print("Now restoring original NumPy FFT submodule.")
102+
if not _is_tls_initialized():
103+
_initialize_tls()
104+
_tls.patch.restore()
105+
106+
107+
def is_patched():
108+
if not _is_tls_initialized():
109+
_initialize_tls()
110+
return _tls.patch.is_patched()
111+
112+
113+
class mkl_fft(ContextDecorator):
114+
def __enter__(self):
115+
patch_numpy_fft()
116+
return self
117+
118+
def __exit__(self, *exc):
119+
restore_numpy_fft()
120+
return False

0 commit comments

Comments
 (0)