diff --git a/.gitignore b/.gitignore index c4eee81..f4e0184 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,4 @@ external/OpenCL-Headers/ external/OpenCL-ICD-Loader/ install/ *~ +.ipynb_checkpoints diff --git a/samples/python/00_enumopencl/CMakeLists.txt b/samples/python/00_enumopencl/CMakeLists.txt index f95de63..5a4074f 100644 --- a/samples/python/00_enumopencl/CMakeLists.txt +++ b/samples/python/00_enumopencl/CMakeLists.txt @@ -1,22 +1,6 @@ -# Copyright (c) 2019-2021 Ben Ashbaugh +# Copyright (c) 2019-2024 Ben Ashbaugh # -# 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. +# SPDX-License-Identifier: MIT add_opencl_python_sample( NUMBER 00 diff --git a/samples/python/00_enumopencl/enumopencl.ipynb b/samples/python/00_enumopencl/enumopencl.ipynb new file mode 100644 index 0000000..602337e --- /dev/null +++ b/samples/python/00_enumopencl/enumopencl.ipynb @@ -0,0 +1,115 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "d0b4a6b7-3ba6-4cc0-8b3c-ba4638247b3d", + "metadata": {}, + "source": [ + "# enumopencl\n", + "\n", + "### Copyright Information" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "163deb93-0c32-40c7-aaf0-a427b453ccc3", + "metadata": {}, + "outputs": [], + "source": [ + "# Copyright (c) 2024 Ben Ashbaugh\n", + "#\n", + "# SPDX-License-Identifier: MIT" + ] + }, + { + "cell_type": "markdown", + "id": "79250647-6a73-42d0-aee8-051aae55a2a8", + "metadata": {}, + "source": [ + "## Sample Purpose\n", + "\n", + "This is a very simple sample that demonstrates how to enumerate the OpenCL platforms that are installed on a machine, and the OpenCL devices that these platforms expose.\n", + "\n", + "This is a good first sample to run to verify that OpenCL is correctly installed on your machine, and that your environment is correctly setup.\n", + "\n", + "## Sample\n", + "\n", + "The first thing we will do is to import pyopencl so we have access to OpenCL from Python." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6c728115-6d8e-4e4c-a4f8-55a6580864f7", + "metadata": {}, + "outputs": [], + "source": [ + "import pyopencl as cl" + ] + }, + { + "cell_type": "markdown", + "id": "b343a628-3e47-4704-8e69-049200236316", + "metadata": {}, + "source": [ + "Assuming that this worked correctly, we can now query the installed OpenCL platforms. An OpenCL platform is an OpenCL implementation for a specific device or collection of devices. There may be an OpenCL platform from a specific device vendor, a specific class of devices from that vendor, or even a specific device. For example, if you have a CPU from one vendor and a GPU from another vendor, you may need to install two OpenCL platforms to enumerate both devices.\n", + "\n", + "If no platforms are found then either no OpenCL platforms are installed or there is a problem with your installation.\n", + "\n", + "For each of the platforms that we find we will print information about the platform and information about each of the devices that the platform supports." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "23b4e3c9-0d34-43af-95fb-2a207d6942fc", + "metadata": {}, + "outputs": [], + "source": [ + "for p, platform in enumerate(cl.get_platforms()):\n", + " print(\"Platform[{}]:\".format(p))\n", + " print(\" Name: \" + platform.get_info(cl.platform_info.NAME))\n", + " print(\" Vendor: \" + platform.get_info(cl.platform_info.VENDOR))\n", + " print(\" Driver Version: \" + platform.get_info(cl.platform_info.VERSION))\n", + " for d, device in enumerate(platform.get_devices()):\n", + " print(\"Device[{}]:\".format(d))\n", + " print(\" Type: \" + cl.device_type.to_string(device.get_info(cl.device_info.TYPE)))\n", + " print(\" Name: \" + device.get_info(cl.device_info.NAME))\n", + " print(\" Vendor: \" + device.get_info(cl.device_info.VENDOR))\n", + " print(\" Device Version: \" + device.get_info(cl.device_info.VERSION))\n", + " print(\" Driver Version: \" + device.get_info(cl.device_info.DRIVER_VERSION))\n", + " print()" + ] + }, + { + "cell_type": "markdown", + "id": "d447785a-0580-423a-b56e-63bb424fe608", + "metadata": {}, + "source": [ + "If you see at least one platform and device listed above, great, your installation is working!" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.12" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/samples/python/00_enumopencl/enumopencl.py b/samples/python/00_enumopencl/enumopencl.py index 838ab88..c689283 100644 --- a/samples/python/00_enumopencl/enumopencl.py +++ b/samples/python/00_enumopencl/enumopencl.py @@ -1,24 +1,8 @@ #!/usr/bin/env python -# Copyright (c) 2019-2021 Ben Ashbaugh +# Copyright (c) 2019-2024 Ben Ashbaugh # -# 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. +# SPDX-License-Identifier: MIT import pyopencl as cl diff --git a/samples/python/01_copybuffer/CMakeLists.txt b/samples/python/01_copybuffer/CMakeLists.txt index e0e15c2..47c85a8 100644 --- a/samples/python/01_copybuffer/CMakeLists.txt +++ b/samples/python/01_copybuffer/CMakeLists.txt @@ -1,22 +1,6 @@ -# Copyright (c) 2019-2021 Ben Ashbaugh +# Copyright (c) 2019-2024 Ben Ashbaugh # -# 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. +# SPDX-License-Identifier: MIT add_opencl_python_sample( NUMBER 01 diff --git a/samples/python/01_copybuffer/copybuffer.ipynb b/samples/python/01_copybuffer/copybuffer.ipynb new file mode 100644 index 0000000..d7291bb --- /dev/null +++ b/samples/python/01_copybuffer/copybuffer.ipynb @@ -0,0 +1,254 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "33e2ac4e-10a4-45dd-b8e2-0e6b5c1f7d4d", + "metadata": {}, + "source": [ + "# copybuffer\n", + "\n", + "### Copyright Information" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8dcd0e61-f4e4-4546-b6cc-ab654286167d", + "metadata": {}, + "outputs": [], + "source": [ + "# Copyright (c) 2024 Ben Ashbaugh\n", + "#\n", + "# SPDX-License-Identifier: MIT" + ] + }, + { + "cell_type": "markdown", + "id": "64c7a35b-8247-41ea-a3a9-f18f4ddfb00c", + "metadata": {}, + "source": [ + "## Sample Purpose\n", + "\n", + "This is first example that uses OpenCL APIs to do work. In this very simple sample, OpenCL APIs are used to copy the contents of one buffer to another buffer on the OpenCL device. To do this, OpenCL APIs are used to create both buffers, to create the OpenCL command queue, and to initialize the source buffer and verify the contents of the destination buffer on the host.\n", + "\n", + "## Sample\n", + "\n", + "The first thing we will do is to import pyopencl so we have access to OpenCL from Python.\n", + "We will also import numpy." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "347bcdb3-0363-437b-9e2e-aede28b95ae4", + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "import pyopencl as cl" + ] + }, + { + "cell_type": "markdown", + "id": "5aebf3dd-81fa-42df-98c9-c92f5af4e489", + "metadata": {}, + "source": [ + "By default, this sample will run in the first enumerated OpenCL device on the first enumerated OpenCL platform.\n", + "To choose a different OpenCL platform, simply change the platform index or device index to a different value." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "21c2357c-459c-4927-a084-356cece3d78f", + "metadata": {}, + "outputs": [], + "source": [ + "if __name__ == \"__main__\":\n", + " platformIndex = 0\n", + " deviceIndex = 0\n", + "\n", + " platforms = cl.get_platforms()\n", + " print('Running on platform: ' + platforms[platformIndex].get_info(cl.platform_info.NAME))\n", + "\n", + " devices = platforms[platformIndex].get_devices()\n", + " print('Running on device: ' + devices[deviceIndex].get_info(cl.device_info.NAME))" + ] + }, + { + "cell_type": "markdown", + "id": "c202b133-e6b9-4368-a00d-caf77b5d61c3", + "metadata": {}, + "source": [ + "In order to create OpenCL objects we first need to create an OpenCL _context_.\n", + "An OpenCL context describes the state of an OpenCL application.\n", + "Most OpenCL objects created against one context cannot be used in a different context.\n", + "\n", + "To create an OpenCL context we must pass the set of OpenCL devices in the context.\n", + "It is most common to create an OpenCL context for a single OpenCL device, but a context can also be created for multiple OpenCL devices if the devices are in the same OpenCL platform.\n", + "In this example we are going to create an OpenCL context for a single OpenCL device." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3fdae0d5-2116-4f46-8447-afdb1faeb6cf", + "metadata": {}, + "outputs": [], + "source": [ + " context = cl.Context([devices[deviceIndex]])" + ] + }, + { + "cell_type": "markdown", + "id": "74d31f4c-15eb-4f40-8a05-3e5db577e7fd", + "metadata": {}, + "source": [ + "Now that we have a context we can create an OpenCL command queue.\n", + "An OpenCL command queue is the way to submit work to an OpenCL device.\n", + "To create an OpenCL command queue we must pass the context that the command queue will be created in, and the OpenCL device that the command queue will submit work to.\n", + "We need to pass the OpenCL device becauase the OpenCL context may be created for multiple OpenCL devices." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1613f5d2-a8b5-4f86-b15f-0795694a8b1a", + "metadata": {}, + "outputs": [], + "source": [ + " commandQueue = cl.CommandQueue(context, devices[deviceIndex])" + ] + }, + { + "cell_type": "markdown", + "id": "2cd289b3-2edd-476c-931a-2bf405ba3c28", + "metadata": {}, + "source": [ + "In this example we are going to copy data from one OpenCL buffer to a different OpenCL buffer, on the OpenCL device.\n", + "To do this we need to create a source buffer to copy from and a destination buffer to copy to.\n", + "By default we will copy one million integers, but this can be changed by modifying the constant below." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e327b529-8604-45fd-8496-dbe77151712e", + "metadata": {}, + "outputs": [], + "source": [ + " numElems = 1024 * 1024\n", + " deviceMemSrc = cl.Buffer(context, cl.mem_flags.ALLOC_HOST_PTR, numElems * np.uint32().itemsize)\n", + " deviceMemDst = cl.Buffer(context, cl.mem_flags.ALLOC_HOST_PTR, numElems * np.uint32().itemsize)" + ] + }, + { + "cell_type": "markdown", + "id": "d3e1d757-94e0-4fff-bb5e-10118c263acb", + "metadata": {}, + "source": [ + "There are several ways to modify the data in an OpenCL buffer, but one of the most common ways is to map the buffer so it is accessible on the host.\n", + "We will map the source buffer to initialize its contents.\n", + "Mapping the buffer uses the command queue we created earlier." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a26446e0-3efc-43fc-a3ca-cccf5b496d35", + "metadata": {}, + "outputs": [], + "source": [ + " mapped_src, event = cl.enqueue_map_buffer(commandQueue, deviceMemSrc,\n", + " cl.map_flags.WRITE_INVALIDATE_REGION,\n", + " 0, numElems, np.uint32)\n", + " with mapped_src.base:\n", + " for i in range(numElems):\n", + " mapped_src[i] = i" + ] + }, + { + "cell_type": "markdown", + "id": "44a6ce2e-e2ec-4838-b8c1-fb88134b6ce1", + "metadata": {}, + "source": [ + "With the source buffer initialized, we can finally copy its contents to the destination buffer.\n", + "Copying memory is a common operation so there is a dedicated OpenCL function to perform the copy.\n", + "In a subsequent sample we will explore how to do the copy ourselves, instead.\n", + "For now though, we will simply call the OpenCL function to perform the copy.\n", + "Because the copy is executing on the OpenCL device it also uses the command queue we created earlier." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "85579595-39d4-49bc-88c6-a780416b8762", + "metadata": {}, + "outputs": [], + "source": [ + " event = cl.enqueue_copy(commandQueue, deviceMemDst, deviceMemSrc)" + ] + }, + { + "cell_type": "markdown", + "id": "365795d0-332f-464e-8923-adddc7e3cbed", + "metadata": {}, + "source": [ + "All that remains now is to verify that the copy succeeded!\n", + "To do this, we will map the destination buffer, and check that it has the same data we used to initilaize the source buffer." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e6686f52-ce08-4140-812f-805f4c3fdb7b", + "metadata": {}, + "outputs": [], + "source": [ + " mapped_dst, event = cl.enqueue_map_buffer(commandQueue, deviceMemDst,\n", + " cl.map_flags.READ,\n", + " 0, numElems, np.uint32)\n", + " with mapped_dst.base:\n", + " mismatches = 0\n", + " for i, val in enumerate(mapped_dst):\n", + " if val != i:\n", + " if mismatches < 16:\n", + " print('Mismatch! dst[{}] == {}, want {}'.format(i, val, i))\n", + " mismatches = mismatches + 1\n", + " if mismatches != 0:\n", + " print('Error: Found {} mismatches / {} values!!!'.format(mismatches, numElems))\n", + " else:\n", + " print('Success.')" + ] + }, + { + "cell_type": "markdown", + "id": "8c25b94a-f9e3-4916-aca0-a6c15ef61d4e", + "metadata": {}, + "source": [ + "If the copy executed correctly we expect to find zero mismatching elements." + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.12" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/samples/python/01_copybuffer/copybuffer.py b/samples/python/01_copybuffer/copybuffer.py index b43ca51..5d7ec1e 100644 --- a/samples/python/01_copybuffer/copybuffer.py +++ b/samples/python/01_copybuffer/copybuffer.py @@ -1,24 +1,8 @@ #!/usr/bin/env python -# Copyright (c) 2019-2021 Ben Ashbaugh +# Copyright (c) 2019-2024 Ben Ashbaugh # -# 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. +# SPDX-License-Identifier: MIT import numpy as np import pyopencl as cl diff --git a/samples/python/02_copybufferkernel/CMakeLists.txt b/samples/python/02_copybufferkernel/CMakeLists.txt index 4a929f0..1cae4bc 100644 --- a/samples/python/02_copybufferkernel/CMakeLists.txt +++ b/samples/python/02_copybufferkernel/CMakeLists.txt @@ -1,22 +1,6 @@ -# Copyright (c) 2019-2021 Ben Ashbaugh +# Copyright (c) 2019-2024 Ben Ashbaugh # -# 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. +# SPDX-License-Identifier: MIT add_opencl_python_sample( NUMBER 02 diff --git a/samples/python/02_copybufferkernel/copybufferkernel.py b/samples/python/02_copybufferkernel/copybufferkernel.py index 1fb6b76..0cf75ce 100644 --- a/samples/python/02_copybufferkernel/copybufferkernel.py +++ b/samples/python/02_copybufferkernel/copybufferkernel.py @@ -1,24 +1,8 @@ #!/usr/bin/env python -# Copyright (c) 2019-2021 Ben Ashbaugh +# Copyright (c) 2019-2024 Ben Ashbaugh # -# 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. +# SPDX-License-Identifier: MIT import numpy as np import pyopencl as cl diff --git a/samples/python/03_mandelbrot/CMakeLists.txt b/samples/python/03_mandelbrot/CMakeLists.txt index e3819c0..45afbc9 100644 --- a/samples/python/03_mandelbrot/CMakeLists.txt +++ b/samples/python/03_mandelbrot/CMakeLists.txt @@ -1,22 +1,6 @@ -# Copyright (c) 2019-2021 Ben Ashbaugh +# Copyright (c) 2019-2024 Ben Ashbaugh # -# 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. +# SPDX-License-Identifier: MIT add_opencl_python_sample( NUMBER 03 diff --git a/samples/python/03_mandelbrot/mandelbrot.ipynb b/samples/python/03_mandelbrot/mandelbrot.ipynb new file mode 100644 index 0000000..da8b67c --- /dev/null +++ b/samples/python/03_mandelbrot/mandelbrot.ipynb @@ -0,0 +1,321 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "38e0e0ea-6df7-4807-8376-7dfe05f9d24f", + "metadata": { + "tags": [] + }, + "source": [ + "# Mandelbrot Set\n", + "\n", + "### Copyright Information" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "78ca2c6a-2836-4301-a95d-c510b2f67dbd", + "metadata": {}, + "outputs": [], + "source": [ + "# Copyright (c) 2024 Ben Ashbaugh\n", + "#\n", + "# SPDX-License-Identifier: MIT" + ] + }, + { + "cell_type": "markdown", + "id": "63c38e00-e1a1-46dd-b321-7ecef4603d37", + "metadata": { + "tags": [] + }, + "source": [ + "## Sample Purpose\n", + "\n", + "This is a port of the [ISPC Mandelbrot](https://github.com/ispc/ispc/tree/master/examples/mandelbrot) sample.\n", + "It uses an OpenCL kernel to compute a [Mandelbrot set](https://en.wikipedia.org/wiki/Mandelbrot_set) image, which is displayed in this notebook and then written to a BMP file.\n", + "\n", + "This assuredly is not the fastest Mandelbrot kernel on any OpenCL implementation, but it should perform reasonably well - much better than an equivalent serial implementation!\n", + "\n", + "## Sample\n", + "\n", + "To start the sample, we will import pyopencl and a few other packages that this sample uses." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8c0f5462-9f22-4d8d-a899-18e746884daa", + "metadata": {}, + "outputs": [], + "source": [ + "from PIL import Image\n", + "\n", + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "import pyopencl as cl\n", + "import argparse\n", + "import PIL" + ] + }, + { + "cell_type": "markdown", + "id": "2263c509-ccd4-44ae-a243-a78fa047bc23", + "metadata": {}, + "source": [ + "We will then define the size of the image we want to generate and we will write our Mandelbrot kernel.\n", + "Each OpenCL work-item computes one element of the set, or equivalently, one pixel in the output image." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b680426a-ebfa-4f55-bbfb-7748d7509f37", + "metadata": {}, + "outputs": [], + "source": [ + "width = 768\n", + "height = 512\n", + "\n", + "maxIterations = 256\n", + "\n", + "kernelString = \"\"\"\n", + "static inline int mandel(float c_re, float c_im, int count) {\n", + " float z_re = c_re, z_im = c_im;\n", + " int i;\n", + " for (i = 0; i < count; ++i) {\n", + " if (z_re * z_re + z_im * z_im > 4.)\n", + " break;\n", + "\n", + " float new_re = z_re*z_re - z_im*z_im;\n", + " float new_im = 2.f * z_re * z_im;\n", + "\n", + " z_re = c_re + new_re;\n", + " z_im = c_im + new_im;\n", + " }\n", + "\n", + " return i;\n", + "}\n", + "kernel void Mandelbrot(\n", + " float x0, float y0,\n", + " float x1, float y1,\n", + " int width, int height,\n", + " int maxIterations,\n", + " global int* output)\n", + "{\n", + " float dx = (x1 - x0) / width;\n", + " float dy = (y1 - y0) / height;\n", + "\n", + " float x = x0 + get_global_id(0) * dx;\n", + " float y = y0 + get_global_id(1) * dy;\n", + "\n", + " int index = get_global_id(1) * width + get_global_id(0);\n", + " output[index] = mandel(x, y, maxIterations);\n", + "}\n", + "\"\"\"" + ] + }, + { + "cell_type": "markdown", + "id": "a5570031-7517-46be-ac4f-f11da9087875", + "metadata": {}, + "source": [ + "By default, this sample will run on the first platform and device it finds.\n", + "\n", + "To choose a different OpenCL platform, simply change the platform index or device index to a different value." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "227d551e-a088-4e82-90c2-55e368a3ae72", + "metadata": {}, + "outputs": [], + "source": [ + "if __name__ == \"__main__\":\n", + " platformIndex = 0\n", + " deviceIndex = 0\n", + "\n", + " platforms = cl.get_platforms()\n", + " print('Running on platform: ' + platforms[platformIndex].get_info(cl.platform_info.NAME))\n", + "\n", + " devices = platforms[platformIndex].get_devices()\n", + " print('Running on device: ' + devices[deviceIndex].get_info(cl.device_info.NAME))" + ] + }, + { + "cell_type": "markdown", + "id": "40c13aea-05f5-4d9e-b894-7fc68d292ec9", + "metadata": {}, + "source": [ + "As before, we need an OpenCL context to work with and an OpenCL command queue to submit OpenCL commands to the OpenCL device, so create them." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "88b9ad99-871f-4cc5-8ea8-703b674f2658", + "metadata": {}, + "outputs": [], + "source": [ + " context = cl.Context([devices[deviceIndex]])\n", + " commandQueue = cl.CommandQueue(context, devices[deviceIndex])" + ] + }, + { + "cell_type": "markdown", + "id": "2144c0f8-dc69-4f88-8784-83b0173a1ff6", + "metadata": {}, + "source": [ + "Once we have an OpenCL context we can create an OpenCL program with the kernel string we created previously, build it, and get our Mandelbrot kernel." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7fb2e089-5902-4265-b604-d093edf05cca", + "metadata": {}, + "outputs": [], + "source": [ + " program = cl.Program(context, kernelString)\n", + " program.build()\n", + " kernel = program.Mandelbrot" + ] + }, + { + "cell_type": "markdown", + "id": "275055a8-aa23-4132-a599-326070e495fe", + "metadata": {}, + "source": [ + "We can also create a buffer to store our Mandelbrot image." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "499f1c24-1358-475e-910e-89bce37d521e", + "metadata": {}, + "outputs": [], + "source": [ + " deviceMemDst = cl.Buffer(context, cl.mem_flags.ALLOC_HOST_PTR, \n", + " width * height * np.uint32().itemsize)" + ] + }, + { + "cell_type": "markdown", + "id": "4b5db0b6-81a9-4c40-9e25-848fc2ea395e", + "metadata": {}, + "source": [ + "We are now ready to execute our Mandelbrot kernel!\n", + "\n", + "The ND-range for the Mandelbrot kernel will be our image width and height.\n", + "The other kernel arguments will be constants used to compute the Mandelbrot set and the buffer where each work-item will write its results." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a487c65d-4966-4846-903c-3752df6c73e3", + "metadata": {}, + "outputs": [], + "source": [ + " event = kernel(commandQueue, [width, height], None, \n", + " np.float32(-2.0), np.float32(-1.0), np.float32(1.0), np.float32(1.0),\n", + " np.int32(width), np.int32(height), np.int32(maxIterations), deviceMemDst)" + ] + }, + { + "cell_type": "markdown", + "id": "0a28d3ff-e05f-42bc-b55b-adc09d687132", + "metadata": {}, + "source": [ + "All that's left to do now is to get the results of our Mandelbrot kernel.\n", + "We can do this by mapping our output buffer, as usual.\n", + "We will do a small amount of post-processing to make the Mandelbrot output more visually appealing." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "aeed3d87-3821-4653-a47d-9371df02c6cd", + "metadata": {}, + "outputs": [], + "source": [ + " mapped_dst, event = cl.enqueue_map_buffer(commandQueue, deviceMemDst,\n", + " cl.map_flags.READ, \n", + " 0, width * height, np.uint32)\n", + " with mapped_dst.base:\n", + " colors = np.fromiter((240 if x & 1 else 20 for x in mapped_dst), np.uint8)\n", + " image = Image.fromarray(colors.reshape((height, width)))" + ] + }, + { + "cell_type": "markdown", + "id": "7877eaae-938c-4e43-a307-41ba6a43b8d4", + "metadata": {}, + "source": [ + "Now we can display the results." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "82248fc8-efdd-4431-9c4c-0dbc5e32acf6", + "metadata": {}, + "outputs": [], + "source": [ + " plt.imshow(image, cmap=\"gray\")" + ] + }, + { + "cell_type": "markdown", + "id": "3c358810-be72-4630-ba95-5eb7e92b8d3c", + "metadata": {}, + "source": [ + "We can also save a bitmap for future offline viewing." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "97d75ba3-e59e-4c2a-9936-e335f3b3522e", + "metadata": {}, + "outputs": [], + "source": [ + " filename = 'mandelbrot.bmp'\n", + " image.save(filename)\n", + " print('Wrote image file {}'.format(filename))" + ] + }, + { + "cell_type": "markdown", + "id": "403d5bbc-5f1f-4b40-9cea-a54f3c1548ac", + "metadata": {}, + "source": [ + "This is the end of the Mandelbrot sample." + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.12" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/samples/python/03_mandelbrot/mandelbrot.py b/samples/python/03_mandelbrot/mandelbrot.py index e0ffa25..188e368 100644 --- a/samples/python/03_mandelbrot/mandelbrot.py +++ b/samples/python/03_mandelbrot/mandelbrot.py @@ -1,24 +1,8 @@ #!/usr/bin/env python -# Copyright (c) 2019-2021 Ben Ashbaugh +# Copyright (c) 2019-2024 Ben Ashbaugh # -# 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. +# SPDX-License-Identifier: MIT from PIL import Image diff --git a/samples/python/04_julia/CMakeLists.txt b/samples/python/04_julia/CMakeLists.txt index c33bfed..19f2c6b 100644 --- a/samples/python/04_julia/CMakeLists.txt +++ b/samples/python/04_julia/CMakeLists.txt @@ -1,22 +1,6 @@ -# Copyright (c) 2019-2021 Ben Ashbaugh +# Copyright (c) 2019-2024 Ben Ashbaugh # -# 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. +# SPDX-License-Identifier: MIT add_opencl_python_sample( NUMBER 04 diff --git a/samples/python/04_julia/julia.ipynb b/samples/python/04_julia/julia.ipynb new file mode 100644 index 0000000..cbc27d7 --- /dev/null +++ b/samples/python/04_julia/julia.ipynb @@ -0,0 +1,382 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "fe0581a6-da44-41d1-83f7-d593ff325751", + "metadata": {}, + "source": [ + "# Julia Set\n", + "\n", + "### Copyright Information" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8dda25b1-f83f-438d-8629-2874b7d5927b", + "metadata": {}, + "outputs": [], + "source": [ + "# Copyright (c) 2024 Ben Ashbaugh\n", + "#\n", + "# SPDX-License-Identifier: MIT" + ] + }, + { + "cell_type": "markdown", + "id": "7c9179e9-acc9-4b18-bd72-3be7192c1075", + "metadata": {}, + "source": [ + "## Sample Purpose\n", + "\n", + "This is another sample that generates a fractal image.\n", + "It uses an OpenCL kernel to compute a [Julia set](https://en.wikipedia.org/wiki/Julia_set) image, which is displayed in this notebook and then written to a BMP file.\n", + "\n", + "This sample also shows how to time the execution of an OpenCL kernel, and how to pass a different local work group size to change the way the kernel is executed.\n", + "\n", + "## Sample\n", + "\n", + "To start the sample, we will import pyopencl and a few other packages that this sample uses." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f0fcef28-350a-4d24-a9ce-5dcac245055c", + "metadata": {}, + "outputs": [], + "source": [ + "from PIL import Image\n", + "\n", + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "import pyopencl as cl\n", + "import PIL\n", + "import time" + ] + }, + { + "cell_type": "markdown", + "id": "dcdbe54d-cefc-4e7d-a571-ed9f8bbf86cd", + "metadata": {}, + "source": [ + "We will then define the size of the image we want to generate and we will write our Julia kernel.\n", + "Each OpenCL work-item computes one element of the set, or equivalently, one pixel in the output image." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6ae9eed0-301e-49d9-af4b-cd2ab7a9c420", + "metadata": {}, + "outputs": [], + "source": [ + "width = 512\n", + "height = 512\n", + "\n", + "kernelString = \"\"\"\n", + "kernel void Julia( global uchar4* dst, float cr, float ci )\n", + "{\n", + " const float cMinX = -1.5f;\n", + " const float cMaxX = 1.5f;\n", + " const float cMinY = -1.5f;\n", + " const float cMaxY = 1.5f;\n", + "\n", + " const int cWidth = get_global_size(0);\n", + " const int cIterations = 16;\n", + "\n", + " int x = (int)get_global_id(0);\n", + " int y = (int)get_global_id(1);\n", + "\n", + " float a = x * ( cMaxX - cMinX ) / cWidth + cMinX;\n", + " float b = y * ( cMaxY - cMinY ) / cWidth + cMinY;\n", + "\n", + " float result = 0.0f;\n", + " const float thresholdSquared = cIterations * cIterations / 64.0f;\n", + "\n", + " for( int i = 0; i < cIterations; i++ ) {\n", + " float aa = a * a;\n", + " float bb = b * b;\n", + "\n", + " float magnitudeSquared = aa + bb;\n", + " if( magnitudeSquared >= thresholdSquared ) {\n", + " break;\n", + " }\n", + "\n", + " result += 1.0f / cIterations;\n", + " b = 2 * a * b + ci;\n", + " a = aa - bb + cr;\n", + " }\n", + "\n", + " result = max( result, 0.0f );\n", + " result = min( result, 1.0f );\n", + "\n", + " // RGBA\n", + " float4 color = (float4)( result, sqrt(result), 1.0f, 1.0f );\n", + "\n", + " dst[ y * cWidth + x ] = convert_uchar4(color * 255.0f);\n", + "}\n", + "\"\"\"" + ] + }, + { + "cell_type": "markdown", + "id": "82161ee0-8b1c-490c-b456-cec80251bf0c", + "metadata": {}, + "source": [ + "By default, this sample will run on the first platform and device it finds.\n", + "\n", + "To choose a different OpenCL platform, simply change the platform index or device index to a different value." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6f20b587-49a8-4c5e-a202-126883c6ad90", + "metadata": {}, + "outputs": [], + "source": [ + "if __name__ == \"__main__\":\n", + " platformIndex = 0\n", + " deviceIndex = 0\n", + " \n", + " platforms = cl.get_platforms()\n", + " print('Running on platform: ' + platforms[platformIndex].get_info(cl.platform_info.NAME))\n", + "\n", + " devices = platforms[platformIndex].get_devices()\n", + " print('Running on device: ' + devices[deviceIndex].get_info(cl.device_info.NAME))" + ] + }, + { + "cell_type": "markdown", + "id": "aaa1fb1d-c8d3-42dd-a338-c64264edc0c6", + "metadata": {}, + "source": [ + "As before, we need an OpenCL context to work with and an OpenCL command queue to submit OpenCL commands to the OpenCL device, so create them." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b479e2c5-be30-466e-b767-5db92b4b65c3", + "metadata": {}, + "outputs": [], + "source": [ + " context = cl.Context([devices[deviceIndex]])\n", + " commandQueue = cl.CommandQueue(context, devices[deviceIndex])" + ] + }, + { + "cell_type": "markdown", + "id": "40cfbada-35f0-4051-9ab6-a1f540c351f1", + "metadata": {}, + "source": [ + "Once we have an OpenCL context we can create an OpenCL program with the kernel string we created previously, build it, and get our Julia set kernel." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2c5876e7-5fa6-4e80-9b69-fa3fdb68643b", + "metadata": {}, + "outputs": [], + "source": [ + " program = cl.Program(context, kernelString)\n", + " program.build()\n", + " kernel = program.Julia" + ] + }, + { + "cell_type": "markdown", + "id": "66363dd7-f7e7-4bfb-9e66-01540b40e9b5", + "metadata": {}, + "source": [ + "We can also create a buffer to store our Julia set image." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7c2367f3-b3f8-4f32-acfe-6def7f806f49", + "metadata": {}, + "outputs": [], + "source": [ + " deviceMemDst = cl.Buffer(context, cl.mem_flags.ALLOC_HOST_PTR, \n", + " width * height * 4 * np.uint8().itemsize)" + ] + }, + { + "cell_type": "markdown", + "id": "87c17780-8db0-467f-a24c-fbfe187ca692", + "metadata": {}, + "source": [ + "We are now ready to execute our Julia set kernel!\n", + "\n", + "Unlike previous samples, this sample can either use a default `NULL` local work group size, or a specific local work group size." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c4585a5f-a972-4f81-a77c-c69d32834cae", + "metadata": {}, + "outputs": [], + "source": [ + " iterations = 16\n", + " lws = None\n", + "\n", + " print('Executing the kernel {} times'.format(iterations))\n", + " print('Global Work Size = {}'.format([width, height]))\n", + " if lws:\n", + " print('Local Work Size = {}'.format(lws))\n", + " else:\n", + " print('Local Work Size = NULL')" + ] + }, + { + "cell_type": "markdown", + "id": "db2cf35d-8da6-412d-ae60-a4c05eb9c2ee", + "metadata": {}, + "source": [ + "For more stable timing we will execute the kernel multiple times.\n", + "By default, we will execute the kernel 16 times.\n", + "This may not be enough for some very fast devices.\n", + "If the timing is still unstable, please try increasing the number of iterations, or increasing the image size.\n", + "\n", + "Note that we will call `clFinish` to ensure the OpenCL command queue is empty before we start the timer, and we will also call `clFinish` to make sure all commands have finished execution before ending the timer.\n", + "If we do not call `clFinish` in both places then we may measure the cost of commands that were still in the queue before the commands we want to time, or some commands may still be executing." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "144cb5a8-ccc3-4d6c-9097-12319a20e50a", + "metadata": {}, + "outputs": [], + "source": [ + " # Ensure the queue is empty and no processing is happening\n", + " # on the device before starting the timer.\n", + " commandQueue.finish()\n", + "\n", + " cr = -0.123\n", + " ci = 0.745\n", + " \n", + " start = time.perf_counter()\n", + " for i in range(iterations):\n", + " kernel(commandQueue, [width, height], lws,\n", + " deviceMemDst, np.float32(cr), np.float32(ci))\n", + "\n", + " # Ensure all processing is complete before stopping the timer.\n", + " commandQueue.finish()\n", + "\n", + " end = time.perf_counter()\n", + " print('Finished in {} seconds'.format(end - start))" + ] + }, + { + "cell_type": "markdown", + "id": "c65b461d-d95b-41af-baef-4e6bfc9d7a57", + "metadata": {}, + "source": [ + "All that's left to do now is to get the results of our Julia set kernel.\n", + "We can do this by mapping our output buffer, as usual." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7b2039e6-6404-4014-aea2-b4e85eaf54cc", + "metadata": {}, + "outputs": [], + "source": [ + " mapped_dst, event = cl.enqueue_map_buffer(commandQueue, deviceMemDst,\n", + " cl.map_flags.READ, \n", + " 0, width * height, np.uint32)\n", + " with mapped_dst.base:\n", + " (r, g, b, a) = Image.fromarray(mapped_dst.reshape((width, height)), 'RGBA').split()\n", + " image = Image.merge('RGB', (r, g, b))" + ] + }, + { + "cell_type": "markdown", + "id": "9239594c-1049-4e83-b1ff-ba82cb058893", + "metadata": {}, + "source": [ + "Now we can display the results." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7172790b-12f7-47ee-a7c6-ae0cff0dab38", + "metadata": {}, + "outputs": [], + "source": [ + " plt.imshow(image)" + ] + }, + { + "cell_type": "markdown", + "id": "1bccf706-eee5-4682-9856-1705d115e2fa", + "metadata": {}, + "source": [ + "We can also save a bitmap for future offline viewing." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "121bbef3-5fb2-42e9-b60d-c2a75e440fdc", + "metadata": {}, + "outputs": [], + "source": [ + " filename = 'julia.bmp'\n", + " image.save(filename)\n", + " print('Wrote image file {}'.format(filename))" + ] + }, + { + "cell_type": "markdown", + "id": "0d33c7a7-53fc-4370-bacb-1399cf775991", + "metadata": {}, + "source": [ + "Unlike prior samples, this sample can optionally specify a local work size grouping. You can specify a local work size grouping by changing this line from:\n", + "\n", + "```python\n", + "lws = None\n", + "```\n", + "\n", + "to a specific local work size, for example:\n", + "\n", + "```python\n", + "lws = [8, 8]\n", + "```\n", + "\n", + "The local work size grouping is one way to tune an application for an architecture.\n", + "Can you find a local work size grouping that performs better than the implementation-determined grouping?\n", + "Is there a local work size grouping that performs very poorly on your implementation?\n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.12" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/samples/python/04_julia/julia.py b/samples/python/04_julia/julia.py index f487930..69faab3 100644 --- a/samples/python/04_julia/julia.py +++ b/samples/python/04_julia/julia.py @@ -1,24 +1,8 @@ #!/usr/bin/env python -# Copyright (c) 2019-2023 Ben Ashbaugh +# Copyright (c) 2019-2024 Ben Ashbaugh # -# 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. +# SPDX-License-Identifier: MIT from PIL import Image diff --git a/samples/python/CMakeLists.txt b/samples/python/CMakeLists.txt index 6908c34..2f09ee7 100644 --- a/samples/python/CMakeLists.txt +++ b/samples/python/CMakeLists.txt @@ -1,22 +1,6 @@ -# Copyright (c) 2019-2021 Ben Ashbaugh +# Copyright (c) 2019-2024 Ben Ashbaugh # -# 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. +# SPDX-License-Identifier: MIT function(add_opencl_python_sample) set(options ) diff --git a/samples/python/requirements.txt b/samples/python/requirements.txt index 38f243f..9ac1f55 100644 --- a/samples/python/requirements.txt +++ b/samples/python/requirements.txt @@ -1,3 +1,10 @@ +matplotlib<3.4 numpy==1.22.0 pyopencl==2021.1.6 Pillow==10.0.1 + +jupyterlab + +ipython==7.10.* +ipykernel==5.* +