Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added
* `dpctl.SyclQueue.copy` and `dpctl.SyclQueue.copy_async` methods [gh-2273](https://github.com/IntelPython/dpctl/pull/2273)
* Added a number of `sycl::device` info queries to `dpctl.SyclDevice` [gh-2324](https://github.com/IntelPython/dpctl/pull/2324)
* Added `sycl::info::context` queries `sycl_platform`, `atomic_memory_order_capabilities`, `atomic_fence_order_capabilities`, `atomic_memory_scope_capabilities`, and `atomic_fence_scope_capabilities` to `dpctl.SyclContext` [gh-2354](https://github.com/IntelPython/dpctl/pull/2354)

### Changed
* Bump minimum NumPy version to 1.26 [gh-2192](https://github.com/IntelPython/dpctl/pull/2192)
Expand Down
14 changes: 14 additions & 0 deletions dpctl/_backend.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -512,6 +512,20 @@ cdef extern from "syclinterface/dpctl_sycl_context_interface.h":
cdef size_t DPCTLContext_Hash(const DPCTLSyclContextRef CRef)
cdef _backend_type DPCTLContext_GetBackend(const DPCTLSyclContextRef)
cdef void DPCTLContext_Delete(DPCTLSyclContextRef CtxRef)
cdef DPCTLSyclPlatformRef DPCTLContext_GetPlatform(
const DPCTLSyclContextRef CRef)
cdef int *DPCTLContext_GetAtomicMemoryOrderCapabilities(
const DPCTLSyclContextRef CRef,
size_t *res_len)
cdef int *DPCTLContext_GetAtomicFenceOrderCapabilities(
const DPCTLSyclContextRef CRef,
size_t *res_len)
cdef int *DPCTLContext_GetAtomicMemoryScopeCapabilities(
const DPCTLSyclContextRef CRef,
size_t *res_len)
cdef int *DPCTLContext_GetAtomicFenceScopeCapabilities(
const DPCTLSyclContextRef CRef,
size_t *res_len)


cdef extern from "syclinterface/dpctl_sycl_kernel_bundle_interface.h":
Expand Down
141 changes: 141 additions & 0 deletions dpctl/_sycl_context.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -34,20 +34,30 @@ from ._backend cimport ( # noqa: E211
DPCTLContext_CreateFromDevices,
DPCTLContext_Delete,
DPCTLContext_DeviceCount,
DPCTLContext_GetAtomicFenceOrderCapabilities,
DPCTLContext_GetAtomicFenceScopeCapabilities,
DPCTLContext_GetAtomicMemoryOrderCapabilities,
DPCTLContext_GetAtomicMemoryScopeCapabilities,
DPCTLContext_GetDevices,
DPCTLContext_GetPlatform,
DPCTLContext_Hash,
DPCTLDeviceMgr_GetCachedContext,
DPCTLDeviceVector_CreateFromArray,
DPCTLDeviceVector_Delete,
DPCTLDeviceVector_GetAt,
DPCTLDeviceVector_Size,
DPCTLDeviceVectorRef,
DPCTLInt_Array_Delete,
DPCTLSyclContextRef,
DPCTLSyclDeviceRef,
DPCTLSyclPlatformRef,
error_handler_callback,
)
from ._sycl_device cimport SyclDevice
from ._sycl_device import SyclDeviceCreationError
from ._sycl_platform cimport SyclPlatform

from .enum_types import memory_order, memory_scope

__all__ = [
"SyclContext",
Expand Down Expand Up @@ -84,6 +94,33 @@ cdef void _init_helper(_SyclContext context, DPCTLSyclContextRef CRef):
context._ctxt_ref = CRef


cdef tuple _to_enum_tuple(
int *arr, size_t arr_len, object enum_type, str descr
):
"""
Converts an array of DPCTL enum values into a tuple of ``enum_type``s

The DPCTL enums reserve value 0 for an unrecognized value, so a DPCTL
value of ``n`` corresponds to the ``n``-th member of ``enum_type``, whose
members are numbered from 1 by ``enum.auto()``.
"""
cdef list res = []
cdef size_t i

if arr is NULL:
return ()
try:
for i in range(arr_len):
try:
res.append(enum_type(arr[i]))
except ValueError:
raise RuntimeError(f"Unrecognized {descr} reported")
finally:
DPCTLInt_Array_Delete(arr)

return tuple(res)


cdef class _SyclContext:
""" Data owner for SyclContext
"""
Expand Down Expand Up @@ -442,6 +479,110 @@ cdef class SyclContext(_SyclContext):
"associated with this context"
)

@property
def sycl_platform(self):
""" Returns the platform associated with this context.

Returns:
:class:`dpctl.SyclPlatform`:
The platform associated with this context.

Raises:
RuntimeError:
If ``DPCTLContext_GetPlatform`` fails to return a platform.
"""
cdef DPCTLSyclPlatformRef PRef = (
DPCTLContext_GetPlatform(self.get_context_ref())
)
if (PRef == NULL):
raise RuntimeError("Could not get platform for context.")
else:
return SyclPlatform._create(PRef)

@property
def atomic_memory_order_capabilities(self):
""" Returns a tuple of :class:`dpctl.memory_order` describing atomic
memory order capabilities of the context.

Returns:
Tuple[:class:`dpctl.memory_order`]:
Tuple of supported memory orders.

Raises:
RuntimeError:
If an unrecognized memory order is given by runtime.
"""
cdef int *arr = NULL
cdef size_t arr_len = 0

arr = DPCTLContext_GetAtomicMemoryOrderCapabilities(
self.get_context_ref(), &arr_len
)
return _to_enum_tuple(arr, arr_len, memory_order, "memory order")

@property
def atomic_fence_order_capabilities(self):
""" Returns a tuple of :class:`dpctl.memory_order` describing atomic
fence order capabilities of the context.

Returns:
Tuple[:class:`dpctl.memory_order`]:
Tuple of supported fence orders.

Raises:
RuntimeError:
If an unrecognized memory order is given by runtime.
"""
cdef int *arr = NULL
cdef size_t arr_len = 0

arr = DPCTLContext_GetAtomicFenceOrderCapabilities(
self.get_context_ref(), &arr_len
)
return _to_enum_tuple(arr, arr_len, memory_order, "memory order")

@property
def atomic_memory_scope_capabilities(self):
""" Returns a tuple of :class:`dpctl.memory_scope` describing atomic
memory scope capabilities of the context.

Returns:
Tuple[:class:`dpctl.memory_scope`]:
Tuple of supported memory scopes.

Raises:
RuntimeError:
If an unrecognized memory scope is given by runtime.
"""
cdef int *arr = NULL
cdef size_t arr_len = 0

arr = DPCTLContext_GetAtomicMemoryScopeCapabilities(
self.get_context_ref(), &arr_len
)
return _to_enum_tuple(arr, arr_len, memory_scope, "memory scope")

@property
def atomic_fence_scope_capabilities(self):
""" Returns a tuple of :class:`dpctl.memory_scope` describing atomic
fence scope capabilities of the context.

Returns:
Tuple[:class:`dpctl.memory_scope`]:
Tuple of supported fence scopes.

Raises:
RuntimeError:
If an unrecognized memory scope is given by runtime.
"""
cdef int *arr = NULL
cdef size_t arr_len = 0

arr = DPCTLContext_GetAtomicFenceScopeCapabilities(
self.get_context_ref(), &arr_len
)
return _to_enum_tuple(arr, arr_len, memory_scope, "memory scope")

@property
def __name__(self):
return "SyclContext"
Expand Down
68 changes: 68 additions & 0 deletions dpctl/tests/test_sycl_context.py
Original file line number Diff line number Diff line change
Expand Up @@ -273,3 +273,71 @@ def test_multi_device_different_platforms():
dpctl.SyclContext(devs)
else:
pytest.skip("Insufficient amount of available devices for this test")


def test_context_sycl_platform(valid_filter):
"""
Test that :attr:`dpctl.SyclContext.sycl_platform` returns the
platform shared by the context's devices.
"""
try:
ctx = dpctl.SyclContext(valid_filter)
except dpctl.SyclContextCreationError:
pytest.skip()
plat = ctx.sycl_platform
assert isinstance(plat, dpctl.SyclPlatform)
for d in ctx.get_devices():
assert d.sycl_platform == plat


def test_context_atomic_memory_order_capabilities(valid_filter):
try:
ctx = dpctl.SyclContext(valid_filter)
except dpctl.SyclContextCreationError:
pytest.skip()
caps = ctx.atomic_memory_order_capabilities
assert isinstance(caps, tuple)
assert all(isinstance(m, dpctl.memory_order) for m in caps)
# SYCL 2020 requires at least these capabilities
assert dpctl.memory_order.relaxed in caps
# capabilities of the context must be a subset of every device
for d in ctx.get_devices():
assert set(caps).issubset(set(d.atomic_memory_order_capabilities))


def test_context_atomic_fence_order_capabilities(valid_filter):
try:
ctx = dpctl.SyclContext(valid_filter)
except dpctl.SyclContextCreationError:
pytest.skip()
caps = ctx.atomic_fence_order_capabilities
assert isinstance(caps, tuple)
assert all(isinstance(m, dpctl.memory_order) for m in caps)
for d in ctx.get_devices():
assert set(caps).issubset(set(d.atomic_fence_order_capabilities))


def test_context_atomic_memory_scope_capabilities(valid_filter):
try:
ctx = dpctl.SyclContext(valid_filter)
except dpctl.SyclContextCreationError:
pytest.skip()
caps = ctx.atomic_memory_scope_capabilities
assert isinstance(caps, tuple)
assert all(isinstance(m, dpctl.memory_scope) for m in caps)
# SYCL 2020 requires at least these capabilities
assert dpctl.memory_scope.work_group in caps
for d in ctx.get_devices():
assert set(caps).issubset(set(d.atomic_memory_scope_capabilities))


def test_context_atomic_fence_scope_capabilities(valid_filter):
try:
ctx = dpctl.SyclContext(valid_filter)
except dpctl.SyclContextCreationError:
pytest.skip()
caps = ctx.atomic_fence_scope_capabilities
assert isinstance(caps, tuple)
assert all(isinstance(m, dpctl.memory_scope) for m in caps)
for d in ctx.get_devices():
assert set(caps).issubset(set(d.atomic_fence_scope_capabilities))
Original file line number Diff line number Diff line change
Expand Up @@ -161,4 +161,73 @@ void DPCTLContext_Delete(__dpctl_take DPCTLSyclContextRef CtxRef);
DPCTL_API
size_t DPCTLContext_Hash(__dpctl_keep DPCTLSyclContextRef CtxRef);

/*!
* @brief Wrapper over
* context.get_info<info::context::platform>().
*
* @param CtxRef Opaque pointer to a ``sycl::context``.
* @return Returns an opaque pointer to the ``sycl::platform`` associated with
* the context.
* @ingroup ContextInterface
*/
DPCTL_API
__dpctl_give DPCTLSyclPlatformRef
DPCTLContext_GetPlatform(__dpctl_keep const DPCTLSyclContextRef CtxRef);

/*!
* @brief Wrapper over
* context.get_info<info::context::atomic_memory_order_capabilities>().
*
* @param CtxRef Opaque pointer to a ``sycl::context``.
* @param res_len Populated with size of the returned array.
* @return Returns an array of DPCTLMemoryOrderType values.
* @ingroup ContextInterface
*/
DPCTL_API
__dpctl_give int *DPCTLContext_GetAtomicMemoryOrderCapabilities(
__dpctl_keep const DPCTLSyclContextRef CtxRef,
size_t *res_len);

/*!
* @brief Wrapper over
* context.get_info<info::context::atomic_fence_order_capabilities>().
*
* @param CtxRef Opaque pointer to a ``sycl::context``.
* @param res_len Populated with size of the returned array.
* @return Returns an array of DPCTLMemoryOrderType values.
* @ingroup ContextInterface
*/
DPCTL_API
__dpctl_give int *DPCTLContext_GetAtomicFenceOrderCapabilities(
__dpctl_keep const DPCTLSyclContextRef CtxRef,
size_t *res_len);

/*!
* @brief Wrapper over
* context.get_info<info::context::atomic_memory_scope_capabilities>().
*
* @param CtxRef Opaque pointer to a ``sycl::context``.
* @param res_len Populated with size of the returned array.
* @return Returns an array of DPCTLMemoryScopeType values.
* @ingroup ContextInterface
*/
DPCTL_API
__dpctl_give int *DPCTLContext_GetAtomicMemoryScopeCapabilities(
__dpctl_keep const DPCTLSyclContextRef CtxRef,
size_t *res_len);

/*!
* @brief Wrapper over
* context.get_info<info::context::atomic_fence_scope_capabilities>().
*
* @param CtxRef Opaque pointer to a ``sycl::context``.
* @param res_len Populated with size of the returned array.
* @return Returns an array of DPCTLMemoryScopeType values.
* @ingroup ContextInterface
*/
DPCTL_API
__dpctl_give int *DPCTLContext_GetAtomicFenceScopeCapabilities(
__dpctl_keep const DPCTLSyclContextRef CtxRef,
size_t *res_len);

DPCTL_C_EXTERN_C_END
Loading
Loading