From 7f8d3e60ea2b6c480b06a2a7a8cb21f906f3bdcd Mon Sep 17 00:00:00 2001 From: Sergey Pokhodenko Date: Fri, 19 Nov 2021 18:31:33 +0300 Subject: [PATCH 01/11] Enable device_context support numba-dppy offloading --- dpctl/_sycl_queue_manager.pyx | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/dpctl/_sycl_queue_manager.pyx b/dpctl/_sycl_queue_manager.pyx index 53d5058d04..53bd2228c5 100644 --- a/dpctl/_sycl_queue_manager.pyx +++ b/dpctl/_sycl_queue_manager.pyx @@ -19,7 +19,7 @@ # cython: linetrace=True import logging -from contextlib import contextmanager +from contextlib import contextmanager, nullcontext from .enum_types import backend_type, device_type @@ -210,6 +210,14 @@ cpdef get_current_backend(): return _mgr.get_current_backend() +def _get_registered_context_manager(sycl_queue): + try: + from numba_dppy import get_context_manager + return get_context_manager(sycl_queue) + except: + return nullcontext() + + @contextmanager def device_context(arg): """ @@ -247,7 +255,8 @@ def device_context(arg): ctxt = None try: ctxt = _mgr._set_as_current_queue(arg) - yield ctxt + with _get_registered_context_manager(ctxt): + yield ctxt finally: # Code to release resource if ctxt: From 4ad7ae1b5030d848176f7db6d2ad3ae4c2e48334 Mon Sep 17 00:00:00 2001 From: Oleksandr Pavlyk Date: Fri, 19 Nov 2021 12:16:14 -0600 Subject: [PATCH 02/11] Update dpctl/_sycl_queue_manager.pyx --- dpctl/_sycl_queue_manager.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dpctl/_sycl_queue_manager.pyx b/dpctl/_sycl_queue_manager.pyx index 53bd2228c5..eaf35d850b 100644 --- a/dpctl/_sycl_queue_manager.pyx +++ b/dpctl/_sycl_queue_manager.pyx @@ -214,7 +214,7 @@ def _get_registered_context_manager(sycl_queue): try: from numba_dppy import get_context_manager return get_context_manager(sycl_queue) - except: + except Exception: return nullcontext() From 21cbea6a124be6fd5c3c4a221361428d16b4908b Mon Sep 17 00:00:00 2001 From: Sergey Pokhodenko Date: Sun, 21 Nov 2021 16:24:38 +0300 Subject: [PATCH 03/11] Add nested_context_factories registry --- dpctl/__init__.py | 1 + dpctl/_sycl_queue_manager.pyx | 22 ++++++++++++++++------ 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/dpctl/__init__.py b/dpctl/__init__.py index 80ce781f3b..22262ab4a6 100644 --- a/dpctl/__init__.py +++ b/dpctl/__init__.py @@ -56,6 +56,7 @@ ) from dpctl._sycl_queue_manager import ( device_context, + nested_context_factories, get_current_backend, get_current_device_type, get_current_queue, diff --git a/dpctl/_sycl_queue_manager.pyx b/dpctl/_sycl_queue_manager.pyx index eaf35d850b..35ee9344a7 100644 --- a/dpctl/_sycl_queue_manager.pyx +++ b/dpctl/_sycl_queue_manager.pyx @@ -19,7 +19,7 @@ # cython: linetrace=True import logging -from contextlib import contextmanager, nullcontext +from contextlib import contextmanager, ExitStack from .enum_types import backend_type, device_type @@ -210,12 +210,20 @@ cpdef get_current_backend(): return _mgr.get_current_backend() -def _get_registered_context_manager(sycl_queue): +nested_context_factories = [] + + +def _get_nested_contexts(ctxt): + _help_numba_dppy() + return (factory(ctxt) for factory in nested_context_factories) + + +def _help_numba_dppy(): + """Import numba-dppy for registering nested contexts""" try: - from numba_dppy import get_context_manager - return get_context_manager(sycl_queue) + import numba_dppy except Exception: - return nullcontext() + pass @contextmanager @@ -255,7 +263,9 @@ def device_context(arg): ctxt = None try: ctxt = _mgr._set_as_current_queue(arg) - with _get_registered_context_manager(ctxt): + with ExitStack() as stack: + for nested_context in _get_nested_contexts(ctxt): + stack.enter_context(nested_context) yield ctxt finally: # Code to release resource From 50c9deeeae734902c267b3e62f65e722893891b5 Mon Sep 17 00:00:00 2001 From: Sergey Pokhodenko Date: Sun, 21 Nov 2021 16:34:04 +0300 Subject: [PATCH 04/11] pre-commit --- dpctl/__init__.py | 2 +- dpctl/_sycl_queue_manager.pyx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dpctl/__init__.py b/dpctl/__init__.py index 22262ab4a6..4725146ac2 100644 --- a/dpctl/__init__.py +++ b/dpctl/__init__.py @@ -56,12 +56,12 @@ ) from dpctl._sycl_queue_manager import ( device_context, - nested_context_factories, get_current_backend, get_current_device_type, get_current_queue, get_num_activated_queues, is_in_device_context, + nested_context_factories, set_global_queue, ) diff --git a/dpctl/_sycl_queue_manager.pyx b/dpctl/_sycl_queue_manager.pyx index 35ee9344a7..793e260640 100644 --- a/dpctl/_sycl_queue_manager.pyx +++ b/dpctl/_sycl_queue_manager.pyx @@ -19,7 +19,7 @@ # cython: linetrace=True import logging -from contextlib import contextmanager, ExitStack +from contextlib import ExitStack, contextmanager from .enum_types import backend_type, device_type From 438a643430b4c62d93621c535aed9eddb7c4e5ee Mon Sep 17 00:00:00 2001 From: Sergey Pokhodenko Date: Sun, 21 Nov 2021 16:36:19 +0300 Subject: [PATCH 05/11] pre-commit --- dpctl/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/dpctl/__init__.py b/dpctl/__init__.py index 4725146ac2..efd93f3630 100644 --- a/dpctl/__init__.py +++ b/dpctl/__init__.py @@ -112,6 +112,7 @@ "get_current_queue", "get_num_activated_queues", "is_in_device_context", + "nested_context_factories", "set_global_queue", ] __all__ += [ From 957c5e863d42b23c800291ca14e4b34bc7184fac Mon Sep 17 00:00:00 2001 From: Sergey Pokhodenko Date: Tue, 23 Nov 2021 12:38:54 +0300 Subject: [PATCH 06/11] Add tests for registering nested context factory --- dpctl/tests/test_sycl_queue_manager.py | 53 ++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/dpctl/tests/test_sycl_queue_manager.py b/dpctl/tests/test_sycl_queue_manager.py index 5ff33e09b3..5613874f6a 100644 --- a/dpctl/tests/test_sycl_queue_manager.py +++ b/dpctl/tests/test_sycl_queue_manager.py @@ -17,6 +17,8 @@ """Defines unit test cases for the SyclQueueManager class. """ +import contextlib + import pytest import dpctl @@ -156,3 +158,54 @@ def test_get_current_backend(): dpctl.set_global_queue("gpu") elif has_cpu(): dpctl.set_global_queue("cpu") + + +def test_nested_context_factory_is_empty_list(): + assert isinstance(dpctl.nested_context_factories, list) + assert not dpctl.nested_context_factories + + +@contextlib.contextmanager +def _register_nested_context_factory(factory): + dpctl.nested_context_factories.append(factory) + yield + dpctl.nested_context_factories.remove(factory) + + +def test_register_nested_context_factory_context(): + def factory(): + pass + + with _register_nested_context_factory(factory): + assert factory in dpctl.nested_context_factories + + assert isinstance(dpctl.nested_context_factories, list) + assert not dpctl.nested_context_factories + + +@pytest.mark.skipif(not has_gpu(), reason="No OpenCL GPU queues available") +def test_device_context_activates_nested_context(): + in_context = False + factory_called = False + + @contextlib.contextmanager + def context(): + nonlocal in_context + old, in_context = in_context, True + yield + in_context = old + + def factory(_): + nonlocal factory_called + factory_called = True + return context() + + with _register_nested_context_factory(factory): + assert not factory_called + assert not in_context + + with dpctl.device_context("opencl:gpu:0"): + assert factory_called + assert in_context + + assert not in_context From 54a023c01154e612c4b83e3231c7264518d22e6c Mon Sep 17 00:00:00 2001 From: Sergey Pokhodenko Date: Tue, 23 Nov 2021 17:45:19 +0300 Subject: [PATCH 07/11] Add docs for registering nested contexts --- dpctl/_sycl_queue_manager.pyx | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/dpctl/_sycl_queue_manager.pyx b/dpctl/_sycl_queue_manager.pyx index 793e260640..c814b7286a 100644 --- a/dpctl/_sycl_queue_manager.pyx +++ b/dpctl/_sycl_queue_manager.pyx @@ -238,6 +238,9 @@ def device_context(arg): the context manager's scope. The yielded queue is removed as the currently usable queue on exiting the context manager. + You can register context factory in the list of factories. + This context manager uses context factories to create and activate nested contexts. + Args: queue_str (str) : A string corresponding to the DPC++ filter selector. @@ -259,6 +262,18 @@ def device_context(arg): with dpctl.device_context("level0:gpu:0"): pass + The following example registers nested context factory: + + .. code-block:: python + + import dctl + + def factory(sycl_queue): + ... + return context + + dpctl.nested_context_factories.append(factory) + """ ctxt = None try: From 087e31fd027833111df6d42cb4184fc23946734c Mon Sep 17 00:00:00 2001 From: Sergey Pokhodenko Date: Tue, 23 Nov 2021 17:49:49 +0300 Subject: [PATCH 08/11] Update CHANGELOG --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1a31f3801b..31f950be76 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [0.11.2] - 11/xx/2021 +### Added +- Extending `dpctl.device_context` with nested contexts (#678) + ## Fixed - Fixed issue #649 about incorrect behavior of `.T` method on sliced arrays (#653) From 6ba489e625bec5681bef81fe6f5dc7bc7ca4f1b1 Mon Sep 17 00:00:00 2001 From: Sergey Pokhodenko Date: Wed, 24 Nov 2021 12:56:08 +0300 Subject: [PATCH 09/11] Use `[Unreleased]` in CHANGELOG --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 31f950be76..dfe3906e48 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,8 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [Unreleased] + ## [0.11.2] - 11/xx/2021 ### Added From bfb133ff34a63a227561a24152cf63617da38b85 Mon Sep 17 00:00:00 2001 From: Sergey Pokhodenko Date: Wed, 24 Nov 2021 13:36:09 +0300 Subject: [PATCH 10/11] More rainy day tests --- dpctl/tests/test_sycl_queue_manager.py | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/dpctl/tests/test_sycl_queue_manager.py b/dpctl/tests/test_sycl_queue_manager.py index 5613874f6a..a0c5260b67 100644 --- a/dpctl/tests/test_sycl_queue_manager.py +++ b/dpctl/tests/test_sycl_queue_manager.py @@ -168,8 +168,10 @@ def test_nested_context_factory_is_empty_list(): @contextlib.contextmanager def _register_nested_context_factory(factory): dpctl.nested_context_factories.append(factory) - yield - dpctl.nested_context_factories.remove(factory) + try: + yield + finally: + dpctl.nested_context_factories.remove(factory) def test_register_nested_context_factory_context(): @@ -209,3 +211,19 @@ def factory(_): assert in_context assert not in_context + + +@pytest.mark.parametrize( + "factory, exception, match", + [ + (True, TypeError, "object is not callable"), + (lambda x: None, AttributeError, "no attribute '__exit__'"), + ], +) +def test_nested_context_factory_exception_if_wrong_factory( + factory, exception, match +): + with pytest.raises(exception, match=match): + with _register_nested_context_factory(factory): + with dpctl.device_context("opencl:gpu:0"): + pass From f964e22aae662428187944e92796cdb07e5594b8 Mon Sep 17 00:00:00 2001 From: Sergey Pokhodenko Date: Wed, 24 Nov 2021 13:52:05 +0300 Subject: [PATCH 11/11] Use CPU for tests --- dpctl/tests/test_sycl_queue_manager.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/dpctl/tests/test_sycl_queue_manager.py b/dpctl/tests/test_sycl_queue_manager.py index a0c5260b67..ae7c75cbbd 100644 --- a/dpctl/tests/test_sycl_queue_manager.py +++ b/dpctl/tests/test_sycl_queue_manager.py @@ -185,7 +185,7 @@ def factory(): assert not dpctl.nested_context_factories -@pytest.mark.skipif(not has_gpu(), reason="No OpenCL GPU queues available") +@pytest.mark.skipif(not has_cpu(), reason="No OpenCL CPU queues available") def test_device_context_activates_nested_context(): in_context = False factory_called = False @@ -206,13 +206,14 @@ def factory(_): assert not factory_called assert not in_context - with dpctl.device_context("opencl:gpu:0"): + with dpctl.device_context("opencl:cpu:0"): assert factory_called assert in_context assert not in_context +@pytest.mark.skipif(not has_cpu(), reason="No OpenCL CPU queues available") @pytest.mark.parametrize( "factory, exception, match", [ @@ -225,5 +226,5 @@ def test_nested_context_factory_exception_if_wrong_factory( ): with pytest.raises(exception, match=match): with _register_nested_context_factory(factory): - with dpctl.device_context("opencl:gpu:0"): + with dpctl.device_context("opencl:cpu:0"): pass