Kokkos Core Kernels Package  Version of the Day
Kokkos_TaskPolicy.hpp
1 
2 /*
3 //@HEADER
4 // ************************************************************************
5 //
6 // Kokkos v. 2.0
7 // Copyright (2014) Sandia Corporation
8 //
9 // Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
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 SANDIA CORPORATION "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 SANDIA CORPORATION 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 H. Carter Edwards (hcedwar@sandia.gov)
40 //
41 // ************************************************************************
42 //@HEADER
43 */
44 
45 // Experimental unified task-data parallel manycore LDRD
46 
47 #ifndef KOKKOS_TASKPOLICY_HPP
48 #define KOKKOS_TASKPOLICY_HPP
49 
50 #include <Kokkos_Core_fwd.hpp>
51 #include <impl/Kokkos_Traits.hpp>
52 #include <impl/Kokkos_Tags.hpp>
53 #include <impl/Kokkos_StaticAssert.hpp>
54 #include <impl/Kokkos_AllocationTracker.hpp>
55 
56 //----------------------------------------------------------------------------
57 
58 namespace Kokkos {
59 namespace Experimental {
60 namespace Impl {
61 
62 struct FutureValueTypeIsVoidError {};
63 
64 template < class ExecSpace , class ResultType , class FunctorType >
65 class TaskMember ;
66 
67 template< class ExecPolicy , class ResultType , class FunctorType >
68 class TaskForEach ;
69 
70 template< class ExecPolicy , class ResultType , class FunctorType >
71 class TaskReduce ;
72 
73 template< class ExecPolicy , class ResultType , class FunctorType >
74 struct TaskScan ;
75 
76 } /* namespace Impl */
77 } /* namespace Experimental */
78 } /* namespace Kokkos */
79 
80 //----------------------------------------------------------------------------
81 
82 namespace Kokkos {
83 namespace Experimental {
84 
86 enum TaskState
87  { TASK_STATE_NULL = 0
88  , TASK_STATE_CONSTRUCTING = 1
89  , TASK_STATE_WAITING = 2
90  , TASK_STATE_EXECUTING = 4
91  , TASK_STATE_COMPLETE = 8
92  };
93 
101 template< class Arg1 = void , class Arg2 = void >
102 class Future {
103 private:
104 
105  template< class , class , class > friend class Impl::TaskMember ;
106  template< class > friend class TaskPolicy ;
107  template< class , class > friend class Future ;
108 
109  // Argument #2, if not void, must be the space.
110  enum { Arg1_is_space = Kokkos::Impl::is_execution_space< Arg1 >::value };
111  enum { Arg2_is_space = Kokkos::Impl::is_execution_space< Arg2 >::value };
112  enum { Arg2_is_void = Kokkos::Impl::is_same< Arg2 , void >::value };
113 
114  struct ErrorNoExecutionSpace {};
115 
116  enum { Opt1 = Arg1_is_space && Arg2_is_void
117  , Opt2 = ! Arg1_is_space && Arg2_is_void
118  , Opt3 = ! Arg1_is_space && Arg2_is_space
119  , OptOK = Kokkos::Impl::StaticAssert< Opt1 || Opt2 || Opt3 , ErrorNoExecutionSpace >::value
120  };
121 
122  typedef typename
123  Kokkos::Impl::if_c< Opt2 || Opt3 , Arg1 , void >::type
124  ValueType ;
125 
126  typedef typename
127  Kokkos::Impl::if_c< Opt1 , Arg1 , typename
128  Kokkos::Impl::if_c< Opt2 , Kokkos::DefaultExecutionSpace , typename
129  Kokkos::Impl::if_c< Opt3 , Arg2 , void
130  >::type >::type >::type
131  ExecutionSpace ;
132 
133  typedef Impl::TaskMember< ExecutionSpace , void , void > TaskRoot ;
134  typedef Impl::TaskMember< ExecutionSpace , ValueType , void > TaskValue ;
135 
136  TaskRoot * m_task ;
137 
138 public:
139 
140  typedef ValueType value_type;
141  typedef ExecutionSpace execution_space ;
142 
143  //----------------------------------------
144 
145  KOKKOS_INLINE_FUNCTION
146  TaskState get_task_state() const
147  { return 0 != m_task ? m_task->get_state() : TASK_STATE_NULL ; }
148 
149  //----------------------------------------
150 
151  explicit
152  Future( TaskRoot * task )
153  : m_task(0)
154  { TaskRoot::assign( & m_task , TaskRoot::template verify_type< value_type >( task ) ); }
155 
156  //----------------------------------------
157 
158  KOKKOS_INLINE_FUNCTION
159  ~Future() { TaskRoot::assign( & m_task , 0 ); }
160 
161  //----------------------------------------
162 
163  KOKKOS_INLINE_FUNCTION
164  Future() : m_task(0) {}
165 
166  KOKKOS_INLINE_FUNCTION
167  Future( const Future & rhs )
168  : m_task(0)
169  { TaskRoot::assign( & m_task , rhs.m_task ); }
170 
171  KOKKOS_INLINE_FUNCTION
172  Future & operator = ( const Future & rhs )
173  { TaskRoot::assign( & m_task , rhs.m_task ); return *this ; }
174 
175  //----------------------------------------
176 
177  template< class A1 , class A2 >
178  KOKKOS_INLINE_FUNCTION
179  Future( const Future<A1,A2> & rhs )
180  : m_task(0)
181  { TaskRoot::assign( & m_task , TaskRoot::template verify_type< value_type >( rhs.m_task ) ); }
182 
183  template< class A1 , class A2 >
184  KOKKOS_INLINE_FUNCTION
185  Future & operator = ( const Future<A1,A2> & rhs )
186  { TaskRoot::assign( & m_task , TaskRoot::template verify_type< value_type >( rhs.m_task ) ); return *this ; }
187 
188  //----------------------------------------
189 
190  typedef typename TaskValue::get_result_type get_result_type ;
191 
192  KOKKOS_INLINE_FUNCTION
193  get_result_type get() const
194  { return static_cast<TaskValue*>( m_task )->get(); }
195 };
196 
197 namespace Impl {
198 
199 template< class T >
200 struct is_future : public Kokkos::Impl::bool_< false > {};
201 
202 template< class Arg0 , class Arg1 >
203 struct is_future< Kokkos::Experimental::Future<Arg0,Arg1> > : public Kokkos::Impl::bool_< true > {};
204 
205 } /* namespace Impl */
206 } /* namespace Experimental */
207 } /* namespace Kokkos */
208 
209 //----------------------------------------------------------------------------
210 //----------------------------------------------------------------------------
211 
212 namespace Kokkos {
213 namespace Experimental {
214 
216 template< class Arg0 = Kokkos::DefaultExecutionSpace >
217 class TaskPolicy {
218 public:
219 
220  typedef typename Arg0::execution_space execution_space ;
221 
222  //----------------------------------------
227  template< class FunctorType >
229  create( const FunctorType & functor
230  , const unsigned dependence_capacity /* = default */ ) const ;
231 
233  template< class ExecPolicy , class FunctorType >
235  create_foreach( const ExecPolicy & policy
236  , const FunctorType & functor
237  , const unsigned dependence_capacity /* = default */ ) const ;
238 
240  template< class ExecPolicy , class FunctorType >
242  create_reduce( const ExecPolicy & policy
243  , const FunctorType & functor
244  , const unsigned dependence_capacity /* = default */ ) const ;
245 
247  template< class ExecPolicy , class FunctorType >
249  create_scan( const ExecPolicy & policy
250  , const FunctorType & functor
251  , const unsigned dependence_capacity /* = default */ ) const ;
252 
258  template< class TA , class TB >
259  void set_dependence( const Future<TA,execution_space> & after
260  , const Future<TB,execution_space> & before ) const ;
261 
267  template< class T >
269  spawn( const Future<T,execution_space> & ) const ;
270 
271  //----------------------------------------
274  template< class FunctorType >
276  get_dependence( FunctorType * , const int ) const ;
277 
278  //----------------------------------------
285  template< class FunctorType >
286  void clear_dependence( FunctorType * ) const ;
287 
293  template< class FunctorType , class TB >
294  void set_dependence( FunctorType * after
295  , const Future<TB,execution_space> & before ) const ;
296 
300  template< class FunctorType >
301  void respawn( FunctorType * ) const ;
302 };
303 
304 //----------------------------------------------------------------------------
306 template< class ExecSpace , class FunctorType >
307 inline
309 spawn( TaskPolicy<ExecSpace> & policy , const FunctorType & functor )
310 { return policy.spawn( policy.create( functor ) ); }
311 
313 template< class ExecSpace , class FunctorType , class Arg0 , class Arg1 >
314 inline
316 spawn( TaskPolicy<ExecSpace> & policy
317  , const FunctorType & functor
318  , const Future<Arg0,Arg1> & before_0
319  , const Future<Arg0,Arg1> & before_1 )
320 {
322  f = policy.create( functor , 2 );
323  policy.add_dependence( f , before_0 );
324  policy.add_dependence( f , before_1 );
325  policy.spawn( f );
326  return f ;
327 }
328 
329 //----------------------------------------------------------------------------
331 template< class ExecSpace , class ParallelPolicyType , class FunctorType >
332 inline
334 spawn_foreach( TaskPolicy<ExecSpace> & task_policy
335  , const ParallelPolicyType & parallel_policy
336  , const FunctorType & functor )
337 { return task_policy.spawn( task_policy.create_foreach( parallel_policy , functor ) ); }
338 
340 template< class ExecSpace , class ParallelPolicyType , class FunctorType >
341 inline
343 spawn_reduce( TaskPolicy<ExecSpace> & task_policy
344  , const ParallelPolicyType & parallel_policy
345  , const FunctorType & functor )
346 { return task_policy.spawn( task_policy.create_reduce( parallel_policy , functor ) ); }
347 
348 //----------------------------------------------------------------------------
350 template< class ExecSpace , class FunctorType , class Arg0 , class Arg1 >
351 inline
352 void respawn( TaskPolicy<ExecSpace> & policy
353  , FunctorType * functor
354  , const Future<Arg0,Arg1> & before_0
355  , const Future<Arg0,Arg1> & before_1
356  )
357 {
358  policy.clear_dependence( functor );
359  policy.add_dependence( functor , before_0 );
360  policy.add_dependence( functor , before_1 );
361  policy.respawn( functor );
362 }
363 
364 //----------------------------------------------------------------------------
365 
366 template< class ExecSpace >
367 void wait( TaskPolicy< ExecSpace > & );
368 
369 } /* namespace Experimental */
370 } /* namespace Kokkos */
371 
372 //----------------------------------------------------------------------------
373 //----------------------------------------------------------------------------
374 
375 #endif /* #define KOKKOS_TASKPOLICY_HPP */
376 
Future< typename FunctorType::value_type, execution_space > create(const FunctorType &functor, const unsigned dependence_capacity) const
Create a serial task with storage for dependences.
void respawn(FunctorType *) const
Respawn (reschedule) an executing task to be called again after all dependences have completed...
Future< typename FunctorType::value_type, execution_space > create_foreach(const ExecPolicy &policy, const FunctorType &functor, const unsigned dependence_capacity) const
Create a foreach task with storage for dependences.
void clear_dependence(FunctorType *) const
Clear current dependences of an executing task in preparation for setting new dependences and respawn...
const Future< T, execution_space > & spawn(const Future< T, execution_space > &) const
Spawn a task in the &#39;Constructing&#39; state.
If the argument is an execution space then a serial task in that space.
Future< typename FunctorType::value_type, execution_space > create_reduce(const ExecPolicy &policy, const FunctorType &functor, const unsigned dependence_capacity) const
Create a reduce task with storage for dependences.