Extensions to Parallel STL

oneDPL extends Parallel STL with the following APIs:

DPC++ Execution Policy

// Defined in <dpstd/execution>

namespace dpstd {
  namespace execution {

    template <typename BasePolicy, typename KernelName = /*unspecified*/>
    class device_policy;

    template <typename KernelName, typename Arg>
    device_policy<std::execution::parallel_unsequenced_policy, KernelName>
    make_device_policy( const Arg& );

    device_policy<parallel_unsequenced_policy, /*unspecified*/> default_policy;

  }
}

A DPC++ execution policy specifies where and how an algorithm runs. It inherits a standard C++ execution policy and allows specification of an optional kernel name as a template parameter.

An object of a device_policy type encapsulates a SYCL queue which runs algorithms on a DPC++ compliant device. You can create a policy object from a SYCL queue, device, or device selector, as well as from an existing policy object.

The make_device_policy function simplifies device_policy creation.

dpstd::execution::default_policy is a predefined DPC++ execution policy object that can run algorithms on a default SYCL device.

Examples:

using namespace dpstd::execution;

auto policy_a =
  device_policy<parallel_unsequenced_policy, class PolicyA>{cl::sycl::queue{}};
std::for_each(policy_a, …);

auto policy_b = make_device_policy<class PolicyB>(cl::sycl::queue{});
std::for_each(policy_b, …);

auto policy_c =
  make_device_policy<class PolicyC>(cl::sycl::device{cl::sycl::gpu_selector{}});
std::for_each(policy_c, …);

auto policy_d = make_device_policy<class PolicyD>(cl::sycl::default_selector{});
std::for_each(policy_d, …);

// use the predefined dpstd::execution::default_policy policy object
std::for_each(default_policy, …);

Wrappers for SYCL Buffers

// Defined in <dpstd/iterators.h>

namespace dpstd {

  template <cl::sycl::access::mode = cl::sycl::access::mode::read_write, ... >
  /*unspecified*/ begin(cl::sycl::buffer<...>);

  template <cl::sycl::access::mode = cl::sycl::access::mode::read_write, ... >
  /*unspecified*/ end(cl::sycl::buffer<...>);

}

dpstd::begin and dpstd::end are helper functions for passing SYCL buffers to oneDPL algorithms. These functions accept a SYCL buffer and return an object of an unspecified type that satisfies the following requirements:

  • Is CopyConstructible, CopyAssignable, and comparable with operators == and !=

  • The following expressions are valid: a + n, a - n, a - b, where a and b are objects of the type, and n is an integer value

  • Provides get_buffer() method that returns the SYCL buffer passed to dpstd::begin or dpstd::end function.

Example:

#include <CL/sycl.hpp>
#include <dpstd/execution>
#include <dpstd/algorithm>
#include <dpstd/iterators.h>

int main(){
    cl::sycl::queue q;
    cl::sycl::buffer<int> buf { 1000 };
    auto buf_begin = dpstd::begin(buf);
    auto buf_end   = dpstd::end(buf);
    auto policy = dpstd::execution::make_device_policy<class Fill>( q );
    std::fill(policy, buf_begin, buf_end, 42);
    return 0;
}