2#ifndef TTG_DEVICE_TASK_H
3#define TTG_DEVICE_TASK_H
15#ifdef TTG_HAVE_COROUTINE
21 struct device_input_data_t {
22 using impl_data_t =
decltype(TTG_IMPL_NS::buffer_data(std::declval<
ttg::Buffer<int>>()));
24 device_input_data_t(impl_data_t data,
ttg::scope scope,
bool isconst,
bool isscratch)
27 impl_data_t impl_data;
33 template <
typename... Ts>
35 std::tuple<std::add_lvalue_reference_t<Ts>...> ties;
39 template<
typename... Ts, std::size_t... Is>
40 auto extract_buffer_data(detail::to_device_t<Ts...>& a, std::index_sequence<Is...>) {
41 using arg_types = std::tuple<Ts...>;
42 return std::array<device_input_data_t,
sizeof...(Ts)>{
43 device_input_data_t{TTG_IMPL_NS::buffer_data(std::get<Is>(a.ties)),
44 std::get<Is>(a.ties).scope(),
59 std::vector<detail::device_input_data_t> m_data;
63 template<
typename... Args>
65 : m_data{{TTG_IMPL_NS::buffer_data(args), args.scope(),
66 std::is_const_v<std::remove_reference_t<Args>>,
72 using type = std::remove_reference_t<T>;
73 m_data.emplace_back(TTG_IMPL_NS::buffer_data(v), v.scope(), std::is_const_v<type>,
77 ttg::span<detail::device_input_data_t> span() {
78 return ttg::span(m_data);
85 struct to_device_t<Input> {
97 template <
typename... Args>
99 inline auto select(Args &&...args) {
100 return detail::to_device_t<std::remove_reference_t<Args>...>{std::tie(std::forward<Args>(args)...)};
104 inline auto select(Input& input) {
105 return detail::to_device_t<Input>{input};
110 enum ttg_device_coro_state {
111 TTG_DEVICE_CORO_STATE_NONE,
112 TTG_DEVICE_CORO_INIT,
113 TTG_DEVICE_CORO_WAIT_TRANSFER,
114 TTG_DEVICE_CORO_WAIT_KERNEL,
115 TTG_DEVICE_CORO_SENDOUT,
116 TTG_DEVICE_CORO_COMPLETE
119 template <
typename... Ts>
120 struct wait_kernel_t {
121 std::tuple<std::add_lvalue_reference_t<Ts>...> ties;
124 constexpr bool await_ready() const noexcept {
return false; }
127 template <
typename Promise>
130 void await_resume() noexcept {
131 if constexpr (
sizeof...(Ts) > 0) {
133 TTG_IMPL_NS::post_device_out(ties);
144 template <
typename... Buffers>
146 inline auto wait(Buffers &&...args) {
150 "Only ttg::Buffer and ttg::devicescratch can be waited on!");
151 return detail::wait_kernel_t<std::remove_reference_t<Buffers>...>{std::tie(std::forward<Buffers>(args)...)};
162 struct send_coro_promise_type;
167 struct send_coro_state :
public send_coro_handle_type {
168 using base_type = send_coro_handle_type;
173 using promise_type = send_coro_promise_type;
177 send_coro_state(base_type base) : base_type(
std::move(base)) {}
179 base_type &handle() {
return *
this; }
182 inline bool ready() {
return true; }
185 inline bool completed();
189 struct send_coro_promise_type {
200 send_coro_state get_return_object() {
return send_coro_state{send_coro_handle_type::from_promise(*
this)}; }
205 void unhandled_exception() {
206 std::cerr <<
"Send coroutine caught an unhandled exception!" << std::endl;
210 void return_void() {}
213 template <
typename Key,
typename Value, ttg::Runtime Runtime = ttg::ttg_runtime>
214 inline send_coro_state send_coro(
const Key &key, Value &&value,
ttg::Out<Key, std::decay_t<Value>> &t,
218 t.prepare_send(k, std::forward<Value>(value));
220 t.send(k, std::forward<Value>(value));
223 template <
typename Value, ttg::Runtime Runtime = ttg::ttg_runtime>
224 inline send_coro_state sendv_coro(Value &&value,
ttg::Out<
void, std::decay_t<Value>> &t,
227 t.prepare_send(std::forward<Value>(value));
229 t.sendv(std::forward<Value>(value));
232 template <
typename Key, ttg::Runtime Runtime = ttg::ttg_runtime>
240 template <ttg::Runtime Runtime = ttg::ttg_runtime>
248 send_coro_state coro;
252 template <
size_t i,
typename keyT,
typename valueT,
typename... out_keysT,
typename... out_valuesT,
256 return detail::send_t{
257 detail::send_coro(key, copy_handler(std::forward<valueT>(value)), std::get<i>(t), copy_handler)};
260 template <
size_t i,
typename valueT,
typename... out_keysT,
typename... out_valuesT,
264 return detail::send_t{detail::sendv_coro(copy_handler(std::forward<valueT>(value)), std::get<i>(t), copy_handler)};
267 template <
size_t i,
typename Key,
typename... out_keysT,
typename... out_valuesT,
270 return detail::send_t{detail::sendk_coro(key, std::get<i>(t))};
279 template <
typename keyT,
typename valueT, ttg::Runtime Runtime = ttg::ttg_runtime>
280 inline detail::send_t
send(
size_t i,
const keyT &key, valueT &&value) {
282 auto *terminal_ptr = ttg::detail::get_out_terminal<keyT, valueT>(i,
"ttg::device::send(i, key, value)");
283 return detail::send_t{detail::send_coro(key, copy_handler(std::forward<valueT>(value)), *terminal_ptr, copy_handler)};
293 template <
size_t i,
typename keyT,
typename valueT>
294 inline auto send(
const keyT &key, valueT &&value) {
295 return ttg::device::send(i, key, std::forward<valueT>(value));
299 template <
typename valueT, ttg::Runtime Runtime = ttg::ttg_runtime>
300 inline detail::send_t
sendv(std::size_t i, valueT &&value) {
301 auto *terminal_ptr = ttg::detail::get_out_terminal<void, valueT>(i,
"ttg::device::send(i, key, value)");
303 return detail::send_t{detail::sendv_coro(copy_handler(std::forward<valueT>(value)), *terminal_ptr, copy_handler)};
306 template <
typename Key, ttg::Runtime Runtime = ttg::ttg_runtime>
307 inline detail::send_t
sendk(std::size_t i,
const Key& key) {
308 auto *terminal_ptr = ttg::detail::get_out_terminal<Key, void>(i,
"ttg::device::send(i, key, value)");
309 return detail::send_t{detail::sendk_coro(key, *terminal_ptr)};
312 template <ttg::Runtime Runtime = ttg::ttg_runtime>
313 inline detail::send_t
send(std::size_t i) {
314 auto *terminal_ptr = ttg::detail::get_out_terminal<void, void>(i,
"ttg::device::send(i, key, value)");
315 return detail::send_t{detail::send_coro(*terminal_ptr)};
319 template <std::
size_t i,
typename valueT, ttg::Runtime Runtime = ttg::ttg_runtime>
320 inline detail::send_t
sendv(valueT &&value) {
321 return sendv(i, std::forward<valueT>(value));
324 template <
size_t i,
typename Key, ttg::Runtime Runtime = ttg::ttg_runtime>
325 inline detail::send_t
sendk(
const Key& key) {
326 return sendk(i, key);
329 template <
size_t i, ttg::Runtime Runtime = ttg::ttg_runtime>
330 inline detail::send_t
sendk() {
336 template<
typename T,
typename Enabler =
void>
337 struct broadcast_keylist_trait {
343 struct broadcast_keylist_trait<T,
std::enable_if_t<ttg::meta::is_iterable_v<T>>> {
344 using key_type =
decltype(*std::begin(std::declval<T>()));
347 template <
size_t KeyId,
size_t I,
size_t... Is,
typename... RangesT,
typename valueT,
348 typename... out_keysT,
typename... out_valuesT>
349 inline void prepare_broadcast(
const std::tuple<RangesT...> &keylists, valueT &&value,
351 std::get<I>(t).prepare_send(std::get<KeyId>(keylists), std::forward<valueT>(value));
352 if constexpr (
sizeof...(Is) > 0) {
353 prepare_broadcast<KeyId+1, Is...>(keylists, std::forward<valueT>(value), t);
357 template <
size_t KeyId,
size_t I,
size_t... Is,
typename... RangesT,
typename valueT>
358 inline void prepare_broadcast(
const std::tuple<RangesT...> &keylists, valueT &&value) {
359 using key_t =
typename broadcast_keylist_trait<
360 std::tuple_element_t<KeyId, std::tuple<std::remove_reference_t<RangesT>...>>
362 auto *terminal_ptr = ttg::detail::get_out_terminal<key_t, valueT>(I,
"ttg::device::broadcast(keylists, value)");
363 terminal_ptr->prepare_send(std::get<KeyId>(keylists), value);
364 if constexpr (
sizeof...(Is) > 0) {
365 prepare_broadcast<KeyId+1, Is...>(keylists, std::forward<valueT>(value));
369 template <
size_t KeyId,
size_t I,
size_t... Is,
typename... RangesT,
typename valueT,
370 typename... out_keysT,
typename... out_valuesT>
371 inline void broadcast(
const std::tuple<RangesT...> &keylists, valueT &&value,
373 std::get<I>(t).broadcast(std::get<KeyId>(keylists), std::forward<valueT>(value));
374 if constexpr (
sizeof...(Is) > 0) {
375 detail::broadcast<KeyId+1, Is...>(keylists, std::forward<valueT>(value), t);
379 template <
size_t KeyId,
size_t I,
size_t... Is,
typename... RangesT,
typename valueT>
380 inline void broadcast(
const std::tuple<RangesT...> &keylists, valueT &&value) {
381 using key_t =
typename broadcast_keylist_trait<
382 std::tuple_element_t<KeyId, std::tuple<std::remove_reference_t<RangesT>...>>
384 auto *terminal_ptr = ttg::detail::get_out_terminal<key_t, valueT>(I,
"ttg::device::broadcast(keylists, value)");
385 terminal_ptr->broadcast(std::get<KeyId>(keylists), value);
386 if constexpr (
sizeof...(Is) > 0) {
387 ttg::device::detail::broadcast<KeyId+1, Is...>(keylists, std::forward<valueT>(value));
392 template <
size_t I,
size_t... Is,
typename RangesT,
typename valueT,
393 typename... out_keysT,
typename... out_valuesT,
395 inline send_coro_state
396 broadcast_coro(RangesT &&keylists, valueT &&value,
400 RangesT kl = std::forward<RangesT>(keylists);
403 static_assert(
sizeof...(Is)+1 == std::tuple_size_v<std::remove_cvref_t<RangesT>>,
404 "Size of keylist tuple must match the number of output terminals");
405 prepare_broadcast<0, I, Is...>(kl, std::forward<valueT>(value), t);
407 ttg::device::detail::broadcast<0, I, Is...>(kl, std::forward<valueT>(value), t);
410 prepare_broadcast<0, I, Is...>(std::tie(kl), std::forward<valueT>(value), t);
412 ttg::device::detail::broadcast<0, I, Is...>(std::tie(kl), std::forward<valueT>(value), t);
417 template <
size_t I,
size_t... Is,
typename RangesT,
typename valueT,
419 inline send_coro_state
420 broadcast_coro(RangesT &&keylists, valueT &&value,
423 RangesT kl = std::forward<RangesT>(keylists);
426 static_assert(
sizeof...(Is)+1 == std::tuple_size_v<std::remove_cvref_t<RangesT>>,
427 "Size of keylist tuple must match the number of output terminals");
428 prepare_broadcast<0, I, Is...>(kl, std::forward<valueT>(value));
430 ttg::device::detail::broadcast<0, I, Is...>(kl, std::forward<valueT>(value));
433 prepare_broadcast<0, I, Is...>(std::tie(kl), std::forward<valueT>(value));
435 ttg::device::detail::broadcast<0, I, Is...>(std::tie(kl), std::forward<valueT>(value));
443 template <
size_t KeyId,
size_t I,
size_t... Is,
typename... RangesT,
444 typename... out_keysT,
typename... out_valuesT>
445 inline void broadcastk(
const std::tuple<RangesT...> &keylists,
447 std::get<I>(t).broadcast(std::get<KeyId>(keylists));
448 if constexpr (
sizeof...(Is) > 0) {
449 detail::broadcastk<KeyId+1, Is...>(keylists, t);
453 template <
size_t KeyId,
size_t I,
size_t... Is,
typename... RangesT>
454 inline void broadcastk(
const std::tuple<RangesT...> &keylists) {
455 using key_t =
typename broadcast_keylist_trait<
456 std::tuple_element_t<KeyId, std::tuple<std::remove_reference_t<RangesT>...>>
458 auto *terminal_ptr = ttg::detail::get_out_terminal<key_t, void>(I,
"ttg::device::broadcastk(keylists)");
459 terminal_ptr->broadcast(std::get<KeyId>(keylists));
460 if constexpr (
sizeof...(Is) > 0) {
461 ttg::device::detail::broadcastk<KeyId+1, Is...>(keylists);
466 template <
size_t I,
size_t... Is,
typename RangesT,
467 typename... out_keysT,
typename... out_valuesT,
469 inline send_coro_state
470 broadcastk_coro(RangesT &&keylists,
472 RangesT kl = std::forward<RangesT>(keylists);
475 static_assert(
sizeof...(Is)+1 == std::tuple_size_v<std::remove_cvref_t<RangesT>>,
476 "Size of keylist tuple must match the number of output terminals");
478 ttg::device::detail::broadcastk<0, I, Is...>(kl, t);
482 ttg::device::detail::broadcastk<0, I, Is...>(std::tie(kl), t);
487 template <
size_t I,
size_t... Is,
typename RangesT,
489 inline send_coro_state
490 broadcastk_coro(RangesT &&keylists) {
491 RangesT kl = std::forward<RangesT>(keylists);
494 static_assert(
sizeof...(Is)+1 == std::tuple_size_v<std::remove_cvref_t<RangesT>>,
495 "Size of keylist tuple must match the number of output terminals");
497 ttg::device::detail::broadcastk<0, I, Is...>(kl);
501 ttg::device::detail::broadcastk<0, I, Is...>(std::tie(kl));
513 template <
size_t I,
size_t... Is,
typename RangesT,
typename valueT,
typename... out_keysT,
typename... out_valuesT,
516 inline detail::send_t
broadcast(RangesT &&keylist,
520 return detail::send_t{
521 detail::broadcast_coro<I, Is...>(std::forward<RangesT>(keylist),
522 copy_handler(std::forward<valueT>(value)),
523 t, std::move(copy_handler))};
527 template <
size_t I,
size_t... Is,
typename RangesT,
typename valueT,
530 inline detail::send_t
broadcast(RangesT &&keylist, valueT &&value) {
532 return detail::send_t{
533 detail::broadcast_coro<I, Is...>(std::forward<RangesT>(keylist),
534 copy_handler(std::forward<valueT>(value)),
535 std::move(copy_handler))};
539 template <
size_t I,
size_t... Is,
typename RangesT,
typename... out_keysT,
typename... out_valuesT>
541 inline detail::send_t
broadcastk(RangesT &&keylist,
543 return detail::send_t{detail::broadcastk_coro<I, Is...>(std::forward<RangesT>(keylist), t)};
547 template <
size_t I,
size_t... Is,
typename RangesT>
549 inline detail::send_t
broadcastk(RangesT &&keylist) {
550 return detail::send_t{detail::broadcastk_coro<I, Is...>(std::forward<RangesT>(keylist))};
555 std::vector<device::detail::send_t> forward(Args&&... args) {
557 return std::vector<device::detail::send_t>{std::forward<Args>(args)...};
566 struct device_task_promise_type;
579 struct Task :
public detail::device_task_handle_type {
580 using base_type = detail::device_task_handle_type;
585 using promise_type = detail::device_task_promise_type;
589 Task(base_type base) : base_type(
std::move(base)) {}
591 base_type& handle() {
return *
this; }
594 inline bool ready() {
599 inline bool completed();
608 struct device_task_promise_type {
614 m_state = ttg::device::detail::TTG_DEVICE_CORO_INIT;
623 m_state = ttg::device::detail::TTG_DEVICE_CORO_COMPLETE;
628 template<
typename... Views>
630 return yield_value(views);
633 template<
typename... Ts>
635 auto arr = detail::extract_buffer_data(a, std::make_index_sequence<
sizeof...(Ts)>{});
636 bool need_transfer = !(TTG_IMPL_NS::register_device_memory(ttg::span(arr)));
638 m_state = ttg::device::detail::TTG_DEVICE_CORO_WAIT_TRANSFER;
643 bool need_transfer = !(TTG_IMPL_NS::register_device_memory(a.input.span()));
645 m_state = ttg::device::detail::TTG_DEVICE_CORO_WAIT_TRANSFER;
649 template<
typename... Ts>
650 auto await_transform(detail::wait_kernel_t<Ts...>&& a) {
652 if constexpr (
sizeof...(Ts) > 0) {
653 TTG_IMPL_NS::mark_device_out(a.ties);
655 m_state = ttg::device::detail::TTG_DEVICE_CORO_WAIT_KERNEL;
660 m_sends = std::forward<std::vector<device::detail::send_t>>(v);
661 m_state = ttg::device::detail::TTG_DEVICE_CORO_SENDOUT;
667 m_sends.push_back(std::forward<device::detail::send_t>(v));
668 m_state = ttg::device::detail::TTG_DEVICE_CORO_SENDOUT;
673 m_state = ttg::device::detail::TTG_DEVICE_CORO_COMPLETE;
676 bool complete()
const {
677 return m_state == ttg::device::detail::TTG_DEVICE_CORO_COMPLETE;
680 ttg::device::Task get_return_object() {
return {detail::device_task_handle_type::from_promise(*
this)}; }
682 void unhandled_exception() {
683 std::cerr <<
"Task coroutine caught an unhandled exception!" << std::endl;
691 for (
auto& send : m_sends) {
702 std::vector<device::detail::send_t> m_sends;
703 ttg_device_coro_state m_state = ttg::device::detail::TTG_DEVICE_CORO_STATE_NONE;
709 bool Task::completed() {
return base_type::promise().state() == ttg::device::detail::TTG_DEVICE_CORO_COMPLETE; }
711 struct device_wait_kernel
721 struct device_reducer_promise_type;
726 struct device_reducer :
public device_reducer_handle_type {
727 using base_type = device_reducer_handle_type;
732 using promise_type = device_reducer_promise_type;
736 device_reducer(base_type base) : base_type(
std::move(base)) {}
738 base_type& handle() {
return *
this; }
741 inline bool ready() {
746 inline bool completed();
754 struct device_reducer_promise_type {
760 m_state = ttg::device::detail::TTG_DEVICE_CORO_INIT;
769 m_state = ttg::device::detail::TTG_DEVICE_CORO_COMPLETE;
773 template<
typename... Ts>
775 bool need_transfer = !(TTG_IMPL_NS::register_device_memory(a.ties));
777 m_state = ttg::device::detail::TTG_DEVICE_CORO_WAIT_TRANSFER;
782 m_state = ttg::device::detail::TTG_DEVICE_CORO_COMPLETE;
785 bool complete()
const {
786 return m_state == ttg::device::detail::TTG_DEVICE_CORO_COMPLETE;
789 device_reducer get_return_object() {
return device_reducer{device_reducer_handle_type::from_promise(*
this)}; }
791 void unhandled_exception() { }
799 ttg::device::detail::ttg_device_coro_state m_state = ttg::device::detail::TTG_DEVICE_CORO_STATE_NONE;
803 bool device_reducer::completed() {
return base_type::promise().state() == ttg::device::detail::TTG_DEVICE_CORO_COMPLETE; }
std::enable_if_t<!meta::is_void_v< Key > &&meta::is_void_v< Value >, void > sendk(const Key &key)
std::enable_if_t< meta::is_all_void_v< Key, Value >, void > send()
A complete version of void.
constexpr auto data(C &c) -> decltype(c.data())
std::integral_constant< bool,(Flags &const_) !=0 > is_const
void broadcast(const std::tuple< RangesT... > &keylists, valueT &&value, std::tuple< ttg::Out< out_keysT, out_valuesT >... > &t)
TTG_CXX_COROUTINE_NAMESPACE::suspend_always suspend_always
void send(const keyT &key, valueT &&value, ttg::Out< keyT, valueT > &t)
Sends a task id and a value to the given output terminal.
constexpr const ttg::Runtime ttg_runtime
TTG_CXX_COROUTINE_NAMESPACE::suspend_never suspend_never
TTG_CXX_COROUTINE_NAMESPACE::coroutine_handle< Promise > coroutine_handle
void sendk(const keyT &key, ttg::Out< keyT, void > &t)
Sends a task id (without an accompanying value) to the given output terminal.
void sendv(valueT &&value, ttg::Out< void, valueT > &t)
Sends a value (without an accompanying task id) to the given output terminal.
void broadcastk(const rangeT &keylist, std::tuple< ttg::Out< out_keysT, out_valuesT >... > &t)