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 m_track = rhs.m_track;
216 m_queue = rhs.m_queue;
220 explicit BasicTaskScheduler(memory_pool
const& arg_memory_pool) noexcept
221 : m_track(), m_queue(
nullptr) {
223 Kokkos::Impl::SharedAllocationRecord<memory_space,
224 typename queue_type::Destroy>;
226 record_type* record = record_type::allocate(
227 memory_space(),
"Kokkos::TaskQueue",
sizeof(queue_type));
229 m_queue =
new (record->data()) queue_type(arg_memory_pool);
231 record->m_destroy.m_queue = m_queue;
233 m_track.assign_allocated_record_to_uninitialized(record);
236 BasicTaskScheduler(memory_space
const& arg_memory_space,
237 size_t const mempool_capacity,
238 unsigned const mempool_min_block_size
240 unsigned const mempool_max_block_size
242 unsigned const mempool_superblock_size
244 : BasicTaskScheduler(memory_pool(
245 arg_memory_space, mempool_capacity, mempool_min_block_size,
246 mempool_max_block_size, mempool_superblock_size)) {}
250 KOKKOS_INLINE_FUNCTION
251 queue_type& queue() const noexcept {
252 KOKKOS_EXPECTS(m_queue !=
nullptr);
256 KOKKOS_INLINE_FUNCTION
257 memory_pool* memory() const noexcept {
258 return m_queue ? &(m_queue->m_memory) : (memory_pool*)0;
263 template <
typename FunctorType>
264 KOKKOS_FUNCTION
size_t spawn_allocation_size()
const {
265 return m_queue->template spawn_allocation_size<FunctorType>();
270 size_t when_all_allocation_size(
int narg)
const {
271 return m_queue->when_all_allocation_size(narg);
276 template <
int TaskEnum,
typename DepFutureType,
typename FunctorType>
277 KOKKOS_FUNCTION
static Kokkos::BasicFuture<
typename FunctorType::value_type,
279 spawn(Impl::TaskPolicyWithScheduler<TaskEnum, scheduler_type, DepFutureType>&&
281 typename task_base::function_type arg_function,
282 typename task_base::destroy_type arg_destroy,
283 FunctorType&& arg_functor) {
284 return std::move(arg_policy.scheduler())
285 .
template _spawn_impl<TaskEnum>(
286 _get_task_ptr(std::move(arg_policy.predecessor())),
287 arg_policy.priority(), arg_function, arg_destroy,
288 std::forward<FunctorType>(arg_functor));
291 template <
int TaskEnum,
typename DepFutureType,
typename FunctorType>
292 KOKKOS_FUNCTION future_type_for_functor<std::decay_t<FunctorType>> spawn(
293 Impl::TaskPolicyWithPredecessor<TaskEnum, DepFutureType>&& arg_policy,
294 FunctorType&& arg_functor) {
295 using task_type = runnable_task_type<FunctorType>;
296 typename task_type::function_type
const ptr = task_type::apply;
297 typename task_type::destroy_type
const dtor = task_type::destroy;
299 return _spawn_impl<TaskEnum>(
300 _get_task_ptr(std::move(arg_policy).predecessor()),
301 arg_policy.priority(), ptr, dtor,
302 std::forward<FunctorType>(arg_functor));
305 template <
typename FunctorType,
typename ValueType,
typename Scheduler>
306 KOKKOS_FUNCTION
static void respawn(
307 FunctorType* arg_self,
308 BasicFuture<ValueType, Scheduler>
const& arg_dependence,
309 TaskPriority
const& arg_priority) {
312 using value_type =
typename FunctorType::value_type;
313 using task_type = Impl::Task<BasicTaskScheduler, value_type, FunctorType>;
315 task_type*
const task =
static_cast<task_type*
>(arg_self);
317 task->m_priority =
static_cast<int>(arg_priority);
319 task->add_dependence(arg_dependence.m_task);
324 template <
typename FunctorType>
325 KOKKOS_FUNCTION
static void respawn(FunctorType* arg_self,
326 BasicTaskScheduler
const&,
327 TaskPriority
const& arg_priority) {
330 using value_type =
typename FunctorType::value_type;
331 using task_type = Impl::Task<BasicTaskScheduler, value_type, FunctorType>;
333 task_type*
const task =
static_cast<task_type*
>(arg_self);
335 task->m_priority =
static_cast<int>(arg_priority);
337 task->add_dependence(
nullptr);
346 template <
typename ValueType>
347 KOKKOS_FUNCTION BasicFuture<void, scheduler_type> when_all(
348 BasicFuture<ValueType, BasicTaskScheduler>
const arg[],
int narg) {
352 queue_type* q = m_queue;
356 for (
int i = 0; i < narg; ++i) {
357 task_base*
const t = arg[i].m_task;
361 desul::atomic_inc(&(t->m_ref_count), desul::MemoryOrderSeqCst(),
362 desul::MemoryScopeDevice());
363 if (q != static_cast<queue_type const*>(t->m_queue)) {
365 "Kokkos when_all Futures must be in the same scheduler");
373 size_t const alloc_size = q->when_all_allocation_size(narg);
375 f.m_task =
reinterpret_cast<task_base*
>(q->allocate(alloc_size));
383 new (f.m_task) task_base();
385 f.m_task->m_queue = q;
386 f.m_task->m_ref_count = 2;
387 f.m_task->m_alloc_size =
static_cast<int32_t
>(alloc_size);
388 f.m_task->m_dep_count = narg;
389 f.m_task->m_task_type = task_base::Aggregate;
393 task_base*
volatile*
const dep = f.m_task->aggregate_dependences();
395 for (
int i = 0; i < narg; ++i) {
396 dep[i] = arg[i].m_task;
399 Kokkos::memory_fence();
401 q->schedule_aggregate(f.m_task);
411 KOKKOS_FUNCTION BasicFuture<void, scheduler_type> when_all(
int narg,
413 using input_type = decltype(func(0));
415 static_assert(is_future<input_type>::value,
416 "Functor must return a Kokkos::Future");
420 if (0 == narg)
return f;
422 size_t const alloc_size = m_queue->when_all_allocation_size(narg);
424 f.m_task =
reinterpret_cast<task_base*
>(m_queue->allocate(alloc_size));
431 new (f.m_task) task_base();
435 f.m_task->m_queue = m_queue;
436 f.m_task->m_ref_count = 2;
437 f.m_task->m_alloc_size =
static_cast<int32_t
>(alloc_size);
438 f.m_task->m_dep_count = narg;
439 f.m_task->m_task_type = task_base::Aggregate;
445 task_base*
volatile*
const dep = f.m_task->aggregate_dependences();
447 for (
int i = 0; i < narg; ++i) {
448 const input_type arg_f = func(i);
449 if (
nullptr != arg_f.m_task) {
458 desul::atomic_inc(&(arg_f.m_task->m_ref_count),
459 desul::MemoryOrderSeqCst(),
460 desul::MemoryScopeDevice());
461 dep[i] = arg_f.m_task;
465 Kokkos::memory_fence();
467 m_queue->schedule_aggregate(f.m_task);
475 KOKKOS_INLINE_FUNCTION
476 int allocation_capacity() const noexcept {
477 return m_queue->m_memory.capacity();
480 KOKKOS_INLINE_FUNCTION
481 int allocated_task_count() const noexcept {
return m_queue->m_count_alloc; }
483 KOKKOS_INLINE_FUNCTION
484 int allocated_task_count_max() const noexcept {
return m_queue->m_max_alloc; }
486 KOKKOS_INLINE_FUNCTION
487 long allocated_task_count_accum() const noexcept {
488 return m_queue->m_accum_alloc;
493 template <
class S,
class Q>
494 friend void wait(Kokkos::BasicTaskScheduler<S, Q>
const&);
507 template <
class T,
class Scheduler>
508 KOKKOS_DEPRECATED Impl::TaskPolicyWithPredecessor<
509 Impl::TaskType::TaskTeam, Kokkos::BasicFuture<T, Scheduler>>
510 KOKKOS_INLINE_FUNCTION
511 TaskTeam(Kokkos::BasicFuture<T, Scheduler> arg_future,
512 TaskPriority arg_priority = TaskPriority::Regular) {
513 return {std::move(arg_future), arg_priority};
516 template <
class Scheduler>
517 KOKKOS_DEPRECATED Impl::TaskPolicyWithScheduler<Impl::TaskType::TaskTeam,
519 KOKKOS_INLINE_FUNCTION TaskTeam(
520 Scheduler arg_scheduler,
521 std::enable_if_t<Kokkos::is_scheduler<Scheduler>::value, TaskPriority>
522 arg_priority = TaskPriority::Regular) {
523 return {std::move(arg_scheduler), arg_priority};
526 template <
class Scheduler,
class PredecessorFuture>
527 KOKKOS_DEPRECATED Impl::TaskPolicyWithScheduler<
528 Kokkos::Impl::TaskType::TaskTeam, Scheduler, PredecessorFuture>
529 KOKKOS_INLINE_FUNCTION
530 TaskTeam(Scheduler arg_scheduler, PredecessorFuture arg_future,
531 std::enable_if_t<Kokkos::is_scheduler<Scheduler>::value &&
532 Kokkos::is_future<PredecessorFuture>::value,
534 arg_priority = TaskPriority::Regular) {
536 std::is_same_v<typename PredecessorFuture::scheduler_type, Scheduler>,
537 "Can't create a task policy from a scheduler and a future from "
538 "a different scheduler");
540 return {std::move(arg_scheduler), std::move(arg_future), arg_priority};
545 template <
class T,
class Scheduler>
546 KOKKOS_DEPRECATED Impl::TaskPolicyWithPredecessor<
547 Impl::TaskType::TaskSingle, Kokkos::BasicFuture<T, Scheduler>>
548 KOKKOS_INLINE_FUNCTION
549 TaskSingle(Kokkos::BasicFuture<T, Scheduler> arg_future,
550 TaskPriority arg_priority = TaskPriority::Regular) {
551 return {std::move(arg_future), arg_priority};
554 template <
class Scheduler>
555 KOKKOS_DEPRECATED Impl::TaskPolicyWithScheduler<Impl::TaskType::TaskSingle,
557 KOKKOS_INLINE_FUNCTION TaskSingle(
558 Scheduler arg_scheduler,
559 std::enable_if_t<Kokkos::is_scheduler<Scheduler>::value, TaskPriority>
560 arg_priority = TaskPriority::Regular) {
561 return {std::move(arg_scheduler), arg_priority};
564 template <
class Scheduler,
class PredecessorFuture>
565 KOKKOS_DEPRECATED Impl::TaskPolicyWithScheduler<
566 Kokkos::Impl::TaskType::TaskSingle, Scheduler, PredecessorFuture>
567 KOKKOS_INLINE_FUNCTION
568 TaskSingle(Scheduler arg_scheduler, PredecessorFuture arg_future,
569 std::enable_if_t<Kokkos::is_scheduler<Scheduler>::value &&
570 Kokkos::is_future<PredecessorFuture>::value,
572 arg_priority = TaskPriority::Regular) {
574 std::is_same_v<typename PredecessorFuture::scheduler_type, Scheduler>,
575 "Can't create a task policy from a scheduler and a future from "
576 "a different scheduler");
578 return {std::move(arg_scheduler), std::move(arg_future), arg_priority};
589 template <
int TaskEnum,
typename Scheduler,
typename DepFutureType,
590 typename FunctorType>
591 KOKKOS_DEPRECATED
typename Scheduler::template future_type_for_functor<
592 std::decay_t<FunctorType>>
593 host_spawn(Impl::TaskPolicyWithScheduler<TaskEnum, Scheduler, DepFutureType>
595 FunctorType&& arg_functor) {
596 using scheduler_type = Scheduler;
598 typename scheduler_type::template runnable_task_type<FunctorType>;
600 static_assert(TaskEnum == Impl::TaskType::TaskTeam ||
601 TaskEnum == Impl::TaskType::TaskSingle,
602 "Kokkos host_spawn requires TaskTeam or TaskSingle");
606 typename task_type::function_type ptr;
607 typename task_type::destroy_type dtor;
608 Kokkos::Impl::TaskQueueSpecialization<
609 scheduler_type>::template get_function_pointer<task_type>(ptr, dtor);
611 return scheduler_type::spawn(std::move(arg_policy), ptr, dtor,
612 std::forward<FunctorType>(arg_functor));
621 template <
int TaskEnum,
typename Scheduler,
typename DepFutureType,
622 typename FunctorType>
623 KOKKOS_DEPRECATED
typename Scheduler::template future_type_for_functor<
624 std::decay_t<FunctorType>>
625 KOKKOS_INLINE_FUNCTION
626 task_spawn(Impl::TaskPolicyWithScheduler<TaskEnum, Scheduler, DepFutureType>
628 FunctorType&& arg_functor) {
629 using scheduler_type = Scheduler;
632 typename scheduler_type::template runnable_task_type<FunctorType>;
634 static_assert(TaskEnum == Impl::TaskType::TaskTeam ||
635 TaskEnum == Impl::TaskType::TaskSingle,
636 "Kokkos task_spawn requires TaskTeam or TaskSingle");
638 typename task_type::function_type
const ptr = task_type::apply;
639 typename task_type::destroy_type
const dtor = task_type::destroy;
641 return scheduler_type::spawn(std::move(arg_policy), ptr, dtor,
642 std::forward<FunctorType>(arg_functor));
650 template <
typename FunctorType,
typename T>
651 KOKKOS_DEPRECATED
void KOKKOS_INLINE_FUNCTION
652 respawn(FunctorType* arg_self, T
const& arg,
653 TaskPriority
const& arg_priority = TaskPriority::Regular) {
654 static_assert(Kokkos::is_future<T>::value || Kokkos::is_scheduler<T>::value,
655 "Kokkos respawn argument must be Future or TaskScheduler");
657 T::scheduler_type::respawn(arg_self, arg, arg_priority);
673 template <
class ExecSpace,
class QueueType>
674 KOKKOS_DEPRECATED
inline void wait(
675 BasicTaskScheduler<ExecSpace, QueueType>
const& scheduler) {
676 using scheduler_type = BasicTaskScheduler<ExecSpace, QueueType>;
677 scheduler_type::specialization::execute(scheduler);
683 #ifdef KOKKOS_ENABLE_DEPRECATION_WARNINGS
684 KOKKOS_IMPL_DISABLE_DEPRECATED_WARNINGS_POP()