diff options
Diffstat (limited to 'numpy')
-rw-r--r-- | numpy/distutils/system_info.py | 301 |
1 files changed, 194 insertions, 107 deletions
diff --git a/numpy/distutils/system_info.py b/numpy/distutils/system_info.py index cd78fa37f..1f4552aea 100644 --- a/numpy/distutils/system_info.py +++ b/numpy/distutils/system_info.py @@ -479,6 +479,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. @@ -1582,139 +1589,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): |