17 #include <Kokkos_Macros.hpp>
19 #ifndef KOKKOS_IMPL_PUBLIC_INCLUDE
21 "Including non-public Kokkos header files is not allowed.");
24 #ifndef KOKKOS_ENABLE_DEPRECATED_CODE_4
25 #error "The tasking framework is deprecated"
28 #ifndef KOKKOS_TASKSCHEDULER_HPP
29 #define KOKKOS_TASKSCHEDULER_HPP
33 #include <Kokkos_Macros.hpp>
34 #if defined(KOKKOS_ENABLE_TASKDAG)
36 #include <Kokkos_Core_fwd.hpp>
37 #include <Kokkos_TaskScheduler_fwd.hpp>
40 #include <Kokkos_MemoryPool.hpp>
42 #include <Kokkos_Future.hpp>
43 #include <impl/Kokkos_TaskQueue.hpp>
44 #include <impl/Kokkos_SingleTaskQueue.hpp>
45 #include <impl/Kokkos_TaskQueueMultiple.hpp>
46 #include <impl/Kokkos_TaskPolicyData.hpp>
47 #include <impl/Kokkos_TaskTeamMember.hpp>
48 #include <impl/Kokkos_SimpleTaskScheduler.hpp>
53 #ifdef KOKKOS_ENABLE_DEPRECATION_WARNINGS
55 KOKKOS_IMPL_DISABLE_DEPRECATED_WARNINGS_PUSH()
62 template <
class,
class>
67 template <
class ExecSpace,
class QueueType>
68 class KOKKOS_DEPRECATED BasicTaskScheduler :
public Impl::TaskSchedulerBase {
70 using scheduler_type = BasicTaskScheduler;
71 using execution_space = ExecSpace;
72 using queue_type = QueueType;
73 using memory_space =
typename queue_type::memory_space;
74 using memory_pool =
typename queue_type::memory_pool;
75 using specialization = Impl::TaskQueueSpecialization<BasicTaskScheduler>;
76 using member_type =
typename specialization::member_type;
77 using team_scheduler_type = BasicTaskScheduler;
78 template <
class Functor>
79 using runnable_task_type =
80 Impl::Task<scheduler_type, typename Functor::value_type, Functor>;
81 template <
class ValueType>
82 using future_type = Kokkos::BasicFuture<ValueType, BasicTaskScheduler>;
83 template <
class FunctorType>
84 using future_type_for_functor = future_type<typename FunctorType::value_type>;
87 using track_type = Kokkos::Impl::SharedAllocationTracker;
88 using task_base = Impl::TaskBase;
95 template <
typename,
typename>
96 friend class Impl::TaskQueue;
98 friend struct Impl::TaskQueueSpecialization;
99 template <
typename,
typename>
100 friend class Impl::TaskQueueSpecializationConstrained;
101 template <
typename,
typename>
102 friend class Impl::TaskTeamMemberAdapter;
103 template <
typename,
typename>
104 friend class Impl::TaskExec;
108 KOKKOS_INLINE_FUNCTION
109 BasicTaskScheduler(track_type arg_track, queue_type* arg_queue)
110 : m_track(std::move(arg_track)), m_queue(std::move(arg_queue)) {}
112 KOKKOS_INLINE_FUNCTION
113 team_scheduler_type get_team_scheduler(
int team_rank)
const {
114 return {m_track, &m_queue->get_team_queue(team_rank)};
119 KOKKOS_INLINE_FUNCTION
120 static constexpr task_base* _get_task_ptr(std::nullptr_t) {
return nullptr; }
122 template <
class ValueType>
123 KOKKOS_INLINE_FUNCTION
static constexpr task_base* _get_task_ptr(
124 future_type<ValueType>&& f) {
128 template <
int TaskEnum,
typename DepTaskType,
typename FunctorType>
130 Kokkos::BasicFuture<typename FunctorType::value_type, scheduler_type>
131 _spawn_impl(DepTaskType* arg_predecessor_task, TaskPriority arg_priority,
132 typename task_base::function_type arg_function,
133 typename task_base::destroy_type ,
134 FunctorType&& arg_functor) {
135 using functor_future_type =
136 future_type_for_functor<std::decay_t<FunctorType>>;
138 Impl::Task<BasicTaskScheduler,
typename functor_future_type::value_type,
150 functor_future_type f;
154 const size_t alloc_size =
155 m_queue->template spawn_allocation_size<FunctorType>();
157 void* task_storage = m_queue->allocate(alloc_size);
165 new (task_storage) task_type(std::forward<FunctorType>(arg_functor));
167 f.m_task->m_apply = arg_function;
169 f.m_task->m_queue = m_queue;
170 f.m_task->m_next = arg_predecessor_task;
171 f.m_task->m_ref_count = 2;
172 f.m_task->m_alloc_size = alloc_size;
173 f.m_task->m_task_type = TaskEnum;
174 f.m_task->m_priority = (int16_t)arg_priority;
176 Kokkos::memory_fence();
183 m_queue->schedule_runnable(f.m_task);
192 KOKKOS_INLINE_FUNCTION
193 BasicTaskScheduler() : m_track(), m_queue(nullptr) {}
195 KOKKOS_INLINE_FUNCTION
196 BasicTaskScheduler(BasicTaskScheduler&& rhs) noexcept
197 : m_track(rhs.m_track),
199 m_queue(std::move(rhs.m_queue)) {}
201 KOKKOS_INLINE_FUNCTION
202 BasicTaskScheduler(BasicTaskScheduler
const& rhs)
203 : m_track(rhs.m_track), m_queue(rhs.m_queue) {}
205 KOKKOS_INLINE_FUNCTION
206 BasicTaskScheduler& operator=(BasicTaskScheduler&& rhs) noexcept {
207 m_track = rhs.m_track;
209 m_queue = std::move(rhs.m_queue);
213 KOKKOS_INLINE_FUNCTION
214 BasicTaskScheduler& operator=(BasicTaskScheduler
const& rhs) {
215 if (&rhs ==
this)
return *
this;
216 m_track = rhs.m_track;
217 m_queue = rhs.m_queue;
221 explicit BasicTaskScheduler(memory_pool
const& arg_memory_pool) noexcept
222 : m_track(), m_queue(
nullptr) {
224 Kokkos::Impl::SharedAllocationRecord<memory_space,
225 typename queue_type::Destroy>;
227 record_type* record = record_type::allocate(
228 memory_space(),
"Kokkos::TaskQueue",
sizeof(queue_type));
230 m_queue =
new (record->data()) queue_type(arg_memory_pool);
232 record->m_destroy.m_queue = m_queue;
234 m_track.assign_allocated_record_to_uninitialized(record);
237 BasicTaskScheduler(memory_space
const& arg_memory_space,
238 size_t const mempool_capacity,
239 unsigned const mempool_min_block_size
241 unsigned const mempool_max_block_size
243 unsigned const mempool_superblock_size
245 : BasicTaskScheduler(memory_pool(
246 arg_memory_space, mempool_capacity, mempool_min_block_size,
247 mempool_max_block_size, mempool_superblock_size)) {}
251 KOKKOS_INLINE_FUNCTION
252 queue_type& queue() const noexcept {
253 KOKKOS_EXPECTS(m_queue !=
nullptr);
257 KOKKOS_INLINE_FUNCTION
258 memory_pool* memory() const noexcept {
259 return m_queue ? &(m_queue->m_memory) : (memory_pool*)0;
264 template <
typename FunctorType>
265 KOKKOS_FUNCTION
size_t spawn_allocation_size()
const {
266 return m_queue->template spawn_allocation_size<FunctorType>();
271 size_t when_all_allocation_size(
int narg)
const {
272 return m_queue->when_all_allocation_size(narg);
277 template <
int TaskEnum,
typename DepFutureType,
typename FunctorType>
278 KOKKOS_FUNCTION
static Kokkos::BasicFuture<
typename FunctorType::value_type,
280 spawn(Impl::TaskPolicyWithScheduler<TaskEnum, scheduler_type, DepFutureType>&&
282 typename task_base::function_type arg_function,
283 typename task_base::destroy_type arg_destroy,
284 FunctorType&& arg_functor) {
285 return std::move(arg_policy.scheduler())
286 .
template _spawn_impl<TaskEnum>(
287 _get_task_ptr(std::move(arg_policy.predecessor())),
288 arg_policy.priority(), arg_function, arg_destroy,
289 std::forward<FunctorType>(arg_functor));
292 template <
int TaskEnum,
typename DepFutureType,
typename FunctorType>
293 KOKKOS_FUNCTION future_type_for_functor<std::decay_t<FunctorType>> spawn(
294 Impl::TaskPolicyWithPredecessor<TaskEnum, DepFutureType>&& arg_policy,
295 FunctorType&& arg_functor) {
296 using task_type = runnable_task_type<FunctorType>;
297 typename task_type::function_type
const ptr = task_type::apply;
298 typename task_type::destroy_type
const dtor = task_type::destroy;
300 auto const priority = arg_policy.priority();
301 return _spawn_impl<TaskEnum>(
302 _get_task_ptr(std::move(arg_policy).predecessor()), priority, ptr, dtor,
303 std::forward<FunctorType>(arg_functor));
306 template <
typename FunctorType,
typename ValueType,
typename Scheduler>
307 KOKKOS_FUNCTION
static void respawn(
308 FunctorType* arg_self,
309 BasicFuture<ValueType, Scheduler>
const& arg_dependence,
310 TaskPriority
const& arg_priority) {
313 using value_type =
typename FunctorType::value_type;
314 using task_type = Impl::Task<BasicTaskScheduler, value_type, FunctorType>;
316 task_type*
const task =
static_cast<task_type*
>(arg_self);
318 task->m_priority =
static_cast<int>(arg_priority);
320 task->add_dependence(arg_dependence.m_task);
325 template <
typename FunctorType>
326 KOKKOS_FUNCTION
static void respawn(FunctorType* arg_self,
327 BasicTaskScheduler
const&,
328 TaskPriority
const& arg_priority) {
331 using value_type =
typename FunctorType::value_type;
332 using task_type = Impl::Task<BasicTaskScheduler, value_type, FunctorType>;
334 task_type*
const task =
static_cast<task_type*
>(arg_self);
336 task->m_priority =
static_cast<int>(arg_priority);
338 task->add_dependence(
nullptr);
347 template <
typename ValueType>
348 KOKKOS_FUNCTION BasicFuture<void, scheduler_type> when_all(
349 BasicFuture<ValueType, BasicTaskScheduler>
const arg[],
int narg) {
353 queue_type* q = m_queue;
357 for (
int i = 0; i < narg; ++i) {
358 task_base*
const t = arg[i].m_task;
362 desul::atomic_inc(&(t->m_ref_count), desul::MemoryOrderSeqCst(),
363 desul::MemoryScopeDevice());
364 if (q != static_cast<queue_type const*>(t->m_queue)) {
366 "Kokkos when_all Futures must be in the same scheduler");
374 size_t const alloc_size = q->when_all_allocation_size(narg);
376 f.m_task =
reinterpret_cast<task_base*
>(q->allocate(alloc_size));
384 new (f.m_task) task_base();
386 f.m_task->m_queue = q;
387 f.m_task->m_ref_count = 2;
388 f.m_task->m_alloc_size =
static_cast<int32_t
>(alloc_size);
389 f.m_task->m_dep_count = narg;
390 f.m_task->m_task_type = task_base::Aggregate;
394 task_base*
volatile*
const dep = f.m_task->aggregate_dependences();
396 for (
int i = 0; i < narg; ++i) {
397 dep[i] = arg[i].m_task;
400 Kokkos::memory_fence();
402 q->schedule_aggregate(f.m_task);
412 KOKKOS_FUNCTION BasicFuture<void, scheduler_type> when_all(
int narg,
414 using input_type = decltype(func(0));
416 static_assert(is_future<input_type>::value,
417 "Functor must return a Kokkos::Future");
421 if (0 == narg)
return f;
423 size_t const alloc_size = m_queue->when_all_allocation_size(narg);
425 f.m_task =
reinterpret_cast<task_base*
>(m_queue->allocate(alloc_size));
432 new (f.m_task) task_base();
436 f.m_task->m_queue = m_queue;
437 f.m_task->m_ref_count = 2;
438 f.m_task->m_alloc_size =
static_cast<int32_t
>(alloc_size);
439 f.m_task->m_dep_count = narg;
440 f.m_task->m_task_type = task_base::Aggregate;
446 task_base*
volatile*
const dep = f.m_task->aggregate_dependences();
448 for (
int i = 0; i < narg; ++i) {
449 const input_type arg_f = func(i);
450 if (
nullptr != arg_f.m_task) {
459 desul::atomic_inc(&(arg_f.m_task->m_ref_count),
460 desul::MemoryOrderSeqCst(),
461 desul::MemoryScopeDevice());
462 dep[i] = arg_f.m_task;
466 Kokkos::memory_fence();
468 m_queue->schedule_aggregate(f.m_task);
476 KOKKOS_INLINE_FUNCTION
477 int allocation_capacity() const noexcept {
478 return m_queue->m_memory.capacity();
481 KOKKOS_INLINE_FUNCTION
482 int allocated_task_count() const noexcept {
return m_queue->m_count_alloc; }
484 KOKKOS_INLINE_FUNCTION
485 int allocated_task_count_max() const noexcept {
return m_queue->m_max_alloc; }
487 KOKKOS_INLINE_FUNCTION
488 long allocated_task_count_accum() const noexcept {
489 return m_queue->m_accum_alloc;
494 template <
class S,
class Q>
495 friend void wait(Kokkos::BasicTaskScheduler<S, Q>
const&);
508 template <
class T,
class Scheduler>
509 KOKKOS_DEPRECATED Impl::TaskPolicyWithPredecessor<
510 Impl::TaskType::TaskTeam, Kokkos::BasicFuture<T, Scheduler>>
511 KOKKOS_INLINE_FUNCTION
512 TaskTeam(Kokkos::BasicFuture<T, Scheduler> arg_future,
513 TaskPriority arg_priority = TaskPriority::Regular) {
514 return {std::move(arg_future), arg_priority};
517 template <
class Scheduler>
518 KOKKOS_DEPRECATED Impl::TaskPolicyWithScheduler<Impl::TaskType::TaskTeam,
520 KOKKOS_INLINE_FUNCTION TaskTeam(
521 Scheduler arg_scheduler,
522 std::enable_if_t<Kokkos::is_scheduler<Scheduler>::value, TaskPriority>
523 arg_priority = TaskPriority::Regular) {
524 return {std::move(arg_scheduler), arg_priority};
527 template <
class Scheduler,
class PredecessorFuture>
528 KOKKOS_DEPRECATED Impl::TaskPolicyWithScheduler<
529 Kokkos::Impl::TaskType::TaskTeam, Scheduler, PredecessorFuture>
530 KOKKOS_INLINE_FUNCTION
531 TaskTeam(Scheduler arg_scheduler, PredecessorFuture arg_future,
532 std::enable_if_t<Kokkos::is_scheduler<Scheduler>::value &&
533 Kokkos::is_future<PredecessorFuture>::value,
535 arg_priority = TaskPriority::Regular) {
537 std::is_same_v<typename PredecessorFuture::scheduler_type, Scheduler>,
538 "Can't create a task policy from a scheduler and a future from "
539 "a different scheduler");
541 return {std::move(arg_scheduler), std::move(arg_future), arg_priority};
546 template <
class T,
class Scheduler>
547 KOKKOS_DEPRECATED Impl::TaskPolicyWithPredecessor<
548 Impl::TaskType::TaskSingle, Kokkos::BasicFuture<T, Scheduler>>
549 KOKKOS_INLINE_FUNCTION
550 TaskSingle(Kokkos::BasicFuture<T, Scheduler> arg_future,
551 TaskPriority arg_priority = TaskPriority::Regular) {
552 return {std::move(arg_future), arg_priority};
555 template <
class Scheduler>
556 KOKKOS_DEPRECATED Impl::TaskPolicyWithScheduler<Impl::TaskType::TaskSingle,
558 KOKKOS_INLINE_FUNCTION TaskSingle(
559 Scheduler arg_scheduler,
560 std::enable_if_t<Kokkos::is_scheduler<Scheduler>::value, TaskPriority>
561 arg_priority = TaskPriority::Regular) {
562 return {std::move(arg_scheduler), arg_priority};
565 template <
class Scheduler,
class PredecessorFuture>
566 KOKKOS_DEPRECATED Impl::TaskPolicyWithScheduler<
567 Kokkos::Impl::TaskType::TaskSingle, Scheduler, PredecessorFuture>
568 KOKKOS_INLINE_FUNCTION
569 TaskSingle(Scheduler arg_scheduler, PredecessorFuture arg_future,
570 std::enable_if_t<Kokkos::is_scheduler<Scheduler>::value &&
571 Kokkos::is_future<PredecessorFuture>::value,
573 arg_priority = TaskPriority::Regular) {
575 std::is_same_v<typename PredecessorFuture::scheduler_type, Scheduler>,
576 "Can't create a task policy from a scheduler and a future from "
577 "a different scheduler");
579 return {std::move(arg_scheduler), std::move(arg_future), arg_priority};
590 template <
int TaskEnum,
typename Scheduler,
typename DepFutureType,
591 typename FunctorType>
592 KOKKOS_DEPRECATED
typename Scheduler::template future_type_for_functor<
593 std::decay_t<FunctorType>>
594 host_spawn(Impl::TaskPolicyWithScheduler<TaskEnum, Scheduler, DepFutureType>
596 FunctorType&& arg_functor) {
597 using scheduler_type = Scheduler;
599 typename scheduler_type::template runnable_task_type<FunctorType>;
601 static_assert(TaskEnum == Impl::TaskType::TaskTeam ||
602 TaskEnum == Impl::TaskType::TaskSingle,
603 "Kokkos host_spawn requires TaskTeam or TaskSingle");
607 typename task_type::function_type ptr;
608 typename task_type::destroy_type dtor;
609 Kokkos::Impl::TaskQueueSpecialization<
610 scheduler_type>::template get_function_pointer<task_type>(ptr, dtor);
612 return scheduler_type::spawn(std::move(arg_policy), ptr, dtor,
613 std::forward<FunctorType>(arg_functor));
622 template <
int TaskEnum,
typename Scheduler,
typename DepFutureType,
623 typename FunctorType>
624 KOKKOS_DEPRECATED
typename Scheduler::template future_type_for_functor<
625 std::decay_t<FunctorType>>
626 KOKKOS_INLINE_FUNCTION
627 task_spawn(Impl::TaskPolicyWithScheduler<TaskEnum, Scheduler, DepFutureType>
629 FunctorType&& arg_functor) {
630 using scheduler_type = Scheduler;
633 typename scheduler_type::template runnable_task_type<FunctorType>;
635 static_assert(TaskEnum == Impl::TaskType::TaskTeam ||
636 TaskEnum == Impl::TaskType::TaskSingle,
637 "Kokkos task_spawn requires TaskTeam or TaskSingle");
639 typename task_type::function_type
const ptr = task_type::apply;
640 typename task_type::destroy_type
const dtor = task_type::destroy;
642 return scheduler_type::spawn(std::move(arg_policy), ptr, dtor,
643 std::forward<FunctorType>(arg_functor));
651 template <
typename FunctorType,
typename T>
652 KOKKOS_DEPRECATED
void KOKKOS_INLINE_FUNCTION
653 respawn(FunctorType* arg_self, T
const& arg,
654 TaskPriority
const& arg_priority = TaskPriority::Regular) {
655 static_assert(Kokkos::is_future<T>::value || Kokkos::is_scheduler<T>::value,
656 "Kokkos respawn argument must be Future or TaskScheduler");
658 T::scheduler_type::respawn(arg_self, arg, arg_priority);
674 template <
class ExecSpace,
class QueueType>
675 KOKKOS_DEPRECATED
inline void wait(
676 BasicTaskScheduler<ExecSpace, QueueType>
const& scheduler) {
677 using scheduler_type = BasicTaskScheduler<ExecSpace, QueueType>;
678 scheduler_type::specialization::execute(scheduler);
684 #ifdef KOKKOS_ENABLE_DEPRECATION_WARNINGS
685 KOKKOS_IMPL_DISABLE_DEPRECATED_WARNINGS_POP()