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