Policies
The dynamic selection API is an experimental feature in the Intel® 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.
Policy Traits
Traits can be used to determine useful type information about policies.
namespace oneapi::dpl::experimental { template<typename Policy> struct policy_traits { using selection_type = typename std::decay_t<Policy>::selection_type; using resource_type = typename std::decay_t<Policy>::resource_type; using wait_type = typename std::decay_t<Policy>::wait_type; }; template<typename Policy> using selection_t = typename policy_traits<Policy>::selection_type; template<typename Policy> using resource_t = typename policy_traits<Policy>::resource_type; template<typename Policy> using wait_t = typename policy_traits<Policy>::wait_type; }
selection_t<Policy> is the type returned by calls to select when using policy of type Policy. Calling unwrap on an object of type selection_t<Policy> returns an object of type resource_t<Policy>. When using the default SYCL backend, resource_t<Policy> is sycl::queue and sycl::wait_t<Policy> is sycl::event. The user functions passed to submit and submit_and_wait are expected to have a signature of:
wait_t<Policy> user_function(resource_t<Policy>, ...);
Common Reference Semantics
If a policy maintains state, the state is maintained separately for each independent policy instance. So for example, two independently constructed instances of a round_robin_policy will operate independently of each other. However, policies provide common reference semantics, so copies of a policy instance share state.
An example, demonstrating this difference, is shown below:
#include <oneapi/dpl/dynamic_selection> #include <sycl/sycl.hpp> #include <iostream> #include <string> namespace ex = oneapi::dpl::experimental; template<typename Selection> void print_type(const std::string &str, Selection s) { auto q = ex::unwrap(s); std::cout << str << ((q.get_device().is_gpu()) ? "gpu\n" : "cpu\n"); } int main() { ex::round_robin_policy p1{ { sycl::queue{ sycl::cpu_selector_v }, sycl::queue{ sycl::gpu_selector_v } } }; ex::round_robin_policy p2{ { sycl::queue{ sycl::cpu_selector_v }, sycl::queue{ sycl::gpu_selector_v } } }; ex::round_robin_policy p3 = p2; std::cout << "independent instances operate independently\n"; auto p1s1 = ex::select(p1); print_type("p1 selection 1: ", p1s1); auto p2s1 = ex::select(p2); print_type("p2 selection 1: ", p2s1); auto p2s2 = ex::select(p2); print_type("p2 selection 2: ", p2s2); auto p1s2 = ex::select(p1); print_type("p1 selection 2: ", p1s2); std::cout << "\ncopies provide common reference semantics\n"; auto p3s1 = ex::select(p3); print_type("p3 (copy of p2) selection 1: ", p3s1); auto p2s3 = ex::select(p2); print_type("p2 selection 3: ", p2s3); auto p3s2 = ex::select(p3); print_type("p3 (copy of p2) selection 2: ", p3s2); auto p3s3 = ex::select(p3); print_type("p3 (copy of p2) selection 3: ", p3s3); auto p2s4 = ex::select(p2); print_type("p2 selection 4: ", p2s4); }
The output of this example:
p1 selection 1: cpu p2 selection 1: cpu p2 selection 2: gpu p1 selection 2: gpu copies provide common reference semantics p3 (copy of p2) selection 1: cpu p2 selection 3: gpu p3 (copy of p2) selection 2: cpu p3 (copy of p2) selection 3: gpu p2 selection 4: cpu
Available Policies
More detailed information about the API is provided in the following sections: