Kokkos Core Kernels Package  Version of the Day
Kokkos_DynamicView.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_DYNAMIC_VIEW_HPP
45 #define KOKKOS_DYNAMIC_VIEW_HPP
46 
47 #include <cstdio>
48 
49 #include <Kokkos_Core.hpp>
50 #include <impl/Kokkos_Error.hpp>
51 
52 namespace Kokkos {
53 namespace Experimental {
54 
58 template< typename DataType , typename ... P >
59 class DynamicView : public Kokkos::ViewTraits< DataType , P ... >
60 {
61 public:
62 
63  typedef ViewTraits< DataType , P ... > traits ;
64 
65 private:
66 
67  template< class , class ... > friend class DynamicView ;
68 
69  typedef Kokkos::Experimental::Impl::SharedAllocationTracker track_type ;
70 
71  static_assert( traits::rank == 1 && traits::rank_dynamic == 1
72  , "DynamicView must be rank-one" );
73 
74  static_assert( std::is_trivial< typename traits::value_type >::value &&
75  std::is_same< typename traits::specialize , void >::value
76  , "DynamicView must have trivial data type" );
77 
78 public:
79 
81 
82 private:
83 
84  memory_pool m_pool ;
85  track_type m_track ;
86  typename traits::value_type ** m_chunks ;
87  unsigned m_chunk_shift ;
88  unsigned m_chunk_mask ;
89  unsigned m_chunk_max ;
90 
91 public:
92 
93  //----------------------------------------------------------------------
94 
96  typedef DynamicView< typename traits::data_type ,
97  typename traits::device_type >
99 
101  typedef DynamicView< typename traits::const_data_type ,
102  typename traits::device_type >
104 
106  typedef DynamicView< typename traits::non_const_data_type ,
107  typename traits::device_type >
109 
112 
113  //----------------------------------------------------------------------
114 
115  enum { Rank = 1 };
116 
117  KOKKOS_INLINE_FUNCTION constexpr size_t size() const
118  {
119  return
120  Kokkos::Impl::VerifyExecutionCanAccessMemorySpace
121  < Kokkos::Impl::ActiveExecutionMemorySpace
122  , typename traits::memory_space
123  >::value
124  ? // Runtime size is at the end of the chunk pointer array
125  (*reinterpret_cast<const uintptr_t*>( m_chunks + m_chunk_max ))
126  << m_chunk_shift
127  : 0 ;
128  }
129 
130  template< typename iType >
131  KOKKOS_INLINE_FUNCTION constexpr
132  size_t extent( const iType & r ) const
133  { return r == 0 ? size() : 1 ; }
134 
135  template< typename iType >
136  KOKKOS_INLINE_FUNCTION constexpr
137  size_t extent_int( const iType & r ) const
138  { return r == 0 ? size() : 1 ; }
139 
140  KOKKOS_INLINE_FUNCTION constexpr size_t dimension_0() const { return size(); }
141  KOKKOS_INLINE_FUNCTION constexpr size_t dimension_1() const { return 1 ; }
142  KOKKOS_INLINE_FUNCTION constexpr size_t dimension_2() const { return 1 ; }
143  KOKKOS_INLINE_FUNCTION constexpr size_t dimension_3() const { return 1 ; }
144  KOKKOS_INLINE_FUNCTION constexpr size_t dimension_4() const { return 1 ; }
145  KOKKOS_INLINE_FUNCTION constexpr size_t dimension_5() const { return 1 ; }
146  KOKKOS_INLINE_FUNCTION constexpr size_t dimension_6() const { return 1 ; }
147  KOKKOS_INLINE_FUNCTION constexpr size_t dimension_7() const { return 1 ; }
148 
149  KOKKOS_INLINE_FUNCTION constexpr size_t stride_0() const { return 0 ; }
150  KOKKOS_INLINE_FUNCTION constexpr size_t stride_1() const { return 0 ; }
151  KOKKOS_INLINE_FUNCTION constexpr size_t stride_2() const { return 0 ; }
152  KOKKOS_INLINE_FUNCTION constexpr size_t stride_3() const { return 0 ; }
153  KOKKOS_INLINE_FUNCTION constexpr size_t stride_4() const { return 0 ; }
154  KOKKOS_INLINE_FUNCTION constexpr size_t stride_5() const { return 0 ; }
155  KOKKOS_INLINE_FUNCTION constexpr size_t stride_6() const { return 0 ; }
156  KOKKOS_INLINE_FUNCTION constexpr size_t stride_7() const { return 0 ; }
157 
158  template< typename iType >
159  KOKKOS_INLINE_FUNCTION void stride( iType * const s ) const { *s = 0 ; }
160 
161  //----------------------------------------------------------------------
162  // Range span is the span which contains all members.
163 
164  typedef typename traits::value_type & reference_type ;
165  typedef typename traits::value_type * pointer_type ;
166 
167  enum { reference_type_is_lvalue_reference = std::is_lvalue_reference< reference_type >::value };
168 
169  KOKKOS_INLINE_FUNCTION constexpr bool span_is_contiguous() const { return false ; }
170  KOKKOS_INLINE_FUNCTION constexpr size_t span() const { return 0 ; }
171  KOKKOS_INLINE_FUNCTION constexpr pointer_type data() const { return 0 ; }
172 
173  //----------------------------------------
174 
175  template< typename I0 , class ... Args >
176  KOKKOS_INLINE_FUNCTION
177  reference_type operator()( const I0 & i0 , const Args & ... args ) const
178  {
179  static_assert( Kokkos::Impl::are_integral<I0,Args...>::value
180  , "Indices must be integral type" );
181 
182  Kokkos::Impl::VerifyExecutionCanAccessMemorySpace
183  < Kokkos::Impl::ActiveExecutionMemorySpace
184  , typename traits::memory_space
185  >::verify();
186 
187  // Which chunk is being indexed.
188  const uintptr_t ic = uintptr_t( i0 >> m_chunk_shift );
189 
190  typename traits::value_type * volatile * const ch = m_chunks + ic ;
191 
192  // Do bounds checking if enabled or if the chunk pointer is zero.
193  // If not bounds checking then we assume a non-zero pointer is valid.
194 
195 #if ! defined( KOKKOS_ENABLE_DEBUG_BOUNDS_CHECK )
196  if ( 0 == *ch )
197 #endif
198  {
199  // Verify that allocation of the requested chunk in in progress.
200 
201  // The allocated chunk counter is m_chunks[ m_chunk_max ]
202  const uintptr_t n =
203  *reinterpret_cast<uintptr_t volatile *>( m_chunks + m_chunk_max );
204 
205  if ( n <= ic ) {
206  Kokkos::abort("Kokkos::DynamicView array bounds error");
207  }
208 
209  // Allocation of this chunk is in progress
210  // so wait for allocation to complete.
211  while ( 0 == *ch );
212  }
213 
214  return (*ch)[ i0 & m_chunk_mask ];
215  }
216 
217  //----------------------------------------
221  KOKKOS_INLINE_FUNCTION
222  void resize_parallel( size_t n ) const
223  {
224  typedef typename traits::value_type value_type ;
225 
226  Kokkos::Impl::VerifyExecutionCanAccessMemorySpace
227  < Kokkos::Impl::ActiveExecutionMemorySpace
228  , typename traits::memory_space >::verify();
229 
230  const uintptr_t NC = ( n + m_chunk_mask ) >> m_chunk_shift ;
231 
232  if ( m_chunk_max < NC ) {
233 #if defined( KOKKOS_ENABLE_DEBUG_BOUNDS_CHECK )
234  printf("DynamicView::resize_parallel(%lu) m_chunk_max(%u) NC(%lu)\n"
235  , n , m_chunk_max , NC );
236 #endif
237  Kokkos::abort("DynamicView::resize_parallel exceeded maximum size");
238  }
239 
240  typename traits::value_type * volatile * const ch = m_chunks ;
241 
242  // The allocated chunk counter is m_chunks[ m_chunk_max ]
243  uintptr_t volatile * const pc =
244  reinterpret_cast<uintptr_t volatile*>( m_chunks + m_chunk_max );
245 
246  // Potentially concurrent iteration of allocation to the required size.
247 
248  for ( uintptr_t jc = *pc ; jc < NC ; ) {
249 
250  // Claim the 'jc' chunk to-be-allocated index
251 
252  const uintptr_t jc_try = jc ;
253 
254  // Jump iteration to the chunk counter.
255 
256  jc = atomic_compare_exchange( pc , jc_try , jc_try + 1 );
257 
258  if ( jc_try == jc ) {
259 
260  ch[jc_try] = reinterpret_cast<value_type*>(
261  m_pool.allocate( sizeof(value_type) << m_chunk_shift ));
262 
263  Kokkos::memory_fence();
264  }
265  }
266  }
267 
269  inline
270  void resize_serial( size_t n )
271  {
272  Kokkos::Impl::VerifyExecutionCanAccessMemorySpace
273  < Kokkos::Impl::ActiveExecutionMemorySpace
274  , typename traits::memory_space >::verify();
275 
276  const uintptr_t NC = ( n + m_chunk_mask ) >> m_chunk_shift ;
277 
278  if ( m_chunk_max < NC ) {
279  Kokkos::abort("DynamicView::resize_serial exceeded maximum size");
280  }
281 
282  uintptr_t * const pc =
283  reinterpret_cast<uintptr_t*>( m_chunks + m_chunk_max );
284 
285  if ( *pc < NC ) {
286  while ( *pc < NC ) {
287  m_chunks[*pc] =
288  m_pool.allocate( sizeof(traits::value_type) << m_chunk_shift );
289  ++*pc ;
290  }
291  }
292  else {
293  while ( NC + 1 <= *pc ) {
294  --*pc ;
295  m_pool.deallocate( m_chunks[*pc]
296  , sizeof(traits::value_type) << m_chunk_shift );
297  m_chunks[*pc] = 0 ;
298  }
299  }
300  }
301 
302  //----------------------------------------------------------------------
303 
304  ~DynamicView() = default ;
305  DynamicView() = default ;
306  DynamicView( DynamicView && ) = default ;
307  DynamicView( const DynamicView & ) = default ;
308  DynamicView & operator = ( DynamicView && ) = default ;
309  DynamicView & operator = ( const DynamicView & ) = default ;
310 
311  template< class RT , class ... RP >
312  KOKKOS_INLINE_FUNCTION
313  DynamicView( const DynamicView<RT,RP...> & rhs )
314  : m_pool( rhs.m_pool )
315  , m_track( rhs.m_track )
316  , m_chunks( rhs.m_chunks )
317  , m_chunk_shift( rhs.m_chunk_shift )
318  , m_chunk_mask( rhs.m_chunk_mask )
319  , m_chunk_max( rhs.m_chunk_max )
320  {
321  }
322 
323  //----------------------------------------------------------------------
324 
325  struct Destroy {
326  memory_pool m_pool ;
327  typename traits::value_type ** m_chunks ;
328  unsigned m_chunk_max ;
329  bool m_destroy ;
330 
331  // Initialize or destroy array of chunk pointers.
332  // Two entries beyond the max chunks are allocation counters.
333 
334  KOKKOS_INLINE_FUNCTION
335  void operator()( unsigned i ) const
336  {
337  if ( m_destroy && i < m_chunk_max && 0 != m_chunks[i] ) {
338  m_pool.deallocate( m_chunks[i] , m_pool.get_min_block_size() );
339  }
340  m_chunks[i] = 0 ;
341  }
342 
343  void execute( bool arg_destroy )
344  {
346 
347  m_destroy = arg_destroy ;
348 
350  closure( *this , Range(0, m_chunk_max + 1) );
351 
352  closure.execute();
353 
354  traits::execution_space::fence();
355  }
356 
357  void construct_shared_allocation()
358  { execute( false ); }
359 
360  void destroy_shared_allocation()
361  { execute( true ); }
362 
363  Destroy() = default ;
364  Destroy( Destroy && ) = default ;
365  Destroy( const Destroy & ) = default ;
366  Destroy & operator = ( Destroy && ) = default ;
367  Destroy & operator = ( const Destroy & ) = default ;
368 
369  Destroy( const memory_pool & arg_pool
370  , typename traits::value_type ** arg_chunk
371  , const unsigned arg_chunk_max )
372  : m_pool( arg_pool )
373  , m_chunks( arg_chunk )
374  , m_chunk_max( arg_chunk_max )
375  , m_destroy( false )
376  {}
377  };
378 
379 
387  explicit inline
388  DynamicView( const std::string & arg_label
389  , const memory_pool & arg_pool
390  , const size_t arg_size_max )
391  : m_pool( arg_pool )
392  , m_track()
393  , m_chunks(0)
394  // The memory pool chunk is guaranteed to be a power of two
395  , m_chunk_shift(
396  Kokkos::Impl::integral_power_of_two(
397  m_pool.get_min_block_size()/sizeof(typename traits::value_type)) )
398  , m_chunk_mask( ( 1 << m_chunk_shift ) - 1 )
399  , m_chunk_max( ( arg_size_max + m_chunk_mask ) >> m_chunk_shift )
400  {
401  Kokkos::Impl::VerifyExecutionCanAccessMemorySpace
402  < Kokkos::Impl::ActiveExecutionMemorySpace
403  , typename traits::memory_space >::verify();
404 
405  // A functor to deallocate all of the chunks upon final destruction
406 
407  typedef typename traits::memory_space memory_space ;
408  typedef Kokkos::Experimental::Impl::SharedAllocationRecord< memory_space , Destroy > record_type ;
409 
410  // Allocate chunk pointers and allocation counter
411  record_type * const record =
412  record_type::allocate( memory_space()
413  , arg_label
414  , ( sizeof(pointer_type) * ( m_chunk_max + 1 ) ) );
415 
416  m_chunks = reinterpret_cast<pointer_type*>( record->data() );
417 
418  record->m_destroy = Destroy( m_pool , m_chunks , m_chunk_max );
419 
420  // Initialize to zero
421 
422  record->m_destroy.construct_shared_allocation();
423 
424  m_track.assign_allocated_record_to_uninitialized( record );
425  }
426 };
427 
428 } // namespace Experimental
429 } // namespace Kokkos
430 
431 namespace Kokkos {
432 namespace Experimental {
433 
434 template< class T , class ... P >
435 inline
436 typename Kokkos::Experimental::DynamicView<T,P...>::HostMirror
437 create_mirror_view( const Kokkos::Experimental::DynamicView<T,P...> & src )
438 {
439  return src ;
440 }
441 
442 template< class T , class ... DP , class ... SP >
443 inline
444 void deep_copy( const View<T,DP...> & dst
445  , const DynamicView<T,SP...> & src
446  )
447 {
448  typedef View<T,DP...> dst_type ;
449  typedef DynamicView<T,SP...> src_type ;
450 
451  typedef typename ViewTraits<T,DP...>::execution_space dst_execution_space ;
452  typedef typename ViewTraits<T,SP...>::memory_space src_memory_space ;
453 
454  enum { DstExecCanAccessSrc =
455  Kokkos::Impl::VerifyExecutionCanAccessMemorySpace< typename dst_execution_space::memory_space , src_memory_space >::value };
456 
457  if ( DstExecCanAccessSrc ) {
458  // Copying data between views in accessible memory spaces and either non-contiguous or incompatible shape.
459  Kokkos::Experimental::Impl::ViewRemap< dst_type , src_type >( dst , src );
460  }
461  else {
462  Kokkos::Impl::throw_runtime_exception("deep_copy given views that would require a temporary allocation");
463  }
464 }
465 
466 template< class T , class ... DP , class ... SP >
467 inline
468 void deep_copy( const DynamicView<T,DP...> & dst
469  , const View<T,SP...> & src
470  )
471 {
472  typedef DynamicView<T,SP...> dst_type ;
473  typedef View<T,DP...> src_type ;
474 
475  typedef typename ViewTraits<T,DP...>::execution_space dst_execution_space ;
476  typedef typename ViewTraits<T,SP...>::memory_space src_memory_space ;
477 
478  enum { DstExecCanAccessSrc =
479  Kokkos::Impl::VerifyExecutionCanAccessMemorySpace< typename dst_execution_space::memory_space , src_memory_space >::value };
480 
481  if ( DstExecCanAccessSrc ) {
482  // Copying data between views in accessible memory spaces and either non-contiguous or incompatible shape.
483  Kokkos::Experimental::Impl::ViewRemap< dst_type , src_type >( dst , src );
484  }
485  else {
486  Kokkos::Impl::throw_runtime_exception("deep_copy given views that would require a temporary allocation");
487  }
488 }
489 
490 } // namespace Experimental
491 } // namespace Kokkos
492 
493 #endif /* #ifndef KOKKOS_DYNAMIC_VIEW_HPP */
494 
DynamicView< typename traits::data_type, typename traits::device_type > array_type
Compatible view of array of scalar types.
Dynamic views are restricted to rank-one and no layout. Subviews are not allowed. ...
DynamicView(const std::string &arg_label, const memory_pool &arg_pool, const size_t arg_size_max)
Allocation constructor.
KOKKOS_FUNCTION void deallocate(void *alloc_ptr, size_t alloc_size) const
Release allocated memory back to the pool.
DynamicView< typename traits::const_data_type, typename traits::device_type > const_type
Compatible view of const data type.
KOKKOS_INLINE_FUNCTION void resize_parallel(size_t n) const
Resizing in parallel only increases the array size, never decrease.
Memory space for main process and CPU execution spaces.
View
DynamicView HostMirror
Must be accessible everywhere.
Implementation of the ParallelFor operator that has a partial specialization for the device...
KOKKOS_FUNCTION void * allocate(size_t alloc_size) const
Allocate a chunk of memory.
void deep_copy(const View< DT, DP... > &dst, typename ViewTraits< DT, DP... >::const_value_type &value, typename std::enable_if< std::is_same< typename ViewTraits< DT, DP... >::specialize, void >::value >::type *=0)
Deep copy a value from Host memory into a view.
Execution policy for work over a range of an integral type.
void resize_serial(size_t n)
Resizing in serial can grow or shrink the array size,.
Traits class for accessing attributes of a View.
DynamicView< typename traits::non_const_data_type, typename traits::device_type > non_const_type
Compatible view of non-const data type.