Backends
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. For the policies to work with different resource types. the resource management and work submission mechanics are handled separately by resource-specific backends.
A backend is responsible for:
Resource Management - storing and providing access to a set of resources
Work Submission - executing user functions on selected resources
Synchronization - waiting for submitted work to complete
Instrumentation - optionally reporting execution information (timing, completion)
Backends are typically not directly visible to application developers - they work behind the scenes to enable policies to function.
SYCL Backend
A SYCL backend specialization of core_resource_backend is provided to support sycl::queue resources.
The SYCL backend provides:
Default initialization, which automatically discovers all available SYCL devices and creates queues
Event-based submission and waiting
Optional profiling and timing instrumentation
If no list of resources or explicit resource type is provided upon policy construction, the SYCL backend is the default, and sycl::queue is the resource type.
#include <oneapi/dpl/dynamic_selection>
namespace ex = oneapi::dpl::experimental;
// Uses SYCL backend with default device initialization
ex::round_robin_policy<> policy;
// Explicitly specifying SYCL queues
std::vector<sycl::queue> my_queues = { /* ... */ };
ex::round_robin_policy<sycl::queue> policy2{my_queues};
The SYCL backend supports the reporting for Execution Information of task_submission, task_completion, and task_time.
User functions submitted to the SYCL backend must return a sycl::event, which is its wait type.
Backend Architecture
The backend system uses a layered design to support multiple resource types:
default_backend: When you create a policy, default_backend automatically determines the core resource type by applying any resource adapter to your resource type. It then delegates to the appropriate core_resource_backend specialization.
core_resource_backend: Specialized backend implementations exist for specific core resource types (like sycl::queue). For a resource type without an explicitly specialized implementation, a generic implementation provides the minimally necessary functionality:
Basic resource storage and retrieval
Simple work submission without instrumentation (No execution information reporting)
To use a custom resource type with full instrumentation support, you must create a core_resource_backend specialization.
Lazy Reporting
For asynchronous execution, backends may use lazy reporting where Execution Information is not immediately available. The SYCL backend uses lazy reporting for task_completion and task_time.
Policies that use execution information always call the backend’s lazy_report() function before making selections, ensuring they have up-to-date information about completed tasks.
This is transparent to application developers - the policy handles the details.
Backend Traits
Backend traits provide compile-time information about backend capabilities:
namespace oneapi::dpl::experimental
{
template<typename Backend>
struct backend_traits {
// True if backend has explicit wait_type
static constexpr bool has_wait_type_v = /* ... */;
// If has_wait_type_v is True, specific type required from user functions.
// If has_wait_type_v is False, void (user functions must return waitable-type)
using wait_type = /* ... */;
// True if backend requires lazy_report() to be called
static constexpr bool lazy_report_v = /* ... */;
// Scratch space type for selection handles
template<typename... ReportReqs>
using selection_scratch_t = /* ... */;
};
}
These traits are primarily used by policy implementers, not application developers.
Wait Type Requirements
Backends specify return type requirements for user-submitted functions through the wait_type member:
Explicit wait_type: If a backend defines a wait_type alias (e.g., using wait_type = sycl::event;), user functions must return that specific type. This is typically required when the backend needs to instrument or track asynchronous operations.
No explicit wait_type: If a backend does not define a wait_type alias, user functions may return any waitable-type. A waitable-type is any type with a wait() member function that can be called to synchronize with the operation’s completion.
The SYCL backend defines wait_type = sycl::event, requiring user functions to return sycl::event for proper instrumentation and synchronization.
Selection Scratch Space
Backends need storage space within selection handles to implement instrumentation. The selection_scratch_t trait specifies what additional data a backend requires based on the policy’s reporting needs.
When a policy tracks execution information (like task timing or completion), the backend needs to store temporary data with each selection. For example, the SYCL backend stores an extra sycl::event for start-time profiling tags when task_time reporting is requested.
The backend populates and uses this scratch space during work submission and reporting. For policies without reporting requirements, selection_scratch_t<> is empty, adding no overhead.
Custom Backends
For advanced use cases, you can create custom backends to support new resource types or provide specialized instrumentation. Custom backends are created by specializing core_resource_backend for your resource type. For an example of how to do this, look at core_resource_backend<sycl::queue, ...>.