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 //----------------------------------------------------------------------------
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< void , void , 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  int is_ready() const noexcept
297  { return ( 0 == m_task ) || ( ((task_base*) task_base::LockTag) == m_task->m_wait ); }
298 
299  KOKKOS_INLINE_FUNCTION
300  const typename Impl::TaskResult< ValueType >::reference_type
301  get() const
302  {
303  if ( 0 == m_task ) {
304  Kokkos::abort( "Kokkos:::Future::get ERROR: is_null()");
305  }
306  return Impl::TaskResult< ValueType >::get( m_task );
307  }
308 };
309 
310 // Is a Future with the given execution space
311 template< typename , typename ExecSpace = void >
312 struct is_future : public std::false_type {};
313 
314 template< typename Arg1 , typename Arg2 , typename ExecSpace >
315 struct is_future< Future<Arg1,Arg2> , ExecSpace >
316  : public std::integral_constant
317  < bool ,
318  ( std::is_same< ExecSpace , void >::value ||
319  std::is_same< ExecSpace
320  , typename Future<Arg1,Arg2>::execution_space >::value )
321  > {};
322 
323 } // namespace Kokkos
324 
325 //----------------------------------------------------------------------------
326 //----------------------------------------------------------------------------
327 
328 namespace Kokkos {
329 
330 enum class TaskPriority : int { High = 0
331  , Regular = 1
332  , Low = 2 };
333 
334 } // namespace Kokkos
335 
336 //----------------------------------------------------------------------------
337 //----------------------------------------------------------------------------
338 
339 namespace Kokkos {
340 namespace Impl {
341 
342 //----------------------------------------------------------------------------
343 
344 template< int TaskEnum , typename DepFutureType >
345 struct TaskPolicyData
346 {
347  using execution_space = typename DepFutureType::execution_space ;
348  using scheduler_type = TaskScheduler< execution_space > ;
349 
350  enum : int { m_task_type = TaskEnum };
351 
352  scheduler_type const * m_scheduler ;
353  DepFutureType const m_dependence ;
354  int m_priority ;
355 
356  TaskPolicyData() = delete ;
357  TaskPolicyData( TaskPolicyData && ) = default ;
358  TaskPolicyData( TaskPolicyData const & ) = default ;
359  TaskPolicyData & operator = ( TaskPolicyData && ) = default ;
360  TaskPolicyData & operator = ( TaskPolicyData const & ) = default ;
361 
362  KOKKOS_INLINE_FUNCTION
363  TaskPolicyData( DepFutureType const & arg_future
364  , Kokkos::TaskPriority const & arg_priority )
365  : m_scheduler( 0 )
366  , m_dependence( arg_future )
367  , m_priority( static_cast<int>( arg_priority ) )
368  {}
369 
370  KOKKOS_INLINE_FUNCTION
371  TaskPolicyData( scheduler_type const & arg_scheduler
372  , Kokkos::TaskPriority const & arg_priority )
373  : m_scheduler( & arg_scheduler )
374  , m_dependence()
375  , m_priority( static_cast<int>( arg_priority ) )
376  {}
377 
378  KOKKOS_INLINE_FUNCTION
379  TaskPolicyData( scheduler_type const & arg_scheduler
380  , DepFutureType const & arg_future
381  , Kokkos::TaskPriority const & arg_priority )
382  : m_scheduler( & arg_scheduler )
383  , m_dependence( arg_future )
384  , m_priority( static_cast<int>( arg_priority ) )
385  {}
386 };
387 
388 } // namespace Impl
389 } // namespace Kokkos
390 
391 //----------------------------------------------------------------------------
392 //----------------------------------------------------------------------------
393 
394 namespace Kokkos {
395 
396 template< typename ExecSpace >
397 class TaskScheduler
398 {
399 private:
400 
401  using track_type = Kokkos::Impl::SharedAllocationTracker ;
402  using queue_type = Kokkos::Impl::TaskQueue< ExecSpace > ;
403  using task_base = Impl::TaskBase< void , void , void > ;
404 
405  track_type m_track ;
406  queue_type * m_queue ;
407 
408  //----------------------------------------
409 
410 public:
411 
412  using execution_space = ExecSpace ;
413  using memory_space = typename queue_type::memory_space ;
414  using memory_pool = typename queue_type::memory_pool ;
415  using member_type =
416  typename Kokkos::Impl::TaskQueueSpecialization< ExecSpace >::member_type ;
417 
418  KOKKOS_INLINE_FUNCTION
419  TaskScheduler() : m_track(), m_queue(0) {}
420 
421  KOKKOS_INLINE_FUNCTION
422  TaskScheduler( TaskScheduler && rhs )
423  : m_track( rhs.m_track ), m_queue( rhs.m_queue ) {}
424 
425  KOKKOS_INLINE_FUNCTION
426  TaskScheduler( TaskScheduler const & rhs )
427  : m_track( rhs.m_track ), m_queue( rhs.m_queue ) {}
428 
429  KOKKOS_INLINE_FUNCTION
430  TaskScheduler & operator = ( TaskScheduler && rhs )
431  { m_track = rhs.m_track ; m_queue = rhs.m_queue ; return *this ; }
432 
433  KOKKOS_INLINE_FUNCTION
434  TaskScheduler & operator = ( TaskScheduler const & rhs )
435  { m_track = rhs.m_track ; m_queue = rhs.m_queue ; return *this ; }
436 
437  TaskScheduler( memory_pool const & arg_memory_pool )
438  : m_track()
439  , m_queue(0)
440  {
441  typedef Kokkos::Impl::SharedAllocationRecord
442  < memory_space , typename queue_type::Destroy >
443  record_type ;
444 
445  record_type * record =
446  record_type::allocate( memory_space()
447  , "TaskQueue"
448  , sizeof(queue_type)
449  );
450 
451  m_queue = new( record->data() ) queue_type( arg_memory_pool );
452 
453  record->m_destroy.m_queue = m_queue ;
454 
455  m_track.assign_allocated_record_to_uninitialized( record );
456  }
457 
458  TaskScheduler( memory_space const & arg_memory_space
459  , size_t const mempool_capacity
460  , unsigned const mempool_min_block_size // = 1u << 6
461  , unsigned const mempool_max_block_size // = 1u << 10
462  , unsigned const mempool_superblock_size // = 1u << 12
463  )
464  : TaskScheduler( memory_pool( arg_memory_space
465  , mempool_capacity
466  , mempool_min_block_size
467  , mempool_max_block_size
468  , mempool_superblock_size ) )
469  {}
470 
471  //----------------------------------------
472 
473  KOKKOS_INLINE_FUNCTION
474  memory_pool * memory() const noexcept
475  { return m_queue ? &( m_queue->m_memory ) : (memory_pool*) 0 ; }
476 
477  //----------------------------------------
479  template< typename FunctorType >
480  KOKKOS_FUNCTION
481  size_t spawn_allocation_size() const
482  { return m_queue->template spawn_allocation_size< FunctorType >(); }
483 
485  KOKKOS_FUNCTION
486  size_t when_all_allocation_size( int narg ) const
487  { return m_queue->when_all_allocation_size( narg ); }
488 
489  //----------------------------------------
490 
491  template< int TaskEnum , typename DepFutureType , typename FunctorType >
492  KOKKOS_FUNCTION static
494  spawn( Impl::TaskPolicyData<TaskEnum,DepFutureType> const & arg_policy
495  , typename task_base::function_type arg_function
496  , FunctorType && arg_functor
497  )
498  {
499  using value_type = typename FunctorType::value_type ;
500  using future_type = Future< value_type , execution_space > ;
501  using task_type = Impl::TaskBase< execution_space
502  , value_type
503  , FunctorType > ;
504 
505  queue_type * const queue =
506  arg_policy.m_scheduler ? arg_policy.m_scheduler->m_queue : (
507  arg_policy.m_dependence.m_task
508  ? static_cast<queue_type*>(arg_policy.m_dependence.m_task->m_queue)
509  : (queue_type*) 0 );
510 
511  if ( 0 == queue ) {
512  Kokkos::abort("Kokkos spawn requires scheduler or non-null Future");
513  }
514 
515  if ( arg_policy.m_dependence.m_task != 0 &&
516  arg_policy.m_dependence.m_task->m_queue != queue ) {
517  Kokkos::abort("Kokkos spawn given incompatible scheduler and Future");
518  }
519 
520  //----------------------------------------
521  // Give single-thread back-ends an opportunity to clear
522  // queue of ready tasks before allocating a new task
523 
524  queue->iff_single_thread_recursive_execute();
525 
526  //----------------------------------------
527 
528  future_type f ;
529 
530  // Allocate task from memory pool
531 
532  const size_t alloc_size =
533  queue->template spawn_allocation_size< FunctorType >();
534 
535  f.m_task =
536  reinterpret_cast< task_type * >(queue->allocate(alloc_size) );
537 
538  if ( f.m_task ) {
539 
540  // Placement new construction
541  // Reference count starts at two:
542  // +1 for the matching decrement when task is complete
543  // +1 for the future
544  new ( f.m_task ) task_type( std::move(arg_functor) );
545 
546  f.m_task->m_apply = arg_function ;
547  f.m_task->m_queue = queue ;
548  f.m_task->m_next = arg_policy.m_dependence.m_task ;
549  f.m_task->m_ref_count = 2 ;
550  f.m_task->m_alloc_size = alloc_size ;
551  f.m_task->m_task_type = arg_policy.m_task_type ;
552  f.m_task->m_priority = arg_policy.m_priority ;
553 
554  Kokkos::memory_fence();
555 
556  // The dependence (if any) is processed immediately
557  // within the schedule function, as such the dependence's
558  // reference count does not need to be incremented for
559  // the assignment.
560 
561  queue->schedule_runnable( f.m_task );
562  // This task may be updated or executed at any moment,
563  // even during the call to 'schedule'.
564  }
565 
566  return f ;
567  }
568 
569  template< typename FunctorType , typename A1 , typename A2 >
570  KOKKOS_FUNCTION static
571  void
572  respawn( FunctorType * arg_self
573  , Future<A1,A2> const & arg_dependence
574  , TaskPriority const & arg_priority
575  )
576  {
577  // Precondition: task is in Executing state
578 
579  using value_type = typename FunctorType::value_type ;
580  using task_type = Impl::TaskBase< execution_space
581  , value_type
582  , FunctorType > ;
583 
584  task_type * const task = static_cast< task_type * >( arg_self );
585 
586  task->m_priority = static_cast<int>(arg_priority);
587 
588  task->add_dependence( arg_dependence.m_task );
589 
590  // Postcondition: task is in Executing-Respawn state
591  }
592 
593  template< typename FunctorType >
594  KOKKOS_FUNCTION static
595  void
596  respawn( FunctorType * arg_self
597  , TaskScheduler const &
598  , TaskPriority const & arg_priority
599  )
600  {
601  // Precondition: task is in Executing state
602 
603  using value_type = typename FunctorType::value_type ;
604  using task_type = Impl::TaskBase< execution_space
605  , value_type
606  , FunctorType > ;
607 
608  task_type * const task = static_cast< task_type * >( arg_self );
609 
610  task->m_priority = static_cast<int>(arg_priority);
611 
612  task->add_dependence( (task_base*) 0 );
613 
614  // Postcondition: task is in Executing-Respawn state
615  }
616 
617  //----------------------------------------
621  template< typename A1 , typename A2 >
622  KOKKOS_FUNCTION static
623  Future< execution_space >
624  when_all( Future< A1 , A2 > const arg[] , int narg )
625  {
626  using future_type = Future< execution_space > ;
627 
628  future_type f ;
629 
630  if ( narg ) {
631 
632  queue_type * queue = 0 ;
633 
634  for ( int i = 0 ; i < narg ; ++i ) {
635  task_base * const t = arg[i].m_task ;
636  if ( 0 != t ) {
637  // Increment reference count to track subsequent assignment.
638  Kokkos::atomic_increment( &(t->m_ref_count) );
639  if ( queue == 0 ) {
640  queue = static_cast< queue_type * >( t->m_queue );
641  }
642  else if ( queue != static_cast< queue_type * >( t->m_queue ) ) {
643  Kokkos::abort("Kokkos when_all Futures must be in the same scheduler" );
644  }
645  }
646  }
647 
648  if ( queue != 0 ) {
649 
650  size_t const alloc_size = queue->when_all_allocation_size( narg );
651 
652  f.m_task =
653  reinterpret_cast< task_base * >( queue->allocate( alloc_size ) );
654 
655  if ( f.m_task ) {
656 
657  // Reference count starts at two:
658  // +1 to match decrement when task completes
659  // +1 for the future
660 
661  new( f.m_task ) task_base();
662 
663  f.m_task->m_queue = queue ;
664  f.m_task->m_ref_count = 2 ;
665  f.m_task->m_alloc_size = alloc_size ;
666  f.m_task->m_dep_count = narg ;
667  f.m_task->m_task_type = task_base::Aggregate ;
668 
669  // Assign dependences, reference counts were already incremented
670 
671  task_base * volatile * const dep =
672  f.m_task->aggregate_dependences();
673 
674  for ( int i = 0 ; i < narg ; ++i ) { dep[i] = arg[i].m_task ; }
675 
676  Kokkos::memory_fence();
677 
678  queue->schedule_aggregate( f.m_task );
679  // this when_all may be processed at any moment
680  }
681  }
682  }
683 
684  return f ;
685  }
686 
687  template < class F >
688  KOKKOS_FUNCTION
689  Future< execution_space >
690  when_all( int narg , F const func )
691  {
692  using input_type = decltype( func(0) );
693  using future_type = Future< execution_space > ;
694 
695  static_assert( is_future< input_type >::value
696  , "Functor must return a Kokkos::Future" );
697 
698  future_type f ;
699 
700  if ( 0 == narg ) return f ;
701 
702  size_t const alloc_size = m_queue->when_all_allocation_size( narg );
703 
704  f.m_task =
705  reinterpret_cast< task_base * >( m_queue->allocate( alloc_size ) );
706 
707  if ( f.m_task ) {
708 
709  // Reference count starts at two:
710  // +1 to match decrement when task completes
711  // +1 for the future
712 
713  new( f.m_task ) task_base();
714 
715  f.m_task->m_queue = m_queue ;
716  f.m_task->m_ref_count = 2 ;
717  f.m_task->m_alloc_size = alloc_size ;
718  f.m_task->m_dep_count = narg ;
719  f.m_task->m_task_type = task_base::Aggregate ;
720 
721  // Assign dependences, reference counts were already incremented
722 
723  task_base * volatile * const dep =
724  f.m_task->aggregate_dependences();
725 
726  for ( int i = 0 ; i < narg ; ++i ) {
727  const input_type arg_f = func(i);
728  if ( 0 != arg_f.m_task ) {
729 
730  if ( m_queue != static_cast< queue_type * >( arg_f.m_task->m_queue ) ) {
731  Kokkos::abort("Kokkos when_all Futures must be in the same scheduler" );
732  }
733  // Increment reference count to track subsequent assignment.
734  Kokkos::atomic_increment( &(arg_f.m_task->m_ref_count) );
735  dep[i] = arg_f.m_task ;
736  }
737  }
738 
739  Kokkos::memory_fence();
740 
741  m_queue->schedule_aggregate( f.m_task );
742  // this when_all may be processed at any moment
743  }
744  return f ;
745  }
746 
747  //----------------------------------------
748 
749  KOKKOS_INLINE_FUNCTION
750  int allocation_capacity() const noexcept
751  { return m_queue->m_memory.capacity(); }
752 
753  KOKKOS_INLINE_FUNCTION
754  int allocated_task_count() const noexcept
755  { return m_queue->m_count_alloc ; }
756 
757  KOKKOS_INLINE_FUNCTION
758  int allocated_task_count_max() const noexcept
759  { return m_queue->m_max_alloc ; }
760 
761  KOKKOS_INLINE_FUNCTION
762  long allocated_task_count_accum() const noexcept
763  { return m_queue->m_accum_alloc ; }
764 
765  //----------------------------------------
766 
767  template< typename S >
768  friend
769  void Kokkos::wait( Kokkos::TaskScheduler< S > const & );
770 
771 };
772 
773 } // namespace Kokkos
774 
775 //----------------------------------------------------------------------------
776 //----------------------------------------------------------------------------
777 
778 namespace Kokkos {
779 
780 //----------------------------------------------------------------------------
781 // Construct a TaskTeam execution policy
782 
783 template< typename T >
784 Kokkos::Impl::TaskPolicyData
785  < Kokkos::Impl::TaskBase<void,void,void>::TaskTeam
786  , typename std::conditional< Kokkos::is_future< T >::value , T ,
788  >
789 KOKKOS_INLINE_FUNCTION
790 TaskTeam( T const & arg
791  , TaskPriority const & arg_priority = TaskPriority::Regular
792  )
793 {
794  static_assert( Kokkos::is_future<T>::value ||
795  Kokkos::is_scheduler<T>::value
796  , "Kokkos TaskTeam argument must be Future or TaskScheduler" );
797 
798  return
799  Kokkos::Impl::TaskPolicyData
800  < Kokkos::Impl::TaskBase<void,void,void>::TaskTeam
801  , typename std::conditional< Kokkos::is_future< T >::value , T ,
803  >( arg , arg_priority );
804 }
805 
806 template< typename E , typename F >
807 Kokkos::Impl::
808  TaskPolicyData< Kokkos::Impl::TaskBase<void,void,void>::TaskTeam , F >
809 KOKKOS_INLINE_FUNCTION
810 TaskTeam( TaskScheduler<E> const & arg_scheduler
811  , F const & arg_future
812  , typename std::enable_if< Kokkos::is_future<F>::value ,
813  TaskPriority >::type const & arg_priority = TaskPriority::Regular
814  )
815 {
816  return
817  Kokkos::Impl::TaskPolicyData
818  < Kokkos::Impl::TaskBase<void,void,void>::TaskTeam , F >
819  ( arg_scheduler , arg_future , arg_priority );
820 }
821 
822 // Construct a TaskSingle execution policy
823 
824 template< typename T >
825 Kokkos::Impl::TaskPolicyData
826  < Kokkos::Impl::TaskBase<void,void,void>::TaskSingle
827  , typename std::conditional< Kokkos::is_future< T >::value , T ,
829  >
830 KOKKOS_INLINE_FUNCTION
831 TaskSingle( T const & arg
832  , TaskPriority const & arg_priority = TaskPriority::Regular
833  )
834 {
835  static_assert( Kokkos::is_future<T>::value ||
836  Kokkos::is_scheduler<T>::value
837  , "Kokkos TaskSingle argument must be Future or TaskScheduler" );
838 
839  return
840  Kokkos::Impl::TaskPolicyData
841  < Kokkos::Impl::TaskBase<void,void,void>::TaskSingle
842  , typename std::conditional< Kokkos::is_future< T >::value , T ,
844  >( arg , arg_priority );
845 }
846 
847 template< typename E , typename F >
848 Kokkos::Impl::
849  TaskPolicyData< Kokkos::Impl::TaskBase<void,void,void>::TaskSingle , F >
850 KOKKOS_INLINE_FUNCTION
851 TaskSingle( TaskScheduler<E> const & arg_scheduler
852  , F const & arg_future
853  , typename std::enable_if< Kokkos::is_future<F>::value ,
854  TaskPriority >::type const & arg_priority = TaskPriority::Regular
855  )
856 {
857  return
858  Kokkos::Impl::TaskPolicyData
859  < Kokkos::Impl::TaskBase<void,void,void>::TaskSingle , F >
860  ( arg_scheduler , arg_future , arg_priority );
861 }
862 
863 //----------------------------------------------------------------------------
864 
871 template< int TaskEnum
872  , typename DepFutureType
873  , typename FunctorType >
874 Future< typename FunctorType::value_type
875  , typename DepFutureType::execution_space >
876 host_spawn( Impl::TaskPolicyData<TaskEnum,DepFutureType> const & arg_policy
877  , FunctorType && arg_functor
878  )
879 {
880  using exec_space = typename DepFutureType::execution_space ;
881  using scheduler = TaskScheduler< exec_space > ;
882 
883  typedef Impl::TaskBase< exec_space
884  , typename FunctorType::value_type
885  , FunctorType
886  > task_type ;
887 
888  static_assert( TaskEnum == task_type::TaskTeam ||
889  TaskEnum == task_type::TaskSingle
890  , "Kokkos host_spawn requires TaskTeam or TaskSingle" );
891 
892  // May be spawning a Cuda task, must use the specialization
893  // to query on-device function pointer.
894  typename task_type::function_type const ptr =
895  Kokkos::Impl::TaskQueueSpecialization< exec_space >::
896  template get_function_pointer< task_type >();
897 
898  return scheduler::spawn( arg_policy , ptr , std::move(arg_functor) );
899 }
900 
907 template< int TaskEnum
908  , typename DepFutureType
909  , typename FunctorType >
910 Future< typename FunctorType::value_type
911  , typename DepFutureType::execution_space >
912 KOKKOS_INLINE_FUNCTION
913 task_spawn( Impl::TaskPolicyData<TaskEnum,DepFutureType> const & arg_policy
914  , FunctorType && arg_functor
915  )
916 {
917  using exec_space = typename DepFutureType::execution_space ;
918  using scheduler = TaskScheduler< exec_space > ;
919 
920  typedef Impl::TaskBase< exec_space
921  , typename FunctorType::value_type
922  , FunctorType
923  > task_type ;
924 
925 #if defined( KOKKOS_ACTIVE_EXECUTION_MEMORY_SPACE_HOST ) && \
926  defined( KOKKOS_ENABLE_CUDA )
927 
928  static_assert( ! std::is_same< Kokkos::Cuda , exec_space >::value
929  , "Error calling Kokkos::task_spawn for Cuda space within Host code" );
930 
931 #endif
932 
933  static_assert( TaskEnum == task_type::TaskTeam ||
934  TaskEnum == task_type::TaskSingle
935  , "Kokkos host_spawn requires TaskTeam or TaskSingle" );
936 
937  typename task_type::function_type const ptr = task_type::apply ;
938 
939  return scheduler::spawn( arg_policy , ptr , std::move(arg_functor) );
940 }
941 
947 template< typename FunctorType , typename T >
948 void
949 KOKKOS_INLINE_FUNCTION
950 respawn( FunctorType * arg_self
951  , T const & arg
952  , TaskPriority const & arg_priority = TaskPriority::Regular
953  )
954 {
955  static_assert( Kokkos::is_future<T>::value ||
956  Kokkos::is_scheduler<T>::value
957  , "Kokkos respawn argument must be Future or TaskScheduler" );
958 
959  TaskScheduler< typename T::execution_space >::
960  respawn( arg_self , arg , arg_priority );
961 }
962 
963 //----------------------------------------------------------------------------
964 
965 template< typename A1 , typename A2 >
966 KOKKOS_INLINE_FUNCTION
967 Future< typename Future< A1 , A2 >::execution_space >
968 when_all( Future< A1 , A2 > const arg[]
969  , int narg
970  )
971 {
972  return TaskScheduler< typename Future<A1,A2>::execution_space >::
973  when_all( arg , narg );
974 }
975 
976 //----------------------------------------------------------------------------
977 // Wait for all runnable tasks to complete
978 
979 template< typename ExecSpace >
980 inline
981 void wait( TaskScheduler< ExecSpace > const & scheduler )
982 { scheduler.m_queue->execute(); }
983 
984 } // namespace Kokkos
985 
986 //----------------------------------------------------------------------------
987 //----------------------------------------------------------------------------
988 
989 #endif /* #if defined( KOKKOS_ENABLE_TASKDAG ) */
990 #endif /* #ifndef KOKKOS_TASKSCHEDULER_HPP */
991 
bool is_null(const boost::shared_ptr< T > &p)
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.