From 0df45812b93229b3186c061cb84ec29fd380e09c Mon Sep 17 00:00:00 2001 From: Moritz Kern <92092328+Moritz-Alexander-Kern@users.noreply.github.com> Date: Fri, 20 May 2022 16:06:09 +0200 Subject: [PATCH] fix Issue #481, ASSET tries to use a backend that is not present in the environment (#485) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * added coverage to MPI runner, removed MPI from pip added function get_opencl_capability() to utils, to detect openCL devices * updated docstring, changed return logic * added unittest, regression Issue #481 Co-authored-by: Cristiano Köhler --- elephant/asset/asset.py | 6 ++++-- elephant/test/test_asset.py | 35 ++++++++++++++++++++++++++++++++++- elephant/utils.py | 22 ++++++++++++++++++++++ 3 files changed, 60 insertions(+), 3 deletions(-) diff --git a/elephant/asset/asset.py b/elephant/asset/asset.py index 7a28089b5..7382718ba 100644 --- a/elephant/asset/asset.py +++ b/elephant/asset/asset.py @@ -136,7 +136,7 @@ import elephant.conversion as conv from elephant import spike_train_surrogates -from elephant.utils import get_cuda_capability_major +from elephant.utils import get_cuda_capability_major, get_opencl_capability try: from mpi4py import MPI @@ -513,9 +513,11 @@ def _choose_backend(self): use_cuda = int(os.getenv("ELEPHANT_USE_CUDA", '1')) use_opencl = int(os.getenv("ELEPHANT_USE_OPENCL", '1')) cuda_detected = get_cuda_capability_major() != 0 + opencl_detected = get_opencl_capability() + if use_cuda and cuda_detected: return self.pycuda - if use_opencl: + if use_opencl and opencl_detected: return self.pyopencl return self.cpu diff --git a/elephant/test/test_asset.py b/elephant/test/test_asset.py index 0962c5844..9a1f00f5a 100644 --- a/elephant/test/test_asset.py +++ b/elephant/test/test_asset.py @@ -33,7 +33,7 @@ try: import pyopencl - HAVE_PYOPENCL = True + HAVE_PYOPENCL = asset.get_opencl_capability() except ImportError: HAVE_PYOPENCL = False @@ -393,6 +393,39 @@ def test_intersection_matrix(self): spiketrains_i=[st1, st2], bin_size=bin_size, t_stop_j=5 * pq.ms) + # regression test Issue #481 + # see: https://github.com/NeuralEnsemble/elephant/issues/481 + def test_asset_choose_backend_opencl(self): + class TestClassBackend(asset._GPUBackend): + + def __init__(self): + super().__init__() + self.backend = self._choose_backend() + + def cpu(self): + return "cpu" + + def pycuda(self): + return "cuda" + + def pyopencl(self): + return "opencl" + + # check which backend is chosen if environment variable for opencl + # is not set + os.environ.pop('ELEPHANT_USE_OPENCL', None) + # create object of TestClass + backend_obj = TestClassBackend() + + if HAVE_PYOPENCL: + self.assertEqual(backend_obj.backend(), 'opencl') + else: + # if environment variable is not set and no module pyopencl or + # device is found: choose cpu backend + self.assertEqual(backend_obj.backend(), 'cpu') + + os.environ['ELEPHANT_USE_OPENCL'] = '0' + @unittest.skipUnless(HAVE_SKLEARN, 'requires sklearn') class TestJSFUniformOrderStat3D(unittest.TestCase): diff --git a/elephant/utils.py b/elephant/utils.py index 3ce1e9206..f634a570a 100644 --- a/elephant/utils.py +++ b/elephant/utils.py @@ -340,3 +340,25 @@ def get_cuda_capability_major(): ctypes.byref(cc_minor), device) return cc_major.value + + +def get_opencl_capability(): + """ + Return a list of available OpenCL devices. + + Returns + ------- + bool + True: if openCL platform detected and at least one device is found, + False: if OpenCL is not found or if no OpenCL devices are found + """ + try: + import pyopencl + platforms = pyopencl.get_platforms() + + if len(platforms) == 0: + return False + # len(platforms) is > 0, if it is not == 0 + return True + except ImportError: + return False