diff options
author | Picca Frédéric-Emmanuel <picca@synchrotron-soleil.fr> | 2017-08-18 14:48:52 +0200 |
---|---|---|
committer | Picca Frédéric-Emmanuel <picca@synchrotron-soleil.fr> | 2017-08-18 14:48:52 +0200 |
commit | f7bdc2acff3c13a6d632c28c4569690ab106eed7 (patch) | |
tree | 9d67cdb7152ee4e711379e03fe0546c7c3b97303 /silx/opencl/test |
Import Upstream version 0.5.0+dfsg
Diffstat (limited to 'silx/opencl/test')
-rw-r--r-- | silx/opencl/test/__init__.py | 41 | ||||
-rw-r--r-- | silx/opencl/test/test_addition.py | 135 | ||||
-rw-r--r-- | silx/opencl/test/test_medfilt.py | 175 |
3 files changed, 351 insertions, 0 deletions
diff --git a/silx/opencl/test/__init__.py b/silx/opencl/test/__init__.py new file mode 100644 index 0000000..24aa06e --- /dev/null +++ b/silx/opencl/test/__init__.py @@ -0,0 +1,41 @@ +# -*- coding: utf-8 -*- +# +# Project: silx +# https://github.com/silx-kit/silx +# +# Copyright (C) 2012-2016 European Synchrotron Radiation Facility, Grenoble, France +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +__authors__ = ["J. Kieffer"] +__license__ = "MIT" +__date__ = "15/03/2017" + +import unittest +from . import test_addition +from . import test_medfilt +from ..sift import test as test_sift + + +def suite(): + test_suite = unittest.TestSuite() + test_suite.addTests(test_addition.suite()) + test_suite.addTests(test_medfilt.suite()) + test_suite.addTests(test_sift.suite()) + + return test_suite diff --git a/silx/opencl/test/test_addition.py b/silx/opencl/test/test_addition.py new file mode 100644 index 0000000..89e49be --- /dev/null +++ b/silx/opencl/test/test_addition.py @@ -0,0 +1,135 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +# Project: Sift implementation in Python + OpenCL +# https://github.com/silx-kit/silx +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation +# files (the "Software"), to deal in the Software without +# restriction, including without limitation the rights to use, +# copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following +# conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +# OTHER DEALINGS IN THE SOFTWARE. + +""" +Simple test of an addition +""" + +from __future__ import division, print_function + +__authors__ = ["Henri Payno, Jérôme Kieffer"] +__contact__ = "jerome.kieffer@esrf.eu" +__license__ = "MIT" +__copyright__ = "2013 European Synchrotron Radiation Facility, Grenoble, France" +__date__ = "15/03/2017" + +import logging +import numpy + +import unittest +from ..common import ocl, _measure_workgroup_size +if ocl: + import pyopencl + import pyopencl.array +from ..utils import get_opencl_code +logger = logging.getLogger(__name__) + + +@unittest.skipUnless(ocl, "PyOpenCl is missing") +class TestAddition(unittest.TestCase): + + @classmethod + def setUpClass(cls): + super(TestAddition, cls).setUpClass() + if ocl: + cls.ctx = ocl.create_context() + if logger.getEffectiveLevel() <= logging.INFO: + cls.PROFILE = True + cls.queue = pyopencl.CommandQueue( + cls.ctx, + properties=pyopencl.command_queue_properties.PROFILING_ENABLE) + else: + cls.PROFILE = False + cls.queue = pyopencl.CommandQueue(cls.ctx) + cls.max_valid_wg = 0 + + @classmethod + def tearDownClass(cls): + super(TestAddition, cls).tearDownClass() + print("Maximum valid workgroup size %s on device %s" % (cls.max_valid_wg, cls.ctx.devices[0])) + cls.ctx = None + cls.queue = None + + def setUp(self): + if ocl is None: + return + self.shape = 4096 + self.data = numpy.random.random(self.shape).astype(numpy.float32) + self.d_array_img = pyopencl.array.to_device(self.queue, self.data) + self.d_array_5 = pyopencl.array.zeros_like(self.d_array_img) - 5 + self.program = pyopencl.Program(self.ctx, get_opencl_code("addition")).build() + + def tearDown(self): + self.img = self.data = None + self.d_array_img = self.d_array_5 = self.program = None + + @unittest.skipUnless(ocl, "pyopencl is missing") + def test_add(self): + """ + tests the addition kernel + """ + maxi = int(round(numpy.log2(self.shape))) + for i in range(maxi): + d_array_result = pyopencl.array.empty_like(self.d_array_img) + wg = 1 << i + try: + evt = self.program.addition(self.queue, (self.shape,), (wg,), + self.d_array_img.data, self.d_array_5.data, d_array_result.data, numpy.int32(self.shape)) + evt.wait() + except Exception as error: + max_valid_wg = self.program.addition.get_work_group_info(pyopencl.kernel_work_group_info.WORK_GROUP_SIZE, self.ctx.devices[0]) + msg = "Error %s on WG=%s: %s" % (error, wg, max_valid_wg) + self.assertLess(max_valid_wg, wg, msg) + break + else: + res = d_array_result.get() + good = numpy.allclose(res, self.data - 5) + if good and wg>self.max_valid_wg: + self.__class__.max_valid_wg = wg + self.assert_(good, "calculation is correct for WG=%s" % wg) + + @unittest.skipUnless(ocl, "pyopencl is missing") + def test_measurement(self): + """ + tests that all devices are working properly ... + """ + for platform in ocl.platforms: + for did, device in enumerate(platform.devices): + meas = _measure_workgroup_size((platform.id, device.id)) + self.assertEqual(meas, device.max_work_group_size, + "Workgroup size for %s/%s: %s == %s" % (platform, device, meas, device.max_work_group_size)) + + +def suite(): + testSuite = unittest.TestSuite() + testSuite.addTest(TestAddition("test_add")) + testSuite.addTest(TestAddition("test_measurement")) + return testSuite + + +if __name__ == '__main__': + unittest.main(defaultTest="suite") diff --git a/silx/opencl/test/test_medfilt.py b/silx/opencl/test/test_medfilt.py new file mode 100644 index 0000000..f4e4cc8 --- /dev/null +++ b/silx/opencl/test/test_medfilt.py @@ -0,0 +1,175 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +# Project: Median filter of images + OpenCL +# https://github.com/silx-kit/silx +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation +# files (the "Software"), to deal in the Software without +# restriction, including without limitation the rights to use, +# copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following +# conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +# OTHER DEALINGS IN THE SOFTWARE. + +""" +Simple test of the median filter +""" + +from __future__ import division, print_function + +__authors__ = ["Jérôme Kieffer"] +__contact__ = "jerome.kieffer@esrf.eu" +__license__ = "MIT" +__copyright__ = "2013-2017 European Synchrotron Radiation Facility, Grenoble, France" +__date__ = "15/03/2017" + + +import sys +import time +import logging +import numpy +import unittest +from collections import namedtuple +try: + import mako +except ImportError: + mako = None +from ..common import ocl +if ocl: + import pyopencl + import pyopencl.array + from .. import medfilt + +logger = logging.getLogger(__name__) + +Result = namedtuple("Result", ["size", "error", "sp_time", "oc_time"]) + +try: + from scipy.misc import ascent +except: + def ascent(): + """Dummy image from random data""" + return numpy.random.random((512, 512)) +try: + from scipy.ndimage import filters + median_filter = filters.median_filter + HAS_SCIPY = True +except: + HAS_SCIPY = False + from silx.math import medfilt2d as median_filter + +@unittest.skipUnless(ocl and mako, "PyOpenCl is missing") +class TestMedianFilter(unittest.TestCase): + + def setUp(self): + if ocl is None: + return + self.data = ascent().astype(numpy.float32) + self.medianfilter = medfilt.MedianFilter2D(self.data.shape, devicetype="gpu") + + def tearDown(self): + self.data = None + self.medianfilter = None + + def measure(self, size): + "Common measurement of accuracy and timings" + t0 = time.time() + if HAS_SCIPY: + ref = median_filter(self.data, size, mode="nearest") + else: + ref = median_filter(self.data, size) + t1 = time.time() + try: + got = self.medianfilter.medfilt2d(self.data, size) + except RuntimeError as msg: + logger.error(msg) + return + t2 = time.time() + delta = abs(got - ref).max() + return Result(size, delta, t1 - t0, t2 - t1) + + @unittest.skipUnless(ocl and mako, "pyopencl is missing") + def test_medfilt(self): + """ + tests the median filter kernel + """ + r = self.measure(size=11) + if r is None: + logger.info("test_medfilt: size: %s: skipped") + else: + logger.info("test_medfilt: size: %s error %s, t_ref: %.3fs, t_ocl: %.3fs" % r) + self.assert_(r.error == 0, 'Results are correct') + + def benchmark(self, limit=36): + "Run some benchmarking" + try: + import PyQt5 + from ...gui.matplotlib import pylab + from ...gui.utils import update_fig + except: + pylab = None + + def update_fig(*ag, **kwarg): + pass + + fig = pylab.figure() + fig.suptitle("Median filter of an image 512x512") + sp = fig.add_subplot(1, 1, 1) + sp.set_title(self.medianfilter.ctx.devices[0].name) + sp.set_xlabel("Window width & height") + sp.set_ylabel("Execution time (s)") + sp.set_xlim(2, limit + 1) + sp.set_ylim(0, 4) + data_size = [] + data_scipy = [] + data_opencl = [] + plot_sp = sp.plot(data_size, data_scipy, "-or", label="scipy")[0] + plot_opencl = sp.plot(data_size, data_opencl, "-ob", label="opencl")[0] + sp.legend(loc=2) + fig.show() + update_fig(fig) + for s in range(3, limit, 2): + r = self.measure(s) + print(r) + if r.error == 0: + data_size.append(s) + data_scipy.append(r.sp_time) + data_opencl.append(r.oc_time) + plot_sp.set_data(data_size, data_scipy) + plot_opencl.set_data(data_size, data_opencl) + update_fig(fig) + fig.show() + if sys.version_info[0] < 3: + raw_input() + else: + input() + + +def suite(): + testSuite = unittest.TestSuite() + testSuite.addTest(TestMedianFilter("test_medfilt")) + return testSuite + + +def benchmark(): + testSuite = unittest.TestSuite() + testSuite.addTest(TestMedianFilter("benchmark")) + return testSuite + + +if __name__ == '__main__': + unittest.main(defaultTest="suite") |