Adopting ISO C++ sender/receiver model #11646
AerialMantis
started this conversation in
Ideas
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
-
Note: this is still an early draft to begin the discussion, much of this will need to be further defined.
Overview
This discussion proposes changes to the SYCL interface which reflect a new design for the SYCL execution model based on the proposed ISO C++ sender/receiver model (https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2300r7.html).
The motivation for this is:
If we want to achieve these goals it will require a change to the SYCL interface, but we should ensure this change is minimal to avoid big breaking changes for users, and we should do it just once if possible.
Motivation
All command functions such as
submit
or shortcut functions likeparallel_for
return anevent
which allows users to create dependency chains and synchronize with submitted commands. However, theevent
class in SYCL conflates usage for dependencies and usage for synchronizing with submitted commands.Furthermore, the SYCL execution model currently does not specify whether commands submitted to the runtime are executed eagerly or lazily. The user has no control over this and as a result must assume that they could be executed lazily and synchronize with the commands (via event wait, queue wait, or buffer destruction) in order to ensure the work has been enqueued to the backend.
This is evident by looking at two use cases.
In the first case, where users require low latency execution, i.e. commands being executed as soon after submission as possible, the SYCL specification cannot guarantee this. If the
event
is implemented as eager then the command is executed immediately, so no synchronization is required to ensure the command is executing. However, if theevent
is implemented as lazy then the command will not execute immediately, and the only way to ensure this is to synchronize with theevent
orqueue
or the destruction of abuffer
which is being written to by the command.In the second case, where users wish to create task graphs, i.e. commands are collected and batched all together and the creation of native event objects can be elided. If the
event
is implemented as eager then the backend must provide a native backend event object for every command, even if it's never used, creating a performance overhead. If theevent
is implemented as lazy then the creation of native backend event objects can be elided, however, theevent
class still requires synchronizations and query capabilities.Considered Solutions
There are a few different options which have been considered to solve this:
event
s; synchronization on an event may also synchronize with earlier events (https://github.com/AdaptiveCpp/AdaptiveCpp/blob/develop/doc/extensions.md#hipsycl_ext_coarse_grained_events).event
s.event
s; synchronization on an event may fail (https://github.com/intel/llvm/blob/sycl/sycl/doc/extensions/supported/sycl_ext_oneapi_discard_queue_events.asciidoc).queue
/handle
which either return anevent
or don't ([SYCL][DOC] Add sycl_ext_oneapi_enqueue_functions #11491).Alternative Approach Using Sender/Receiver
Another option is to adopt the sender/receiver model of execution proposed in P2300 for ISO C++.
The sender/receiver model works by composing senders which are like
std::future
but lazy, starting with a sender produced by scheduling on a particular execution resource and then adding commands via sender algorithms, which can then be synchronized with.In the sender/receiver model:
Receivers are not typically exposed to users.
To introduce the sender/receiver model in SYCL we would need to do the following:
get_scheduler()
member function onqueue
for retrieving a scheduler.schedule
andensure_started
, further algorithms could be added incrementally.submit
and the shortcut functions such asparallel_for
,memcpy
, etc.Benefits of Using Sender/Receiver
There are a number of benefits of using the sender/receiver model.
Status of Senders/Receivers in ISO C++
The senders/receiver paper (P2300) is in review by the C++ committee, and it is hoped that it will be approved for C++26, however, if it isn't then it could be later before it's available in C++.
Example
Below is an example of SYCL using the sender/receiver model.
The above example can also be reprsented differently using the sender/receiver pipe syntax, here this is using the
parallel_for
shortcut function.Proposal
Execution Stream
Introduce a new type;
execution_stream
which represents the smallest granularity of execution resource for a backend, that is a single stream of execution and executes in order.SYCL Scheduler
Introduce a new type;
scheduler
which conforms to the scheduler concept of P2300 and is associated with a SYCLqueue
anddevice
to which work will be enqueued.Add a new member functions to the
queue
andexecution_stream
classes;queue::get_scheduler
andexecution_stream::get_scheduler()
which return ascheduler
.SYCL Senders
Introduce the concept of sender in SYCL as an object which represents a series of commands which have not yet been enqueued to the backend. Specify that there are two kinds of sender:
submit
.Introduce the concept of implementation-defined sender types which conforms to the sender concept of P2300 and represents zero or more commands such as kernel launches or copies which have not yet been enqueued to the backend.
Introduce a new type
sender
which provides a polymorphic wrapper to any implementation-defined sender type, providing a conversion operator for those types.SYCL Sender Factories
Introduce the
schedule
factory function as follows:Returns an empty implementation-defined sender which represents the transition to the target
device
with the sender'squeue
orexecution_stream
.SYCL Sender Algorithms
Introduce all existing command functions (member functions of
queue
) in SYCL 2020 as algorithms, includingsubmit
,single_task
,parallel_for
,memcpy
,memset
,fill
,copy
,prefetch
andmem_advise
as follows:Each function would behave as currently defined in SYCL 2020, but returning an implementation-defined sender representing the specified command as to be executed but not yet enqueued to the backend.
SYCL Sender Adapters
Introduce the
ensure_started
adapter function as follows:Takes a SYCL sender type, ensures that the commands it represents are enqueued to the backend and then returns a new implementation-defined sender type.
SYCL Sender Consumers
Introduce the
sync_wait
consumer function as follows:Takes a SYCL sender type, ensures that the commands it represents are enqueued to the backend and then synchronizes with the execution resource executing those commands before returning.
Note: in P2300
this_thread::sync_wait
returns astd::optional<std::tuple<>>
, it needs to be considered whether SYCL should implement this as in P2300 or returnsvoid
.Beta Was this translation helpful? Give feedback.
All reactions