Fixed-Resource Policy#
The dynamic selection API is an experimental feature in the oneAPI DPC++ Library (oneDPL) that selects an execution resource based on a chosen selection policy. There are several policies provided as part of the API. Policies encapsulate the logic and any associated state needed to make a selection.
The fixed-resource policy always returns the same resource selection.
fixed_resource_policy is designed for two primary scenarios:
debugging the use of dynamic selection
special casing a dynamic selection capable application for a specific resource when it is known to be best on that platform.
namespace oneapi::dpl::experimental {
template <typename ResourceType = sycl::queue, typename ResourceAdapter = oneapi::dpl::identity,
typename Backend = default_backend<ResourceType, ResourceAdapter>>
class fixed_resource_policy
: public policy_base<fixed_resource_policy<ResourceType, ResourceAdapter, Backend>,
ResourceAdapter, Backend>
{
public:
using resource_type = ResourceType;
using backend_type = Backend;
fixed_resource_policy(deferred_initialization_t);
fixed_resource_policy(std::size_t index = 0);
fixed_resource_policy(const std::vector<ResourceType>& u, std::size_t index = 0);
fixed_resource_policy(const std::vector<ResourceType>& u, ResourceAdapter adapter,
std::size_t index = 0);
// deferred initializer
void initialize(std::size_t index = 0);
void initialize(const std::vector<resource_type>& u, std::size_t index = 0);
};
}
This policy can be used with all the dynamic selection free functions, as well as with policy traits.
Example#
In the following example, a fixed_resource_policy is used when the code is
compiled so that it selects a specific device. When USE_CPU is defined at
compile-time, this example always uses the CPU queue. When USE_GPU is defined
at compile-time, it always uses the GPU queue. Otherwise, it uses an
auto_tune_policy to dynamically select between these two queues. Such a scenario
could be used for debugging or simply to maintain the dynamic selection code even if
the best device to use is known for some subset of platforms.
#include <oneapi/dpl/dynamic_selection>
#include <sycl/sycl.hpp>
#include <iostream>
namespace ex = oneapi::dpl::experimental;
int main() {
std::vector<sycl::queue> r { sycl::queue{sycl::cpu_selector_v},
sycl::queue{sycl::gpu_selector_v} };
const std::size_t N = 10000;
std::vector<float> av(N, 0.0);
std::vector<float> bv(N, 0.0);
std::vector<float> cv(N, 0.0);
for (int i = 0; i < N; ++i) {
av[i] = bv[i] = i;
}
#if USE_CPU
ex::fixed_resource_policy p{r}; // (1) uses index 0 of r, the cpu
#elif USE_GPU
ex::fixed_resource_policy p{r, 1}; // (2) uses index 1 of r, the gpu
#else
ex::auto_tune_policy p{r};
#endif
{
sycl::buffer<float> a_b(av);
sycl::buffer<float> b_b(bv);
sycl::buffer<float> c_b(cv);
for (int i = 0; i < 6; ++i) {
ex::submit_and_wait(p, [&](sycl::queue q) { // (3)
// (4)
std::cout << (q.get_device().is_cpu() ? "using cpu\n" : "using gpu\n");
return q.submit([&](sycl::handler &h) { // (5)
sycl::accessor a_a(a_b, h, sycl::read_only);
sycl::accessor b_a(b_b, h, sycl::read_only);
sycl::accessor c_a(c_b, h, sycl::read_write);
h.parallel_for(N, [=](auto i) { c_a[i] = a_a[i] + b_a[i]; });
});
});
};
}
for (int i = 0; i < N; ++i) {
if (cv[i] != 2*i) {
std::cout << "ERROR!\n";
}
}
std::cout << "Done.\n";
}
The key points in this example are:
If
USE_CPUis defined, afixed_resouce_policyis constructed that targets the CPU.If
USE_GPUis defined, afixed_resouce_policyis constructed that targets the GPU.submit_and_waitis invoked with the policy as the first argument. The selected queue will be passed to the user-provided function.For clarity when run, the type of device is displayed.
The queue is used in a function to perform an asynchronous offload. The SYCL event returned from the call to
submitis returned. Returning an event is required for functions passed tosubmitandsubmit_and_wait.
Selection Algorithm#
The selection algorithm for fixed_resource_policy always returns
the same specific resource from its set of resources. The index of the
resource is set during construction or deferred initialization.
Simplified, expository implementation of the selection algorithm:
//not a public function, for exposition purposes only
template<typename... Args>
selection_type fixed_resource_policy::select(Args&& ...) {
if (initialized_) {
return selection_type{*this, resources_[fixed_offset_]};
} else {
throw std::logic_error("select called before initialization");
}
}
where resources_ is a container of resources, such as
std::vector of sycl::queue, and fixed_offset_ stores a
fixed integer offset. Both resources_ and fixed_offset
are set during construction or deferred initialization of the policy
and then remain constant.
Constructors#
fixed_resource_policy provides four constructors.
Signature |
Description |
|---|---|
|
Defers initialization. An |
|
Sets the index for the resource to be selected. Uses the default set of resources. |
fixed_resource_policy(const std::vector<resource_type>& u,std::size_t index = 0); |
Overrides the default set of resources and optionally sets the index for the resource to be selected. |
fixed_resource_policy(const std::vector<resource_type>& u,ResourceAdapter adapter,std::size_t index = 0); |
Overrides the default set of resources with a resource adapter and optionally sets the index for the resource to be selected. |
Deferred Initialization#
A fixed_resource_policy that was constructed with deferred initialization must be
initialized by calling one of its initialize member functions before it can be used
to select or submit.
Signature |
Description |
|---|---|
|
Sets the index for the resource to be selected. Uses the default set of resources. |
initialize(const std::vector<resource_type>& u,std::size_t index = 0); |
Overrides the default set of resources and optionally sets the index for the resource to be selected. |
Queries#
A fixed_resource_policy has get_resources and get_submission_group
member functions.
Signature |
Description |
|---|---|
|
Returns the set of resources the policy is selecting from. |
|
Returns an object that can be used to wait for all active submissions. |