Kokkos Core Kernels Package  Version of the Day
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 H. Carter Edwards (hcedwar@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 //----------------------------------------------------------------------------
54 
55 #include <Kokkos_MemoryPool.hpp>
56 #include <impl/Kokkos_Tags.hpp>
57 
58 //----------------------------------------------------------------------------
59 
60 namespace Kokkos {
61 
62 // Forward declarations used in Impl::TaskQueue
63 
64 template< typename Arg1 = void , typename Arg2 = void >
65 class Future ;
66 
67 template< typename Space >
68 class TaskScheduler ;
69 
70 template< typename Space >
71 void wait( TaskScheduler< Space > const & );
72 
73 template< typename Space >
74 struct is_scheduler : public std::false_type {};
75 
76 template< typename Space >
77 struct is_scheduler< TaskScheduler< Space > > : public std::true_type {};
78 
79 } // namespace Kokkos
80 
81 #include <impl/Kokkos_TaskQueue.hpp>
82 
83 //----------------------------------------------------------------------------
84 //----------------------------------------------------------------------------
85 
86 namespace Kokkos {
87 namespace Impl {
88 
89 /*\brief Implementation data for task data management, access, and execution.
90  *
91  * CRTP Inheritance structure to allow static_cast from the
92  * task root type and a task's FunctorType.
93  *
94  * TaskBase< Space , ResultType , FunctorType >
95  * : TaskBase< Space , ResultType , void >
96  * , FunctorType
97  * { ... };
98  *
99  * TaskBase< Space , ResultType , void >
100  * : TaskBase< Space , void , void >
101  * { ... };
102  */
103 template< typename Space , typename ResultType , typename FunctorType >
104 class TaskBase ;
105 
106 } // namespace Impl
107 } // namespace Kokkos
108 
109 //----------------------------------------------------------------------------
110 
111 namespace Kokkos {
112 
120 template< typename Arg1 , typename Arg2 >
121 class Future {
122 private:
123 
124  template< typename > friend class TaskScheduler ;
125  template< typename , typename > friend class Future ;
126  template< typename , typename , typename > friend class Impl::TaskBase ;
127 
128  enum { Arg1_is_space = Kokkos::is_space< Arg1 >::value };
129  enum { Arg2_is_space = Kokkos::is_space< Arg2 >::value };
130  enum { Arg1_is_value = ! Arg1_is_space &&
131  ! std::is_same< Arg1 , void >::value };
132  enum { Arg2_is_value = ! Arg2_is_space &&
133  ! std::is_same< Arg2 , void >::value };
134 
135  static_assert( ! ( Arg1_is_space && Arg2_is_space )
136  , "Future cannot be given two spaces" );
137 
138  static_assert( ! ( Arg1_is_value && Arg2_is_value )
139  , "Future cannot be given two value types" );
140 
141  using ValueType =
142  typename std::conditional< Arg1_is_value , Arg1 ,
143  typename std::conditional< Arg2_is_value , Arg2 , void
144  >::type >::type ;
145 
146  using Space =
147  typename std::conditional< Arg1_is_space , Arg1 ,
148  typename std::conditional< Arg2_is_space , Arg2 , void
149  >::type >::type ;
150 
151  using task_base = Impl::TaskBase< Space , ValueType , void > ;
152  using queue_type = Impl::TaskQueue< Space > ;
153 
154  task_base * m_task ;
155 
156  KOKKOS_INLINE_FUNCTION explicit
157  Future( task_base * task ) : m_task(0)
158  { if ( task ) queue_type::assign( & m_task , task ); }
159 
160  //----------------------------------------
161 
162 public:
163 
164  using execution_space = typename Space::execution_space ;
165  using value_type = ValueType ;
166 
167  //----------------------------------------
168 
169  KOKKOS_INLINE_FUNCTION
170  bool is_null() const { return 0 == m_task ; }
171 
172  KOKKOS_INLINE_FUNCTION
173  int reference_count() const
174  { return 0 != m_task ? m_task->reference_count() : 0 ; }
175 
176  //----------------------------------------
177 
178  KOKKOS_INLINE_FUNCTION
179  void clear()
180  { if ( m_task ) queue_type::assign( & m_task , (task_base*)0 ); }
181 
182  //----------------------------------------
183 
184  KOKKOS_INLINE_FUNCTION
185  ~Future() { clear(); }
186 
187  //----------------------------------------
188 
189  KOKKOS_INLINE_FUNCTION
190  constexpr Future() noexcept : m_task(0) {}
191 
192  KOKKOS_INLINE_FUNCTION
193  Future( Future && rhs )
194  : m_task( rhs.m_task ) { rhs.m_task = 0 ; }
195 
196  KOKKOS_INLINE_FUNCTION
197  Future( const Future & rhs )
198  : m_task(0)
199  { if ( rhs.m_task ) queue_type::assign( & m_task , rhs.m_task ); }
200 
201  KOKKOS_INLINE_FUNCTION
202  Future & operator = ( Future && rhs )
203  {
204  clear();
205  m_task = rhs.m_task ;
206  rhs.m_task = 0 ;
207  return *this ;
208  }
209 
210  KOKKOS_INLINE_FUNCTION
211  Future & operator = ( const Future & rhs )
212  {
213  if ( m_task || rhs.m_task ) queue_type::assign( & m_task , rhs.m_task );
214  return *this ;
215  }
216 
217  //----------------------------------------
218 
219  template< class A1 , class A2 >
220  KOKKOS_INLINE_FUNCTION
221  Future( Future<A1,A2> && rhs )
222  : m_task( rhs.m_task )
223  {
224  static_assert
225  ( std::is_same< Space , void >::value ||
226  std::is_same< Space , typename Future<A1,A2>::Space >::value
227  , "Assigned Futures must have the same space" );
228 
229  static_assert
230  ( std::is_same< value_type , void >::value ||
231  std::is_same< value_type , typename Future<A1,A2>::value_type >::value
232  , "Assigned Futures must have the same value_type" );
233 
234  rhs.m_task = 0 ;
235  }
236 
237  template< class A1 , class A2 >
238  KOKKOS_INLINE_FUNCTION
239  Future( const Future<A1,A2> & rhs )
240  : m_task(0)
241  {
242  static_assert
243  ( std::is_same< Space , void >::value ||
244  std::is_same< Space , typename Future<A1,A2>::Space >::value
245  , "Assigned Futures must have the same space" );
246 
247  static_assert
248  ( std::is_same< value_type , void >::value ||
249  std::is_same< value_type , typename Future<A1,A2>::value_type >::value
250  , "Assigned Futures must have the same value_type" );
251 
252  if ( rhs.m_task ) queue_type::assign( & m_task , rhs.m_task );
253  }
254 
255  template< class A1 , class A2 >
256  KOKKOS_INLINE_FUNCTION
257  Future & operator = ( const Future<A1,A2> & rhs )
258  {
259  static_assert
260  ( std::is_same< Space , void >::value ||
261  std::is_same< Space , typename Future<A1,A2>::Space >::value
262  , "Assigned Futures must have the same space" );
263 
264  static_assert
265  ( std::is_same< value_type , void >::value ||
266  std::is_same< value_type , typename Future<A1,A2>::value_type >::value
267  , "Assigned Futures must have the same value_type" );
268 
269  if ( m_task || rhs.m_task ) queue_type::assign( & m_task , rhs.m_task );
270  return *this ;
271  }
272 
273  template< class A1 , class A2 >
274  KOKKOS_INLINE_FUNCTION
275  Future & operator = ( Future<A1,A2> && rhs )
276  {
277  static_assert
278  ( std::is_same< Space , void >::value ||
279  std::is_same< Space , typename Future<A1,A2>::Space >::value
280  , "Assigned Futures must have the same space" );
281 
282  static_assert
283  ( std::is_same< value_type , void >::value ||
284  std::is_same< value_type , typename Future<A1,A2>::value_type >::value
285  , "Assigned Futures must have the same value_type" );
286 
287  clear();
288  m_task = rhs.m_task ;
289  rhs.m_task = 0 ;
290  return *this ;
291  }
292 
293  //----------------------------------------
294 
295  KOKKOS_INLINE_FUNCTION
296  typename task_base::get_return_type
297  get() const
298  {
299  if ( 0 == m_task ) {
300  Kokkos::abort( "Kokkos:::Future::get ERROR: is_null()");
301  }
302  return m_task->get();
303  }
304 };
305 
306 // Is a Future with the given execution space
307 template< typename , typename ExecSpace = void >
308 struct is_future : public std::false_type {};
309 
310 template< typename Arg1 , typename Arg2 , typename ExecSpace >
311 struct is_future< Future<Arg1,Arg2> , ExecSpace >
312  : public std::integral_constant
313  < bool ,
314  ( std::is_same< ExecSpace , void >::value ||
315  std::is_same< ExecSpace
316  , typename Future<Arg1,Arg2>::execution_space >::value )
317  > {};
318 
319 } // namespace Kokkos
320 
321 //----------------------------------------------------------------------------
322 //----------------------------------------------------------------------------
323 
324 namespace Kokkos {
325 
326 enum class TaskPriority : int { High = 0
327  , Regular = 1
328  , Low = 2 };
329 
330 } // namespace Kokkos
331 
332 //----------------------------------------------------------------------------
333 //----------------------------------------------------------------------------
334 
335 namespace Kokkos {
336 namespace Impl {
337 
338 //----------------------------------------------------------------------------
339 
340 template< int TaskEnum , typename DepFutureType >
341 struct TaskPolicyData
342 {
343  using execution_space = typename DepFutureType::execution_space ;
344  using scheduler_type = TaskScheduler< execution_space > ;
345 
346  enum : int { m_task_type = TaskEnum };
347 
348  scheduler_type const * m_scheduler ;
349  DepFutureType const m_dependence ;
350  int m_priority ;
351 
352  TaskPolicyData() = delete ;
353  TaskPolicyData( TaskPolicyData && ) = default ;
354  TaskPolicyData( TaskPolicyData const & ) = default ;
355  TaskPolicyData & operator = ( TaskPolicyData && ) = default ;
356  TaskPolicyData & operator = ( TaskPolicyData const & ) = default ;
357 
358  KOKKOS_INLINE_FUNCTION
359  TaskPolicyData( DepFutureType const & arg_future
360  , Kokkos::TaskPriority const & arg_priority )
361  : m_scheduler( 0 )
362  , m_dependence( arg_future )
363  , m_priority( static_cast<int>( arg_priority ) )
364  {}
365 
366  KOKKOS_INLINE_FUNCTION
367  TaskPolicyData( scheduler_type const & arg_scheduler
368  , Kokkos::TaskPriority const & arg_priority )
369  : m_scheduler( & arg_scheduler )
370  , m_dependence()
371  , m_priority( static_cast<int>( arg_priority ) )
372  {}
373 
374  KOKKOS_INLINE_FUNCTION
375  TaskPolicyData( scheduler_type const & arg_scheduler
376  , DepFutureType const & arg_future
377  , Kokkos::TaskPriority const & arg_priority )
378  : m_scheduler( & arg_scheduler )
379  , m_dependence( arg_future )
380  , m_priority( static_cast<int>( arg_priority ) )
381  {}
382 };
383 
384 } // namespace Impl
385 } // namespace Kokkos
386 
387 //----------------------------------------------------------------------------
388 //----------------------------------------------------------------------------
389 
390 namespace Kokkos {
391 
392 template< typename ExecSpace >
393 class TaskScheduler
394 {
395 private:
396 
397  using track_type = Kokkos::Impl::SharedAllocationTracker ;
398  using queue_type = Kokkos::Impl::TaskQueue< ExecSpace > ;
399  using task_base = Impl::TaskBase< ExecSpace , void , void > ;
400 
401  track_type m_track ;
402  queue_type * m_queue ;
403 
404  //----------------------------------------
405 
406 public:
407 
408  using execution_space = ExecSpace ;
409  using memory_space = typename queue_type::memory_space ;
410  using memory_pool = typename queue_type::memory_pool ;
411  using member_type =
412  typename Kokkos::Impl::TaskQueueSpecialization< ExecSpace >::member_type ;
413 
414  KOKKOS_INLINE_FUNCTION
415  TaskScheduler() : m_track(), m_queue(0) {}
416 
417  KOKKOS_INLINE_FUNCTION
418  TaskScheduler( TaskScheduler && rhs ) = default ;
419 
420  KOKKOS_INLINE_FUNCTION
421  TaskScheduler( TaskScheduler const & rhs ) = default ;
422 
423  KOKKOS_INLINE_FUNCTION
424  TaskScheduler & operator = ( TaskScheduler && rhs ) = default ;
425 
426  KOKKOS_INLINE_FUNCTION
427  TaskScheduler & operator = ( TaskScheduler const & rhs ) = default ;
428 
429  TaskScheduler( memory_pool const & arg_memory_pool )
430  : m_track()
431  , m_queue(0)
432  {
433  typedef Kokkos::Impl::SharedAllocationRecord
434  < memory_space , typename queue_type::Destroy >
435  record_type ;
436 
437  record_type * record =
438  record_type::allocate( memory_space()
439  , "TaskQueue"
440  , sizeof(queue_type)
441  );
442 
443  m_queue = new( record->data() ) queue_type( arg_memory_pool );
444 
445  record->m_destroy.m_queue = m_queue ;
446 
447  m_track.assign_allocated_record_to_uninitialized( record );
448  }
449 
450  TaskScheduler( memory_space const & arg_memory_space
451  , size_t const mempool_capacity
452  , unsigned const mempool_min_block_size // = 1u << 6
453  , unsigned const mempool_max_block_size // = 1u << 10
454  , unsigned const mempool_superblock_size // = 1u << 12
455  )
456  : TaskScheduler( memory_pool( arg_memory_space
457  , mempool_capacity
458  , mempool_min_block_size
459  , mempool_max_block_size
460  , mempool_superblock_size ) )
461  {}
462 
463  //----------------------------------------
464 
465  KOKKOS_INLINE_FUNCTION
466  memory_pool * memory() const noexcept
467  { return m_queue ? m_queue->m_memory : (memory_pool*) 0 ; }
468 
469  //----------------------------------------
471  template< typename FunctorType >
472  KOKKOS_FUNCTION
473  size_t spawn_allocation_size() const
474  {
475  using task_type = Impl::TaskBase< execution_space
476  , typename FunctorType::value_type
477  , FunctorType > ;
478 
479  return m_queue->allocate_block_size( sizeof(task_type) );
480  }
481 
483  KOKKOS_FUNCTION
484  size_t when_all_allocation_size( int narg ) const
485  {
486  using task_base = Kokkos::Impl::TaskBase< ExecSpace , void , void > ;
487 
488  return m_queue->allocate_block_size( sizeof(task_base) + narg * sizeof(task_base*) );
489  }
490 
491  //----------------------------------------
492 
493  template< int TaskEnum , typename DepFutureType , typename FunctorType >
494  KOKKOS_FUNCTION static
496  spawn( Impl::TaskPolicyData<TaskEnum,DepFutureType> const & arg_policy
497  , typename task_base::function_type arg_function
498  , FunctorType && arg_functor
499  )
500  {
501  using value_type = typename FunctorType::value_type ;
502  using future_type = Future< value_type , execution_space > ;
503  using task_type = Impl::TaskBase< execution_space
504  , value_type
505  , FunctorType > ;
506 
507  queue_type * const queue =
508  arg_policy.m_scheduler ? arg_policy.m_scheduler->m_queue : (
509  arg_policy.m_dependence.m_task
510  ? arg_policy.m_dependence.m_task->m_queue
511  : (queue_type*) 0 );
512 
513  if ( 0 == queue ) {
514  Kokkos::abort("Kokkos spawn requires scheduler or non-null Future");
515  }
516 
517  if ( arg_policy.m_dependence.m_task != 0 &&
518  arg_policy.m_dependence.m_task->m_queue != queue ) {
519  Kokkos::abort("Kokkos spawn given incompatible scheduler and Future");
520  }
521 
522  //----------------------------------------
523  // Give single-thread back-ends an opportunity to clear
524  // queue of ready tasks before allocating a new task
525 
526  queue->iff_single_thread_recursive_execute();
527 
528  //----------------------------------------
529 
530  future_type f ;
531 
532  // Allocate task from memory pool
533  f.m_task =
534  reinterpret_cast< task_type * >(queue->allocate(sizeof(task_type)));
535 
536  if ( f.m_task ) {
537 
538  // Placement new construction
539  // Reference count starts at two:
540  // +1 for the matching decrement when task is complete
541  // +1 for the future
542  new ( f.m_task )
543  task_type( arg_function
544  , queue
545  , arg_policy.m_dependence.m_task /* dependence */
546  , 2 /* reference count */
547  , int(sizeof(task_type)) /* allocation size */
548  , int(arg_policy.m_task_type)
549  , int(arg_policy.m_priority)
550  , std::move(arg_functor) );
551 
552  // The dependence (if any) is processed immediately
553  // within the schedule function, as such the dependence's
554  // reference count does not need to be incremented for
555  // the assignment.
556 
557  queue->schedule_runnable( f.m_task );
558  // This task may be updated or executed at any moment,
559  // even during the call to 'schedule'.
560  }
561 
562  return f ;
563  }
564 
565  template< typename FunctorType , typename A1 , typename A2 >
566  KOKKOS_FUNCTION static
567  void
568  respawn( FunctorType * arg_self
569  , Future<A1,A2> const & arg_dependence
570  , TaskPriority const & arg_priority
571  )
572  {
573  // Precondition: task is in Executing state
574 
575  using value_type = typename FunctorType::value_type ;
576  using task_type = Impl::TaskBase< execution_space
577  , value_type
578  , FunctorType > ;
579 
580  task_type * const task = static_cast< task_type * >( arg_self );
581 
582  task->m_priority = static_cast<int>(arg_priority);
583 
584  task->add_dependence( arg_dependence.m_task );
585 
586  // Postcondition: task is in Executing-Respawn state
587  }
588 
589  //----------------------------------------
593  template< typename A1 , typename A2 >
594  KOKKOS_FUNCTION static
596  when_all( Future< A1 , A2 > const arg[] , int narg )
597  {
598  using future_type = Future< execution_space > ;
599  using task_base = Kokkos::Impl::TaskBase< execution_space , void , void > ;
600 
601  future_type f ;
602 
603  if ( narg ) {
604 
605  queue_type * queue = 0 ;
606 
607  for ( int i = 0 ; i < narg ; ++i ) {
608  task_base * const t = arg[i].m_task ;
609  if ( 0 != t ) {
610  // Increment reference count to track subsequent assignment.
611  Kokkos::atomic_increment( &(t->m_ref_count) );
612  if ( queue == 0 ) {
613  queue = t->m_queue ;
614  }
615  else if ( queue != t->m_queue ) {
616  Kokkos::abort("Kokkos when_all Futures must be in the same scheduler" );
617  }
618  }
619  }
620 
621  if ( queue != 0 ) {
622 
623  size_t const size = sizeof(task_base) + narg * sizeof(task_base*);
624 
625  f.m_task =
626  reinterpret_cast< task_base * >( queue->allocate( size ) );
627 
628  if ( f.m_task ) {
629 
630  // Reference count starts at two:
631  // +1 to match decrement when task completes
632  // +1 for the future
633  new( f.m_task ) task_base( queue
634  , 2 /* reference count */
635  , size /* allocation size */
636  , narg /* dependence count */
637  );
638 
639  // Assign dependences, reference counts were already incremented
640 
641  task_base ** const dep = f.m_task->aggregate_dependences();
642 
643  for ( int i = 0 ; i < narg ; ++i ) { dep[i] = arg[i].m_task ; }
644 
645  queue->schedule_aggregate( f.m_task );
646  // this when_all may be processed at any moment
647  }
648  }
649  }
650 
651  return f ;
652  }
653 
654  //----------------------------------------
655 
656  KOKKOS_INLINE_FUNCTION
657  int allocation_capacity() const noexcept
658  { return m_queue->m_memory.capacity(); }
659 
660  KOKKOS_INLINE_FUNCTION
661  int allocated_task_count() const noexcept
662  { return m_queue->m_count_alloc ; }
663 
664  KOKKOS_INLINE_FUNCTION
665  int allocated_task_count_max() const noexcept
666  { return m_queue->m_max_alloc ; }
667 
668  KOKKOS_INLINE_FUNCTION
669  long allocated_task_count_accum() const noexcept
670  { return m_queue->m_accum_alloc ; }
671 
672  //----------------------------------------
673 
674  template< typename S >
675  friend
676  void Kokkos::wait( Kokkos::TaskScheduler< S > const & );
677 
678 };
679 
680 } // namespace Kokkos
681 
682 //----------------------------------------------------------------------------
683 //----------------------------------------------------------------------------
684 
685 namespace Kokkos {
686 
687 //----------------------------------------------------------------------------
688 // Construct a TaskTeam execution policy
689 
690 template< typename T >
691 Kokkos::Impl::TaskPolicyData
692  < Kokkos::Impl::TaskBase<void,void,void>::TaskTeam
693  , typename std::conditional< Kokkos::is_future< T >::value , T ,
695  >
696 KOKKOS_INLINE_FUNCTION
697 TaskTeam( T const & arg
698  , TaskPriority const & arg_priority = TaskPriority::Regular
699  )
700 {
701  static_assert( Kokkos::is_future<T>::value ||
702  Kokkos::is_scheduler<T>::value
703  , "Kokkos TaskTeam argument must be Future or TaskScheduler" );
704 
705  return
706  Kokkos::Impl::TaskPolicyData
707  < Kokkos::Impl::TaskBase<void,void,void>::TaskTeam
708  , typename std::conditional< Kokkos::is_future< T >::value , T ,
710  >( arg , arg_priority );
711 }
712 
713 template< typename E , typename F >
714 Kokkos::Impl::
715  TaskPolicyData< Kokkos::Impl::TaskBase<void,void,void>::TaskTeam , F >
716 KOKKOS_INLINE_FUNCTION
717 TaskTeam( TaskScheduler<E> const & arg_scheduler
718  , F const & arg_future
719  , typename std::enable_if< Kokkos::is_future<F>::value ,
720  TaskPriority >::type const & arg_priority = TaskPriority::Regular
721  )
722 {
723  return
724  Kokkos::Impl::TaskPolicyData
725  < Kokkos::Impl::TaskBase<void,void,void>::TaskTeam , F >
726  ( arg_scheduler , arg_future , arg_priority );
727 }
728 
729 // Construct a TaskSingle execution policy
730 
731 template< typename T >
732 Kokkos::Impl::TaskPolicyData
733  < Kokkos::Impl::TaskBase<void,void,void>::TaskSingle
734  , typename std::conditional< Kokkos::is_future< T >::value , T ,
736  >
737 KOKKOS_INLINE_FUNCTION
738 TaskSingle( T const & arg
739  , TaskPriority const & arg_priority = TaskPriority::Regular
740  )
741 {
742  static_assert( Kokkos::is_future<T>::value ||
743  Kokkos::is_scheduler<T>::value
744  , "Kokkos TaskSingle argument must be Future or TaskScheduler" );
745 
746  return
747  Kokkos::Impl::TaskPolicyData
748  < Kokkos::Impl::TaskBase<void,void,void>::TaskSingle
749  , typename std::conditional< Kokkos::is_future< T >::value , T ,
751  >( arg , arg_priority );
752 }
753 
754 template< typename E , typename F >
755 Kokkos::Impl::
756  TaskPolicyData< Kokkos::Impl::TaskBase<void,void,void>::TaskSingle , F >
757 KOKKOS_INLINE_FUNCTION
758 TaskSingle( TaskScheduler<E> const & arg_scheduler
759  , F const & arg_future
760  , typename std::enable_if< Kokkos::is_future<F>::value ,
761  TaskPriority >::type const & arg_priority = TaskPriority::Regular
762  )
763 {
764  return
765  Kokkos::Impl::TaskPolicyData
766  < Kokkos::Impl::TaskBase<void,void,void>::TaskSingle , F >
767  ( arg_scheduler , arg_future , arg_priority );
768 }
769 
770 //----------------------------------------------------------------------------
771 
778 template< int TaskEnum
779  , typename DepFutureType
780  , typename FunctorType >
781 Future< typename FunctorType::value_type
782  , typename DepFutureType::execution_space >
783 host_spawn( Impl::TaskPolicyData<TaskEnum,DepFutureType> const & arg_policy
784  , FunctorType && arg_functor
785  )
786 {
787  using exec_space = typename DepFutureType::execution_space ;
788  using scheduler = TaskScheduler< exec_space > ;
789 
790  typedef Impl::TaskBase< exec_space
791  , typename FunctorType::value_type
792  , FunctorType
793  > task_type ;
794 
795  static_assert( TaskEnum == task_type::TaskTeam ||
796  TaskEnum == task_type::TaskSingle
797  , "Kokkos host_spawn requires TaskTeam or TaskSingle" );
798 
799  // May be spawning a Cuda task, must use the specialization
800  // to query on-device function pointer.
801  typename task_type::function_type const ptr =
802  Kokkos::Impl::TaskQueueSpecialization< exec_space >::
803  template get_function_pointer< task_type >();
804 
805  return scheduler::spawn( arg_policy , ptr , std::move(arg_functor) );
806 }
807 
814 template< int TaskEnum
815  , typename DepFutureType
816  , typename FunctorType >
817 Future< typename FunctorType::value_type
818  , typename DepFutureType::execution_space >
819 KOKKOS_INLINE_FUNCTION
820 task_spawn( Impl::TaskPolicyData<TaskEnum,DepFutureType> const & arg_policy
821  , FunctorType && arg_functor
822  )
823 {
824  using exec_space = typename DepFutureType::execution_space ;
825  using scheduler = TaskScheduler< exec_space > ;
826 
827  typedef Impl::TaskBase< exec_space
828  , typename FunctorType::value_type
829  , FunctorType
830  > task_type ;
831 
832 #if defined( KOKKOS_ACTIVE_EXECUTION_MEMORY_SPACE_HOST ) && \
833  defined( KOKKOS_ENABLE_CUDA )
834 
835  static_assert( ! std::is_same< Kokkos::Cuda , exec_space >::value
836  , "Error calling Kokkos::task_spawn for Cuda space within Host code" );
837 
838 #endif
839 
840  static_assert( TaskEnum == task_type::TaskTeam ||
841  TaskEnum == task_type::TaskSingle
842  , "Kokkos host_spawn requires TaskTeam or TaskSingle" );
843 
844  typename task_type::function_type const ptr = task_type::apply ;
845 
846  return scheduler::spawn( arg_policy , ptr , std::move(arg_functor) );
847 }
848 
854 template< typename FunctorType , typename T >
855 void
856 KOKKOS_INLINE_FUNCTION
857 respawn( FunctorType * arg_self
858  , T const & arg
859  , TaskPriority const & arg_priority = TaskPriority::Regular
860  )
861 {
862  static_assert( Kokkos::is_future<T>::value ||
863  Kokkos::is_scheduler<T>::value
864  , "Kokkos respawn argument must be Future or TaskScheduler" );
865 
866  TaskScheduler< typename T::execution_space >::
867  respawn( arg_self , arg , arg_priority );
868 }
869 
870 //----------------------------------------------------------------------------
871 
872 template< typename A1 , typename A2 >
873 KOKKOS_INLINE_FUNCTION
875 when_all( Future< A1 , A2 > const arg[]
876  , int narg
877  )
878 {
879  return TaskScheduler< typename Future<A1,A2>::execution_space >::
880  when_all( arg , narg );
881 }
882 
883 //----------------------------------------------------------------------------
884 // Wait for all runnable tasks to complete
885 
886 template< typename ExecSpace >
887 inline
888 void wait( TaskScheduler< ExecSpace > const & scheduler )
889 { scheduler.m_queue->execute(); }
890 
891 } // namespace Kokkos
892 
893 //----------------------------------------------------------------------------
894 //----------------------------------------------------------------------------
895 
896 #endif /* #if defined( KOKKOS_ENABLE_TASKDAG ) */
897 #endif /* #ifndef KOKKOS_TASKSCHEDULER_HPP */
898 
Future< typename FunctorType::value_type, typename DepFutureType::execution_space > KOKKOS_INLINE_FUNCTION task_spawn(Impl::TaskPolicyData< TaskEnum, DepFutureType > const &arg_policy, FunctorType &&arg_functor)
A task 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.
Future< typename FunctorType::value_type, typename DepFutureType::execution_space > host_spawn(Impl::TaskPolicyData< TaskEnum, DepFutureType > const &arg_policy, FunctorType &&arg_functor)
A host control thread spawns a task with options.