8000 BLD, ENH: Enable Accelerate Framework by Matthew-Badin · Pull Request #18874 · numpy/numpy · GitHub
[go: up one dir, main page]

Skip to content

BLD, ENH: Enable Accelerate Framework #18874

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

Merged
merged 4 commits into from
May 4, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions doc/release/upcoming_changes/18874.change.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
Enable Accelerate Framework
----------------------------
With the release of macOS 11.3, several different issues that
numpy was encountering when using Accelerate Framework's
implementation of BLAS and LAPACK should be resolved. This
change enables the Accelerate Framework as an option on macOS.
If additional issues are found, please file a bug report
against Accelerate using the developer feedback assistant
tool (https://developer.apple.com/bug-reporting/). We
intend to address issues promptly and plan to continue
supporting and updating our BLAS and LAPACK libraries.
5 changes: 0 additions & 5 deletions numpy/core/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -405,11 +405,6 @@ def configuration(parent_package='',top_path=None):
from numpy.distutils.system_info import (get_info, blas_opt_info,
lapack_opt_info)

# Accelerate is buggy, disallow it. See also numpy/linalg/setup.py
for opt_order in (blas_opt_info.blas_order, lapack_opt_info.lapack_order):
if 'accelerate' in opt_order:
opt_order.remove('accelerate')

config = Configuration('core', parent_package, top_path)
local_dir = config.local_path
codegen_dir = join(local_dir, 'code_generators')
Expand Down
65 changes: 65 additions & 0 deletions numpy/core/tests/test_multiarray.py
Original file line number Diff line number Diff line change
Expand Up @@ -6194,6 +6194,71 @@ def test_dot_array_order(self):
assert_equal(np.dot(b, a), res)
assert_equal(np.dot(b, b), res)

def test_accelerate_framework_sgemv_fix(self):

def aligned_array(shape, align, dtype, order='C'):
d = dtype(0)
N = np.prod(shape)
tmp = np.zeros(N * d.nbytes + align, dtype=np.uint8)
address = tmp.__array_interface__["data"][0]
for offset in range(align):
if (address + offset) % align == 0:
break
tmp = tmp[offset:offset+N*d.nbytes].view(dtype=dtype)
return tmp.reshape(shape, order=order)

def as_aligned(arr, align, dtype, order='C'):
aligned = aligned_array(arr.shape, align, dtype, order)
aligned[:] = arr[:]
return aligned

def assert_dot_close(A, X, desired):
assert_allclose(np.dot(A, X), desired, rtol=1e-5, atol=1e-7)

m = aligned_array(100, 15, np.float32)
s = aligned_array((100, 100), 15, np.float32)
np.dot(s, m) # this will always segfault if the bug is present

testdata = itertools.product((15, 32), (10000,), (200, 89), ('C', 'F'))
for align, m, n, a_order in testdata:
# Calculation in double precision
A_d = np.random.rand(m, n)
X_d = np.random.rand(n)
desired = np.dot(A_d, X_d)
# Calculation with aligned single precision
A_f = as_aligned(A_d, align, np.float32, order=a_order)
X_f = as_aligned(X_d, align, np.float32)
assert_dot_close(A_f, X_f, desired)
# Strided A rows
A_d_2 = A_d[::2]
desired = np.dot(A_d_2, X_d)
A_f_2 = A_f[::2]
assert_dot_close(A_f_2, X_f, desired)
# Strided A columns, strided X vector
A_d_22 = A_d_2[:, ::2]
X_d_2 = X_d[::2]
desired = np.dot(A_d_22, X_d_2)
A_f_22 = A_f_2[:, ::2]
X_f_2 = X_f[::2]
assert_dot_close(A_f_22, X_f_2, desired)
# Check the strides are as expected
if a_order == 'F':
assert_equal(A_f_22.strides, (8, 8 * m))
else:
assert_equal(A_f_22.strides, (8 * n, 8))
assert_equal(X_f_2.strides, (8,))
# Strides in A rows + cols only
X_f_2c = as_aligned(X_f_2, align, np.float32)
assert_dot_close(A_f_22, X_f_2c, desired)
# Strides just in A cols
A_d_12 = A_d[:, ::2]
desired = np.dot(A_d_12, X_d_2)
A_f_12 = A_f[:, ::2]
assert_dot_close(A_f_12, X_f_2c, desired)
# Strides in A cols and X
assert_dot_close(A_f_12, X_f_2, desired)



class MatmulCommon:
"""Common tests for '@' operator and numpy.matmul.
Expand Down
28 changes: 7 additions & 21 deletions numpy/distutils/system_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -375,22 +375,6 @@ def add_system_root(library_root):
so_ext = get_shared_lib_extension()


def is_symlink_to_accelerate(filename):
accelpath = '/System/Library/Frameworks/Accelerate.framework'
return (sys.platform == 'darwin' and os.path.islink(filename) and
os.path.realpath(filename).startswith(accelpath))


_accel_msg = (
'Found {filename}, but that file is a symbolic link to the '
'MacOS Accelerate framework, which is not supported by NumPy. '
'You must configure the build to use a different optimized library, '
'or disable the use of optimized BLAS and LAPACK by setting the '
'environment variables NPY_BLAS_ORDER="" and NPY_LAPACK_ORDER="" '
'before building NumPy.'
)


def get_standard_file(fname):
"""Returns a list of files named 'fname' from
1) System-wide directory (directory-location of this module)
Expand Down Expand Up @@ -539,6 +523,7 @@ def get_info(name, notfound_action=0):
'blis': blis_info, # use blas_opt instead
'lapack_mkl': lapack_mkl_info, # use lapack_opt instead
'blas_mkl': blas_mkl_info, # use blas_opt instead
'accelerate': accelerate_info, # use blas_opt instead
'openblas64_': openblas64__info,
'openblas64__lapack': openblas64__lapack_info,
'openblas_ilp64': openblas_ilp64_info,
Expand Down Expand Up @@ -1029,9 +1014,6 @@ def _find_lib(self, lib_dir, lib, exts):
for prefix in lib_prefixes:
p = self.combine_paths(lib_dir, prefix + lib + ext)
if p:
# p[0] is the full path to the binary library file.
if is_symlink_to_accelerate(p[0]):
raise RuntimeError(_accel_msg.format(filename=p[0]))
break
if p:
assert len(p) == 1
Expand Down Expand Up @@ -1766,8 +1748,10 @@ def get_atlas_version(**config):

