
* Add numpy 1.17.0 * Overhaul numpy package * Flake8 fixes * Undefined reference fix * HeaderList and LibraryList need an arg * veclibfort has no headers * Add patch for older versions of py-numpy * Remove py-meep hack from py-numpy package * libflame: always add max arg hack flag * Fix build with GCC 4.8 * Compiler flags come from self.compiler * Only apply -std=c99 to cflags * Try to fix libflame package * Fix ATLAS build on macOS * --force-clang flag added in 3.10.3
348 lines
12 KiB
Diff
348 lines
12 KiB
Diff
Allows you to specify order of BLAS/LAPACK preference
|
|
https://github.com/numpy/numpy/pull/13132
|
|
diff --git a/numpy/distutils/system_info.py b/numpy/distutils/system_info.py
|
|
index 806f4f7d3..0480d7b5a 100644
|
|
--- a/numpy/distutils/system_info.py
|
|
+++ b/numpy/distutils/system_info.py
|
|
@@ -474,6 +474,13 @@ class LapackSrcNotFoundError(LapackNotFoundError):
|
|
the LAPACK_SRC environment variable."""
|
|
|
|
|
|
+class BlasOptNotFoundError(NotFoundError):
|
|
+ """
|
|
+ Optimized (vendor) Blas libraries are not found.
|
|
+ Falls back to netlib Blas library which has worse performance.
|
|
+ A better performance should be easily gained by switching
|
|
+ Blas library."""
|
|
+
|
|
class BlasNotFoundError(NotFoundError):
|
|
"""
|
|
Blas (http://www.netlib.org/blas/) libraries not found.
|
|
@@ -1541,139 +1548,219 @@ Make sure that -lgfortran is used for C++ extensions.
|
|
class lapack_opt_info(system_info):
|
|
|
|
notfounderror = LapackNotFoundError
|
|
+ # Default order of LAPACK checks
|
|
+ lapack_order = ['mkl', 'openblas', 'atlas', 'accelerate', 'lapack']
|
|
|
|
- def calc_info(self):
|
|
+ def _calc_info_mkl(self):
|
|
+ info = get_info('lapack_mkl')
|
|
+ if info:
|
|
+ self.set_info(**info)
|
|
+ return True
|
|
+ return False
|
|
|
|
- lapack_mkl_info = get_info('lapack_mkl')
|
|
- if lapack_mkl_info:
|
|
- self.set_info(**lapack_mkl_info)
|
|
- return
|
|
+ def _calc_info_openblas(self):
|
|
+ info = get_info('openblas_lapack')
|
|
+ if info:
|
|
+ self.set_info(**info)
|
|
+ return True
|
|
+ info = get_info('openblas_clapack')
|
|
+ if info:
|
|
+ self.set_info(**info)
|
|
+ return True
|
|
+ return False
|
|
|
|
- openblas_info = get_info('openblas_lapack')
|
|
- if openblas_info:
|
|
- self.set_info(**openblas_info)
|
|
- return
|
|
+ def _calc_info_atlas(self):
|
|
+ info = get_info('atlas_3_10_threads')
|
|
+ if not info:
|
|
+ info = get_info('atlas_3_10')
|
|
+ if not info:
|
|
+ info = get_info('atlas_threads')
|
|
+ if not info:
|
|
+ info = get_info('atlas')
|
|
+ if info:
|
|
+ # Figure out if ATLAS has lapack...
|
|
+ # If not we need the lapack library, but not BLAS!
|
|
+ l = info.get('define_macros', [])
|
|
+ if ('ATLAS_WITH_LAPACK_ATLAS', None) in l \
|
|
+ or ('ATLAS_WITHOUT_LAPACK', None) in l:
|
|
+ # Get LAPACK (with possible warnings)
|
|
+ # If not found we don't accept anything
|
|
+ # since we can't use ATLAS with LAPACK!
|
|
+ lapack_info = self._get_info_lapack()
|
|
+ if not lapack_info:
|
|
+ return False
|
|
+ dict_append(info, **lapack_info)
|
|
+ self.set_info(**info)
|
|
+ return True
|
|
+ return False
|
|
|
|
- openblas_info = get_info('openblas_clapack')
|
|
- if openblas_info:
|
|
- self.set_info(**openblas_info)
|
|
- return
|
|
+ def _calc_info_accelerate(self):
|
|
+ info = get_info('accelerate')
|
|
+ if info:
|
|
+ self.set_info(**info)
|
|
+ return True
|
|
+ return False
|
|
|
|
- atlas_info = get_info('atlas_3_10_threads')
|
|
- if not atlas_info:
|
|
- atlas_info = get_info('atlas_3_10')
|
|
- if not atlas_info:
|
|
- atlas_info = get_info('atlas_threads')
|
|
- if not atlas_info:
|
|
- atlas_info = get_info('atlas')
|
|
-
|
|
- accelerate_info = get_info('accelerate')
|
|
- if accelerate_info and not atlas_info:
|
|
- self.set_info(**accelerate_info)
|
|
- return
|
|
+ def _get_info_blas(self):
|
|
+ # Default to get the optimized BLAS implementation
|
|
+ info = get_info('blas_opt')
|
|
+ if not info:
|
|
+ warnings.warn(BlasNotFoundError.__doc__ or '', stacklevel=3)
|
|
+ info_src = get_info('blas_src')
|
|
+ if not info_src:
|
|
+ warnings.warn(BlasSrcNotFoundError.__doc__ or '', stacklevel=3)
|
|
+ return {}
|
|
+ dict_append(info, libraries=[('fblas_src', info_src)])
|
|
+ return info
|
|
|
|
- need_lapack = 0
|
|
- need_blas = 0
|
|
- info = {}
|
|
- if atlas_info:
|
|
- l = atlas_info.get('define_macros', [])
|
|
- if ('ATLAS_WITH_LAPACK_ATLAS', None) in l \
|
|
- or ('ATLAS_WITHOUT_LAPACK', None) in l:
|
|
- need_lapack = 1
|
|
- info = atlas_info
|
|
+ def _get_info_lapack(self):
|
|
+ info = get_info('lapack')
|
|
+ if not info:
|
|
+ warnings.warn(LapackNotFoundError.__doc__ or '', stacklevel=3)
|
|
+ info_src = get_info('lapack_src')
|
|
+ if not info_src:
|
|
+ warnings.warn(LapackSrcNotFoundError.__doc__ or '', stacklevel=3)
|
|
+ return {}
|
|
+ dict_append(info, libraries=[('flapack_src', info_src)])
|
|
+ return info
|
|
|
|
- else:
|
|
- warnings.warn(AtlasNotFoundError.__doc__, stacklevel=2)
|
|
- need_blas = 1
|
|
- need_lapack = 1
|
|
+ def _calc_info_lapack(self):
|
|
+ info = self._get_info_lapack()
|
|
+ if info:
|
|
+ info_blas = self._get_info_blas()
|
|
+ dict_append(info, **info_blas)
|
|
dict_append(info, define_macros=[('NO_ATLAS_INFO', 1)])
|
|
+ self.set_info(**info)
|
|
+ return True
|
|
+ return False
|
|
|
|
- if need_lapack:
|
|
- lapack_info = get_info('lapack')
|
|
- #lapack_info = {} ## uncomment for testing
|
|
- if lapack_info:
|
|
- dict_append(info, **lapack_info)
|
|
- else:
|
|
- warnings.warn(LapackNotFoundError.__doc__, stacklevel=2)
|
|
- lapack_src_info = get_info('lapack_src')
|
|
- if not lapack_src_info:
|
|
- warnings.warn(LapackSrcNotFoundError.__doc__, stacklevel=2)
|
|
- return
|
|
- dict_append(info, libraries=[('flapack_src', lapack_src_info)])
|
|
-
|
|
- if need_blas:
|
|
- blas_info = get_info('blas')
|
|
- if blas_info:
|
|
- dict_append(info, **blas_info)
|
|
- else:
|
|
- warnings.warn(BlasNotFoundError.__doc__, stacklevel=2)
|
|
- blas_src_info = get_info('blas_src')
|
|
- if not blas_src_info:
|
|
- warnings.warn(BlasSrcNotFoundError.__doc__, stacklevel=2)
|
|
- return
|
|
- dict_append(info, libraries=[('fblas_src', blas_src_info)])
|
|
+ def calc_info(self):
|
|
+ user_order = os.environ.get('NPY_LAPACK_ORDER', None)
|
|
+ if user_order is None:
|
|
+ lapack_order = self.lapack_order
|
|
+ else:
|
|
+ # the user has requested the order of the
|
|
+ # check they are all in the available list, a COMMA SEPARATED list
|
|
+ user_order = user_order.lower().split(',')
|
|
+ non_existing = []
|
|
+ lapack_order = []
|
|
+ for order in user_order:
|
|
+ if order in self.lapack_order:
|
|
+ lapack_order.append(order)
|
|
+ elif len(order) > 0:
|
|
+ non_existing.append(order)
|
|
+ if len(non_existing) > 0:
|
|
+ raise ValueError("lapack_opt_info user defined "
|
|
+ "LAPACK order has unacceptable "
|
|
+ "values: {}".format(non_existing))
|
|
+
|
|
+ for lapack in lapack_order:
|
|
+ if getattr(self, '_calc_info_{}'.format(lapack))():
|
|
+ return
|
|
|
|
- self.set_info(**info)
|
|
- return
|
|
+ if 'lapack' not in lapack_order:
|
|
+ # Since the user may request *not* to use any library, we still need
|
|
+ # to raise warnings to signal missing packages!
|
|
+ warnings.warn(LapackNotFoundError.__doc__ or '', stacklevel=2)
|
|
+ warnings.warn(LapackSrcNotFoundError.__doc__ or '', stacklevel=2)
|
|
|
|
|
|
class blas_opt_info(system_info):
|
|
|
|
notfounderror = BlasNotFoundError
|
|
+ # Default order of BLAS checks
|
|
+ blas_order = ['mkl', 'blis', 'openblas', 'atlas', 'accelerate', 'blas']
|
|
|
|
- def calc_info(self):
|
|
+ def _calc_info_mkl(self):
|
|
+ info = get_info('blas_mkl')
|
|
+ if info:
|
|
+ self.set_info(**info)
|
|
+ return True
|
|
+ return False
|
|
|
|
- blas_mkl_info = get_info('blas_mkl')
|
|
- if blas_mkl_info:
|
|
- self.set_info(**blas_mkl_info)
|
|
- return
|
|
+ def _calc_info_blis(self):
|
|
+ info = get_info('blis')
|
|
+ if info:
|
|
+ self.set_info(**info)
|
|
+ return True
|
|
+ return False
|
|
|
|
- blis_info = get_info('blis')
|
|
- if blis_info:
|
|
- self.set_info(**blis_info)
|
|
- return
|
|
+ def _calc_info_openblas(self):
|
|
+ info = get_info('openblas')
|
|
+ if info:
|
|
+ self.set_info(**info)
|
|
+ return True
|
|
+ return False
|
|
|
|
- openblas_info = get_info('openblas')
|
|
- if openblas_info:
|
|
- self.set_info(**openblas_info)
|
|
- return
|
|
+ def _calc_info_atlas(self):
|
|
+ info = get_info('atlas_3_10_blas_threads')
|
|
+ if not info:
|
|
+ info = get_info('atlas_3_10_blas')
|
|
+ if not info:
|
|
+ info = get_info('atlas_blas_threads')
|
|
+ if not info:
|
|
+ info = get_info('atlas_blas')
|
|
+ if info:
|
|
+ self.set_info(**info)
|
|
+ return True
|
|
+ return False
|
|
|
|
- atlas_info = get_info('atlas_3_10_blas_threads')
|
|
- if not atlas_info:
|
|
- atlas_info = get_info('atlas_3_10_blas')
|
|
- if not atlas_info:
|
|
- atlas_info = get_info('atlas_blas_threads')
|
|
- if not atlas_info:
|
|
- atlas_info = get_info('atlas_blas')
|
|
-
|
|
- accelerate_info = get_info('accelerate')
|
|
- if accelerate_info and not atlas_info:
|
|
- self.set_info(**accelerate_info)
|
|
- return
|
|
+ def _calc_info_accelerate(self):
|
|
+ info = get_info('accelerate')
|
|
+ if info:
|
|
+ self.set_info(**info)
|
|
+ return True
|
|
+ return False
|
|
|
|
- need_blas = 0
|
|
+ def _calc_info_blas(self):
|
|
+ # Warn about a non-optimized BLAS library
|
|
+ warnings.warn(BlasOptNotFoundError.__doc__ or '', stacklevel=3)
|
|
info = {}
|
|
- if atlas_info:
|
|
- info = atlas_info
|
|
+ dict_append(info, define_macros=[('NO_ATLAS_INFO', 1)])
|
|
+
|
|
+ blas = get_info('blas')
|
|
+ if blas:
|
|
+ dict_append(info, **blas)
|
|
else:
|
|
- warnings.warn(AtlasNotFoundError.__doc__, stacklevel=2)
|
|
- need_blas = 1
|
|
- dict_append(info, define_macros=[('NO_ATLAS_INFO', 1)])
|
|
+ # Not even BLAS was found!
|
|
+ warnings.warn(BlasNotFoundError.__doc__ or '', stacklevel=3)
|
|
|
|
- if need_blas:
|
|
- blas_info = get_info('blas')
|
|
- if blas_info:
|
|
- dict_append(info, **blas_info)
|
|
- else:
|
|
- warnings.warn(BlasNotFoundError.__doc__, stacklevel=2)
|
|
- blas_src_info = get_info('blas_src')
|
|
- if not blas_src_info:
|
|
- warnings.warn(BlasSrcNotFoundError.__doc__, stacklevel=2)
|
|
- return
|
|
- dict_append(info, libraries=[('fblas_src', blas_src_info)])
|
|
+ blas_src = get_info('blas_src')
|
|
+ if not blas_src:
|
|
+ warnings.warn(BlasSrcNotFoundError.__doc__ or '', stacklevel=3)
|
|
+ return False
|
|
+ dict_append(info, libraries=[('fblas_src', blas_src)])
|
|
|
|
self.set_info(**info)
|
|
- return
|
|
+ return True
|
|
+
|
|
+ def calc_info(self):
|
|
+ user_order = os.environ.get('NPY_BLAS_ORDER', None)
|
|
+ if user_order is None:
|
|
+ blas_order = self.blas_order
|
|
+ else:
|
|
+ # the user has requested the order of the
|
|
+ # check they are all in the available list
|
|
+ user_order = user_order.lower().split(',')
|
|
+ non_existing = []
|
|
+ blas_order = []
|
|
+ for order in user_order:
|
|
+ if order in self.blas_order:
|
|
+ blas_order.append(order)
|
|
+ elif len(order) > 0:
|
|
+ non_existing.append(order)
|
|
+ if len(non_existing) > 0:
|
|
+ raise ValueError("blas_opt_info user defined BLAS order has unacceptable values: {}".format(non_existing))
|
|
+
|
|
+ for blas in blas_order:
|
|
+ if getattr(self, '_calc_info_{}'.format(blas))():
|
|
+ return
|
|
+
|
|
+ if 'blas' not in blas_order:
|
|
+ # Since the user may request *not* to use any library, we still need
|
|
+ # to raise warnings to signal missing packages!
|
|
+ warnings.warn(BlasNotFoundError.__doc__ or '', stacklevel=2)
|
|
+ warnings.warn(BlasSrcNotFoundError.__doc__ or '', stacklevel=2)
|
|
|
|
|
|
class blas_info(system_info):
|