diff --git a/source/elements/oneDPL/source/parallel_api/buffer_wrappers.rst b/source/elements/oneDPL/source/parallel_api/buffer_wrappers.rst index 88e3baa4a..2baba6d64 100644 --- a/source/elements/oneDPL/source/parallel_api/buffer_wrappers.rst +++ b/source/elements/oneDPL/source/parallel_api/buffer_wrappers.rst @@ -6,6 +6,20 @@ Buffer Wrappers --------------- +A *buffer wrapper* is an iterator-like type for processing data in `SYCL`_ buffers with oneDPL algorithms. +It is either the type of a *buffer position object* returned by +``oneapi::dpl::begin`` or ``oneapi::dpl::end`` or a type composed of at least one buffer position object, +with the same capabilities and limitations as buffer position objects. +Buffer wrappers can be used as source types for :doc:`oneDPL iterators `, and the resulting type is also a +buffer wrapper. + +Buffer wrappers substitute for iterators as arguments and return values of oneDPL algorithms, however they cannot be +used as iterators in other contexts, including dereference, as these types do not fully satisfy the C++ standard +requirements for an iterator. + +Buffer Position Objects +----------------------- + .. code:: cpp // Defined in @@ -48,14 +62,18 @@ which type satisfies the following requirements but is otherwise unspecified: - It is copy-constructible and copy-assignable. - It is comparable with ``operator==`` and ``operator!=``. -- It provides the ``get_buffer()`` method that for a buffer position object returns the SYCL buffer, - which the object was built over. - The expressions ``a + n`` and ``a - n``, where ``a`` is a buffer position object and ``n`` is an integer value, are valid and evaluate to a buffer position object such that the corresponding position in the buffer follows (precedes) that of ``a`` by ``n``. If this new position is out of the buffer bounds, the behavior is undefined. - The expression ``a - b``, where ``a`` and ``b`` are buffer position objects, is valid and evaluates to an integer value ``n`` such that ``a == b + n``. +- It provides the ``get_buffer()`` method that for a buffer position object returns the SYCL buffer, + which the object was built over. + +.. note:: + Only buffer position objects are required to support the ``get_buffer()`` method, other buffer wrappers + composed of buffer position objects are not required to support this method. If these operators and expressions are applied to buffer position objects that are not built over the same SYCL buffer, the behavior is undefined. @@ -73,10 +91,6 @@ in expressions with other objects built over the same buffer. auto pos = dpl::find(dpl::execution::dpcpp_default, dpl::begin(buf), dpl::end(buf), value); int value_index = (pos == dpl::end(buf)) ? -1 : (pos - dpl::begin(buf)); -.. note:: - Though buffer position objects substitute for iterators as arguments and return values - of oneDPL algorithms, they cannot be used as iterators in other contexts, including dereference, - as their type does not satisfy the C++ standard requirements for an iterator. SYCL deduction tags (the ``TagT`` parameters) and ``sycl::property::no_init`` allow to specify an access mode to be used by algorithms for accessing a SYCL buffer. diff --git a/source/elements/oneDPL/source/parallel_api/execution_policies.rst b/source/elements/oneDPL/source/parallel_api/execution_policies.rst index df65415d5..1fab6ec9c 100644 --- a/source/elements/oneDPL/source/parallel_api/execution_policies.rst +++ b/source/elements/oneDPL/source/parallel_api/execution_policies.rst @@ -96,9 +96,9 @@ device_policy Class An object of the ``device_policy`` type is associated with a ``sycl::queue`` that is used to run algorithms on a SYCL device. When an algorithm runs with ``device_policy`` -it is capable of processing SYCL buffers (passed via ``oneapi::dpl::begin/end``), -data in the host memory and data in Unified Shared Memory (USM), including device USM. -Data placed in the host memory and USM can be passed to oneDPL algorithms +it is capable of processing SYCL buffers (passed via ``oneapi::dpl::begin/end`` or other +:doc:`buffer wrappers `), data in the host memory and data in Unified Shared Memory (USM), including +device USM. Data placed in the host memory and USM can be passed to oneDPL algorithms as pointers and random access iterators, including :doc:`oneDPL iterators `. The way to transfer data from the host memory to a device and back is unspecified; per-element data movement to/from a temporary storage is a possible valid implementation. diff --git a/source/elements/oneDPL/source/parallel_api/iterators.rst b/source/elements/oneDPL/source/parallel_api/iterators.rst index 6b5da8039..8ecc4c1cf 100644 --- a/source/elements/oneDPL/source/parallel_api/iterators.rst +++ b/source/elements/oneDPL/source/parallel_api/iterators.rst @@ -24,9 +24,13 @@ iterators. However, they are indirectly device accessible because they represent When passed to oneDPL algorithms with a ``device_policy``, indirectly device accessible iterator types that are also random access iterators and satisfy *SYCL device-copyable* must not cause unnecessary data movement beyond what is required by the algorithm's semantics and what would be required to use the type directly within a SYCL kernel. -Indirectly device accessible buffer position objects must not cause unnecessary data movement beyond what is -required by the algorithm's semantics and what would be required by using an accessor to the buffer within a SYCL -kernel. + +Similarly, when passed to oneDPL algorithms with a ``device_policy``, buffer position objects must not cause +unnecessary data movement beyond what is required by the algorithm's semantics and what would be required +by using an accessor to the buffer within a SYCL kernel. + +The same requirement to prevent excessive data movements equally applies to indirectly device accessible types +composed of one or more source components, such as the oneDPL iterators. Indirect Device Accessibility Type Trait ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -52,17 +56,20 @@ oneDPL Iterators The oneDPL iterators are defined in the ```` header, in ``namespace oneapi::dpl``. -Let us define a named requirement, ``AdaptingIteratorSource``, to describe valid random access iterator-like +Let us define a named requirement, ``AdaptingIteratorSource``, to describe random access iterator-like types that can be used as source for oneDPL iterators as described below. The type ``Iter`` satisfies the ``AdaptingIteratorSource`` named requirement if it is any of the following: * A random access iterator -* The unspecified iterator-like type returned by ``oneapi::dpl::begin`` or ``oneapi::dpl::end`` * A ``permutation_iterator`` * A ``transform_iterator`` * A ``counting_iterator`` * A ``discard_iterator`` * A ``zip_iterator`` +* A :doc:`buffer position object ` type returned by ``oneapi::dpl::begin`` and ``oneapi::dpl::end`` + +If ``AdaptingIteratorSource`` is a buffer wrapper, a type built upon that also becomes a buffer wrapper, +not an iterator, and cannot be directly dereferenced (see :doc:`Buffer wrappers `). .. code:: cpp @@ -209,12 +216,15 @@ algorithm with a ``device_policy``, ``SourceIterator`` must be indirectly device The type ``IndexMap`` must be one of the following: * A random access iterator -* The unspecified iterator-like type returned by ``oneapi::dpl::begin`` or ``oneapi::dpl::end`` * A ``permutation_iterator`` * A ``transform_iterator`` * A ``counting_iterator`` * A functor with a signature equivalent to ``T operator()(const T&) const`` where ``T`` is a ``std::iterator_traits::difference_type`` +* A :doc:`buffer position object ` type returned by ``oneapi::dpl::begin`` and ``oneapi::dpl::end`` + +If the ``IndexMap`` is a buffer wrapper, the ``permutation_iterator`` built upon that will be a buffer wrapper, not an +iterator, and cannot be directly dereferenced (see :doc:`Buffer wrappers `). ``permutation_iterator::operator*`` uses the counter value of the instance on which it is invoked to index into the index map. The corresponding value in the map is then used