From 19345492cda6fc30ed43904e32221fb8a16c297c Mon Sep 17 00:00:00 2001 From: Andreas Kloeckner Date: Tue, 12 Feb 2019 15:46:28 -0600 Subject: [PATCH 1/7] Refactor option treatment, don't pass include dir options to linker (Closes #13 on Gitlab) --- pyopencl/__init__.py | 120 +++++++++++++++++++++++++------------------ 1 file changed, 70 insertions(+), 50 deletions(-) diff --git a/pyopencl/__init__.py b/pyopencl/__init__.py index 7f77154f..810ff00e 100644 --- a/pyopencl/__init__.py +++ b/pyopencl/__init__.py @@ -265,6 +265,66 @@ def _find_pyopencl_include_path(): # }}} +# {{{ build option munging + +def _split_options_if_necessary(options): + if isinstance(options, six.string_types): + import shlex + if six.PY2: + # shlex.split takes bytes (py2 str) on py2 + if isinstance(options, six.text_type): + options = options.encode("utf-8") + else: + # shlex.split takes unicode (py3 str) on py3 + if isinstance(options, six.binary_type): + options = options.decode("utf-8") + + options = shlex.split(options) + + return options + + +def _find_include_path(options): + def unquote(path): + if path.startswith('"') and path.endswith('"'): + return path[1:-1] + else: + return path + + include_path = ["."] + + option_idx = 0 + while option_idx < len(options): + option = options[option_idx].strip() + if option.startswith("-I") or option.startswith("/I"): + if len(option) == 2: + if option_idx+1 < len(options): + include_path.append(unquote(options[option_idx+1])) + option_idx += 2 + else: + include_path.append(unquote(option[2:].lstrip())) + option_idx += 1 + else: + option_idx += 1 + + # }}} + + return include_path + + +def _options_to_bytestring(options): + def encode_if_necessary(s): + if isinstance(s, six.text_type): + return s.encode("utf-8") + else: + return s + + return b" ".join(encode_if_necessary(s) for s in options) + + +# }}} + + # {{{ Program (wrapper around _Program, adds caching support) _DEFAULT_BUILD_OPTIONS = [] @@ -390,25 +450,8 @@ class Program(object): # {{{ build @classmethod - def _process_build_options(cls, context, options): - if isinstance(options, six.string_types): - import shlex - if six.PY2: - # shlex.split takes bytes (py2 str) on py2 - if isinstance(options, six.text_type): - options = options.encode("utf-8") - else: - # shlex.split takes unicode (py3 str) on py3 - if isinstance(options, six.binary_type): - options = options.decode("utf-8") - - options = shlex.split(options) - - def encode_if_necessary(s): - if isinstance(s, six.text_type): - return s.encode("utf-8") - else: - return s + def _process_build_options(cls, context, options, _add_include_path=False): + options = _split_options_if_necessary(options) options = (options + _DEFAULT_BUILD_OPTIONS @@ -421,35 +464,9 @@ class Program(object): if forced_options: options = options + forced_options.split() - # {{{ find include path - - def unquote(path): - if path.startswith('"') and path.endswith('"'): - return path[1:-1] - else: - return path - - include_path = ["."] - - option_idx = 0 - while option_idx < len(options): - option = options[option_idx].strip() - if option.startswith("-I") or option.startswith("/I"): - if len(option) == 2: - if option_idx+1 < len(options): - include_path.append(unquote(options[option_idx+1])) - option_idx += 2 - else: - include_path.append(unquote(option[2:].lstrip())) - option_idx += 1 - else: - option_idx += 1 - - # }}} - - options = [encode_if_necessary(s) for s in options] - - return b" ".join(options), include_path + return ( + _options_to_bytestring(options), + _find_include_path(options)) def build(self, options=[], devices=None, cache_dir=None): options_bytes, include_path = self._process_build_options( @@ -559,8 +576,11 @@ def create_program_with_built_in_kernels(context, devices, kernel_names): context, devices, kernel_names)) -def link_program(context, programs, options=[], devices=None): - options_bytes, _ = Program._process_build_options(context, options) +def link_program(context, programs, options=None, devices=None): + if options is None: + options = [] + + options_bytes = _options_to_bytestring(_split_options_if_necessary(options)) programs = [prg._get_prg() for prg in programs] raw_prg = _Program.link(context, programs, options_bytes, devices) return Program(raw_prg) -- GitLab From 598f3dcc42001c020845efab01dfed50f26d20f1 Mon Sep 17 00:00:00 2001 From: Andreas Kloeckner Date: Tue, 12 Feb 2019 15:47:37 -0600 Subject: [PATCH 2/7] Enable AMD GPU CI --- .gitlab-ci.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index ec1495d7..92a000fc 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -101,7 +101,7 @@ Python 3 K40: Python 3 AMD GPU: script: - export PY_EXE=python3 - - export PYOPENCL_TEST=amd:fiji + - export PYOPENCL_TEST=amd:gfx803 - export EXTRA_INSTALL="pybind11 numpy mako" # https://andreask.cs.illinois.edu/MachineShop/UserNotes @@ -109,7 +109,6 @@ Python 3 AMD GPU: - curl -L -O -k https://gitlab.tiker.net/inducer/ci-support/raw/master/build-and-test-py-project.sh - ". ./build-and-test-py-project.sh" - allow_failure: true tags: - python3 - amd-fiji -- GitLab From 2143f488bbb6bd11b1fd6426f48954992802793a Mon Sep 17 00:00:00 2001 From: Andreas Kloeckner Date: Tue, 12 Feb 2019 16:19:52 -0600 Subject: [PATCH 3/7] Wrap clCreateProgramWithIL --- pyopencl/__init__.py | 6 ++++-- src/wrap_cl.hpp | 31 ++++++++++++++++++++++++++++++- src/wrap_cl_part_2.cpp | 5 +++++ 3 files changed, 39 insertions(+), 3 deletions(-) diff --git a/pyopencl/__init__.py b/pyopencl/__init__.py index 810ff00e..2c673fda 100644 --- a/pyopencl/__init__.py +++ b/pyopencl/__init__.py @@ -370,9 +370,9 @@ class Program(object): from pyopencl.tools import is_spirv if is_spirv(source): - # no caching in SPIR-V case + # FIXME no caching in SPIR-V case self._context = context - self._prg = _cl._Program(context, source) + self._prg = _cl._create_program_with_il(context, source) return import sys @@ -720,6 +720,8 @@ def _add_functionality(): build_type = "From-source build" elif self.kind() == program_kind.BINARY: build_type = "From-binary build" + elif self.kind() == program_kind.IL: + build_type = "From-IL build" else: build_type = "Build" diff --git a/src/wrap_cl.hpp b/src/wrap_cl.hpp index 145c0b9c..4892e915 100644 --- a/src/wrap_cl.hpp +++ b/src/wrap_cl.hpp @@ -3768,7 +3768,7 @@ namespace pyopencl class program : noncopyable { public: - enum program_kind_type { KND_UNKNOWN, KND_SOURCE, KND_BINARY }; + enum program_kind_type { KND_UNKNOWN, KND_SOURCE, KND_BINARY, KND_IL }; private: cl_program m_program; @@ -4106,6 +4106,35 @@ namespace pyopencl +#if (PYOPENCL_CL_VERSION >= 0x2010) + inline + program *create_program_with_il( + context &ctx, + std::string const &src) + { + cl_int status_code; + PYOPENCL_PRINT_CALL_TRACE("clCreateProgramWithIL"); + cl_program result = clCreateProgramWithIL( + ctx.data(), src.c_str(), src.size(), &status_code); + if (status_code != CL_SUCCESS) + throw pyopencl::error("clCreateProgramWithIL", status_code); + + try + { + return new program(result, false, program::KND_IL); + } + catch (...) + { + clReleaseProgram(result); + throw; + } + } +#endif + + + + + #if PYOPENCL_CL_VERSION >= 0x1020 inline program *link_program( diff --git a/src/wrap_cl_part_2.cpp b/src/wrap_cl_part_2.cpp index edef9ab7..22d9f3c1 100644 --- a/src/wrap_cl_part_2.cpp +++ b/src/wrap_cl_part_2.cpp @@ -351,6 +351,7 @@ void pyopencl_expose_part_2(py::module &m) .value("UNKNOWN", cls::KND_UNKNOWN) .value("SOURCE", cls::KND_SOURCE) .value("BINARY", cls::KND_BINARY) + .value("IL", cls::KND_IL) ; py::class_(m, "_Program", py::dynamic_attr()) @@ -405,6 +406,10 @@ void pyopencl_expose_part_2(py::module &m) ; } +#if (PYOPENCL_CL_VERSION >= 0x2010) + m.def("_create_program_with_il", create_program_with_il); +#endif + #if PYOPENCL_CL_VERSION >= 0x1020 m.def("unload_platform_compiler", unload_platform_compiler); #endif -- GitLab From 2867d43117f595f4ace43630fbd6382322444752 Mon Sep 17 00:00:00 2001 From: Andreas Kloeckner Date: Tue, 12 Feb 2019 16:20:15 -0600 Subject: [PATCH 4/7] Skip SPIR-V test if no kernels result on AMD --- test/test_wrapper.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/test/test_wrapper.py b/test/test_wrapper.py index ee3219e9..24bcc938 100644 --- a/test/test_wrapper.py +++ b/test/test_wrapper.py @@ -918,8 +918,8 @@ def test_spirv(ctx_factory): if (ctx._get_cl_version() < (2, 1) or cl.get_cl_header_version() < (2, 1)): - from pytest import skip - skip("SPIR-V program creation only available in OpenCL 2.1 and higher") + pytest.skip("SPIR-V program creation only available " + "in OpenCL 2.1 and higher") n = 50000 @@ -930,7 +930,10 @@ def test_spirv(ctx_factory): with open("add-vectors-%d.spv" % queue.device.address_bits, "rb") as spv_file: spv = spv_file.read() - prg = cl.Program(ctx, spv) + prg = cl.Program(ctx, spv).build() + if (not prg.all_kernels() + and queue.device.platform.name.startswith("AMD Accelerated")): + pytest.skip("SPIR-V program creation on AMD did not result in any kernels") prg.sum(queue, a_dev.shape, None, a_dev.data, b_dev.data, dest_dev.data) -- GitLab From 60d9c49f417579a06e4f12ff2fe2dffd0ebeb904 Mon Sep 17 00:00:00 2001 From: Andreas Kloeckner Date: Tue, 12 Feb 2019 16:37:03 -0600 Subject: [PATCH 5/7] SVM fixes --- pyopencl/__init__.py | 11 +++++++---- src/wrap_cl_part_2.cpp | 2 +- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/pyopencl/__init__.py b/pyopencl/__init__.py index 2c673fda..5f92e136 100644 --- a/pyopencl/__init__.py +++ b/pyopencl/__init__.py @@ -1692,10 +1692,11 @@ def enqueue_copy(queue, dest, src, **kwargs): elif get_cl_header_version() >= (2, 0) and isinstance(dest, SVM): # to SVM - if isinstance(src, SVM): - src = src.mem + if not isinstance(src, SVM): + src = SVM(src) - return _cl._enqueue_svm_memcpy(queue, dest.mem, src, **kwargs) + is_blocking = kwargs.pop("is_blocking", True) + return _cl._enqueue_svm_memcpy(queue, is_blocking, dest, src, **kwargs) else: # assume to-host @@ -1723,7 +1724,9 @@ def enqueue_copy(queue, dest, src, **kwargs): elif isinstance(src, SVM): # from svm # dest is not a SVM instance, otherwise we'd be in the branch above - return _cl._enqueue_svm_memcpy(queue, dest, src.mem, **kwargs) + is_blocking = kwargs.pop("is_blocking", True) + return _cl._enqueue_svm_memcpy( + queue, is_blocking, SVM(dest), src, **kwargs) else: # assume from-host raise TypeError("enqueue_copy cannot perform host-to-host transfers") diff --git a/src/wrap_cl_part_2.cpp b/src/wrap_cl_part_2.cpp index 22d9f3c1..4ef6afca 100644 --- a/src/wrap_cl_part_2.cpp +++ b/src/wrap_cl_part_2.cpp @@ -284,7 +284,7 @@ void pyopencl_expose_part_2(py::module &m) ; } - m.def("_enqueue_svm_memcpyw", enqueue_svm_memcpy, + m.def("_enqueue_svm_memcpy", enqueue_svm_memcpy, py::arg("queue"), py::arg("is_blocking"), py::arg("dst"), -- GitLab From 532b76278a9b6ea05736019e6b446d4ebc5a04a7 Mon Sep 17 00:00:00 2001 From: Andreas Kloeckner Date: Tue, 12 Feb 2019 16:37:20 -0600 Subject: [PATCH 6/7] Skip coarse-grain SVM test on AMD for now --- test/test_wrapper.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/test_wrapper.py b/test/test_wrapper.py index 24bcc938..dd5bd976 100644 --- a/test/test_wrapper.py +++ b/test/test_wrapper.py @@ -957,6 +957,10 @@ def test_coarse_grain_svm(ctx_factory): if ("AMD" in dev.platform.name and dev.type & cl.device_type.CPU): pytest.xfail("AMD CPU doesn't do coarse-grain SVM") + if ("AMD" in dev.platform.name + and dev.type & cl.device_type.GPU + ): + pytest.xfail("AMD GPU crashes on SVM unmap") n = 3000 svm_ary = cl.SVM(cl.csvm_empty(ctx, (n,), np.float32, alignment=64)) -- GitLab From b54d09c32dae3942f5d9affb2508b6d8fa739a06 Mon Sep 17 00:00:00 2001 From: Andreas Kloeckner Date: Tue, 12 Feb 2019 16:46:50 -0600 Subject: [PATCH 7/7] Placate Flake8 --- test/test_wrapper.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/test_wrapper.py b/test/test_wrapper.py index dd5bd976..9776b032 100644 --- a/test/test_wrapper.py +++ b/test/test_wrapper.py @@ -958,8 +958,7 @@ def test_coarse_grain_svm(ctx_factory): and dev.type & cl.device_type.CPU): pytest.xfail("AMD CPU doesn't do coarse-grain SVM") if ("AMD" in dev.platform.name - and dev.type & cl.device_type.GPU - ): + and dev.type & cl.device_type.GPU): pytest.xfail("AMD GPU crashes on SVM unmap") n = 3000 -- GitLab