|
1 | | -.. SPDX-FileCopyrightText: 2019-2020 Intel Corporation |
| 1 | +.. SPDX-FileCopyrightText: 2019-2022 Intel Corporation |
2 | 2 | .. |
3 | 3 | .. SPDX-License-Identifier: CC-BY-4.0 |
4 | 4 |
|
5 | | -Specific API of oneDPL |
6 | | ----------------------- |
| 5 | +Parallel API |
| 6 | +------------ |
7 | 7 |
|
8 | | -The oneDPL extensions include iterators, function objects, and parallel algorithms. |
| 8 | +For all C++ algorithms accepting execution policies (as defined by `C++ Standard`_), oneDPL provides |
| 9 | +an implementation for oneAPI devices via :code:`oneapi::dpl::execution::device_policy`. These algorithms |
| 10 | +must be capable of processing data in SYCL buffers (passed via :code:`oneapi::dpl::begin/end`) |
| 11 | +and in unified shared memory (USM). |
9 | 12 |
|
10 | | -Function Objects |
| 13 | +oneDPL extends Parallel STL with the following APIs. |
| 14 | + |
| 15 | +DPC++ Execution Policy |
11 | 16 | ++++++++++++++++++++++ |
12 | 17 |
|
13 | | -The oneDPL function objects are defined in the :code:`<oneapi/dpl/functional>` header, |
14 | | -in :code:`namespace oneapi::dpl`. |
| 18 | +A DPC++ execution policy specifies where and how an algorithm runs. |
15 | 19 |
|
16 | 20 | .. code:: cpp |
17 | 21 |
|
18 | | - namespace oneapi { |
| 22 | + // Defined in <oneapi/dpl/execution> |
| 23 | +
|
| 24 | + namespace oneapi { |
19 | 25 | namespace dpl { |
20 | | - struct identity |
21 | | - { |
22 | | - template <typename T> |
23 | | - constexpr T&& |
24 | | - operator()(T&& t) const noexcept; |
25 | | - }; |
| 26 | + namespace execution { |
| 27 | +
|
| 28 | + template <typename KernelName = /*unspecified*/> |
| 29 | + class device_policy; |
| 30 | +
|
| 31 | + device_policy<> dpcpp_default; |
| 32 | +
|
| 33 | + template <typename KernelName = /*unspecified*/> |
| 34 | + device_policy<KernelName> |
| 35 | + make_device_policy( sycl::queue ); |
| 36 | +
|
| 37 | + template <typename KernelName = /*unspecified*/> |
| 38 | + device_policy<KernelName> |
| 39 | + make_device_policy( sycl::device ); |
| 40 | +
|
| 41 | + template <typename NewKernelName, typename OldKernelName> |
| 42 | + device_policy<NewKernelName> |
| 43 | + make_device_policy( const device_policy<OldKernelName>& = dpcpp_default ); |
| 44 | + } |
26 | 45 | } |
| 46 | + } |
| 47 | +
|
| 48 | +``dpcpp_default`` is a predefined execution policy object to run algorithms on the default DPC++ device. |
| 49 | + |
| 50 | +device_policy class |
| 51 | +^^^^^^^^^^^^^^^^^^^ |
| 52 | + |
| 53 | +.. code:: cpp |
| 54 | +
|
| 55 | + template <typename KernelName = /*unspecified*/> |
| 56 | + class device_policy |
| 57 | + { |
| 58 | + public: |
| 59 | + using kernel_name = KernelName; |
| 60 | +
|
| 61 | + device_policy(); |
| 62 | + template <typename OtherName> |
| 63 | + device_policy( const device_policy<OtherName>& ); |
| 64 | + explicit device_policy( sycl::queue ); |
| 65 | + explicit device_policy( sycl::device ); |
| 66 | +
|
| 67 | + sycl::queue queue() const; |
| 68 | + operator sycl::queue() const; |
| 69 | + }; |
| 70 | +
|
| 71 | +An object of the ``device_policy`` type is associated with a ``sycl::queue`` that is used |
| 72 | +to run algorithms on a DPC++ compliant device. |
| 73 | + |
| 74 | +The ``KernelName`` template parameter, also aliased as ``kernel_name`` within the class template, |
| 75 | +is to explicitly provide a name for DPC++ kernels executed by an algorithm the policy is passed to. |
| 76 | + |
| 77 | +.. code:: cpp |
| 78 | +
|
| 79 | + device_policy() |
| 80 | +
|
| 81 | +Construct a policy object associated with a queue created with the default device selector. |
| 82 | + |
| 83 | +.. code:: cpp |
| 84 | +
|
| 85 | + template <typename OtherName> |
| 86 | + device_policy( const device_policy<OtherName>& policy ) |
| 87 | +
|
| 88 | +Construct a policy object associated with the same queue as ``policy``, by changing |
| 89 | +the kernel name of the given policy to ``kernel_name`` defined for the new policy. |
| 90 | + |
| 91 | +.. code:: cpp |
| 92 | +
|
| 93 | + explicit device_policy( sycl::queue queue ) |
| 94 | +
|
| 95 | +Construct a policy object associated with the given queue. |
| 96 | + |
| 97 | +.. code:: cpp |
| 98 | +
|
| 99 | + explicit device_policy( sycl::device device ) |
| 100 | +
|
| 101 | +Construct a policy object associated with a queue created for the given device. |
| 102 | + |
| 103 | +.. code:: cpp |
| 104 | +
|
| 105 | + sycl::queue queue() const |
| 106 | +
|
| 107 | +Return the queue the policy is associated with. |
| 108 | + |
| 109 | +.. code:: cpp |
| 110 | +
|
| 111 | + operator sycl::queue() const |
| 112 | +
|
| 113 | +Allow implicit conversion of the policy to a ``sycl::queue`` object. |
| 114 | + |
| 115 | +make_device_policy function |
| 116 | +^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
| 117 | + |
| 118 | +The ``make_device_policy`` function templates simplify ``device_policy`` creation. |
| 119 | + |
| 120 | +.. code:: cpp |
| 121 | +
|
| 122 | + template <typename KernelName = /*unspecified*/> |
| 123 | + device_policy<KernelName> |
| 124 | + make_device_policy( sycl::queue queue ) |
| 125 | +
|
| 126 | +Return a policy object associated with ``queue``, with a kernel name possibly provided |
| 127 | +as the template argument, otherwise unspecified. |
| 128 | + |
| 129 | +.. code:: cpp |
| 130 | +
|
| 131 | + template <typename KernelName = /*unspecified*/> |
| 132 | + device_policy<KernelName> |
| 133 | + make_device_policy( sycl::device device ) |
| 134 | +
|
| 135 | +Return a policy object to run algorithms on ``device``, with a kernel name possibly provided |
| 136 | +as the template argument, otherwise unspecified. |
| 137 | + |
| 138 | +.. code:: cpp |
| 139 | +
|
| 140 | + template <typename NewKernelName, typename OldKernelName> |
| 141 | + device_policy<NewKernelName> |
| 142 | + make_device_policy( const device_policy<OldKernelName>& policy = dpcpp_default ) |
| 143 | +
|
| 144 | +Return a policy object constructed from ``policy``, with a new kernel name provided as the template |
| 145 | +argument. If no policy object is provided, the new policy is constructed from ``dpcpp_default``. |
| 146 | + |
| 147 | +Buffer wrappers |
| 148 | ++++++++++++++++ |
| 149 | + |
| 150 | +.. code:: cpp |
| 151 | +
|
| 152 | + // Defined in <oneapi/dpl/iterator> |
| 153 | +
|
| 154 | + namespace oneapi { |
| 155 | + namespace dpl { |
| 156 | +
|
| 157 | + template < typename T, typename AllocatorT, sycl::access::mode Mode > |
| 158 | + /*unspecified*/ begin( sycl::buffer<T, /*dim=*/1, AllocatorT> buf, |
| 159 | + sycl::mode_tag_t<Mode> tag = sycl::read_write ); |
| 160 | +
|
| 161 | + template < typename T, typename AllocatorT, sycl::access::mode Mode > |
| 162 | + /*unspecified*/ begin( sycl::buffer<T, /*dim=*/1, AllocatorT> buf, |
| 163 | + sycl::mode_tag_t<Mode> tag, sycl::property::noinit ); |
| 164 | +
|
| 165 | + template < typename T, typename AllocatorT > |
| 166 | + /*unspecified*/ begin( sycl::buffer<T, /*dim=*/1, AllocatorT> buf, |
| 167 | + sycl::property::noinit ); |
| 168 | +
|
| 169 | +
|
| 170 | + template < typename T, typename AllocatorT, sycl::access::mode Mode > |
| 171 | + /*unspecified*/ end( sycl::buffer<T, /*dim=*/1, AllocatorT> buf, |
| 172 | + sycl::mode_tag_t<Mode> tag = sycl::read_write ); |
| 173 | +
|
| 174 | + template < typename T, typename AllocatorT, sycl::access::mode Mode > |
| 175 | + /*unspecified*/ end( sycl::buffer<T, /*dim=*/1, AllocatorT> buf, |
| 176 | + sycl::mode_tag_t<Mode> tag, sycl::property::noinit ); |
| 177 | +
|
| 178 | + template < typename T, typename AllocatorT > |
| 179 | + /*unspecified*/ end( sycl::buffer<T, /*dim=*/1, AllocatorT> buf, |
| 180 | + sycl::property::noinit ); |
| 181 | +
|
27 | 182 | } |
| 183 | + } |
| 184 | +
|
| 185 | +``oneapi::dpl::begin`` and ``oneapi::dpl::end`` are helper functions |
| 186 | +for passing DPC++ buffers to oneDPL algorithms. |
| 187 | +These functions accept a buffer and return an object |
| 188 | +of an unspecified type that satisfies the following requirements: |
| 189 | + |
| 190 | +- it is ``CopyConstructible``, ``CopyAssignable``, and comparable |
| 191 | + with operators ``==`` and ``!=``; |
| 192 | +- the following expressions are valid: ``a + n``, ``a - n``, |
| 193 | + ``a - b``, where ``a`` and ``b`` are objects of the type, |
| 194 | + and ``n`` is an integer value; |
| 195 | +- it provides the ``get_buffer()`` method that returns the buffer |
| 196 | + passed to the ``begin`` or ``end`` function. |
| 197 | + |
| 198 | +When invoking an algorithm, the buffer passed to ``begin`` should be the same |
| 199 | +as the buffer passed to ``end``. Otherwise, the behavior is undefined. |
| 200 | + |
| 201 | +``sycl::mode_tag_t`` and ``sycl::property::noinit`` parameters allow to specify |
| 202 | +an access mode to be used for accessing the buffer by algorithms. |
| 203 | +The mode serves as a hint, and can be overridden depending on semantics of the algorithm. |
| 204 | +When invoking an algorithm, the same access mode arguments should be used |
| 205 | +for ``begin`` and ``end``. Otherwise, the behavior is undefined. |
28 | 206 |
|
29 | | -The :code:`oneapi::dpl::identity` class implements an identity operation. Its function operator |
30 | | -receives an instance of a type and returns the argument unchanged. |
| 207 | +.. code:: cpp |
| 208 | + |
| 209 | + using namespace oneapi; |
| 210 | + auto buf_begin = dpl::begin(buf, sycl::write_only); |
| 211 | + auto buf_end_1 = dpl::end(buf, sycl::write_only); |
| 212 | + auto buf_end_2 = dpl::end(buf, sycl::write_only, sycl::noinit); |
| 213 | + dpl::fill(dpl::dpcpp_default, buf_begin, buf_end_1, 42); // allowed |
| 214 | + dpl::fill(dpl::dpcpp_default, buf_begin, buf_end_2, 42); // not allowed |
31 | 215 |
|
32 | 216 | Iterators |
33 | | -++++++++++++++++++++++ |
| 217 | ++++++++++ |
34 | 218 |
|
35 | 219 | The oneDPL iterators are defined in the :code:`<oneapi/dpl/iterator>` header, |
36 | 220 | in :code:`namespace oneapi::dpl`. |
@@ -297,7 +481,7 @@ operation were applied to each of these iterators. |
297 | 481 | using the set of source iterators provided. |
298 | 482 |
|
299 | 483 | Parallel Algorithms |
300 | | -++++++++++++++++++++++ |
| 484 | ++++++++++++++++++++ |
301 | 485 |
|
302 | 486 | The parallel algorithms are defined in the :code:`<oneapi/dpl/algorithm>` header, |
303 | 487 | in :code:`namespace oneapi::dpl`. |
@@ -454,3 +638,5 @@ If no comparator is provided, :code:`operator<` is used to determine when the se |
454 | 638 | than an element in the range being searched. |
455 | 639 |
|
456 | 640 | The elements e of [start, end) must be partitioned with respect to the comparator used. |
| 641 | + |
| 642 | +.. _`C++ Standard`: https://isocpp.org/std/the-standard |
0 commit comments