-
Notifications
You must be signed in to change notification settings - Fork 227
Description
We are currently working (with @maartenarnst) on a customization for a scheduler that builds a Kokkos::Experimental::Graph under the hood.
To add a node to a Kokkos::Experimental::Graph, we need to know its predecessor(s).
Here’s an example of a diamond-shaped Kokkos::Experimental::Graph:
auto root = graph.get_root();
auto A = root.then(...);
auto B = A.then(...);
auto C = A.then(...);
auto D = Kokkos::Experimental::when_all(std::move(B), std::move(C)).then(...);Conceptually, we’d like this to naturally translate to something like the following using exec::fork_join:
stdexec::sync_wait(
stdexec::schedule(graph_scheduler)
| then(...A...)
| exec::fork_join(
stdexec::on(graph_scheduler, ...B...),
stdexec::on(graph_scheduler, ...C...))
| then(...D...)
);As mentioned, we need the predecessor(s) in order to add a new node to the graph. We create the node in the operation state.
We have already customized when_all, but we are now running into what feels like a limitation (or at least an awkward spot — or something I'm missing) in the std::execution framework:
There is no built-in mechanism to propagate information from inner to outer operation states.
In our example, A is the innermost node. How would B or C query the node created by A? Obviously (?), this cannot be done through the receiver’s environment, which only propagates information upstream from B/C to A.
Currently, we rely on the fact that the operation states of our customizations provide a get_node() member function. However, this approach breaks when exec::fork_join introduces intermediate layers between A and B/C, because those intermediate layers hide the underlying operation states.
One potential solution would be to make exec::fork_join itself customizable to forward this information. But we feel like the problem could be more general than just ours, so we wonder how more experienced people would handle it 😉
Any suggestion is appreciated !