From ed6611d30aad3e898af823f73ddf9a1bad4cbd79 Mon Sep 17 00:00:00 2001 From: Nick Papior Date: Fri, 15 Mar 2019 14:27:47 +0100 Subject: [PATCH 1/7] ENH: allowed external users to select BLAS and LAPACK library link order Prior to this enhancement compiling numpy would forcefully check BLAS/LAPACK libraries in the following order: BLAS: - mkl - blis - openblas - atlas - accelerate - NetLIB BLAS - LAPACK - mkl - openblas - atlas - accelerate - NetLIB LAPACK This is problematic if a user want to build using, say, OpenBLAS but MKL is installed. Even populating the site.cfg correspondingly one would get a successfull build, but using MKL, if present. The same applies to OpenBLAS vs. ATLAS etc. Especially for developers this may be desirable to check performance with various BLAS/LAPACK libraries. This fixes the above issues by enabling users to forcefully set the order of loads via environment variables: $> export NUMPY_BLAS_ORDER=openblas,mkl,atlas $> python setup.py config ... would first try OpenBLAS (if existing), then MKL, and finally ATLAS. In this case the build would fail if neither of OpenBLAS, MKL or ATLAS is present. I.e. this can also be easierly used to test whether a linking would work. This is because specifying a single library forces only one library check and has no fall-back procedure (as requested by the user!). The same applies to: NUMPY_LAPACK_ORDER=openblas,mkl,atlas This has meant that the blas_opt_info and lapack_opt_info classes in system_info.py has *completely* changed. Effectively there is only ONE change: A fall-back of LAPACK was previously using get_info('blas') to get the BLAS library to correctly link LAPACK. However, this may be undesirable when the user has OpenBLAS/BLIS/ATLAS in a BLAS only installation but wants to use the NetLIB LAPACK. Hence now lapack_opt_info uses get_info('blas_opt') which does change the fall-back routine slightly. But perhaps for an easier build? Signed-off-by: Nick Papior --- numpy/distutils/system_info.py | 292 ++++++++++++++++++++------------- 1 file changed, 182 insertions(+), 110 deletions(-) diff --git a/numpy/distutils/system_info.py b/numpy/distutils/system_info.py index 4d923ad266ec..c937e87cbd56 100644 --- a/numpy/distutils/system_info.py +++ b/numpy/distutils/system_info.py @@ -1539,140 +1539,212 @@ def get_atlas_version(**config): 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) + lapack_info = self._get_info_lapack() + 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): + # TODO this was previously blas? Using blas_opt allows NetLIB lapack and BLIS, for instance. + # However, does this break anything!?!? + info = get_info('blas_opt') + if not info: + warnings.warn(BlasNotFoundError.__doc__, stacklevel=2) + info_src = get_info('blas_src') + if not info_src: + warnings.warn(BlasSrcNotFoundError.__doc__, stacklevel=2) + 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__, stacklevel=2) + info_src = get_info('lapack_src') + if not info_src: + warnings.warn(LapackSrcNotFoundError.__doc__, stacklevel=2) + return {} + dict_append(info, libraries=[('flapack_src', info_src)]) + return info - else: - warnings.warn(AtlasNotFoundError.__doc__, stacklevel=2) - need_blas = 1 - need_lapack = 1 - dict_append(info, define_macros=[('NO_ATLAS_INFO', 1)]) - - 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_lapack(self): + info = self._get_info_lapack() + # TODO check whether this is actually necessary to warn about? + # I think the warning is superfluous! + # warnings.warn(AtlasNotFoundError.__doc__, stacklevel=2) - self.set_info(**info) - return + # Ensure we have NO_ATLAS_INFO in the macro list + dict_append(info, define_macros=[('NO_ATLAS_INFO', 1)]) + info_blas = self._get_info_blas() + dict_append(info, **info_blas) + if info: + self.set_info(**info) + return True + return False + + def calc_info(self): + # Copy list so we can overwrite + lapack_order = self.lapack_order[:] + + user_order = os.environ.get('NUMPY_LAPACK_ORDER', None) + if not user_order is None: + # 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 = [] + for order in user_order: + if order not in lapack_order: + non_existing.append(order) + if len(non_existing) > 0: + raise ValueError("lapack_opt_info user defined LAPACK order has unacceptable values: {}".format(non_existing)) + lapack_order = user_order + + for lapack in lapack_order: + if getattr(self, '_calc_info_{}'.format(lapack))(): + return + + # possible fail-handler? Raise something? + # reaching this point means that nothing has been found 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): + # When one is finally asking for BLAS we need to report + # of insufficient usage of optimized BLAS + warnings.warn(AtlasNotFoundError.__doc__, stacklevel=2) 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)]) - - 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)]) + # Not even BLAS was found! + warnings.warn(BlasNotFoundError.__doc__, stacklevel=2) + + blas_src = get_info('blas_src') + if not blas_src: + warnings.warn(BlasSrcNotFoundError.__doc__, stacklevel=2) + return False + dict_append(info, libraries=[('fblas_src', blas_src)]) self.set_info(**info) - return + return True + + def calc_info(self): + # Copy list so we can overwrite + blas_order = self.blas_order[:] + + user_order = os.environ.get('NUMPY_BLAS_ORDER', None) + if not user_order is None: + # the user has requested the order of the + # check they are all in the available list + user_order = user_order.lower().split(',') + non_existing = [] + for order in user_order: + if order not in blas_order: + non_existing.append(order) + if len(non_existing) > 0: + raise ValueError("blas_opt_info user defined BLAS order has unacceptable values: {}".format(non_existing)) + blas_order = user_order + + for blas in blas_order: + if getattr(self, '_calc_info_{}'.format(blas))(): + return + # possible fail-handler? Raise something? + # reaching this point means that nothing has been found class blas_info(system_info): section = 'blas' From aa144f3661b8ec52290b077ef1c79c367360fb7a Mon Sep 17 00:00:00 2001 From: Nick Papior Date: Mon, 18 Mar 2019 15:36:54 +0100 Subject: [PATCH 2/7] ENH: amended documentation and changed env-vars as suggested Also added a test to travis (apparently ATLAS=None... is not tested on circleCI). Signed-off-by: Nick Papior --- .travis.yml | 7 ++++ doc/source/user/building.rst | 60 +++++++++++++++++++++++++++++++++- numpy/distutils/system_info.py | 35 +++++++++----------- 3 files changed, 82 insertions(+), 20 deletions(-) diff --git a/.travis.yml b/.travis.yml index 7498e1d66ca0..b7a3ee696e11 100644 --- a/.travis.yml +++ b/.travis.yml @@ -64,6 +64,13 @@ matrix: - BLAS=None - LAPACK=None - ATLAS=None + - python: 3.6 + env: + - BLAS=None + - LAPACK=None + - ATLAS=None + - NPY_BLAS_ORDER=mkl,blis,openblas,atlas,accelerate,blas + - NPY_LAPACK_ORDER=MKL,OPENBLAS,ATLAS,ACCELERATE,LAPACK - os: linux-ppc64le python: 3.6 env: diff --git a/doc/source/user/building.rst b/doc/source/user/building.rst index d224951dd5db..a9ec496c5722 100644 --- a/doc/source/user/building.rst +++ b/doc/source/user/building.rst @@ -118,12 +118,70 @@ means that g77 has been used. If libgfortran.so is a dependency, gfortran has been used. If both are dependencies, this means both have been used, which is almost always a very bad idea. +Accelerated BLAS/LAPACK libraries +--------------------------------- + +NumPy searches for optimized linear algebra libraries such as BLAS and LAPACK. +There are specific orders for searching these libraries, as described below. + +BLAS +~~~~ + +The default order for the libraries are: + +1. MKL +2. BLIS +3. OpenBLAS +4. ATLAS +5. Accelerate (MacOS) +6. BLAS (NetLIB) + + +If you wish to build against OpenBLAS but you also have BLIS available one +may predefine the order of searching via the environment variable +``NPY_BLAS_ORDER`` which is a comma-separated list of the above names which +is used to determine what to search for, for instance:: + + NPY_BLAS_ORDER=ATLAS,blis,openblas,MKL python setup.py build + +will prefer to use ATLAS, then BLIS, then OpenBLAS and as a last resort MKL. +If neither of these exists the build will fail (names are compared +lower case). + +LAPACK +~~~~~~ + +The default order for the libraries are: + +1. MKL +2. OpenBLAS +3. ATLAS +4. Accelerate (MacOS) +5. LAPACK (NetLIB) + + +If you wish to build against OpenBLAS but you also have MKL available one +may predefine the order of searching via the environment variable +``NPY_LAPACK_ORDER`` which is a comma-separated list of the above names, +for instance:: + + NPY_LAPACK_ORDER=ATLAS,openblas,MKL python setup.py build + +will prefer to use ATLAS, then OpenBLAS and as a last resort MKL. +If neither of these exists the build will fail (names are compared +lower case). + + Disabling ATLAS and other accelerated libraries ------------------------------------------------ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Usage of ATLAS and other accelerated libraries in NumPy can be disabled via:: + NPY_BLAS_ORDER= NPY_LAPACK_ORDER= python setup.py build + +or:: + BLAS=None LAPACK=None ATLAS=None python setup.py build diff --git a/numpy/distutils/system_info.py b/numpy/distutils/system_info.py index c937e87cbd56..b627fcc381da 100644 --- a/numpy/distutils/system_info.py +++ b/numpy/distutils/system_info.py @@ -1628,29 +1628,27 @@ def _calc_info_lapack(self): return False def calc_info(self): - # Copy list so we can overwrite - lapack_order = self.lapack_order[:] - - user_order = os.environ.get('NUMPY_LAPACK_ORDER', None) - if not user_order is None: + 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 not in lapack_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)) - lapack_order = user_order for lapack in lapack_order: if getattr(self, '_calc_info_{}'.format(lapack))(): return - # possible fail-handler? Raise something? - # reaching this point means that nothing has been found - class blas_opt_info(system_info): @@ -1723,28 +1721,27 @@ def _calc_info_blas(self): return True def calc_info(self): - # Copy list so we can overwrite - blas_order = self.blas_order[:] - - user_order = os.environ.get('NUMPY_BLAS_ORDER', None) - if not user_order is None: + 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 not in blas_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)) - blas_order = user_order for blas in blas_order: if getattr(self, '_calc_info_{}'.format(blas))(): return - # possible fail-handler? Raise something? - # reaching this point means that nothing has been found class blas_info(system_info): section = 'blas' From 146a174d8a66920a734360003cbf09a8fac13bfc Mon Sep 17 00:00:00 2001 From: Nick Papior Date: Mon, 18 Mar 2019 21:21:16 +0100 Subject: [PATCH 3/7] BUG: ensured that warnings/errors are raised when nothing is requested When a user requests NPY_BLAS/LAPACK_ORDER they can omit Netlib BLAS/LAPACK. In that case there will not be raised anything. This commit fixes this issue so that there will always be issues raised if the user hasn't requested the basic libraries. Signed-off-by: Nick Papior --- numpy/distutils/system_info.py | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/numpy/distutils/system_info.py b/numpy/distutils/system_info.py index b627fcc381da..cf06b1ac7111 100644 --- a/numpy/distutils/system_info.py +++ b/numpy/distutils/system_info.py @@ -1593,10 +1593,10 @@ def _get_info_blas(self): # However, does this break anything!?!? info = get_info('blas_opt') if not info: - warnings.warn(BlasNotFoundError.__doc__, stacklevel=2) + warnings.warn(BlasNotFoundError.__doc__, stacklevel=3) info_src = get_info('blas_src') if not info_src: - warnings.warn(BlasSrcNotFoundError.__doc__, stacklevel=2) + warnings.warn(BlasSrcNotFoundError.__doc__, stacklevel=3) return {} dict_append(info, libraries=[('fblas_src', info_src)]) return info @@ -1604,10 +1604,10 @@ def _get_info_blas(self): def _get_info_lapack(self): info = get_info('lapack') if not info: - warnings.warn(LapackNotFoundError.__doc__, stacklevel=2) + warnings.warn(LapackNotFoundError.__doc__, stacklevel=3) info_src = get_info('lapack_src') if not info_src: - warnings.warn(LapackSrcNotFoundError.__doc__, stacklevel=2) + warnings.warn(LapackSrcNotFoundError.__doc__, stacklevel=3) return {} dict_append(info, libraries=[('flapack_src', info_src)]) return info @@ -1649,6 +1649,12 @@ def calc_info(self): if getattr(self, '_calc_info_{}'.format(lapack))(): 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__, stacklevel=2) + warnings.warn(LapackSrcNotFoundError.__doc__, stacklevel=2) + class blas_opt_info(system_info): @@ -1700,7 +1706,7 @@ def _calc_info_accelerate(self): def _calc_info_blas(self): # When one is finally asking for BLAS we need to report # of insufficient usage of optimized BLAS - warnings.warn(AtlasNotFoundError.__doc__, stacklevel=2) + warnings.warn(AtlasNotFoundError.__doc__, stacklevel=3) info = {} dict_append(info, define_macros=[('NO_ATLAS_INFO', 1)]) @@ -1709,11 +1715,11 @@ def _calc_info_blas(self): dict_append(info, **blas) else: # Not even BLAS was found! - warnings.warn(BlasNotFoundError.__doc__, stacklevel=2) + warnings.warn(BlasNotFoundError.__doc__, stacklevel=3) blas_src = get_info('blas_src') if not blas_src: - warnings.warn(BlasSrcNotFoundError.__doc__, stacklevel=2) + warnings.warn(BlasSrcNotFoundError.__doc__, stacklevel=3) return False dict_append(info, libraries=[('fblas_src', blas_src)]) @@ -1742,6 +1748,12 @@ def calc_info(self): 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__, stacklevel=2) + warnings.warn(BlasSrcNotFoundError.__doc__, stacklevel=2) + class blas_info(system_info): section = 'blas' From 74a780884104e9220145805264a4558eb1697df5 Mon Sep 17 00:00:00 2001 From: Nick Papior Date: Mon, 18 Mar 2019 22:25:02 +0100 Subject: [PATCH 4/7] BUG: fixed lapack_lite sources Signed-off-by: Nick Papior --- numpy/distutils/system_info.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/numpy/distutils/system_info.py b/numpy/distutils/system_info.py index cf06b1ac7111..55f0958c6b74 100644 --- a/numpy/distutils/system_info.py +++ b/numpy/distutils/system_info.py @@ -1575,7 +1575,11 @@ def _calc_info_atlas(self): 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 @@ -1617,12 +1621,10 @@ def _calc_info_lapack(self): # TODO check whether this is actually necessary to warn about? # I think the warning is superfluous! # warnings.warn(AtlasNotFoundError.__doc__, stacklevel=2) - - # Ensure we have NO_ATLAS_INFO in the macro list - dict_append(info, define_macros=[('NO_ATLAS_INFO', 1)]) - info_blas = self._get_info_blas() - dict_append(info, **info_blas) 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 From 6781e1faabffeccb88f030512a57b1a25436ed37 Mon Sep 17 00:00:00 2001 From: Nick Papior Date: Mon, 29 Apr 2019 09:15:05 +0200 Subject: [PATCH 5/7] MAINT: fixed last issues and questions according to #13132 Signed-off-by: Nick Papior --- .travis.yml | 12 +++++------- numpy/distutils/system_info.py | 22 +++++++++++++--------- 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/.travis.yml b/.travis.yml index b7a3ee696e11..8c05bdb5b1de 100644 --- a/.travis.yml +++ b/.travis.yml @@ -53,6 +53,11 @@ matrix: - python: 3.6 env: - PYTHONOPTIMIZE=2 + - BLAS=None + - LAPACK=None + - ATLAS=None + - NPY_BLAS_ORDER=mkl,blis,openblas,atlas,accelerate,blas + - NPY_LAPACK_ORDER=MKL,OPENBLAS,ATLAS,ACCELERATE,LAPACK - USE_ASV=1 - python: 3.5 dist: trusty # remove after April 2019 @@ -64,13 +69,6 @@ matrix: - BLAS=None - LAPACK=None - ATLAS=None - - python: 3.6 - env: - - BLAS=None - - LAPACK=None - - ATLAS=None - - NPY_BLAS_ORDER=mkl,blis,openblas,atlas,accelerate,blas - - NPY_LAPACK_ORDER=MKL,OPENBLAS,ATLAS,ACCELERATE,LAPACK - os: linux-ppc64le python: 3.6 env: diff --git a/numpy/distutils/system_info.py b/numpy/distutils/system_info.py index 55f0958c6b74..c03103c283e0 100644 --- a/numpy/distutils/system_info.py +++ b/numpy/distutils/system_info.py @@ -473,6 +473,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. @@ -1593,8 +1600,7 @@ def _calc_info_accelerate(self): return False def _get_info_blas(self): - # TODO this was previously blas? Using blas_opt allows NetLIB lapack and BLIS, for instance. - # However, does this break anything!?!? + # Default to get the optimized BLAS implementation info = get_info('blas_opt') if not info: warnings.warn(BlasNotFoundError.__doc__, stacklevel=3) @@ -1618,9 +1624,6 @@ def _get_info_lapack(self): def _calc_info_lapack(self): info = self._get_info_lapack() - # TODO check whether this is actually necessary to warn about? - # I think the warning is superfluous! - # warnings.warn(AtlasNotFoundError.__doc__, stacklevel=2) if info: info_blas = self._get_info_blas() dict_append(info, **info_blas) @@ -1645,7 +1648,9 @@ def calc_info(self): 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)) + 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))(): @@ -1706,9 +1711,8 @@ def _calc_info_accelerate(self): return False def _calc_info_blas(self): - # When one is finally asking for BLAS we need to report - # of insufficient usage of optimized BLAS - warnings.warn(AtlasNotFoundError.__doc__, stacklevel=3) + # Warn about a non-optimized BLAS library + warnings.warn(BlasOptNotFoundError.__doc__, stacklevel=3) info = {} dict_append(info, define_macros=[('NO_ATLAS_INFO', 1)]) From 178a53fccc4dc7990e59915ef8b666a9cf7e2ef0 Mon Sep 17 00:00:00 2001 From: Nick Papior Date: Mon, 29 Apr 2019 19:11:34 +0200 Subject: [PATCH 6/7] BUG: fixed PYTHONOPTIMIZE run Signed-off-by: Nick Papior --- numpy/distutils/system_info.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/numpy/distutils/system_info.py b/numpy/distutils/system_info.py index c03103c283e0..20b5e2492071 100644 --- a/numpy/distutils/system_info.py +++ b/numpy/distutils/system_info.py @@ -1712,7 +1712,7 @@ def _calc_info_accelerate(self): def _calc_info_blas(self): # Warn about a non-optimized BLAS library - warnings.warn(BlasOptNotFoundError.__doc__, stacklevel=3) + warnings.warn(BlasOptNotFoundError.__doc__ or '', stacklevel=3) info = {} dict_append(info, define_macros=[('NO_ATLAS_INFO', 1)]) From 995665ec7300eac9d7e1215e9980bfbdffcf066b Mon Sep 17 00:00:00 2001 From: Nick Papior Date: Tue, 30 Apr 2019 12:14:34 +0200 Subject: [PATCH 7/7] MAINT: fixed several PYTHONOPTIMIZE=2 failures Signed-off-by: Nick Papior --- numpy/distutils/system_info.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/numpy/distutils/system_info.py b/numpy/distutils/system_info.py index 20b5e2492071..8cc628897f09 100644 --- a/numpy/distutils/system_info.py +++ b/numpy/distutils/system_info.py @@ -1603,10 +1603,10 @@ def _get_info_blas(self): # Default to get the optimized BLAS implementation info = get_info('blas_opt') if not info: - warnings.warn(BlasNotFoundError.__doc__, stacklevel=3) + warnings.warn(BlasNotFoundError.__doc__ or '', stacklevel=3) info_src = get_info('blas_src') if not info_src: - warnings.warn(BlasSrcNotFoundError.__doc__, stacklevel=3) + warnings.warn(BlasSrcNotFoundError.__doc__ or '', stacklevel=3) return {} dict_append(info, libraries=[('fblas_src', info_src)]) return info @@ -1614,10 +1614,10 @@ def _get_info_blas(self): def _get_info_lapack(self): info = get_info('lapack') if not info: - warnings.warn(LapackNotFoundError.__doc__, stacklevel=3) + warnings.warn(LapackNotFoundError.__doc__ or '', stacklevel=3) info_src = get_info('lapack_src') if not info_src: - warnings.warn(LapackSrcNotFoundError.__doc__, stacklevel=3) + warnings.warn(LapackSrcNotFoundError.__doc__ or '', stacklevel=3) return {} dict_append(info, libraries=[('flapack_src', info_src)]) return info @@ -1659,8 +1659,8 @@ def calc_info(self): 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__, stacklevel=2) - warnings.warn(LapackSrcNotFoundError.__doc__, stacklevel=2) + warnings.warn(LapackNotFoundError.__doc__ or '', stacklevel=2) + warnings.warn(LapackSrcNotFoundError.__doc__ or '', stacklevel=2) class blas_opt_info(system_info): @@ -1721,11 +1721,11 @@ def _calc_info_blas(self): dict_append(info, **blas) else: # Not even BLAS was found! - warnings.warn(BlasNotFoundError.__doc__, stacklevel=3) + warnings.warn(BlasNotFoundError.__doc__ or '', stacklevel=3) blas_src = get_info('blas_src') if not blas_src: - warnings.warn(BlasSrcNotFoundError.__doc__, stacklevel=3) + warnings.warn(BlasSrcNotFoundError.__doc__ or '', stacklevel=3) return False dict_append(info, libraries=[('fblas_src', blas_src)]) @@ -1757,8 +1757,8 @@ def calc_info(self): 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__, stacklevel=2) - warnings.warn(BlasSrcNotFoundError.__doc__, stacklevel=2) + warnings.warn(BlasNotFoundError.__doc__ or '', stacklevel=2) + warnings.warn(BlasSrcNotFoundError.__doc__ or '', stacklevel=2) class blas_info(system_info):