Kokkos Core Kernels Package  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
Kokkos_TaskScheduler.hpp
1 /*
2 //@HEADER
3 // ************************************************************************
4 //
5 // Kokkos v. 3.0
6 // Copyright (2020) National Technology & Engineering
7 // Solutions of Sandia, LLC (NTESS).
8 //
9 // Under the terms of Contract DE-NA0003525 with NTESS,
10 // the U.S. Government retains certain rights in this software.
11 //
12 // Redistribution and use in source and binary forms, with or without
13 // modification, are permitted provided that the following conditions are
14 // met:
15 //
16 // 1. Redistributions of source code must retain the above copyright
17 // notice, this list of conditions and the following disclaimer.
18 //
19 // 2. Redistributions in binary form must reproduce the above copyright
20 // notice, this list of conditions and the following disclaimer in the
21 // documentation and/or other materials provided with the distribution.
22 //
23 // 3. Neither the name of the Corporation nor the names of the
24 // contributors may be used to endorse or promote products derived from
25 // this software without specific prior written permission.
26 //
27 // THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY
28 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE
31 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
32 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
33 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
34 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
35 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
36 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
37 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38 //
39 // Questions? Contact Christian R. Trott (crtrott@sandia.gov)
40 //
41 // ************************************************************************
42 //@HEADER
43 */
44 
45 #ifndef KOKKOS_TASKSCHEDULER_HPP
46 #define KOKKOS_TASKSCHEDULER_HPP
47 
48 //----------------------------------------------------------------------------
49 
50 #include <Kokkos_Macros.hpp>
51 #if defined(KOKKOS_ENABLE_TASKDAG)
52 
53 #include <Kokkos_Core_fwd.hpp>
54 #include <Kokkos_TaskScheduler_fwd.hpp>
55 //----------------------------------------------------------------------------
56 
57 #include <Kokkos_MemoryPool.hpp>
58 #include <impl/Kokkos_Tags.hpp>
59 
60 #include <Kokkos_Future.hpp>
61 #include <impl/Kokkos_TaskQueue.hpp>
62 #include <impl/Kokkos_SingleTaskQueue.hpp>
63 #include <impl/Kokkos_TaskQueueMultiple.hpp>
64 #include <impl/Kokkos_TaskPolicyData.hpp>
65 #include <impl/Kokkos_TaskTeamMember.hpp>
66 #include <impl/Kokkos_SimpleTaskScheduler.hpp>
67 
68 //----------------------------------------------------------------------------
69 //----------------------------------------------------------------------------
70 
71 namespace Kokkos {
72 
73 namespace Impl {
74 
75 template <class, class>
76 class TaskExec;
77 
78 } // end namespace Impl
79 
80 template <class ExecSpace, class QueueType>
81 class BasicTaskScheduler : public Impl::TaskSchedulerBase {
82  public:
83  using scheduler_type = BasicTaskScheduler;
84  using execution_space = ExecSpace;
85  using queue_type = QueueType;
86  using memory_space = typename queue_type::memory_space;
87  using memory_pool = typename queue_type::memory_pool;
88  using specialization = Impl::TaskQueueSpecialization<BasicTaskScheduler>;
89  using member_type = typename specialization::member_type;
90  using team_scheduler_type = BasicTaskScheduler;
91  template <class Functor>
92  using runnable_task_type =
93  Impl::Task<scheduler_type, typename Functor::value_type, Functor>;
94  template <class ValueType>
95  using future_type = Kokkos::BasicFuture<ValueType, BasicTaskScheduler>;
96  template <class FunctorType>
97  using future_type_for_functor = future_type<typename FunctorType::value_type>;
98 
99  private:
100  using track_type = Kokkos::Impl::SharedAllocationTracker;
101  using task_base = Impl::TaskBase;
102 
103  track_type m_track;
104  queue_type* m_queue;
105 
106  //----------------------------------------
107 
108  template <typename, typename>
109  friend class Impl::TaskQueue;
110  template <typename>
111  friend struct Impl::TaskQueueSpecialization;
112  template <typename, typename>
113  friend class Impl::TaskQueueSpecializationConstrained;
114  template <typename, typename>
115  friend class Impl::TaskTeamMemberAdapter;
116  template <typename, typename>
117  friend class Impl::TaskExec;
118 
119  //----------------------------------------
120 
121  KOKKOS_INLINE_FUNCTION
122  BasicTaskScheduler(track_type arg_track, queue_type* arg_queue)
123  : m_track(std::move(arg_track)), m_queue(std::move(arg_queue)) {}
124 
125  KOKKOS_INLINE_FUNCTION
126  team_scheduler_type get_team_scheduler(int team_rank) const {
127  return {m_track, &m_queue->get_team_queue(team_rank)};
128  }
129 
130  //----------------------------------------
131 
132  KOKKOS_INLINE_FUNCTION
133  static constexpr task_base* _get_task_ptr(std::nullptr_t) { return nullptr; }
134 
135  template <class ValueType>
136  KOKKOS_INLINE_FUNCTION static constexpr task_base* _get_task_ptr(
137  future_type<ValueType>&& f) {
138  return f.m_task;
139  }
140 
141  template <int TaskEnum, typename DepTaskType, typename FunctorType>
142  KOKKOS_FUNCTION
143  Kokkos::BasicFuture<typename FunctorType::value_type, scheduler_type>
144  _spawn_impl(DepTaskType* arg_predecessor_task, TaskPriority arg_priority,
145  typename task_base::function_type arg_function,
146  typename task_base::destroy_type /*arg_destroy*/,
147  FunctorType&& arg_functor) {
148  using functor_future_type =
149  future_type_for_functor<typename std::decay<FunctorType>::type>;
150  using task_type =
151  Impl::Task<BasicTaskScheduler, typename functor_future_type::value_type,
152  FunctorType>;
153 
154  //----------------------------------------
155  // Give single-thread back-ends an opportunity to clear
156  // queue of ready tasks before allocating a new task
157 
158  // TODO @tasking @optimization DSH re-enable this, maybe?
159  // specialization::iff_single_thread_recursive_execute(scheduler);
160 
161  //----------------------------------------
162 
163  functor_future_type f;
164 
165  // Allocate task from memory pool
166 
167  const size_t alloc_size =
168  m_queue->template spawn_allocation_size<FunctorType>();
169 
170  void* task_storage = m_queue->allocate(alloc_size);
171 
172  if (task_storage) {
173  // Placement new construction
174  // Reference count starts at two:
175  // +1 for the matching decrement when task is complete
176  // +1 for the future
177  f.m_task =
178  new (task_storage) task_type(std::forward<FunctorType>(arg_functor));
179 
180  f.m_task->m_apply = arg_function;
181  // f.m_task->m_destroy = arg_destroy;
182  f.m_task->m_queue = m_queue;
183  f.m_task->m_next = arg_predecessor_task;
184  f.m_task->m_ref_count = 2;
185  f.m_task->m_alloc_size = alloc_size;
186  f.m_task->m_task_type = TaskEnum;
187  f.m_task->m_priority = (int16_t)arg_priority;
188 
189  Kokkos::memory_fence();
190 
191  // The dependence (if any) is processed immediately
192  // within the schedule function, as such the dependence's
193  // reference count does not need to be incremented for
194  // the assignment.
195 
196  m_queue->schedule_runnable(f.m_task);
197  // This task may be updated or executed at any moment,
198  // even during the call to 'schedule'.
199  }
200 
201  return f;
202  }
203 
204  public:
205  KOKKOS_INLINE_FUNCTION
206  BasicTaskScheduler() : m_track(), m_queue(nullptr) {}
207 
208  KOKKOS_INLINE_FUNCTION
209  BasicTaskScheduler(BasicTaskScheduler&& rhs) noexcept
210  : m_track(rhs.m_track), // probably should be a move, but this is
211  // deprecated code anyway
212  m_queue(std::move(rhs.m_queue)) {}
213 
214  KOKKOS_INLINE_FUNCTION
215  BasicTaskScheduler(BasicTaskScheduler const& rhs)
216  : m_track(rhs.m_track), m_queue(rhs.m_queue) {}
217 
218  KOKKOS_INLINE_FUNCTION
219  BasicTaskScheduler& operator=(BasicTaskScheduler&& rhs) noexcept {
220  m_track = rhs.m_track; // probably should be a move, but this is deprecated
221  // code anyway
222  m_queue = std::move(rhs.m_queue);
223  return *this;
224  }
225 
226  KOKKOS_INLINE_FUNCTION
227  BasicTaskScheduler& operator=(BasicTaskScheduler const& rhs) {
228  m_track = rhs.m_track;
229  m_queue = rhs.m_queue;
230  return *this;
231  }
232 
233  explicit BasicTaskScheduler(memory_pool const& arg_memory_pool) noexcept
234  : m_track(), m_queue(nullptr) {
235  typedef Kokkos::Impl::SharedAllocationRecord<memory_space,
236  typename queue_type::Destroy>
237  record_type;
238 
239  record_type* record =
240  record_type::allocate(memory_space(), "TaskQueue", sizeof(queue_type));
241 
242  m_queue = new (record->data()) queue_type(arg_memory_pool);
243 
244  record->m_destroy.m_queue = m_queue;
245 
246  m_track.assign_allocated_record_to_uninitialized(record);
247  }
248 
249  BasicTaskScheduler(memory_space const& arg_memory_space,
250  size_t const mempool_capacity,
251  unsigned const mempool_min_block_size // = 1u << 6
252  ,
253  unsigned const mempool_max_block_size // = 1u << 10
254  ,
255  unsigned const mempool_superblock_size // = 1u << 12
256  )
257  : BasicTaskScheduler(memory_pool(
258  arg_memory_space, mempool_capacity, mempool_min_block_size,
259  mempool_max_block_size, mempool_superblock_size)) {}
260 
261  //----------------------------------------
262 
263  KOKKOS_INLINE_FUNCTION
264  queue_type& queue() const noexcept {
265  KOKKOS_EXPECTS(m_queue != nullptr);
266  return *m_queue;
267  }
268 
269  KOKKOS_INLINE_FUNCTION
270  memory_pool* memory() const noexcept {
271  return m_queue ? &(m_queue->m_memory) : (memory_pool*)0;
272  }
273 
274  //----------------------------------------
276  template <typename FunctorType>
277  KOKKOS_FUNCTION size_t spawn_allocation_size() const {
278  return m_queue->template spawn_allocation_size<FunctorType>();
279  }
280 
282  KOKKOS_FUNCTION
283  size_t when_all_allocation_size(int narg) const {
284  return m_queue->when_all_allocation_size(narg);
285  }
286 
287  //----------------------------------------
288 
289  template <int TaskEnum, typename DepFutureType, typename FunctorType>
290  KOKKOS_FUNCTION static Kokkos::BasicFuture<typename FunctorType::value_type,
291  scheduler_type>
292  spawn(Impl::TaskPolicyWithScheduler<TaskEnum, scheduler_type, DepFutureType>&&
293  arg_policy,
294  typename task_base::function_type arg_function,
295  typename task_base::destroy_type arg_destroy,
296  FunctorType&& arg_functor) {
297  return std::move(arg_policy.scheduler())
298  .template _spawn_impl<TaskEnum>(
299  _get_task_ptr(std::move(arg_policy.predecessor())),
300  arg_policy.priority(), arg_function, arg_destroy,
301  std::forward<FunctorType>(arg_functor));
302  }
303 
304  template <int TaskEnum, typename DepFutureType, typename FunctorType>
305  KOKKOS_FUNCTION
306  future_type_for_functor<typename std::decay<FunctorType>::type>
307  spawn(
308  Impl::TaskPolicyWithPredecessor<TaskEnum, DepFutureType>&& arg_policy,
309  FunctorType&& arg_functor) {
310  using task_type = runnable_task_type<FunctorType>;
311  typename task_type::function_type const ptr = task_type::apply;
312  typename task_type::destroy_type const dtor = task_type::destroy;
313 
314  return _spawn_impl<TaskEnum>(
315  _get_task_ptr(std::move(arg_policy).predecessor()),
316  arg_policy.priority(), ptr, dtor,
317  std::forward<FunctorType>(arg_functor));
318  }
319 
320  template <typename FunctorType, typename ValueType, typename Scheduler>
321  KOKKOS_FUNCTION static void respawn(
322  FunctorType* arg_self,
323  BasicFuture<ValueType, Scheduler> const& arg_dependence,
324  TaskPriority const& arg_priority) {
325  // Precondition: task is in Executing state
326 
327  using value_type = typename FunctorType::value_type;
328  using task_type = Impl::Task<BasicTaskScheduler, value_type, FunctorType>;
329 
330  task_type* const task = static_cast<task_type*>(arg_self);
331 
332  task->m_priority = static_cast<int>(arg_priority);
333 
334  task->add_dependence(arg_dependence.m_task);
335 
336  // Postcondition: task is in Executing-Respawn state
337  }
338 
339  template <typename FunctorType>
340  KOKKOS_FUNCTION static void respawn(FunctorType* arg_self,
341  BasicTaskScheduler const&,
342  TaskPriority const& arg_priority) {
343  // Precondition: task is in Executing state
344 
345  using value_type = typename FunctorType::value_type;
346  using task_type = Impl::Task<BasicTaskScheduler, value_type, FunctorType>;
347 
348  task_type* const task = static_cast<task_type*>(arg_self);
349 
350  task->m_priority = static_cast<int>(arg_priority);
351 
352  task->add_dependence(nullptr);
353 
354  // Postcondition: task is in Executing-Respawn state
355  }
356 
357  //----------------------------------------
361  template <typename ValueType>
362  KOKKOS_FUNCTION BasicFuture<void, scheduler_type> when_all(
363  BasicFuture<ValueType, BasicTaskScheduler> const arg[], int narg) {
364  future_type<void> f;
365 
366  if (narg) {
367  queue_type* q = m_queue;
368 
369  // BasicTaskScheduler const* scheduler_ptr = nullptr;
370 
371  for (int i = 0; i < narg; ++i) {
372  task_base* const t = arg[i].m_task;
373  if (nullptr != t) {
374  // Increment reference count to track subsequent assignment.
375  Kokkos::atomic_increment(&(t->m_ref_count));
376  if (q != static_cast<queue_type const*>(t->m_queue)) {
377  Kokkos::abort(
378  "Kokkos when_all Futures must be in the same scheduler");
379  }
380  }
381  }
382 
383  if (q != nullptr) { // this should probably handle the queue == 0 case,
384  // but this is deprecated code anyway
385 
386  size_t const alloc_size = q->when_all_allocation_size(narg);
387 
388  f.m_task = reinterpret_cast<task_base*>(q->allocate(alloc_size));
389  // f.m_scheduler = *scheduler_ptr;
390 
391  if (f.m_task) {
392  // Reference count starts at two:
393  // +1 to match decrement when task completes
394  // +1 for the future
395 
396  new (f.m_task) task_base();
397 
398  f.m_task->m_queue = q;
399  f.m_task->m_ref_count = 2;
400  f.m_task->m_alloc_size = static_cast<int32_t>(alloc_size);
401  f.m_task->m_dep_count = narg;
402  f.m_task->m_task_type = task_base::Aggregate;
403 
404  // Assign dependences, reference counts were already incremented
405 
406  task_base* volatile* const dep = f.m_task->aggregate_dependences();
407 
408  for (int i = 0; i < narg; ++i) {
409  dep[i] = arg[i].m_task;
410  }
411 
412  Kokkos::memory_fence();
413 
414  q->schedule_aggregate(f.m_task);
415  // this when_all may be processed at any moment
416  }
417  }
418  }
419 
420  return f;
421  }
422 
423  template <class F>
424  KOKKOS_FUNCTION BasicFuture<void, scheduler_type> when_all(int narg,
425  F const func) {
426  using input_type = decltype(func(0));
427 
428  static_assert(is_future<input_type>::value,
429  "Functor must return a Kokkos::Future");
430 
431  future_type<void> f;
432 
433  if (0 == narg) return f;
434 
435  size_t const alloc_size = m_queue->when_all_allocation_size(narg);
436 
437  f.m_task = reinterpret_cast<task_base*>(m_queue->allocate(alloc_size));
438 
439  if (f.m_task) {
440  // Reference count starts at two:
441  // +1 to match decrement when task completes
442  // +1 for the future
443 
444  new (f.m_task) task_base();
445  // f.m_scheduler = *this;
446 
447  // f.m_task->m_scheduler = &f.m_scheduler;
448  f.m_task->m_queue = m_queue;
449  f.m_task->m_ref_count = 2;
450  f.m_task->m_alloc_size = static_cast<int32_t>(alloc_size);
451  f.m_task->m_dep_count = narg;
452  f.m_task->m_task_type = task_base::Aggregate;
453  // f.m_task->m_apply = nullptr;
454  // f.m_task->m_destroy = nullptr;
455 
456  // Assign dependences, reference counts were already incremented
457 
458  task_base* volatile* const dep = f.m_task->aggregate_dependences();
459 
460  for (int i = 0; i < narg; ++i) {
461  const input_type arg_f = func(i);
462  if (nullptr != arg_f.m_task) {
463  // Not scheduled, so task scheduler is not yet set
464  // if ( m_queue != static_cast< BasicTaskScheduler const * >(
465  // arg_f.m_task->m_scheduler )->m_queue ) {
466  // Kokkos::abort("Kokkos when_all Futures must be in the same
467  // scheduler" );
468  //}
469  // Increment reference count to track subsequent assignment.
470  Kokkos::atomic_increment(&(arg_f.m_task->m_ref_count));
471  dep[i] = arg_f.m_task;
472  }
473  }
474 
475  Kokkos::memory_fence();
476 
477  m_queue->schedule_aggregate(f.m_task);
478  // this when_all may be processed at any moment
479  }
480  return f;
481  }
482 
483  //----------------------------------------
484 
485  KOKKOS_INLINE_FUNCTION
486  int allocation_capacity() const noexcept {
487  return m_queue->m_memory.capacity();
488  }
489 
490  KOKKOS_INLINE_FUNCTION
491  int allocated_task_count() const noexcept { return m_queue->m_count_alloc; }
492 
493  KOKKOS_INLINE_FUNCTION
494  int allocated_task_count_max() const noexcept { return m_queue->m_max_alloc; }
495 
496  KOKKOS_INLINE_FUNCTION
497  long allocated_task_count_accum() const noexcept {
498  return m_queue->m_accum_alloc;
499  }
500 
501  //----------------------------------------
502 
503  template <class S, class Q>
504  friend void wait(Kokkos::BasicTaskScheduler<S, Q> const&);
505 };
506 
507 } // namespace Kokkos
508 
509 //----------------------------------------------------------------------------
510 //----------------------------------------------------------------------------
511 
512 namespace Kokkos {
513 
514 //----------------------------------------------------------------------------
515 // Construct a TaskTeam execution policy
516 
517 template <class T, class Scheduler>
518 Impl::TaskPolicyWithPredecessor<Impl::TaskType::TaskTeam,
519  Kokkos::BasicFuture<T, Scheduler> >
520  KOKKOS_INLINE_FUNCTION
521  TaskTeam(Kokkos::BasicFuture<T, Scheduler> arg_future,
522  TaskPriority arg_priority = TaskPriority::Regular) {
523  return {std::move(arg_future), arg_priority};
524 }
525 
526 template <class Scheduler>
527 Impl::TaskPolicyWithScheduler<Impl::TaskType::TaskTeam, Scheduler>
528  KOKKOS_INLINE_FUNCTION
529  TaskTeam(Scheduler arg_scheduler,
530  typename std::enable_if<Kokkos::is_scheduler<Scheduler>::value,
531  TaskPriority>::type arg_priority =
532  TaskPriority::Regular) {
533  return {std::move(arg_scheduler), arg_priority};
534 }
535 
536 template <class Scheduler, class PredecessorFuture>
537 Impl::TaskPolicyWithScheduler<Kokkos::Impl::TaskType::TaskTeam, Scheduler,
538  PredecessorFuture>
539  KOKKOS_INLINE_FUNCTION TaskTeam(
540  Scheduler arg_scheduler, PredecessorFuture arg_future,
541  typename std::enable_if<Kokkos::is_scheduler<Scheduler>::value &&
542  Kokkos::is_future<PredecessorFuture>::value,
543  TaskPriority>::type arg_priority =
544  TaskPriority::Regular) {
545  static_assert(std::is_same<typename PredecessorFuture::scheduler_type,
546  Scheduler>::value,
547  "Can't create a task policy from a scheduler and a future from "
548  "a different scheduler");
549 
550  return {std::move(arg_scheduler), std::move(arg_future), arg_priority};
551 }
552 
553 // Construct a TaskSingle execution policy
554 
555 template <class T, class Scheduler>
556 Impl::TaskPolicyWithPredecessor<Impl::TaskType::TaskSingle,
557  Kokkos::BasicFuture<T, Scheduler> >
558  KOKKOS_INLINE_FUNCTION
559  TaskSingle(Kokkos::BasicFuture<T, Scheduler> arg_future,
560  TaskPriority arg_priority = TaskPriority::Regular) {
561  return {std::move(arg_future), arg_priority};
562 }
563 
564 template <class Scheduler>
565 Impl::TaskPolicyWithScheduler<Impl::TaskType::TaskSingle, Scheduler>
566  KOKKOS_INLINE_FUNCTION
567  TaskSingle(Scheduler arg_scheduler,
568  typename std::enable_if<Kokkos::is_scheduler<Scheduler>::value,
569  TaskPriority>::type arg_priority =
570  TaskPriority::Regular) {
571  return {std::move(arg_scheduler), arg_priority};
572 }
573 
574 template <class Scheduler, class PredecessorFuture>
575 Impl::TaskPolicyWithScheduler<Kokkos::Impl::TaskType::TaskSingle, Scheduler,
576  PredecessorFuture>
577  KOKKOS_INLINE_FUNCTION TaskSingle(
578  Scheduler arg_scheduler, PredecessorFuture arg_future,
579  typename std::enable_if<Kokkos::is_scheduler<Scheduler>::value &&
580  Kokkos::is_future<PredecessorFuture>::value,
581  TaskPriority>::type arg_priority =
582  TaskPriority::Regular) {
583  static_assert(std::is_same<typename PredecessorFuture::scheduler_type,
584  Scheduler>::value,
585  "Can't create a task policy from a scheduler and a future from "
586  "a different scheduler");
587 
588  return {std::move(arg_scheduler), std::move(arg_future), arg_priority};
589 }
590 
591 //----------------------------------------------------------------------------
592 
599 template <int TaskEnum, typename Scheduler, typename DepFutureType,
600  typename FunctorType>
601 typename Scheduler::template future_type_for_functor<
602  typename std::decay<FunctorType>::type>
603 host_spawn(Impl::TaskPolicyWithScheduler<TaskEnum, Scheduler, DepFutureType>
604  arg_policy,
605  FunctorType&& arg_functor) {
606  using scheduler_type = Scheduler;
607  using task_type =
608  typename scheduler_type::template runnable_task_type<FunctorType>;
609 
610  static_assert(TaskEnum == Impl::TaskType::TaskTeam ||
611  TaskEnum == Impl::TaskType::TaskSingle,
612  "Kokkos host_spawn requires TaskTeam or TaskSingle");
613 
614  // May be spawning a Cuda task, must use the specialization
615  // to query on-device function pointer.
616  typename task_type::function_type ptr;
617  typename task_type::destroy_type dtor;
618  Kokkos::Impl::TaskQueueSpecialization<
619  scheduler_type>::template get_function_pointer<task_type>(ptr, dtor);
620 
621  return scheduler_type::spawn(std::move(arg_policy), ptr, dtor,
622  std::forward<FunctorType>(arg_functor));
623 }
624 
631 template <int TaskEnum, typename Scheduler, typename DepFutureType,
632  typename FunctorType>
633 typename Scheduler::template future_type_for_functor<
634  typename std::decay<FunctorType>::type>
635  KOKKOS_INLINE_FUNCTION
636  task_spawn(Impl::TaskPolicyWithScheduler<TaskEnum, Scheduler, DepFutureType>
637  arg_policy,
638  FunctorType&& arg_functor) {
639  using scheduler_type = Scheduler;
640 
641  using task_type =
642  typename scheduler_type::template runnable_task_type<FunctorType>;
643 
644 #if defined(KOKKOS_ACTIVE_EXECUTION_MEMORY_SPACE_HOST) && \
645  defined(KOKKOS_ENABLE_CUDA)
646 
647  // This doesn't work with clang cuda
648  // static_assert(
649  // !std::is_same<Kokkos::Cuda, typename Scheduler::execution_space>::value,
650  // "Error calling Kokkos::task_spawn for Cuda space within Host code");
651 
652 #endif
653 
654  static_assert(TaskEnum == Impl::TaskType::TaskTeam ||
655  TaskEnum == Impl::TaskType::TaskSingle,
656  "Kokkos task_spawn requires TaskTeam or TaskSingle");
657 
658  typename task_type::function_type const ptr = task_type::apply;
659  typename task_type::destroy_type const dtor = task_type::destroy;
660 
661  return scheduler_type::spawn(std::move(arg_policy), ptr, dtor,
662  std::forward<FunctorType>(arg_functor));
663 }
664 
670 template <typename FunctorType, typename T>
671 void KOKKOS_INLINE_FUNCTION
672 respawn(FunctorType* arg_self, T const& arg,
673  TaskPriority const& arg_priority = TaskPriority::Regular) {
674  static_assert(Kokkos::is_future<T>::value || Kokkos::is_scheduler<T>::value,
675  "Kokkos respawn argument must be Future or TaskScheduler");
676 
677  T::scheduler_type::respawn(arg_self, arg, arg_priority);
678 }
679 
680 //----------------------------------------------------------------------------
681 
682 // template<typename ValueType, typename Scheduler>
683 // KOKKOS_INLINE_FUNCTION
684 // BasicFuture<void, Scheduler>
685 // when_all(BasicFuture<ValueType, Scheduler> const arg[], int narg)
686 //{
687 // return BasicFuture<void, Scheduler>::scheduler_type::when_all(arg, narg);
688 //}
689 
690 //----------------------------------------------------------------------------
691 // Wait for all runnable tasks to complete
692 
693 template <class ExecSpace, class QueueType>
694 inline void wait(BasicTaskScheduler<ExecSpace, QueueType> const& scheduler) {
695  using scheduler_type = BasicTaskScheduler<ExecSpace, QueueType>;
696  scheduler_type::specialization::execute(scheduler);
697  // scheduler.m_queue->execute();
698 }
699 
700 } // namespace Kokkos
701 
702 //----------------------------------------------------------------------------
703 //----------------------------------------------------------------------------
704 
706 // END OLD CODE
708 
709 #endif /* #if defined( KOKKOS_ENABLE_TASKDAG ) */
710 #endif /* #ifndef KOKKOS_TASKSCHEDULER_HPP */
void KOKKOS_INLINE_FUNCTION respawn(FunctorType *arg_self, T const &arg, TaskPriority const &arg_priority=TaskPriority::Regular)
A task respawns itself with options.
Scheduler::template future_type_for_functor< typename std::decay< FunctorType >::type > host_spawn(Impl::TaskPolicyWithScheduler< TaskEnum, Scheduler, DepFutureType > arg_policy, FunctorType &&arg_functor)
A host control thread spawns a task with options.
Scheduler::template future_type_for_functor< typename std::decay< FunctorType >::type > KOKKOS_INLINE_FUNCTION task_spawn(Impl::TaskPolicyWithScheduler< TaskEnum, Scheduler, DepFutureType > arg_policy, FunctorType &&arg_functor)
A task spawns a task with options.