class lapack_opt_info(system_info):
notfounderror = LapackNotFoundError

# List of all known LAPACK libraries, in the default order
lapack_order = ['mkl', 'openblas', 'flame', 'atlas', 'lapack']
lapack_order = ['mkl', 'openblas', 'flame',
'accelerate', 'atlas', 'lapack']
order_env_var_name = 'NPY_LAPACK_ORDER'

def _calc_info_mkl(self):
Expand Down Expand Up @@ -1942,7 +1926,9 @@ class lapack64__opt_info(lapack_ilp64_opt_info):
class blas_opt_info(system_info):
notfounderror = BlasNotFoundError
# List of all known BLAS libraries, in the default order
blas_order = ['mkl', 'blis', 'openblas', 'atlas', 'blas']

blas_order = ['mkl', 'blis', 'openblas',
'accelerate', 'atlas', 'blas']
order_env_var_name = 'NPY_BLAS_ORDER'

def _calc_info_mkl(self):
Expand Down
5 changes: 0 additions & 5 deletions numpy/linalg/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,6 @@ def configuration(parent_package='', top_path=None):

config.add_subpackage('tests')

# Accelerate is buggy, disallow it. See also numpy/core/setup.py
for opt_order in (blas_opt_info.blas_order, lapack_opt_info.lapack_order):
if 'accelerate' in opt_order:
opt_order.remove('accelerate')

# Configure lapack_lite

src_dir = 'lapack_lite'
Expand Down
0