From 155eec47d7f351b799dd9fcd89e69fc734946da9 Mon Sep 17 00:00:00 2001 From: "Larsen, Steffen" Date: Mon, 14 Nov 2022 00:14:46 -0800 Subject: [PATCH 01/15] [SYCL][Docs] Add sycl_ext_oneapi_weak_object extension and implementation This commit add the sycl_ext_oneapi_weak_object extension together with its implementation. This extension intendeds to allow users to weak variants of SYCL objects with common reference semantics, similar to how std::weak_ptr works with std::shared_ptr. Among other benefits, this allows user code to store these SYCL objects without worrying about the storage keeping the objects alive for longer than needed. Additionally the extension adds the notion of owner ordering of SYCL objects. This can be used as less-than comparison between SYCL objects and their corresponding weak variants. Signed-off-by: Larsen, Steffen --- .../sycl_ext_oneapi_weak_object.asciidoc | 332 ++++++++++++++++ sycl/include/sycl/accessor.hpp | 227 +++++++++++ sycl/include/sycl/buffer.hpp | 19 + sycl/include/sycl/context.hpp | 21 + sycl/include/sycl/device.hpp | 21 + sycl/include/sycl/event.hpp | 21 + sycl/include/sycl/ext/oneapi/owner_less.hpp | 101 +++++ sycl/include/sycl/ext/oneapi/sub_group.hpp | 71 ++-- sycl/include/sycl/ext/oneapi/weak_object.hpp | 149 ++++++++ .../sycl/ext/oneapi/weak_object_base.hpp | 67 ++++ sycl/include/sycl/feature_test.hpp.in | 1 + sycl/include/sycl/kernel.hpp | 21 + sycl/include/sycl/kernel_bundle.hpp | 61 +++ sycl/include/sycl/platform.hpp | 21 + sycl/include/sycl/queue.hpp | 21 + sycl/include/sycl/stream.hpp | 28 ++ sycl/include/sycl/sycl.hpp | 2 + sycl/unittests/Extensions/CMakeLists.txt | 1 + sycl/unittests/Extensions/WeakObject.cpp | 361 ++++++++++++++++++ 19 files changed, 1514 insertions(+), 32 deletions(-) create mode 100644 sycl/doc/extensions/supported/sycl_ext_oneapi_weak_object.asciidoc create mode 100644 sycl/include/sycl/ext/oneapi/owner_less.hpp create mode 100644 sycl/include/sycl/ext/oneapi/weak_object.hpp create mode 100644 sycl/include/sycl/ext/oneapi/weak_object_base.hpp create mode 100644 sycl/unittests/Extensions/WeakObject.cpp diff --git a/sycl/doc/extensions/supported/sycl_ext_oneapi_weak_object.asciidoc b/sycl/doc/extensions/supported/sycl_ext_oneapi_weak_object.asciidoc new file mode 100644 index 0000000000000..3f1aa71c14582 --- /dev/null +++ b/sycl/doc/extensions/supported/sycl_ext_oneapi_weak_object.asciidoc @@ -0,0 +1,332 @@ += sycl_ext_oneapi_weak_object + +:source-highlighter: coderay +:coderay-linenums-mode: table + +// This section needs to be after the document title. +:doctype: book +:toc2: +:toc: left +:encoding: utf-8 +:lang: en +:dpcpp: pass:[DPC++] + +// Set the default source code type in this document to C++, +// for syntax highlighting purposes. This is needed because +// docbook uses c++ and html5 uses cpp. +:language: {basebackend@docbook:c++:cpp} + + +== Notice + +[%hardbreaks] +Copyright (C) 2022-2022 Intel Corporation. All rights reserved. + +Khronos(R) is a registered trademark and SYCL(TM) and SPIR(TM) are trademarks +of The Khronos Group Inc. OpenCL(TM) is a trademark of Apple Inc. used by +permission by Khronos. + + +== Contact + +To report problems with this extension, please open a new issue at: + +https://github.com/intel/llvm/issues + + +== Dependencies + +This extension is written against the SYCL 2020 revision 5 specification. All +references below to the "core SYCL specification" or to section numbers in the +SYCL specification refer to that revision. + + +== Status + +This extension is implemented and fully supported by {dpcpp}. + + +== Overview + +SYCL 2020 has a number of classes with common reference semantics, which mean +that copies of objects of these classes will reference the same objects and +will be considered the same. As a result, these objects will only be fully +destroyed when all copies have been destroyed. However, there is currently no +way to have a reference to an object with these semantics without keeping the +object alive. + +This extension adds the notion of a "weak" SYCL object, represented by the +`weak_object` class. A weak object holds a reference to a SYCL object with +common reference semantics of the specified type but will not keep the +underlying object alive. As such, a weak object can be queries about having +expired and exposes interfaces for locking the underlying object, creating a +copy of it if it is still alive. + +Additionally this extension adds the notion of owner-based ordering to allow for +use of SYCL object and their weak variants in order-oriented data structures and +operations. + + +== Specification + +=== Feature test macro + +This extension provides a feature-test macro as described in the core SYCL +specification. An implementation supporting this extension must predefine the +macro `SYCL_EXT_ONEAPI_WEAK_OBJECT` to one of the values defined in the table +below. Applications can test for the existence of this macro to determine if +the implementation supports this feature, or applications can test the macro's +value to determine which of the extension's features the implementation +supports. + +[%header,cols="1,5"] +|=== +|Value +|Description + +|1 +|Initial version of this extension. +|=== + + +=== The new `weak_object` class + +This extension adds the following class: + +[source] +---- +namespace sycl { +namespace ext { +namespace oneapi { + +template +class weak_object { +public: + using object_type = SyclObject; + + constexpr weak_object() noexcept; + weak_object(const SyclObject &SYCLObj) noexcept; + weak_object(const weak_object &Other) noexcept; + weak_object(weak_object &&Other) noexcept; + + weak_object &operator=(const SyclObject &SYCLObj) noexcept; + weak_object &operator=(const weak_object &Other) noexcept; + weak_object &operator=(weak_object &&Other) noexcept; + + void reset() noexcept; + void swap(weak_object &Other) noexcept; + + bool expired() const noexcept; + std::optional try_lock() const noexcept; + SyclObject lock() const noexcept; + + bool owner_before(const weak_object &Other) const noexcept; + bool owner_before(const SyclObject &Other) const noexcept; +}; + +} // namespace oneapi +} // namespace ext +} // namespace sycl +---- + +The methods of the new `weak_object` class have the following semantics: + +[cols="60a,40"] +|=== +| Member Function | Description + +a| +[source,c++] +---- +constexpr weak_object() noexcept; +---- + +| Constructor for creating an empty `weak_object`. These are + +a| +[source,c++] +---- +weak_object(const SyclObject &SYCLObj) noexcept; + +weak_object(const weak_object &Other) noexcept; +---- + +| Copy constructor. + +a| +[source,c++] +---- +weak_object(weak_object &&Other) noexcept; +---- + +| Move constructor. + +a| +[source,c++] +---- +weak_object &operator=(const SyclObject &SYCLObj) noexcept; + +weak_object &operator=(const weak_object &Other) noexcept; +---- + +| Copy assignment operator. + +a| +[source,c++] +---- +weak_object &operator=(weak_object &&Other) noexcept; +---- + +| Move assignment operator. + +a| +[source,c++] +---- +void reset() noexcept; +---- + +| Releases the reference to the underlying SYCL object. + +a| +[source,c++] +---- +void swap(weak_object &Other) noexcept; +---- + +| Exhanges the reference to the underlying SYCL object with the one held by +`Other`. + +a| +[source,c++] +---- +bool expired() const noexcept; +---- + +| Returns `true` if the underlying SYCL object has been destroyed or its +destruction is imminent. Otherwise returns `false`. + +a| +[source,c++] +---- +std::optional try_lock() const noexcept; +---- + +| Attempts to return the underlying SYCL object. Returns `std::nullopt` if the +`weak_object` is empty or if `expired()` returns `true`. + +a| +[source,c++] +---- +SyclObject lock() const noexcept; +---- + +| Returns the underlying SYCL object. + +Throws an exception with the `errc::invalid` error code if `std::nullopt` if the +`weak_object` is empty or if `expired()` returns `true`. + +a| +[source,c++] +---- +bool owner_before(const weak_object &Other) const noexcept; + +bool owner_before(const SyclObject &Other) const noexcept; +---- + +| Checks whether this `weak_object` precedes `Other` in the +implementation-defined owner-based order. The order is defined such that two +objects defining this ordering compare equivalent if both are `weak_object` +without an underlying SYCL object or if both reference the same SYCL object. + +|=== + +Additionally the following members are added to the members in SYCL classes with +common reference semantics: + +[source] +---- +namespace sycl { + +// Where T is a SYCL type with common reference semantics. +class T { + ... + +public: + ... + + bool ext_oneapi_owner_before(const ext::oneapi::weak_object &Other) const noexcept; + bool ext_oneapi_owner_before(const T &Other) const noexcept; +}; + +} // namespace sycl +---- + +These new methods have the following semantics: + +[cols="60a,40"] +|=== +| Member Function | Description + +a| +[source,c++] +---- +bool ext_oneapi_owner_before(const ext::oneapi::weak_object &Other) const noexcept; + +bool ext_oneapi_owner_before(const T &Other) const noexcept; +---- + +| Checks whether this SYCL object precedes `Other` in the +implementation-defined owner-based order. The order is defined such that two +objects defining this ordering compare equivalent if both are `weak_object` +without an underlying SYCL object or if both reference the same SYCL object. + +|=== + +The `owner_less` function object is added with the following specializations: + +[source] +---- +namespace sycl { +namespace ext { +namespace oneapi { + +template struct owner_less; + +// Where T is a SYCL type with common reference semantics. +template <> struct owner_less { + bool operator()(const T &lhs, const T &rhs) const noexcept; + bool operator()(const weak_object &lhs, + const weak_object &rhs) const noexcept; + bool operator()(const T &lhs, const weak_object &rhs) const noexcept; + bool operator()(const weak_object &lhs, const T &rhs) const noexcept; +}; + +} // namespace oneapi +} // namespace ext +} // namespace sycl +---- + +The operator overloads of the new `owner_less` function object have the +following semantics: + +[cols="60a,40"] +|=== +| Member Function | Description + +a| +[source,c++] +---- +bool operator()(const T &lhs, const T &rhs) const noexcept; +bool operator()(const weak_object &lhs, + const weak_object &rhs) const noexcept; +bool operator()(const T &lhs, const weak_object &rhs) const noexcept; +bool operator()(const weak_object &lhs, const T &rhs) const noexcept; +---- + +| Compares `lhs` and `rhs` using owner-based semantics, similar to calling +`owner_before` on `weak_object` or `ext_oneapi_owner_before` on SYCL objects. +`lhs` and `rhs` are equivalent if they both reference the same SYCL object or if +they are both empty `weak_object` instances. + +|=== + diff --git a/sycl/include/sycl/accessor.hpp b/sycl/include/sycl/accessor.hpp index 1874bc570ff17..c002991a27bff 100644 --- a/sycl/include/sycl/accessor.hpp +++ b/sycl/include/sycl/accessor.hpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -473,6 +474,9 @@ class SYCLMemObjI; using AccessorImplPtr = std::shared_ptr; class __SYCL_EXPORT AccessorBaseHost { +protected: + AccessorBaseHost(const AccessorImplPtr &Impl) : impl{Impl} {} + public: AccessorBaseHost(id<3> Offset, range<3> AccessRange, range<3> MemoryRange, access::mode AccessMode, void *SYCLMemObject, int Dims, @@ -501,6 +505,9 @@ class __SYCL_EXPORT AccessorBaseHost { template friend decltype(Obj::impl) getSyclObjImpl(const Obj &SyclObject); + template + friend Obj detail::createSyclObjFromImpl(decltype(Obj::impl) ImplObj); + template friend class accessor; @@ -515,6 +522,9 @@ class LocalAccessorImplHost; using LocalAccessorImplPtr = std::shared_ptr; class __SYCL_EXPORT LocalAccessorBaseHost { +protected: + LocalAccessorBaseHost(const LocalAccessorImplPtr &Impl) : impl{Impl} {} + public: LocalAccessorBaseHost(sycl::range<3> Size, int Dims, int ElemSize, const property_list &PropertyList = {}); @@ -530,6 +540,9 @@ class __SYCL_EXPORT LocalAccessorBaseHost { template friend decltype(Obj::impl) getSyclObjImpl(const Obj &SyclObject); + template + friend Obj detail::createSyclObjFromImpl(decltype(Obj::impl) ImplObj); + LocalAccessorImplPtr impl; }; @@ -657,6 +670,11 @@ class image_accessor #endif +#ifndef __SYCL_DEVICE_ONLY__ +protected: + image_accessor(const AccessorImplPtr &Impl) : AccessorBaseHost{Impl} {} +#endif // __SYCL_DEVICE_ONLY__ + private: friend class sycl::ext::intel::esimd::detail::AccessorPrivateProxy; @@ -1125,6 +1143,9 @@ class __SYCL_SPECIAL_CLASS __SYCL_TYPE(accessor) accessor : detail::InitializedVal::template get<0>()) {} #else + accessor(const detail::AccessorImplPtr &Impl) + : detail::AccessorBaseHost{Impl} {} + id<3> &getOffset() { if constexpr (IsHostBuf) return MAccData->MOffset; @@ -1204,6 +1225,9 @@ class __SYCL_SPECIAL_CLASS __SYCL_TYPE(accessor) accessor : friend class sycl::stream; friend class sycl::ext::intel::esimd::detail::AccessorPrivateProxy; + template + friend Obj detail::createSyclObjFromImpl(decltype(Obj::impl) ImplObj); + public: // 4.7.6.9.1. Interface for buffer command accessors // value_type is defined as const DataT for read_only accessors, DataT @@ -2121,6 +2145,34 @@ class __SYCL_SPECIAL_CLASS __SYCL_TYPE(accessor) accessor : bool operator==(const accessor &Rhs) const { return impl == Rhs.impl; } bool operator!=(const accessor &Rhs) const { return !(*this == Rhs); } +#ifndef __SYCL_DEVICE_ONLY__ + /// Compares the accessor against a weak object using an owner-based + /// implementation-defined ordering. + /// + /// \param Other is the weak object to compare ordering against. + /// \return true if this object precedes \param Other and false otherwise. + bool ext_oneapi_owner_before( + const ext::oneapi::detail::weak_object_base &Other) + const noexcept { + return impl.owner_before(ext::oneapi::detail::getSyclWeakObjImpl(Other)); + } + + /// Compares the accessor against another accessor using an owner-based + /// implementation-defined ordering. + /// + /// \param Other is the object to compare ordering against. + /// \return true if this object precedes \param Other and false otherwise. + bool ext_oneapi_owner_before(const accessor &Other) const noexcept { + return impl.owner_before(Other.impl); + } +#else + bool ext_oneapi_owner_before( + const ext::oneapi::detail::weak_object_base &Other) + const noexcept; + + bool ext_oneapi_owner_before(const accessor &Other) const noexcept; +#endif + iterator begin() const noexcept { return iterator::getBegin( get_pointer(), @@ -2434,6 +2486,8 @@ class __SYCL_SPECIAL_CLASS local_accessor_base : ConcreteASPtrType MData; #else + local_accessor_base(const detail::LocalAccessorImplPtr &Impl) + : detail::LocalAccessorBaseHost{Impl} {} char padding[sizeof(detail::LocalAccessorBaseDevice) + sizeof(PtrType) - sizeof(detail::LocalAccessorBaseHost)]; @@ -2471,6 +2525,9 @@ class __SYCL_SPECIAL_CLASS local_accessor_base : return Result; } + template + friend Obj detail::createSyclObjFromImpl(decltype(Obj::impl) ImplObj); + public: using value_type = DataT; using reference = DataT &; @@ -2647,6 +2704,37 @@ class __SYCL_SPECIAL_CLASS accessor::template get<0>(); } + bool ext_oneapi_owner_before( + const ext::oneapi::detail::weak_object_base &Other) + const noexcept; + bool ext_oneapi_owner_before(const accessor &Other) const noexcept; + +#else +private: + accessor(const detail::AccessorImplPtr &Impl) : local_acc{Impl} {} + +public: + /// Compares the accessor against a weak object using an owner-based + /// implementation-defined ordering. + /// + /// \param Other is the weak object to compare ordering against. + /// \return true if this object precedes \param Other and false otherwise. + bool ext_oneapi_owner_before( + const ext::oneapi::detail::weak_object_base &Other) + const noexcept { + return local_acc::impl.owner_before( + ext::oneapi::detail::getSyclWeakObjImpl(Other)); + } + + /// Compares the accessor against another accessor using an owner-based + /// implementation-defined ordering. + /// + /// \param Other is the object to compare ordering against. + /// \return true if this object precedes \param Other and false otherwise. + bool ext_oneapi_owner_before(const accessor &Other) const noexcept { + return local_acc::impl.owner_before(Other.impl); + } + #endif }; @@ -2680,6 +2768,35 @@ class __SYCL_SPECIAL_CLASS __SYCL_TYPE(local_accessor) local_accessor range>::template get<0>(); } + bool ext_oneapi_owner_before( + const ext::oneapi::detail::weak_object_base &Other) + const noexcept; + bool ext_oneapi_owner_before(const local_accessor &Other) const noexcept; + +#else + local_accessor(const detail::AccessorImplPtr &Impl) : local_acc{Impl} {} + +public: + /// Compares the local_accessor against a weak object using an owner-based + /// implementation-defined ordering. + /// + /// \param Other is the weak object to compare ordering against. + /// \return true if this object precedes \param Other and false otherwise. + bool ext_oneapi_owner_before( + const ext::oneapi::detail::weak_object_base &Other) + const noexcept { + return local_acc::impl.owner_before( + ext::oneapi::detail::getSyclWeakObjImpl(Other)); + } + + /// Compares the local_accessor against another local_accessor using an + /// owner-based implementation-defined ordering. + /// + /// \param Other is the object to compare ordering against. + /// \return true if this object precedes \param Other and false otherwise. + bool ext_oneapi_owner_before(const local_accessor &Other) const noexcept { + return local_acc::impl.owner_before(Other.impl); + } #endif public: @@ -2748,6 +2865,11 @@ __SYCL_TYPE(accessor) accessor : public detail::image_accessor { +private: + accessor(const detail::AccessorImplPtr &Impl) + : detail::image_accessor{Impl} {} + public: template accessor(sycl::image &Image, @@ -2789,6 +2911,34 @@ __SYCL_TYPE(accessor) accessor &Other) + const noexcept; + bool ext_oneapi_owner_before(const accessor &Other) const noexcept; +#else +public: + /// Compares the accessor against a weak object using an owner-based + /// implementation-defined ordering. + /// + /// \param Other is the weak object to compare ordering against. + /// \return true if this object precedes \param Other and false otherwise. + bool ext_oneapi_owner_before( + const ext::oneapi::detail::weak_object_base &Other) + const noexcept { + return detail::AccessorBaseHost::impl.owner_before( + ext::oneapi::detail::getSyclWeakObjImpl(Other)); + } + + /// Compares the accessor against another accessor using an + /// owner-based implementation-defined ordering. + /// + /// \param Other is the object to compare ordering against. + /// \return true if this object precedes \param Other and false otherwise. + bool ext_oneapi_owner_before(const accessor &Other) const noexcept { + return detail::AccessorBaseHost::impl.owner_before(Other.impl); + } + #endif }; @@ -2820,6 +2970,34 @@ class accessor &Other) + const noexcept { + return detail::AccessorBaseHost::impl.owner_before( + ext::oneapi::detail::getSyclWeakObjImpl(Other)); + } + + /// Compares the accessor against another accessor using an + /// owner-based implementation-defined ordering. + /// + /// \param Other is the object to compare ordering against. + /// \return true if this object precedes \param Other and false otherwise. + bool ext_oneapi_owner_before(const accessor &Other) const noexcept { + return detail::AccessorBaseHost::impl.owner_before(Other.impl); + } +#else + bool ext_oneapi_owner_before( + const ext::oneapi::detail::weak_object_base &Other) + const noexcept; + bool ext_oneapi_owner_before(const accessor &Other) const noexcept; +#endif }; /// Image array accessor. @@ -2885,6 +3063,34 @@ __SYCL_TYPE(accessor) accessor(*this, Index); } + +#ifndef __SYCL_DEVICE_ONLY__ + /// Compares the accessor against a weak object using an owner-based + /// implementation-defined ordering. + /// + /// \param Other is the weak object to compare ordering against. + /// \return true if this object precedes \param Other and false otherwise. + bool ext_oneapi_owner_before( + const ext::oneapi::detail::weak_object_base &Other) + const noexcept { + return detail::AccessorBaseHost::impl.owner_before( + ext::oneapi::detail::getSyclWeakObjImpl(Other)); + } + + /// Compares the accessor against another accessor using an + /// owner-based implementation-defined ordering. + /// + /// \param Other is the object to compare ordering against. + /// \return true if this object precedes \param Other and false otherwise. + bool ext_oneapi_owner_before(const accessor &Other) const noexcept { + return detail::AccessorBaseHost::impl.owner_before(Other.impl); + } +#else + bool ext_oneapi_owner_before( + const ext::oneapi::detail::weak_object_base &Other) + const noexcept; + bool ext_oneapi_owner_before(const accessor &Other) const noexcept; +#endif }; template &Other) + const noexcept { + return detail::AccessorBaseHost::impl.owner_before( + ext::oneapi::detail::getSyclWeakObjImpl(Other)); + } + + /// Compares the host_accessor against another host_accessor using an + /// owner-based implementation-defined ordering. + /// + /// \param Other is the object to compare ordering against. + /// \return true if this object precedes \param Other and false otherwise. + bool ext_oneapi_owner_before(const host_accessor &Other) const noexcept { + return detail::AccessorBaseHost::impl.owner_before(Other.impl); + } }; #if __cplusplus >= 201703L diff --git a/sycl/include/sycl/buffer.hpp b/sycl/include/sycl/buffer.hpp index ffcfcc9802677..38dd2a759a8a6 100644 --- a/sycl/include/sycl/buffer.hpp +++ b/sycl/include/sycl/buffer.hpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -34,6 +35,12 @@ class host_accessor; template class buffer; +namespace ext { +namespace oneapi { +template class weak_object; +} // namespace oneapi +} // namespace ext + namespace detail { class buffer_impl; @@ -680,6 +687,16 @@ class buffer : public detail::buffer_plain { return buffer_plain::template get_property(); } + bool ext_oneapi_owner_before( + const ext::oneapi::detail::weak_object_base &Other) + const noexcept { + return impl.owner_before(ext::oneapi::detail::getSyclWeakObjImpl(Other)); + } + + bool ext_oneapi_owner_before(const buffer &Other) const noexcept { + return impl.owner_before(Other.impl); + } + protected: bool isOutOfBounds(const id &offset, const range &newRange, @@ -702,6 +719,8 @@ class buffer : public detail::buffer_plain { template friend buffer detail::make_buffer_helper(pi_native_handle, const context &, event, bool); + template friend class ext::oneapi::weak_object; + range Range; // Offset field specifies the origin of the sub buffer inside the parent // buffer diff --git a/sycl/include/sycl/context.hpp b/sycl/include/sycl/context.hpp index ac82bfd4197ae..4aaa1e17233fd 100644 --- a/sycl/include/sycl/context.hpp +++ b/sycl/include/sycl/context.hpp @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -219,6 +220,26 @@ class __SYCL_EXPORT context { /// \return a vector of valid SYCL device instances. std::vector get_devices() const; + /// Compares the context against a weak object using an owner-based + /// implementation-defined ordering. + /// + /// \param Other is the weak object to compare ordering against. + /// \return true if this object precedes \param Other and false otherwise. + bool ext_oneapi_owner_before( + const ext::oneapi::detail::weak_object_base &Other) + const noexcept { + return impl.owner_before(ext::oneapi::detail::getSyclWeakObjImpl(Other)); + } + + /// Compares the context against another context using an owner-based + /// implementation-defined ordering. + /// + /// \param Other is the object to compare ordering against. + /// \return true if this object precedes \param Other and false otherwise. + bool ext_oneapi_owner_before(const context &Other) const noexcept { + return impl.owner_before(Other.impl); + } + private: /// Constructs a SYCL context object from a valid context_impl instance. context(std::shared_ptr Impl); diff --git a/sycl/include/sycl/device.hpp b/sycl/include/sycl/device.hpp index 686d7e730edc4..7e157364e035a 100644 --- a/sycl/include/sycl/device.hpp +++ b/sycl/include/sycl/device.hpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -218,6 +219,26 @@ class __SYCL_EXPORT device { /// \return true if the SYCL device has the given feature. bool has(aspect Aspect) const; + /// Compares the device against a weak object using an owner-based + /// implementation-defined ordering. + /// + /// \param Other is the weak object to compare ordering against. + /// \return true if this object precedes \param Other and false otherwise. + bool ext_oneapi_owner_before( + const ext::oneapi::detail::weak_object_base &Other) + const noexcept { + return impl.owner_before(ext::oneapi::detail::getSyclWeakObjImpl(Other)); + } + + /// Compares the device against another device using an owner-based + /// implementation-defined ordering. + /// + /// \param Other is the object to compare ordering against. + /// \return true if this object precedes \param Other and false otherwise. + bool ext_oneapi_owner_before(const device &Other) const noexcept { + return impl.owner_before(Other.impl); + } + private: std::shared_ptr impl; device(std::shared_ptr impl) : impl(impl) {} diff --git a/sycl/include/sycl/event.hpp b/sycl/include/sycl/event.hpp index b672e1c114280..c5b9d728240ea 100644 --- a/sycl/include/sycl/event.hpp +++ b/sycl/include/sycl/event.hpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -129,6 +130,26 @@ class __SYCL_EXPORT event { /// \return the backend associated with this platform backend get_backend() const noexcept; + /// Compares the event against a weak object using an owner-based + /// implementation-defined ordering. + /// + /// \param Other is the weak object to compare ordering against. + /// \return true if this object precedes \param Other and false otherwise. + bool ext_oneapi_owner_before( + const ext::oneapi::detail::weak_object_base &Other) + const noexcept { + return impl.owner_before(ext::oneapi::detail::getSyclWeakObjImpl(Other)); + } + + /// Compares the event against another event using an owner-based + /// implementation-defined ordering. + /// + /// \param Other is the object to compare ordering against. + /// \return true if this object precedes \param Other and false otherwise. + bool ext_oneapi_owner_before(const event &Other) const noexcept { + return impl.owner_before(Other.impl); + } + private: event(std::shared_ptr EventImpl); diff --git a/sycl/include/sycl/ext/oneapi/owner_less.hpp b/sycl/include/sycl/ext/oneapi/owner_less.hpp new file mode 100644 index 0000000000000..c05554b95a6c8 --- /dev/null +++ b/sycl/include/sycl/ext/oneapi/owner_less.hpp @@ -0,0 +1,101 @@ +//==-------------- weak_object.hpp --- SYCL weak objects -------------------==// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace sycl { +__SYCL_INLINE_VER_NAMESPACE(_V1) { +namespace ext { +namespace oneapi { + +namespace detail { +template struct owner_less_base { + bool operator()(const SyclObject &lhs, const SyclObject &rhs) const noexcept { + return lhs.ext_oneapi_owner_before(rhs); + } + + bool operator()(const weak_object &lhs, + const weak_object &rhs) const noexcept { + return lhs.owner_before(rhs); + } + + bool operator()(const SyclObject &lhs, + const weak_object &rhs) const noexcept { + return lhs.ext_oneapi_owner_before(rhs); + } + + bool operator()(const weak_object &lhs, + const SyclObject &rhs) const noexcept { + return lhs.owner_before(rhs); + } +}; +} // namespace detail + +template struct owner_less; + +template <> +struct owner_less : public detail::owner_less_base {}; +template <> +struct owner_less : public detail::owner_less_base {}; +template <> struct owner_less : public detail::owner_less_base {}; +template <> +struct owner_less : public detail::owner_less_base {}; +template <> +struct owner_less : public detail::owner_less_base {}; +template <> +struct owner_less : public detail::owner_less_base {}; +template <> struct owner_less : public detail::owner_less_base {}; + +template +struct owner_less> + : public detail::owner_less_base> {}; + +template +struct owner_less> + : public detail::owner_less_base> {}; + +template +struct owner_less> + : public detail::owner_less_base> {}; + +template +struct owner_less< + accessor> + : public detail::owner_less_base> {}; + +template +struct owner_less> + : public detail::owner_less_base< + host_accessor> {}; + +template +struct owner_less> + : public detail::owner_less_base> {}; + +template +struct owner_less> + : public detail::owner_less_base> {}; + +} // namespace oneapi +} // namespace ext +} // __SYCL_INLINE_VER_NAMESPACE(_V1) +} // namespace sycl diff --git a/sycl/include/sycl/ext/oneapi/sub_group.hpp b/sycl/include/sycl/ext/oneapi/sub_group.hpp index e0f33486749e5..3be48fb447d76 100644 --- a/sycl/include/sycl/ext/oneapi/sub_group.hpp +++ b/sycl/include/sycl/ext/oneapi/sub_group.hpp @@ -205,8 +205,7 @@ struct sub_group { template using EnableIfIsScalarArithmetic = - sycl::detail::enable_if_t::value, - T>; + std::enable_if_t::value, T>; /* --- one-input shuffles --- */ /* indices in [0 , sub_group size) */ @@ -260,7 +259,7 @@ struct sub_group { #ifdef __SYCL_DEVICE_ONLY__ // Method for decorated pointer template > - detail::enable_if_t, T>::value, T> + std::enable_if_t, T>::value, T> load(CVT *cv_src) const { T *src = const_cast(cv_src); return load(sycl::multi_ptr, @@ -270,7 +269,7 @@ struct sub_group { // Method for raw pointer template > - detail::enable_if_t, T>::value, T> + std::enable_if_t, T>::value, T> load(CVT *cv_src) const { T *src = const_cast(cv_src); @@ -300,10 +299,11 @@ struct sub_group { template > - sycl::detail::enable_if_t< + std::enable_if_t< sycl::detail::sub_group::AcceptableForGlobalLoadStore::value, T> load(const multi_ptr cv_src) const { - multi_ptr src = detail::GetUnqualMultiPtr(cv_src); + multi_ptr src = + sycl::detail::GetUnqualMultiPtr(cv_src); #ifdef __SYCL_DEVICE_ONLY__ #ifdef __NVPTX__ return src.get()[get_local_id()[0]]; @@ -319,10 +319,11 @@ struct sub_group { template > - sycl::detail::enable_if_t< + std::enable_if_t< sycl::detail::sub_group::AcceptableForLocalLoadStore::value, T> load(const multi_ptr cv_src) const { - multi_ptr src = detail::GetUnqualMultiPtr(cv_src); + multi_ptr src = + sycl::detail::GetUnqualMultiPtr(cv_src); #ifdef __SYCL_DEVICE_ONLY__ return src.get()[get_local_id()[0]]; #else @@ -335,11 +336,12 @@ struct sub_group { #ifdef __NVPTX__ template > - sycl::detail::enable_if_t< + std::enable_if_t< sycl::detail::sub_group::AcceptableForGlobalLoadStore::value, vec> load(const multi_ptr cv_src) const { - multi_ptr src = detail::GetUnqualMultiPtr(cv_src); + multi_ptr src = + sycl::detail::GetUnqualMultiPtr(cv_src); vec res; for (int i = 0; i < N; ++i) { res[i] = *(src.get() + i * get_max_local_range()[0] + get_local_id()[0]); @@ -349,23 +351,25 @@ struct sub_group { #else // __NVPTX__ template > - sycl::detail::enable_if_t< + std::enable_if_t< sycl::detail::sub_group::AcceptableForGlobalLoadStore::value && N != 1 && N != 3 && N != 16, vec> load(const multi_ptr cv_src) const { - multi_ptr src = detail::GetUnqualMultiPtr(cv_src); + multi_ptr src = + sycl::detail::GetUnqualMultiPtr(cv_src); return sycl::detail::sub_group::load(src); } template > - sycl::detail::enable_if_t< + std::enable_if_t< sycl::detail::sub_group::AcceptableForGlobalLoadStore::value && N == 16, vec> load(const multi_ptr cv_src) const { - multi_ptr src = detail::GetUnqualMultiPtr(cv_src); + multi_ptr src = + sycl::detail::GetUnqualMultiPtr(cv_src); return {sycl::detail::sub_group::load<8, T>(src), sycl::detail::sub_group::load<8, T>(src + 8 * get_max_local_range()[0])}; @@ -373,12 +377,13 @@ struct sub_group { template > - sycl::detail::enable_if_t< + std::enable_if_t< sycl::detail::sub_group::AcceptableForGlobalLoadStore::value && N == 3, vec> load(const multi_ptr cv_src) const { - multi_ptr src = detail::GetUnqualMultiPtr(cv_src); + multi_ptr src = + sycl::detail::GetUnqualMultiPtr(cv_src); return { sycl::detail::sub_group::load<1, T>(src), sycl::detail::sub_group::load<2, T>(src + get_max_local_range()[0])}; @@ -386,19 +391,20 @@ struct sub_group { template > - sycl::detail::enable_if_t< + std::enable_if_t< sycl::detail::sub_group::AcceptableForGlobalLoadStore::value && N == 1, vec> load(const multi_ptr cv_src) const { - multi_ptr src = detail::GetUnqualMultiPtr(cv_src); + multi_ptr src = + sycl::detail::GetUnqualMultiPtr(cv_src); return sycl::detail::sub_group::load(src); } #endif // ___NVPTX___ #else // __SYCL_DEVICE_ONLY__ template > - sycl::detail::enable_if_t< + std::enable_if_t< sycl::detail::sub_group::AcceptableForGlobalLoadStore::value, vec> load(const multi_ptr src) const { @@ -410,11 +416,12 @@ struct sub_group { template > - sycl::detail::enable_if_t< + std::enable_if_t< sycl::detail::sub_group::AcceptableForLocalLoadStore::value, vec> load(const multi_ptr cv_src) const { - multi_ptr src = detail::GetUnqualMultiPtr(cv_src); + multi_ptr src = + sycl::detail::GetUnqualMultiPtr(cv_src); #ifdef __SYCL_DEVICE_ONLY__ vec res; for (int i = 0; i < N; ++i) { @@ -431,7 +438,7 @@ struct sub_group { #ifdef __SYCL_DEVICE_ONLY__ // Method for decorated pointer template - detail::enable_if_t, T>::value> + std::enable_if_t, T>::value> store(T *dst, const remove_decoration_t &x) const { store(sycl::multi_ptr, sycl::detail::deduce_AS::value, @@ -441,7 +448,7 @@ struct sub_group { // Method for raw pointer template - detail::enable_if_t, T>::value> + std::enable_if_t, T>::value> store(T *dst, const remove_decoration_t &x) const { #ifdef __NVPTX__ @@ -475,7 +482,7 @@ struct sub_group { template - sycl::detail::enable_if_t< + std::enable_if_t< sycl::detail::sub_group::AcceptableForGlobalLoadStore::value> store(multi_ptr dst, const T &x) const { #ifdef __SYCL_DEVICE_ONLY__ @@ -494,7 +501,7 @@ struct sub_group { template - sycl::detail::enable_if_t< + std::enable_if_t< sycl::detail::sub_group::AcceptableForLocalLoadStore::value> store(multi_ptr dst, const T &x) const { #ifdef __SYCL_DEVICE_ONLY__ @@ -511,7 +518,7 @@ struct sub_group { #ifdef __NVPTX__ template - sycl::detail::enable_if_t< + std::enable_if_t< sycl::detail::sub_group::AcceptableForGlobalLoadStore::value> store(multi_ptr dst, const vec &x) const { for (int i = 0; i < N; ++i) { @@ -521,7 +528,7 @@ struct sub_group { #else // __NVPTX__ template - sycl::detail::enable_if_t< + std::enable_if_t< sycl::detail::sub_group::AcceptableForGlobalLoadStore::value && N != 1 && N != 3 && N != 16> store(multi_ptr dst, const vec &x) const { @@ -530,7 +537,7 @@ struct sub_group { template - sycl::detail::enable_if_t< + std::enable_if_t< sycl::detail::sub_group::AcceptableForGlobalLoadStore::value && N == 1> store(multi_ptr dst, const vec &x) const { @@ -539,7 +546,7 @@ struct sub_group { template - sycl::detail::enable_if_t< + std::enable_if_t< sycl::detail::sub_group::AcceptableForGlobalLoadStore::value && N == 3> store(multi_ptr dst, const vec &x) const { @@ -550,7 +557,7 @@ struct sub_group { template - sycl::detail::enable_if_t< + std::enable_if_t< sycl::detail::sub_group::AcceptableForGlobalLoadStore::value && N == 16> store(multi_ptr dst, const vec &x) const { @@ -563,7 +570,7 @@ struct sub_group { #else // __SYCL_DEVICE_ONLY__ template - sycl::detail::enable_if_t< + std::enable_if_t< sycl::detail::sub_group::AcceptableForGlobalLoadStore::value> store(multi_ptr dst, const vec &x) const { (void)dst; @@ -575,7 +582,7 @@ struct sub_group { template - sycl::detail::enable_if_t< + std::enable_if_t< sycl::detail::sub_group::AcceptableForLocalLoadStore::value> store(multi_ptr dst, const vec &x) const { #ifdef __SYCL_DEVICE_ONLY__ diff --git a/sycl/include/sycl/ext/oneapi/weak_object.hpp b/sycl/include/sycl/ext/oneapi/weak_object.hpp new file mode 100644 index 0000000000000..316bf170b5523 --- /dev/null +++ b/sycl/include/sycl/ext/oneapi/weak_object.hpp @@ -0,0 +1,149 @@ +//==-------------- weak_object.hpp --- SYCL weak objects -------------------==// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#pragma once + +#include +#include +#include + +namespace sycl { +__SYCL_INLINE_VER_NAMESPACE(_V1) { +namespace ext { +namespace oneapi { +namespace detail { +// Helper for creating ranges for empty weak_objects. +template static range createDummyRange() { + static_assert(Dims > 0 && Dims < 4, "Invalid dimensionality in range."); + if constexpr (Dims == 1) + return {1}; + else if constexpr (Dims == 2) + return {1, 1}; + else + return {1, 1, 1}; +} +} // namespace detail + +template +class weak_object : public detail::weak_object_base { +public: + using object_type = typename detail::weak_object_base::object_type; + + constexpr weak_object() noexcept : detail::weak_object_base() {} + weak_object(const SYCLObjT &SYCLObj) noexcept + : detail::weak_object_base(SYCLObj) {} + weak_object(const weak_object &Other) noexcept + : detail::weak_object_base(Other) {} + weak_object(weak_object &&Other) noexcept + : detail::weak_object_base(Other) {} + + weak_object &operator=(const SYCLObjT &SYCLObj) noexcept { + this->MObjWeakPtr = sycl::detail::getSyclObjImpl(SYCLObj); + return *this; + } + weak_object &operator=(const weak_object &Other) noexcept { + this->MObjWeakPtr = Other.MObjWeakPtr; + return *this; + } + weak_object &operator=(weak_object &&Other) noexcept { + this->MObjWeakPtr = std::move(Other.MObjWeakPtr); + return *this; + } + + std::optional try_lock() const noexcept { + auto MObjImplPtr = this->MObjWeakPtr.lock(); + if (!MObjImplPtr) + return std::nullopt; + return sycl::detail::createSyclObjFromImpl(MObjImplPtr); + } + SYCLObjT lock() const { + std::optional OptionalObj = try_lock(); + if (!OptionalObj) + throw sycl::exception(sycl::make_error_code(sycl::errc::invalid), + "Referenced object has expired."); + return *OptionalObj; + } +}; + +// Specialization of weak_object for buffer as it needs additional members +// to reconstruct the original buffer. +template +class weak_object> + : public detail::weak_object_base> { +private: + using buffer_type = buffer; + +public: + using object_type = + typename detail::weak_object_base::object_type; + + constexpr weak_object() noexcept + : detail::weak_object_base(), + MRange{detail::createDummyRange()}, MOffsetInBytes{0}, + MIsSubBuffer{false} {} + weak_object(const buffer_type &SYCLObj) noexcept + : detail::weak_object_base(SYCLObj), MRange{SYCLObj.Range}, + MOffsetInBytes{SYCLObj.OffsetInBytes}, MIsSubBuffer{ + SYCLObj.IsSubBuffer} {} + weak_object(const weak_object &Other) noexcept + : detail::weak_object_base(Other), MRange{Other.MRange}, + MOffsetInBytes{Other.MOffsetInBytes}, MIsSubBuffer{Other.MIsSubBuffer} { + } + weak_object(weak_object &&Other) noexcept + : detail::weak_object_base(Other), MRange{std::move( + Other.MRange)}, + MOffsetInBytes{std::move(Other.MOffsetInBytes)}, + MIsSubBuffer{std::move(Other.MIsSubBuffer)} {} + + weak_object &operator=(const buffer_type &SYCLObj) noexcept { + this->MObjWeakPtr = sycl::detail::getSyclObjImpl(SYCLObj); + this->MRange = SYCLObj.Range; + this->MOffsetInBytes = SYCLObj.OffsetInBytes; + this->MIsSubBuffer = SYCLObj.IsSubBuffer; + return *this; + } + weak_object &operator=(const weak_object &Other) noexcept { + this->MObjWeakPtr = Other.MObjWeakPtr; + this->MRange = Other.MRange; + this->MOffsetInBytes = Other.MOffsetInBytes; + this->MIsSubBuffer = Other.MIsSubBuffer; + return *this; + } + weak_object &operator=(weak_object &&Other) noexcept { + this->MObjWeakPtr = std::move(Other.MObjWeakPtr); + this->MRange = std::move(Other.MRange); + this->MOffsetInBytes = std::move(Other.MOffsetInBytes); + this->MIsSubBuffer = std::move(Other.MIsSubBuffer); + return *this; + } + + std::optional try_lock() const noexcept { + auto MObjImplPtr = this->MObjWeakPtr.lock(); + if (!MObjImplPtr) + return std::nullopt; + // To reconstruct the buffer we use the reinterpret constructor. + return buffer_type{MObjImplPtr, MRange, MOffsetInBytes, MIsSubBuffer}; + } + buffer_type lock() const { + std::optional OptionalObj = try_lock(); + if (!OptionalObj) + throw sycl::exception(sycl::make_error_code(sycl::errc::invalid), + "Referenced object has expired."); + return *OptionalObj; + } + +private: + range MRange; + size_t MOffsetInBytes; + bool MIsSubBuffer; +}; + +} // namespace oneapi +} // namespace ext +} // __SYCL_INLINE_VER_NAMESPACE(_V1) +} // namespace sycl diff --git a/sycl/include/sycl/ext/oneapi/weak_object_base.hpp b/sycl/include/sycl/ext/oneapi/weak_object_base.hpp new file mode 100644 index 0000000000000..0f4e744c39247 --- /dev/null +++ b/sycl/include/sycl/ext/oneapi/weak_object_base.hpp @@ -0,0 +1,67 @@ +//==------- weak_object_base.hpp --- SYCL weak objects base class ----------==// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#pragma once + +#include + +namespace sycl { +__SYCL_INLINE_VER_NAMESPACE(_V1) { +namespace ext { +namespace oneapi { +namespace detail { +template class weak_object_base; + +// Helper function for getting the underlying weak_ptr from a weak_object. +template +decltype(weak_object_base::MObjWeakPtr) +getSyclWeakObjImpl(const weak_object_base &WeakObj) { + return WeakObj.MObjWeakPtr; +} + +// Common base class for weak_object. +template class weak_object_base { +public: + using object_type = SYCLObjT; + + constexpr weak_object_base() noexcept : MObjWeakPtr() {} + weak_object_base(const SYCLObjT &SYCLObj) noexcept + : MObjWeakPtr(sycl::detail::getSyclObjImpl(SYCLObj)) {} + weak_object_base(const weak_object_base &Other) noexcept + : MObjWeakPtr(Other.MObjWeakPtr) {} + weak_object_base(weak_object_base &&Other) noexcept + : MObjWeakPtr(std::move(Other.MObjWeakPtr)) {} + + void reset() noexcept { MObjWeakPtr.reset(); } + void swap(weak_object_base &Other) noexcept { + MObjWeakPtr.swap(Other.MObjWeakPtr); + } + + bool expired() const noexcept { return MObjWeakPtr.expired(); } + + bool owner_before(const SYCLObjT &Other) const noexcept { + return MObjWeakPtr.owner_before(sycl::detail::getSyclObjImpl(Other)); + } + bool owner_before(const weak_object_base &Other) const noexcept { + return MObjWeakPtr.owner_before(Other.MObjWeakPtr); + } + +protected: + typename std::invoke_result_t), + SYCLObjT>::weak_type MObjWeakPtr; + + template + friend decltype(weak_object_base::MObjWeakPtr) + detail::getSyclWeakObjImpl(const weak_object_base &WeakObj); +}; +} // namespace detail +} // namespace oneapi +} // namespace ext +} // __SYCL_INLINE_VER_NAMESPACE(_V1) +} // namespace sycl diff --git a/sycl/include/sycl/feature_test.hpp.in b/sycl/include/sycl/feature_test.hpp.in index e5f50236cf4e7..66943dc17b591 100644 --- a/sycl/include/sycl/feature_test.hpp.in +++ b/sycl/include/sycl/feature_test.hpp.in @@ -66,6 +66,7 @@ __SYCL_INLINE_VER_NAMESPACE(_V1) { #define SYCL_EXT_ONEAPI_BACKEND_LEVEL_ZERO 3 #define SYCL_EXT_ONEAPI_USM_DEVICE_READ_ONLY 1 #define SYCL_EXT_ONEAPI_KERNEL_PROPERTIES 1 +#define SYCL_EXT_ONEAPI_WEAK_OBJECT 1 #cmakedefine01 SYCL_BUILD_PI_CUDA #if SYCL_BUILD_PI_CUDA #define SYCL_EXT_ONEAPI_BACKEND_CUDA 1 diff --git a/sycl/include/sycl/kernel.hpp b/sycl/include/sycl/kernel.hpp index 14efb878bc7ef..9081f7333f87d 100644 --- a/sycl/include/sycl/kernel.hpp +++ b/sycl/include/sycl/kernel.hpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -155,6 +156,26 @@ class __SYCL_EXPORT kernel { typename detail::is_kernel_device_specific_info_desc::return_type get_info(const device &Device, const range<3> &WGSize) const; + /// Compares the kernel against a weak object using an owner-based + /// implementation-defined ordering. + /// + /// \param Other is the weak object to compare ordering against. + /// \return true if this object precedes \param Other and false otherwise. + bool ext_oneapi_owner_before( + const ext::oneapi::detail::weak_object_base &Other) + const noexcept { + return impl.owner_before(ext::oneapi::detail::getSyclWeakObjImpl(Other)); + } + + /// Compares the kernel against another kernel using an owner-based + /// implementation-defined ordering. + /// + /// \param Other is the object to compare ordering against. + /// \return true if this object precedes \param Other and false otherwise. + bool ext_oneapi_owner_before(const kernel &Other) const noexcept { + return impl.owner_before(Other.impl); + } + private: /// Constructs a SYCL kernel object from a valid kernel_impl instance. kernel(std::shared_ptr Impl); diff --git a/sycl/include/sycl/kernel_bundle.hpp b/sycl/include/sycl/kernel_bundle.hpp index 23b540cc810b7..4f5a960ea9760 100644 --- a/sycl/include/sycl/kernel_bundle.hpp +++ b/sycl/include/sycl/kernel_bundle.hpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -48,6 +49,26 @@ class __SYCL_EXPORT kernel_id { bool operator!=(const kernel_id &RHS) const { return !(*this == RHS); } + /// Compares the kernel_id against a weak object using an owner-based + /// implementation-defined ordering. + /// + /// \param Other is the weak object to compare ordering against. + /// \return true if this object precedes \param Other and false otherwise. + bool ext_oneapi_owner_before( + const ext::oneapi::detail::weak_object_base &Other) + const noexcept { + return impl.owner_before(ext::oneapi::detail::getSyclWeakObjImpl(Other)); + } + + /// Compares the kernel_id against another kernel_id using an owner-based + /// implementation-defined ordering. + /// + /// \param Other is the object to compare ordering against. + /// \return true if this object precedes \param Other and false otherwise. + bool ext_oneapi_owner_before(const kernel_id &Other) const noexcept { + return impl.owner_before(Other.impl); + } + private: kernel_id(const char *Name); @@ -117,6 +138,26 @@ class device_image : public detail::device_image_plain { return device_image_plain::has_kernel(KernelID, Dev); } + /// Compares the kernel against a weak object using an owner-based + /// implementation-defined ordering. + /// + /// \param Other is the weak object to compare ordering against. + /// \return true if this object precedes \param Other and false otherwise. + bool ext_oneapi_owner_before( + const ext::oneapi::detail::weak_object_base &Other) + const noexcept { + return impl.owner_before(ext::oneapi::detail::getSyclWeakObjImpl(Other)); + } + + /// Compares the device_image against another device_image using an + /// owner-based implementation-defined ordering. + /// + /// \param Other is the object to compare ordering against. + /// \return true if this object precedes \param Other and false otherwise. + bool ext_oneapi_owner_before(const device_image &Other) const noexcept { + return impl.owner_before(Other.impl); + } + private: device_image(detail::DeviceImageImplPtr Impl) : device_image_plain(std::move(Impl)) {} @@ -311,6 +352,26 @@ class kernel_bundle : public detail::kernel_bundle_plain { return reinterpret_cast(kernel_bundle_plain::end()); } + /// Compares the kernel against a weak object using an owner-based + /// implementation-defined ordering. + /// + /// \param Other is the weak object to compare ordering against. + /// \return true if this object precedes \param Other and false otherwise. + bool ext_oneapi_owner_before( + const ext::oneapi::detail::weak_object_base &Other) + const noexcept { + return impl.owner_before(ext::oneapi::detail::getSyclWeakObjImpl(Other)); + } + + /// Compares the kernel_bundle against another kernel_bundle using an + /// owner-based implementation-defined ordering. + /// + /// \param Other is the object to compare ordering against. + /// \return true if this object precedes \param Other and false otherwise. + bool ext_oneapi_owner_before(const kernel_bundle &Other) const noexcept { + return impl.owner_before(Other.impl); + } + private: kernel_bundle(detail::KernelBundleImplPtr Impl) : kernel_bundle_plain(std::move(Impl)) {} diff --git a/sycl/include/sycl/platform.hpp b/sycl/include/sycl/platform.hpp index 4b07626eeb385..8813b810cab6a 100644 --- a/sycl/include/sycl/platform.hpp +++ b/sycl/include/sycl/platform.hpp @@ -15,6 +15,7 @@ #include #include #include +#include #include // 4.6.2 Platform class @@ -158,6 +159,26 @@ class __SYCL_EXPORT platform { /// \return the default context context ext_oneapi_get_default_context() const; + /// Compares the platform against a weak object using an owner-based + /// implementation-defined ordering. + /// + /// \param Other is the weak object to compare ordering against. + /// \return true if this object precedes \param Other and false otherwise. + bool ext_oneapi_owner_before( + const ext::oneapi::detail::weak_object_base &Other) + const noexcept { + return impl.owner_before(ext::oneapi::detail::getSyclWeakObjImpl(Other)); + } + + /// Compares the platform against another platform using an owner-based + /// implementation-defined ordering. + /// + /// \param Other is the object to compare ordering against. + /// \return true if this object precedes \param Other and false otherwise. + bool ext_oneapi_owner_before(const platform &Other) const noexcept { + return impl.owner_before(Other.impl); + } + private: pi_native_handle getNative() const; diff --git a/sycl/include/sycl/queue.hpp b/sycl/include/sycl/queue.hpp index 2c14089e8e3b4..2366855a36ac0 100644 --- a/sycl/include/sycl/queue.hpp +++ b/sycl/include/sycl/queue.hpp @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -1264,6 +1265,26 @@ class __SYCL_EXPORT queue { /// \return the backend associated with this queue. backend get_backend() const noexcept; + /// Compares the queue against a weak object using an owner-based + /// implementation-defined ordering. + /// + /// \param Other is the weak object to compare ordering against. + /// \return true if this object precedes \param Other and false otherwise. + bool ext_oneapi_owner_before( + const ext::oneapi::detail::weak_object_base &Other) + const noexcept { + return impl.owner_before(ext::oneapi::detail::getSyclWeakObjImpl(Other)); + } + + /// Compares the queue against another queue using an owner-based + /// implementation-defined ordering. + /// + /// \param Other is the object to compare ordering against. + /// \return true if this object precedes \param Other and false otherwise. + bool ext_oneapi_owner_before(const queue &Other) const noexcept { + return impl.owner_before(Other.impl); + } + private: pi_native_handle getNative() const; diff --git a/sycl/include/sycl/stream.hpp b/sycl/include/sycl/stream.hpp index 761767ae75c41..b665c1d24f034 100644 --- a/sycl/include/sycl/stream.hpp +++ b/sycl/include/sycl/stream.hpp @@ -11,6 +11,7 @@ #include #include #include +#include #include namespace sycl { @@ -772,6 +773,33 @@ class __SYCL_EXPORT __SYCL_SPECIAL_CLASS __SYCL_TYPE(stream) stream { template propertyT get_property() const; +#ifndef __SYCL_DEVICE_ONLY__ + /// Compares the platform against a weak object using an owner-based + /// implementation-defined ordering. + /// + /// \param Other is the weak object to compare ordering against. + /// \return true if this object precedes \param Other and false otherwise. + bool ext_oneapi_owner_before( + const ext::oneapi::detail::weak_object_base &Other) + const noexcept { + return impl.owner_before(ext::oneapi::detail::getSyclWeakObjImpl(Other)); + } + + /// Compares the platform against another platform using an owner-based + /// implementation-defined ordering. + /// + /// \param Other is the object to compare ordering against. + /// \return true if this object precedes \param Other and false otherwise. + bool ext_oneapi_owner_before(const stream &Other) const noexcept { + return impl.owner_before(Other.impl); + } +#else + bool ext_oneapi_owner_before( + const ext::oneapi::detail::weak_object_base &Other) + const noexcept; + bool ext_oneapi_owner_before(const stream &Other) const noexcept; +#endif + private: #ifdef __SYCL_DEVICE_ONLY__ char padding[sizeof(std::shared_ptr)]; diff --git a/sycl/include/sycl/sycl.hpp b/sycl/include/sycl/sycl.hpp index 70a29d96d5097..8624edafd73fd 100644 --- a/sycl/include/sycl/sycl.hpp +++ b/sycl/include/sycl/sycl.hpp @@ -67,7 +67,9 @@ #include #include #include +#include #include #include #include #include +#include diff --git a/sycl/unittests/Extensions/CMakeLists.txt b/sycl/unittests/Extensions/CMakeLists.txt index dd43966e3b257..dde8d39cf9f80 100644 --- a/sycl/unittests/Extensions/CMakeLists.txt +++ b/sycl/unittests/Extensions/CMakeLists.txt @@ -4,5 +4,6 @@ add_sycl_unittest(ExtensionsTests OBJECT DefaultContext.cpp FPGADeviceSelectors.cpp DeviceArchitecture.cpp + WeakObject.cpp ) diff --git a/sycl/unittests/Extensions/WeakObject.cpp b/sycl/unittests/Extensions/WeakObject.cpp new file mode 100644 index 0000000000000..07c9a22dca1fc --- /dev/null +++ b/sycl/unittests/Extensions/WeakObject.cpp @@ -0,0 +1,361 @@ +//==------------------------- WeakObject.cpp -------------------------------==// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include + +#include +#include + +#include + +template struct WeakObjectCheckExpired { + void operator()(SyclObjT Obj) { + sycl::ext::oneapi::weak_object WeakObj{Obj}; + sycl::ext::oneapi::weak_object NullWeakObj; + + EXPECT_FALSE(WeakObj.expired()); + EXPECT_TRUE(NullWeakObj.expired()); + } +}; + +template struct WeakObjectCheckTryLock { + void operator()(SyclObjT Obj) { + sycl::ext::oneapi::weak_object WeakObj{Obj}; + sycl::ext::oneapi::weak_object NullWeakObj; + + std::optional TLObj = WeakObj.try_lock(); + std::optional TLNull = NullWeakObj.try_lock(); + + EXPECT_TRUE(TLObj.has_value()); + EXPECT_FALSE(TLNull.has_value()); + + EXPECT_TRUE(TLObj.value() == Obj); + } +}; + +template struct WeakObjectCheckLock { + void operator()(SyclObjT Obj) { + sycl::ext::oneapi::weak_object WeakObj{Obj}; + sycl::ext::oneapi::weak_object NullWeakObj; + + SyclObjT LObj = WeakObj.lock(); + EXPECT_TRUE(LObj == Obj); + + try { + SyclObjT LNull = NullWeakObj.lock(); + FAIL() << "Locking empty weak object did not throw."; + } catch (sycl::exception &E) { + EXPECT_EQ(E.code(), sycl::make_error_code(sycl::errc::invalid)) + << "Unexpected thrown error code."; + } + } +}; + +template struct WeakObjectCheckOwnerBefore { + void operator()(SyclObjT Obj) { + sycl::ext::oneapi::weak_object WeakObj{Obj}; + sycl::ext::oneapi::weak_object NullWeakObj; + + EXPECT_TRUE(WeakObj.owner_before(NullWeakObj) || + NullWeakObj.owner_before(WeakObj)); + EXPECT_FALSE(WeakObj.owner_before(NullWeakObj) && + NullWeakObj.owner_before(WeakObj)); + + EXPECT_FALSE(WeakObj.owner_before(Obj)); + EXPECT_FALSE(Obj.ext_oneapi_owner_before(WeakObj)); + } +}; + +template struct WeakObjectCheckOwnerLess { + void operator()(SyclObjT Obj) { + sycl::ext::oneapi::weak_object WeakObj{Obj}; + sycl::ext::oneapi::weak_object NullWeakObj; + sycl::ext::oneapi::owner_less Comparator; + + EXPECT_TRUE(Comparator(WeakObj, NullWeakObj) || + Comparator(NullWeakObj, WeakObj)); + EXPECT_FALSE(Comparator(WeakObj, NullWeakObj) && + Comparator(NullWeakObj, WeakObj)); + + EXPECT_FALSE(Comparator(WeakObj, Obj)); + EXPECT_FALSE(Comparator(Obj, WeakObj)); + } +}; + +template struct WeakObjectCheckReset { + void operator()(SyclObjT Obj) { + sycl::ext::oneapi::weak_object WeakObj{Obj}; + sycl::ext::oneapi::weak_object NullWeakObj; + + WeakObj.reset(); + EXPECT_TRUE(WeakObj.expired()); + EXPECT_FALSE(WeakObj.owner_before(NullWeakObj)); + EXPECT_FALSE(NullWeakObj.owner_before(WeakObj)); + + std::optional TLObj = WeakObj.try_lock(); + EXPECT_FALSE(TLObj.has_value()); + + try { + SyclObjT LObj = WeakObj.lock(); + FAIL() << "Locking reset weak object did not throw."; + } catch (sycl::exception &E) { + EXPECT_EQ(E.code(), sycl::make_error_code(sycl::errc::invalid)) + << "Unexpected thrown error code."; + } + } +}; + +template struct WeakObjectCheckOwnerLessMulti { + void operator()(SyclObjT Obj1, SyclObjT Obj2) { + sycl::ext::oneapi::weak_object WeakObj1{Obj1}; + sycl::ext::oneapi::weak_object WeakObj2{Obj2}; + sycl::ext::oneapi::owner_less Comparator; + + EXPECT_TRUE(Comparator(WeakObj1, WeakObj2) || + Comparator(WeakObj2, WeakObj1)); + EXPECT_FALSE(Comparator(WeakObj1, WeakObj2) && + Comparator(WeakObj2, WeakObj1)); + + EXPECT_FALSE(Comparator(WeakObj1, Obj1)); + EXPECT_FALSE(Comparator(Obj1, WeakObj1)); + + EXPECT_FALSE(Comparator(WeakObj2, Obj2)); + EXPECT_FALSE(Comparator(Obj2, WeakObj2)); + } +}; + +template struct WeakObjectCheckOwnerBeforeMulti { + void operator()(SyclObjT Obj1, SyclObjT Obj2) { + sycl::ext::oneapi::weak_object WeakObj1{Obj1}; + sycl::ext::oneapi::weak_object WeakObj2{Obj2}; + + EXPECT_TRUE(WeakObj1.owner_before(WeakObj2) || + WeakObj2.owner_before(WeakObj1)); + EXPECT_FALSE(WeakObj1.owner_before(WeakObj2) && + WeakObj2.owner_before(WeakObj1)); + + EXPECT_FALSE(WeakObj1.owner_before(Obj1)); + EXPECT_FALSE(Obj1.ext_oneapi_owner_before(WeakObj1)); + + EXPECT_FALSE(WeakObj2.owner_before(Obj2)); + EXPECT_FALSE(Obj2.ext_oneapi_owner_before(WeakObj2)); + } +}; + +template struct WeakObjectCheckOwnerLessMap { + void operator()(SyclObjT Obj1, SyclObjT Obj2) { + sycl::ext::oneapi::weak_object WeakObj1{Obj1}; + sycl::ext::oneapi::weak_object WeakObj2{Obj2}; + + std::map, int, + sycl::ext::oneapi::owner_less> + Map; + Map[WeakObj1] = 1; + Map[WeakObj2] = 2; + + EXPECT_EQ(Map.size(), (size_t)2); + EXPECT_EQ(Map[WeakObj1], 1); + EXPECT_EQ(Map[WeakObj2], 2); + EXPECT_EQ(Map[Obj1], 1); + EXPECT_EQ(Map[Obj2], 2); + + Map[WeakObj1] = 2; + Map[WeakObj2] = 3; + + EXPECT_EQ(Map.size(), (size_t)2); + EXPECT_EQ(Map[WeakObj1], 2); + EXPECT_EQ(Map[WeakObj2], 3); + EXPECT_EQ(Map[Obj1], 2); + EXPECT_EQ(Map[Obj2], 3); + + Map[Obj1] = 5; + Map[Obj2] = 6; + + EXPECT_EQ(Map.size(), (size_t)2); + EXPECT_EQ(Map[WeakObj1], 5); + EXPECT_EQ(Map[WeakObj2], 6); + EXPECT_EQ(Map[Obj1], 5); + EXPECT_EQ(Map[Obj2], 6); + + Map[sycl::ext::oneapi::weak_object{Obj1}] = 10; + Map[sycl::ext::oneapi::weak_object{Obj2}] = 13; + + EXPECT_EQ(Map.size(), (size_t)2); + EXPECT_EQ(Map[WeakObj1], 10); + EXPECT_EQ(Map[WeakObj2], 13); + EXPECT_EQ(Map[Obj1], 10); + EXPECT_EQ(Map[Obj2], 13); + } +}; + +template