Skip to content

Commit a421dc3

Browse files
committed
add manual patching to mkl_fft
1 parent c4696d2 commit a421dc3

File tree

2 files changed

+133
-0
lines changed

2 files changed

+133
-0
lines changed

mkl_fft/__init__.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,17 @@
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 ._version import __version__
4349

4450
import mkl_fft.interfaces # isort: skip
4551

52+
4653
__all__ = [
4754
"fft",
4855
"ifft",
@@ -57,6 +64,10 @@
5764
"rfftn",
5865
"irfftn",
5966
"interfaces",
67+
"mkl_fft",
68+
"patch_numpy_fft",
69+
"restore_numpy_fft",
70+
"is_patched",
6071
]
6172

6273
del _init_helper

mkl_fft/_patch_numpy.py

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
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, verbose=False):
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+
if verbose:
60+
print("failed to restore")
61+
return
62+
else:
63+
if verbose:
64+
print("found and restoring...")
65+
setattr(np.fft, name, val)
66+
67+
def restore(self, verbose=False):
68+
for name in self._restore_dict.keys():
69+
self._restore_func(name, verbose=verbose)
70+
self._is_patched = False
71+
72+
def do_patch(self):
73+
for f in self.__patched_functions__:
74+
self._register_func(f, getattr(_nfft, f))
75+
self._is_patched = True
76+
77+
def is_patched(self):
78+
return self._is_patched
79+
80+
81+
def _initialize_tls():
82+
_tls.patch = _Patch()
83+
_tls.initialized = True
84+
85+
86+
def _is_tls_initialized():
87+
return (getattr(_tls, "initialized", None) is not None) and (
88+
_tls.initialized is True
89+
)
90+
91+
92+
def patch_numpy_fft(verbose=False):
93+
if verbose:
94+
print("Now patching NumPy FFT submodule with mkl_fft NumPy interface.")
95+
print("Please direct bug reports to https://github.com/IntelPython/mkl_fft")
96+
if not _is_tls_initialized():
97+
_initialize_tls()
98+
_tls.patch.do_patch()
99+
100+
101+
def restore_numpy_fft(verbose=False):
102+
if verbose:
103+
print("Now restoring original NumPy FFT submodule.")
104+
if not _is_tls_initialized():
105+
_initialize_tls()
106+
_tls.patch.restore(verbose=verbose)
107+
108+
109+
def is_patched():
110+
if not _is_tls_initialized():
111+
_initialize_tls()
112+
return _tls.patch.is_patched()
113+
114+
115+
class mkl_fft(ContextDecorator):
116+
def __enter__(self):
117+
patch_numpy_fft()
118+
return self
119+
120+
def __exit__(self, *exc):
121+
restore_numpy_fft()
122+
return False

0 commit comments

Comments
 (0)