Skip to content

Commit d225957

Browse files
[oneDPL] Indirectly Device Accessible Iterator Customization Point and Public Trait (#620)
--------- Signed-off-by: Dan Hoeflinger <[email protected]> Co-authored-by: Alexey Kukanov <[email protected]>
1 parent 0d15166 commit d225957

File tree

2 files changed

+146
-6
lines changed

2 files changed

+146
-6
lines changed

source/elements/oneDPL/source/parallel_api/execution_policies.rst

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -99,9 +99,9 @@ to run algorithms on a SYCL device. When an algorithm runs with ``device_policy`
9999
it is capable of processing SYCL buffers (passed via ``oneapi::dpl::begin/end``),
100100
data in the host memory and data in Unified Shared Memory (USM), including device USM.
101101
Data placed in the host memory and USM can be passed to oneDPL algorithms
102-
as pointers and random access iterators. The way to transfer data from the host memory
103-
to a device and back is unspecified; per-element data movement to/from a temporary storage
104-
is a possible valid implementation.
102+
as pointers and random access iterators, including :doc:`oneDPL iterators <iterators>`. The way to transfer data from
103+
the host memory to a device and back is unspecified; per-element data movement to/from a temporary storage is a possible
104+
valid implementation.
105105

106106
The ``KernelName`` template parameter, also aliased as ``kernel_name`` within the class template,
107107
is to explicitly provide a name for SYCL kernels executed by an algorithm the policy is passed to.

source/elements/oneDPL/source/parallel_api/iterators.rst

Lines changed: 143 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,52 @@
33
..
44
.. SPDX-License-Identifier: CC-BY-4.0
55
6+
.. _iterators:
7+
68
Iterators
79
---------
810

11+
Requirements For Iterator Use With Device Policies
12+
++++++++++++++++++++++++++++++++++++++++++++++++++
13+
Iterators and iterator-like types may or may not refer to content accessible within a `SYCL`_ kernel on a device.
14+
The term *indirectly device accessible* refers to a type that represents content accessible on a device.
15+
An *indirectly device accessible iterator* is such a type that can also be dereferenced within a SYCL kernel.
16+
17+
An example of indirectly device accessible iterators include SYCL USM shared pointers which can inherently be used in
18+
a SYCL kernel. An example of an iterator type that is not indirectly device accessible is a random access iterator
19+
referring to host allocated data because dereferencing it within a SYCL kernel would result in undefined behavior.
20+
21+
:doc:`Buffer position objects <buffer_wrappers>` returned by ``oneapi::dpl::begin`` and ``oneapi::dpl::end`` are not
22+
iterators. However, they are indirectly device accessible because they represent data accessible on the device.
23+
24+
When passed to oneDPL algorithms with a ``device_policy``, indirectly device accessible iterator types that are also
25+
random access iterators and satisfy *SYCL device-copyable* must not cause unnecessary data movement beyond what is
26+
required by the algorithm's semantics and what would be required to use the type directly within a SYCL kernel.
27+
Indirectly device accessible buffer position objects must not cause unnecessary data movement beyond what is
28+
required by the algorithm's semantics and what would be required by using an accessor to the buffer within a SYCL
29+
kernel.
30+
31+
Indirect Device Accessibility Type Trait
32+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
33+
34+
The following class template and variable template are defined in ``<oneapi/dpl/iterator>`` inside the namespace
35+
``oneapi::dpl``:
36+
37+
.. code:: cpp
38+
39+
template <typename T>
40+
struct is_indirectly_device_accessible{ /* see below */ };
41+
42+
template <typename T>
43+
inline constexpr bool is_indirectly_device_accessible_v = is_indirectly_device_accessible<T>::value;
44+
45+
``template <typename T> oneapi::dpl::is_indirectly_device_accessible`` is a type which has the base characteristic
46+
of ``std::true_type`` if ``T`` is indirectly device accessible. Otherwise, it has the base characteristic of
47+
``std::false_type``.
48+
49+
oneDPL Iterators
50+
++++++++++++++++
51+
952
The oneDPL iterators are defined in the ``<oneapi/dpl/iterator>`` header,
1053
in ``namespace oneapi::dpl``.
1154

@@ -64,6 +107,8 @@ counter; dereference operations cannot be used to modify the counter. The arithm
64107
operators of ``counting_iterator`` behave as if applied to the values of Integral type
65108
representing the counters of the iterator instances passed to the operators.
66109

110+
``counting_iterator`` is SYCL device-copyable, and is an indirectly device accessible iterator.
111+
67112
.. code:: cpp
68113
69114
class discard_iterator
@@ -104,6 +149,8 @@ lvalue that may be assigned an arbitrary value. The assignment has no effect on
104149
of ``discard_iterator`` behave as if applied to integer counter values maintained by the
105150
iterator instances to determine their position relative to each other.
106151

152+
``discard_iterator`` is SYCL device-copyable, and is an indirectly device accessible iterator.
153+
107154
.. code:: cpp
108155
109156
template <typename SourceIterator, typename IndexMap>
@@ -150,8 +197,14 @@ defined by the source iterator provided, and whose iteration order over the dere
150197
is defined by either another iterator or a functor that maps the ``permutation_iterator`` index
151198
to the index of the source iterator. The arithmetic and comparison operators of
152199
``permutation_iterator`` behave as if applied to integer counter values maintained by the
153-
iterator instances to determine their position in the index map. ``SourceIterator`` must satisfy
154-
``AdaptingIteratorSource``.
200+
iterator instances to determine their position in the index map.
201+
202+
``permutation_iterator`` is SYCL device-copyable if both the ``SourceIterator`` and the ``IndexMap``
203+
are SYCL device-copyable. ``permutation_iterator`` is indirectly device accessible if both the
204+
``SourceIterator`` and the ``IndexMap`` are indirectly device accessible.
205+
206+
``SourceIterator`` must satisfy ``AdaptingIteratorSource``. When using ``permutation_iterator`` in combination with an
207+
algorithm with a ``device_policy``, ``SourceIterator`` must be indirectly device accessible.
155208

156209
The type ``IndexMap`` must be one of the following:
157210

@@ -163,7 +216,6 @@ The type ``IndexMap`` must be one of the following:
163216
* A functor with a signature equivalent to ``T operator()(const T&) const`` where ``T`` is a
164217
``std::iterator_traits<SourceIterator>::difference_type``
165218

166-
167219
``permutation_iterator::operator*`` uses the counter value of the instance on which
168220
it is invoked to index into the index map. The corresponding value in the map is then used
169221
to index into the value set defined by the source iterator. The resulting lvalue is returned
@@ -234,6 +286,9 @@ arithmetic and comparison operators of ``transform_iterator`` behave as if appli
234286
source iterator itself. The template type ``Iterator`` must satisfy
235287
``AdaptingIteratorSource``.
236288

289+
``transform_iterator`` is SYCL device-copyable if the source iterator is SYCL device-copyable, and
290+
is indirectly device accessible if the source iterator is indirectly device accessible.
291+
237292
.. code:: cpp
238293
239294
template <typename UnaryFunc, typename Iterator>
@@ -293,6 +348,9 @@ source iterators over which the ``zip_iterator`` is defined. The arithmetic oper
293348
operation were applied to each of these iterators. The types ``T`` within the template pack
294349
``Iterators...`` must satisfy ``AdaptingIteratorSource``.
295350

351+
``zip_iterator`` is SYCL device-copyable if all the source iterators are SYCL device-copyable, and is indirectly
352+
device accessible if all the source iterators are indirectly device accessible.
353+
296354
.. code:: cpp
297355
298356
template <typename... Iterators>
@@ -301,3 +359,85 @@ operation were applied to each of these iterators. The types ``T`` within the te
301359
302360
``make_zip_iterator`` constructs and returns an instance of ``zip_iterator``
303361
using the set of source iterators provided.
362+
363+
Other Iterators
364+
+++++++++++++++
365+
Pointers are assumed to be USM shared or device memory pointers when used in combination with an algorithm with a
366+
``device_policy`` and are indirectly device accessible. Pointers are trivially copyable and therefore SYCL
367+
device-copyable.
368+
369+
It is implementation defined whether other iterators are indirectly device accessible, including iterator types from
370+
the `C++ Standard`_.
371+
372+
.. _iterators-device-accessible:
373+
374+
Customization For User Defined Iterators
375+
++++++++++++++++++++++++++++++++++++++++
376+
oneDPL provides a mechanism to indicate whether custom iterators are indirectly device accessible.
377+
378+
Applications may define a free function ``is_onedpl_indirectly_device_accessible(T)``, which accepts an argument of
379+
type ``T`` and returns a type with the base characteristic of ``std::true_type`` if ``T`` is indirectly device
380+
accessible. Otherwise, it returns a type with the base characteristic of ``std::false_type``. The function must be
381+
discoverable by argument-dependent lookup (ADL). It may be provided as a forward declaration only, without defining a
382+
body.
383+
384+
The return type of ``is_onedpl_indirectly_device_accessible`` is examined at compile time to determine if ``T`` is
385+
indirectly device accessible. The function overload to use must be selected with argument-dependent lookup.
386+
[*Note*: Therefore, according to the rules in the C++ Standard, a derived type for which there is no
387+
function overload will match its most specific base type for which an overload exists. -- *end note*]
388+
389+
Once ``is_onedpl_indirectly_device_accessible(T)`` is defined, the public trait
390+
``template<typename T> oneapi::dpl::is_indirectly_device_accessible[_v]`` will return the appropriate value. This public
391+
trait can also be used to define the return type of ``is_onedpl_indirectly_device_accessible(T)`` by applying it to any
392+
source iterator component types. Refer to the example below.
393+
394+
Example
395+
^^^^^^^
396+
397+
The following example shows how to define a customization for ``is_indirectly_device_accessible`` trait for a simple
398+
user defined iterator. It also shows a more complicated example where the customization is defined as a hidden friend
399+
of the iterator class.
400+
401+
.. code:: cpp
402+
403+
namespace usr
404+
{
405+
struct accessible_it
406+
{
407+
/* user definition of an indirectly device accessible iterator */
408+
};
409+
410+
std::true_type
411+
is_onedpl_indirectly_device_accessible(accessible_it);
412+
413+
struct inaccessible_it
414+
{
415+
/* user definition of an iterator which is not indirectly device accessible */
416+
};
417+
418+
// The following could be omitted, as returning std::false_type matches the default behavior.
419+
std::false_type
420+
is_onedpl_indirectly_device_accessible(inaccessible_it);
421+
}
422+
423+
static_assert(oneapi::dpl::is_indirectly_device_accessible<usr::accessible_it> == true);
424+
static_assert(oneapi::dpl::is_indirectly_device_accessible<usr::inaccessible_it> == false);
425+
426+
// Example with base iterators and ADL overload as a hidden friend
427+
template <typename It1, typename It2>
428+
struct it_pair
429+
{
430+
It1 first;
431+
It2 second;
432+
friend auto is_onedpl_indirectly_device_accessible(it_pair) ->
433+
std::conjunction<oneapi::dpl::is_indirectly_device_accessible<It1>,
434+
oneapi::dpl::is_indirectly_device_accessible<It2>>;
435+
};
436+
437+
static_assert(oneapi::dpl::is_indirectly_device_accessible<
438+
it_pair<usr::accessible_it, usr::accessible_it>> == true);
439+
static_assert(oneapi::dpl::is_indirectly_device_accessible<
440+
it_pair<usr::accessible_it, usr::inaccessible_it>> == false);
441+
442+
.. _`C++ Standard`: https://isocpp.org/std/the-standard
443+
.. _`SYCL`: https://registry.khronos.org/SYCL/specs/sycl-2020/html/sycl-2020.html

0 commit comments

Comments
 (0)