diff --git a/conda-recipe/run_test.bat b/conda-recipe/run_test.bat index 0d7f07db97..2154d564b2 100644 --- a/conda-recipe/run_test.bat +++ b/conda-recipe/run_test.bat @@ -1,15 +1,7 @@ -call "%ONEAPI_ROOT%\compiler\latest\env\vars.bat" -if errorlevel 1 ( - echo "oneAPI compiler activation failed%" - exit /b 1 -) -REM conda uses %ERRORLEVEL% but FPGA scripts can set it. So it should be reseted. -set ERRORLEVEL= - @echo on "%PYTHON%" -c "import dpctl" if errorlevel 1 exit 1 -pytest -q -ra --disable-warnings --pyargs dpctl -vv +python -m pytest -q -ra --disable-warnings --pyargs dpctl -vv if errorlevel 1 exit 1 diff --git a/conda-recipe/run_test.sh b/conda-recipe/run_test.sh index c0ecfec7e3..01cbba54b4 100644 --- a/conda-recipe/run_test.sh +++ b/conda-recipe/run_test.sh @@ -2,8 +2,5 @@ set -e -# Suppress error b/c it could fail on Ubuntu 18.04 -source ${ONEAPI_ROOT}/compiler/latest/env/vars.sh || true - ${PYTHON} -c "import dpctl" -pytest -q -ra --disable-warnings --cov dpctl --cov-report term-missing --pyargs dpctl -vv +python -m pytest -q -ra --disable-warnings --cov dpctl --cov-report term-missing --pyargs dpctl -vv diff --git a/dpctl-capi/include/dpctl_sycl_context_interface.h b/dpctl-capi/include/dpctl_sycl_context_interface.h index b750084e3f..f93125092d 100644 --- a/dpctl-capi/include/dpctl_sycl_context_interface.h +++ b/dpctl-capi/include/dpctl_sycl_context_interface.h @@ -161,4 +161,14 @@ DPCTLContext_GetBackend(__dpctl_keep const DPCTLSyclContextRef CtxRef); DPCTL_API void DPCTLContext_Delete(__dpctl_take DPCTLSyclContextRef CtxRef); +/*! + * @brief Wrapper over std::hash's operator() + * + * @param CtxRef The DPCTLSyclContextRef pointer. + * @return Hash value of the underlying ``sycl::context`` instance. + * @ingroup ContextInterface + */ +DPCTL_API +size_t DPCTLContext_Hash(__dpctl_take DPCTLSyclContextRef CtxRef); + DPCTL_C_EXTERN_C_END diff --git a/dpctl-capi/include/dpctl_sycl_device_interface.h b/dpctl-capi/include/dpctl_sycl_device_interface.h index bfd7708047..4976f3497f 100644 --- a/dpctl-capi/include/dpctl_sycl_device_interface.h +++ b/dpctl-capi/include/dpctl_sycl_device_interface.h @@ -555,3 +555,13 @@ uint32_t DPCTLDevice_GetPreferredVectorWidthHalf( DPCTL_API __dpctl_give DPCTLSyclDeviceRef DPCTLDevice_GetParentDevice(__dpctl_keep const DPCTLSyclDeviceRef DRef); + +/*! + * @brief Wrapper over + * std::hash's operator() + * + * @param DRef Opaque pointer to a sycl::device + * @return Returns hash value. + */ +DPCTL_API +size_t DPCTLDevice_Hash(__dpctl_keep const DPCTLSyclDeviceRef DRef); diff --git a/dpctl-capi/include/dpctl_sycl_queue_interface.h b/dpctl-capi/include/dpctl_sycl_queue_interface.h index 8871e58dcc..08cfae264d 100644 --- a/dpctl-capi/include/dpctl_sycl_queue_interface.h +++ b/dpctl-capi/include/dpctl_sycl_queue_interface.h @@ -126,10 +126,11 @@ __dpctl_give DPCTLSyclQueueRef DPCTLQueue_Copy(__dpctl_keep const DPCTLSyclQueueRef QRef); /*! - * @brief Checks if two DPCTLSyclQueueRef objects point to the same sycl::queue. + * @brief Checks if two DPCTLSyclQueueRef objects point to the + * same ``sycl::queue``. * - * @param QRef1 First opaque pointer to the sycl queue. - * @param QRef2 Second opaque pointer to the sycl queue. + * @param QRef1 First opaque pointer to the ``sycl::queue``. + * @param QRef2 Second opaque pointer to the ``sycl::queue``. * @return True if the underlying sycl::queue are same, false otherwise. * @ingroup QueueInterface */ @@ -174,11 +175,12 @@ DPCTLQueue_GetDevice(__dpctl_keep const DPCTLSyclQueueRef QRef); * @brief Submits the kernel to the specified queue with the provided range * argument. * - * A wrapper over sycl::queue.submit(). The function takes an interoperability - * kernel, the kernel arguments, and a Sycl queue as input. The kernel is - * submitted as parallel_for(range, *unwrap(KRef)). + * A wrapper over ``sycl::queue.submit()``. The function takes an + * interoperability kernel, the kernel arguments, and a ``sycl::queue`` as + * input. The kernel is submitted as + * ``parallel_for(range, *unwrap(KRef))``. * - * \todo sycl::buffer arguments are not supported yet. + * \todo ``sycl::buffer`` arguments are not supported yet. * \todo Add support for id WorkItemOffset * * @param KRef Opaque pointer to an OpenCL interoperability kernel @@ -195,11 +197,11 @@ DPCTLQueue_GetDevice(__dpctl_keep const DPCTLSyclQueueRef QRef); * dimensions. * @param NRange Size of the gRange array. * @param DepEvents List of dependent DPCTLSyclEventRef objects (events) - * for the kernel. We call sycl::handler.depends_on for - * each of the provided events. + * for the kernel. We call ``sycl::handler.depends_on`` + * for each of the provided events. * @param NDepEvents Size of the DepEvents list. - * @return An opaque pointer to the sycl::event returned by the - * sycl::queue.submit() function. + * @return An opaque pointer to the ``sycl::event`` returned by the + * ``sycl::queue.submit()`` function. * @ingroup QueueInterface */ DPCTL_API @@ -218,9 +220,9 @@ DPCTLQueue_SubmitRange(__dpctl_keep const DPCTLSyclKernelRef KRef, * @brief Submits the kernel to the specified queue with the provided nd_range * argument. * - * A wrapper over sycl::queue.submit(). The function takes an interoperability - * kernel, the kernel arguments, and a Sycl queue as input. The kernel is - * submitted as parallel_for(nd_range, *unwrap(KRef)). + * A wrapper over ``sycl::queue.submit()``. The function takes an + * interoperability kernel, the kernel arguments, and a Sycl queue as input. + * The kernel is submitted as ``parallel_for(nd_range, *unwrap(KRef))``. * * \todo sycl::buffer arguments are not supported yet. * \todo Add support for id WorkItemOffset @@ -243,11 +245,11 @@ DPCTLQueue_SubmitRange(__dpctl_keep const DPCTLSyclKernelRef KRef, * @param NDims The number of dimensions for both local and global * ranges. * @param DepEvents List of dependent DPCTLSyclEventRef objects (events) - * for the kernel. We call sycl::handler.depends_on for - * each of the provided events. + * for the kernel. We call ``sycl::handler.depends_on`` + * for each of the provided events. * @param NDepEvents Size of the DepEvents list. - * @return An opaque pointer to the sycl::event returned by the - * sycl::queue.submit() function. + * @return An opaque pointer to the ``sycl::event`` returned by the + * ``sycl::queue.submit()`` function. * @ingroup QueueInterface */ DPCTL_API @@ -264,20 +266,20 @@ DPCTLQueue_SubmitNDRange(__dpctl_keep const DPCTLSyclKernelRef KRef, size_t NDepEvents); /*! - * @brief Calls the sycl::queue.submit function to do a blocking wait on all - * enqueued tasks in the queue. + * @brief Calls the ``sycl::queue.submit`` function to do a blocking wait on + * all enqueued tasks in the queue. * - * @param QRef Opaque pointer to a sycl::queue. + * @param QRef Opaque pointer to a ``sycl::queue``. * @ingroup QueueInterface */ DPCTL_API void DPCTLQueue_Wait(__dpctl_keep const DPCTLSyclQueueRef QRef); /*! - * @brief C-API wrapper for sycl::queue::memcpy, the function waits on an event - * till the memcpy operation completes. + * @brief C-API wrapper for ``sycl::queue::memcpy``, the function waits on an + * event till the memcpy operation completes. * - * @param QRef An opaque pointer to the sycl queue. + * @param QRef An opaque pointer to the ``sycl::queue``. * @param Dest An USM pointer to the destination memory. * @param Src An USM pointer to the source memory. * @param Count A number of bytes to copy. @@ -290,10 +292,10 @@ void DPCTLQueue_Memcpy(__dpctl_keep const DPCTLSyclQueueRef QRef, size_t Count); /*! - * @brief C-API wrapper for sycl::queue::prefetch, the function waits on an + * @brief C-API wrapper for ``sycl::queue::prefetch``, the function waits on an * event till the prefetch operation completes. * - * @param QRef An opaque pointer to the sycl queue. + * @param QRef An opaque pointer to the ``sycl::queue``. * @param Ptr An USM pointer to memory. * @param Count A number of bytes to prefetch. * @ingroup QueueInterface @@ -307,7 +309,7 @@ void DPCTLQueue_Prefetch(__dpctl_keep DPCTLSyclQueueRef QRef, * @brief C-API wrapper for sycl::queue::mem_advise, the function waits on an * event till the operation completes. * - * @param QRef An opaque pointer to the sycl queue. + * @param QRef An opaque pointer to the ``sycl::queue``. * @param Ptr An USM pointer to memory. * @param Count A number of bytes to prefetch. * @param Advice Device-defined advice for the specified allocation. @@ -325,10 +327,20 @@ void DPCTLQueue_MemAdvise(__dpctl_keep DPCTLSyclQueueRef QRef, * @brief C-API wrapper for sycl::queue::is_in_order that indicates whether * the referenced queue is in-order or out-of-order. * - * @param QRef An opaque pointer to the sycl queue. + * @param QRef An opaque pointer to the ``sycl::queue``. * @ingroup QueueInterface */ DPCTL_API bool DPCTLQueue_IsInOrder(__dpctl_keep const DPCTLSyclQueueRef QRef); +/*! + * @brief C-API wrapper for std::hash's operator(). + * + * @param QRef An opaque pointer to the ``sycl::queue``. + * @return Hash value of the underlying ``sycl::queue`` instance. + * @ingroup QueueInterface + */ +DPCTL_API +size_t DPCTLQueue_Hash(__dpctl_keep const DPCTLSyclQueueRef QRef); + DPCTL_C_EXTERN_C_END diff --git a/dpctl-capi/source/dpctl_sycl_context_interface.cpp b/dpctl-capi/source/dpctl_sycl_context_interface.cpp index c45ab6891e..42c24b4e4d 100644 --- a/dpctl-capi/source/dpctl_sycl_context_interface.cpp +++ b/dpctl-capi/source/dpctl_sycl_context_interface.cpp @@ -197,3 +197,17 @@ DPCTLContext_GetBackend(__dpctl_keep const DPCTLSyclContextRef CtxRef) return DPCTL_UNKNOWN_BACKEND; } } + +size_t DPCTLContext_Hash(__dpctl_keep const DPCTLSyclContextRef CtxRef) +{ + if (CtxRef) { + auto C = unwrap(CtxRef); + std::hash hash_fn; + return hash_fn(*C); + } + else { + std::cerr << "Argument CtxRef is null" + << "/n"; + return 0; + } +} diff --git a/dpctl-capi/source/dpctl_sycl_device_interface.cpp b/dpctl-capi/source/dpctl_sycl_device_interface.cpp index 80a0f983e0..bbf510f5c9 100644 --- a/dpctl-capi/source/dpctl_sycl_device_interface.cpp +++ b/dpctl-capi/source/dpctl_sycl_device_interface.cpp @@ -690,3 +690,18 @@ __dpctl_give DPCTLDeviceVectorRef DPCTLDevice_CreateSubDevicesByAffinity( } return wrap(Devices); } + +size_t DPCTLDevice_Hash(__dpctl_keep const DPCTLSyclDeviceRef DRef) +{ + if (DRef) { + auto D = unwrap(DRef); + std::hash hash_fn; + return hash_fn(*D); + } + else { + // todo: log error + std::cerr << "Argument DRef is null" + << "/n"; + return 0; + } +} diff --git a/dpctl-capi/source/dpctl_sycl_queue_interface.cpp b/dpctl-capi/source/dpctl_sycl_queue_interface.cpp index cf679a2ed5..8a93b31f4f 100644 --- a/dpctl-capi/source/dpctl_sycl_queue_interface.cpp +++ b/dpctl-capi/source/dpctl_sycl_queue_interface.cpp @@ -454,9 +454,15 @@ void DPCTLQueue_Wait(__dpctl_keep DPCTLSyclQueueRef QRef) { // \todo what happens if the QRef is null or a pointer to a valid sycl // queue - auto SyclQueue = unwrap(QRef); - if (SyclQueue) - SyclQueue->wait(); + if (QRef) { + auto SyclQueue = unwrap(QRef); + if (SyclQueue) + SyclQueue->wait(); + } + else { + // todo: log error + std::cerr << "Argument QRef is NULL" << '\n'; + } } void DPCTLQueue_Memcpy(__dpctl_keep const DPCTLSyclQueueRef QRef, @@ -504,3 +510,17 @@ bool DPCTLQueue_IsInOrder(__dpctl_keep const DPCTLSyclQueueRef QRef) else return false; } + +size_t DPCTLQueue_Hash(__dpctl_keep const DPCTLSyclQueueRef QRef) +{ + auto Q = unwrap(QRef); + if (Q) { + std::hash hash_fn; + return hash_fn(*Q); + } + else { + // todo: log error + std::cerr << "Argument QRef is null" << '\n'; + return 0; + } +} diff --git a/dpctl-capi/tests/test_sycl_context_interface.cpp b/dpctl-capi/tests/test_sycl_context_interface.cpp index ae1a06950d..76431bef9d 100644 --- a/dpctl-capi/tests/test_sycl_context_interface.cpp +++ b/dpctl-capi/tests/test_sycl_context_interface.cpp @@ -177,6 +177,8 @@ TEST_P(TestDPCTLContextInterface, ChkAreEq) EXPECT_NO_FATAL_FAILURE(are_not_eq = DPCTLContext_AreEq(CRef1, CRef3)); EXPECT_TRUE(are_eq); EXPECT_FALSE(are_not_eq); + EXPECT_TRUE(DPCTLContext_Hash(CRef1) == DPCTLContext_Hash(CRef2)); + EXPECT_FALSE(DPCTLContext_Hash(CRef1) == DPCTLContext_Hash(CRef3)); EXPECT_NO_FATAL_FAILURE(DPCTLContext_Delete(CRef1)); EXPECT_NO_FATAL_FAILURE(DPCTLContext_Delete(CRef2)); diff --git a/dpctl-capi/tests/test_sycl_device_interface.cpp b/dpctl-capi/tests/test_sycl_device_interface.cpp index a17145e5cb..5a7f898962 100644 --- a/dpctl-capi/tests/test_sycl_device_interface.cpp +++ b/dpctl-capi/tests/test_sycl_device_interface.cpp @@ -68,6 +68,8 @@ TEST_P(TestDPCTLSyclDeviceInterface, ChkCopy) DPCTLSyclDeviceRef Copied_DRef = nullptr; EXPECT_NO_FATAL_FAILURE(Copied_DRef = DPCTLDevice_Copy(DRef)); EXPECT_TRUE(bool(Copied_DRef)); + EXPECT_TRUE(DPCTLDevice_AreEq(DRef, Copied_DRef)); + EXPECT_TRUE(DPCTLDevice_Hash(DRef) == DPCTLDevice_Hash(Copied_DRef)); EXPECT_NO_FATAL_FAILURE(DPCTLDevice_Delete(Copied_DRef)); } diff --git a/dpctl-capi/tests/test_sycl_queue_interface.cpp b/dpctl-capi/tests/test_sycl_queue_interface.cpp index 3120bc3446..d2f3504f3d 100644 --- a/dpctl-capi/tests/test_sycl_queue_interface.cpp +++ b/dpctl-capi/tests/test_sycl_queue_interface.cpp @@ -166,11 +166,13 @@ TEST_F(TestDPCTLSyclQueueInterface, CheckAreEq) } EXPECT_TRUE(DPCTLQueue_AreEq(Q1, Q2)); + EXPECT_TRUE(DPCTLQueue_Hash(Q1) == DPCTLQueue_Hash(Q2)); auto Q3 = DPCTLQueue_CreateForDevice(DRef, nullptr, 0); auto Q4 = DPCTLQueue_CreateForDevice(DRef, nullptr, 0); // These are different queues EXPECT_FALSE(DPCTLQueue_AreEq(Q3, Q4)); + EXPECT_FALSE(DPCTLQueue_Hash(Q3) == DPCTLQueue_Hash(Q4)); auto C0 = DPCTLQueue_GetContext(Q3); auto C1 = DPCTLQueue_GetContext(Q4); diff --git a/dpctl/_backend.pxd b/dpctl/_backend.pxd index cdc3f63e27..14917afe78 100644 --- a/dpctl/_backend.pxd +++ b/dpctl/_backend.pxd @@ -152,6 +152,7 @@ cdef extern from "dpctl_sycl_device_interface.h": cdef DPCTLSyclPlatformRef DPCTLDevice_GetPlatform( const DPCTLSyclDeviceRef DRef) cdef const char *DPCTLDevice_GetVendor(const DPCTLSyclDeviceRef DRef) + cdef size_t DPCTLDevice_Hash(const DPCTLSyclDeviceRef DRef) cdef bool DPCTLDevice_IsAccelerator(const DPCTLSyclDeviceRef DRef) cdef bool DPCTLDevice_IsCPU(const DPCTLSyclDeviceRef DRef) cdef bool DPCTLDevice_IsGPU(const DPCTLSyclDeviceRef DRef) @@ -268,6 +269,7 @@ cdef extern from "dpctl_sycl_context_interface.h": cdef size_t DPCTLContext_DeviceCount(const DPCTLSyclContextRef CRef) cdef bool DPCTLContext_AreEq(const DPCTLSyclContextRef CtxRef1, const DPCTLSyclContextRef CtxRef2) + cdef size_t DPCTLContext_Hash(const DPCTLSyclContextRef CRef) cdef _backend_type DPCTLContext_GetBackend(const DPCTLSyclContextRef) cdef void DPCTLContext_Delete(DPCTLSyclContextRef CtxRef) @@ -307,6 +309,7 @@ cdef extern from "dpctl_sycl_queue_interface.h": cdef _backend_type DPCTLQueue_GetBackend(const DPCTLSyclQueueRef Q) cdef DPCTLSyclContextRef DPCTLQueue_GetContext(const DPCTLSyclQueueRef Q) cdef DPCTLSyclDeviceRef DPCTLQueue_GetDevice(const DPCTLSyclQueueRef Q) + cdef size_t DPCTLQueue_Hash(const DPCTLSyclQueueRef Q) cdef DPCTLSyclEventRef DPCTLQueue_SubmitRange( const DPCTLSyclKernelRef Ref, const DPCTLSyclQueueRef QRef, diff --git a/dpctl/_sycl_context.pyx b/dpctl/_sycl_context.pyx index 2ba0fd0e02..0ceafe857c 100644 --- a/dpctl/_sycl_context.pyx +++ b/dpctl/_sycl_context.pyx @@ -34,6 +34,7 @@ from ._backend cimport ( # noqa: E211 DPCTLContext_Delete, DPCTLContext_DeviceCount, DPCTLContext_GetDevices, + DPCTLContext_Hash, DPCTLDevice_Copy, DPCTLDevice_Delete, DPCTLDeviceMgr_GetCachedContext, @@ -335,6 +336,13 @@ cdef class SyclContext(_SyclContext): else: return False + def __hash__(self): + """ + Returns a hash value by hashing the underlying ``sycl::context`` object. + + """ + return DPCTLContext_Hash(self._ctxt_ref) + cdef DPCTLSyclContextRef get_context_ref(self): return self._ctxt_ref diff --git a/dpctl/_sycl_device.pyx b/dpctl/_sycl_device.pyx index 5a05e7e8b6..31d20c8928 100644 --- a/dpctl/_sycl_device.pyx +++ b/dpctl/_sycl_device.pyx @@ -58,6 +58,7 @@ from ._backend cimport ( # noqa: E211 DPCTLDevice_GetSubGroupIndependentForwardProgress, DPCTLDevice_GetVendor, DPCTLDevice_HasAspect, + DPCTLDevice_Hash, DPCTLDevice_IsAccelerator, DPCTLDevice_IsCPU, DPCTLDevice_IsGPU, @@ -709,6 +710,13 @@ cdef class SyclDevice(_SyclDevice): + "] at {}>".format(hex(id(self))) ) + def __hash__(self): + """ + Returns a hash value by hashing the underlying ``sycl::device`` object. + + """ + return DPCTLDevice_Hash(self._device_ref) + cdef list create_sub_devices_equally(self, size_t count): """ Returns a list of sub-devices partitioned from this SYCL device based on the ``count`` parameter. diff --git a/dpctl/_sycl_queue.pyx b/dpctl/_sycl_queue.pyx index 9607f88e15..41586fd3b5 100644 --- a/dpctl/_sycl_queue.pyx +++ b/dpctl/_sycl_queue.pyx @@ -38,6 +38,7 @@ from ._backend cimport ( # noqa: E211 DPCTLQueue_GetBackend, DPCTLQueue_GetContext, DPCTLQueue_GetDevice, + DPCTLQueue_Hash, DPCTLQueue_IsInOrder, DPCTLQueue_MemAdvise, DPCTLQueue_Memcpy, @@ -863,6 +864,13 @@ cdef class SyclQueue(_SyclQueue): else: return "".format(hex(id(self))) + def __hash__(self): + """ + Returns a hash value by hashing the underlying ``sycl::queue`` object. + + """ + return DPCTLQueue_Hash(self._queue_ref) + def _get_capsule(self): cdef DPCTLSyclQueueRef QRef = NULL QRef = DPCTLQueue_Copy(self._queue_ref) diff --git a/dpctl/tests/test_sycl_context.py b/dpctl/tests/test_sycl_context.py index 7a71b6626f..756c92cbd7 100644 --- a/dpctl/tests/test_sycl_context.py +++ b/dpctl/tests/test_sycl_context.py @@ -76,6 +76,7 @@ def test_context_not_equals(): except ValueError: pytest.skip() assert ctx_cpu != ctx_gpu + assert hash(ctx_cpu) != hash(ctx_gpu) def test_context_not_equals2(): @@ -94,6 +95,7 @@ def test_context_equals(): except ValueError: pytest.skip() assert ctx0 == ctx1 + assert hash(ctx0) == hash(ctx1) def test_name(): @@ -157,3 +159,13 @@ def test_context_multi_device(): shmem_1 = dpmem.MemoryUSMShared(256, queue=q1) shmem_2 = dpmem.MemoryUSMDevice(256, queue=q2) shmem_2.copy_from_device(shmem_1) + + +def test_hashing_of_context(): + """ + Test that a :class:`dpctl.SyclContext` object can be used + as a dictionary key. + + """ + ctx_dict = {dpctl.SyclContext(): "default_context"} + assert ctx_dict diff --git a/dpctl/tests/test_sycl_device.py b/dpctl/tests/test_sycl_device.py index 882bcebc6b..ddf72268c8 100644 --- a/dpctl/tests/test_sycl_device.py +++ b/dpctl/tests/test_sycl_device.py @@ -615,6 +615,7 @@ def test_filter_string_property(): dev_id = d.filter_string d_r = dpctl.SyclDevice(dev_id) assert d == d_r + assert hash(d) == hash(d_r) def test_filter_string_method(): @@ -631,3 +632,16 @@ def test_filter_string_method(): ) d_r = dpctl.SyclDevice(dev_id) assert d == d_r, "Failed " + assert hash(d) == hash( + d_r + ), "Hash equality is inconsistent with __eq__" + + +def test_hashing_of_device(): + """ + Test that a :class:`dpctl.SyclDevice` object can be used as + a dictionary key. + + """ + device_dict = {dpctl.SyclDevice(): "default_device"} + assert device_dict diff --git a/dpctl/tests/test_sycl_queue.py b/dpctl/tests/test_sycl_queue.py index c9739f0cda..9d3b1008a7 100644 --- a/dpctl/tests/test_sycl_queue.py +++ b/dpctl/tests/test_sycl_queue.py @@ -358,6 +358,7 @@ def test_context_not_equals(): pytest.skip() ctx_cpu = cpuQ.get_sycl_context() assert ctx_cpu != ctx_gpu + assert hash(ctx_cpu) != hash(ctx_gpu) def test_context_equals(): @@ -369,3 +370,14 @@ def test_context_equals(): ctx0 = gpuQ0.get_sycl_context() ctx1 = gpuQ1.get_sycl_context() assert ctx0 == ctx1 + assert hash(ctx0) == hash(ctx1) + + +def test_hashing_of_queue(): + """ + Test that a :class:`dpctl.SyclQueue` object can be used as + a dictionary key. + + """ + queue_dict = {dpctl.SyclQueue(): "default_queue"} + assert queue_dict