Kokkos Core Kernels Package  Version of the Day
Kokkos_DualView.hpp
Go to the documentation of this file.
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 
49 
50 #ifndef KOKKOS_DUALVIEW_HPP
51 #define KOKKOS_DUALVIEW_HPP
52 
53 #include <Kokkos_Core.hpp>
54 #include <impl/Kokkos_Error.hpp>
55 
56 namespace Kokkos {
57 
58 /* \class DualView
59  * \brief Container to manage mirroring a Kokkos::View that lives
60  * in device memory with a Kokkos::View that lives in host memory.
61  *
62  * This class provides capabilities to manage data which exists in two
63  * memory spaces at the same time. It keeps views of the same layout
64  * on two memory spaces as well as modified flags for both
65  * allocations. Users are responsible for setting the modified flags
66  * manually if they change the data in either memory space, by calling
67  * the sync() method templated on the device where they modified the
68  * data. Users may synchronize data by calling the modify() function,
69  * templated on the device towards which they want to synchronize
70  * (i.e., the target of the one-way copy operation).
71  *
72  * The DualView class also provides convenience methods such as
73  * realloc, resize and capacity which call the appropriate methods of
74  * the underlying Kokkos::View objects.
75  *
76  * The four template arguments are the same as those of Kokkos::View.
77  * (Please refer to that class' documentation for a detailed
78  * description.)
79  *
80  * \tparam DataType The type of the entries stored in the container.
81  *
82  * \tparam Layout The array's layout in memory.
83  *
84  * \tparam Device The Kokkos Device type. If its memory space is
85  * not the same as the host's memory space, then DualView will
86  * contain two separate Views: one in device memory, and one in
87  * host memory. Otherwise, DualView will only store one View.
88  *
89  * \tparam MemoryTraits (optional) The user's intended memory access
90  * behavior. Please see the documentation of Kokkos::View for
91  * examples. The default suffices for most users.
92  */
93 template< class DataType ,
94  class Arg1Type = void ,
95  class Arg2Type = void ,
96  class Arg3Type = void>
97 class DualView : public ViewTraits< DataType , Arg1Type , Arg2Type, Arg3Type >
98 {
99 public:
101 
102  typedef ViewTraits< DataType , Arg1Type , Arg2Type, Arg3Type > traits ;
103 
105  typedef typename traits::host_mirror_space host_mirror_space ;
106 
108  typedef View< typename traits::data_type ,
109  Arg1Type ,
110  Arg2Type ,
111  Arg3Type > t_dev ;
112 
115  typedef typename t_dev::HostMirror t_host ;
116 
119  typedef View< typename traits::const_data_type ,
120  Arg1Type ,
121  Arg2Type ,
122  Arg3Type > t_dev_const ;
123 
126  typedef typename t_dev_const::HostMirror t_host_const;
127 
129  typedef View< typename traits::const_data_type ,
130  typename traits::array_layout ,
131  typename traits::device_type ,
132  Kokkos::MemoryTraits<Kokkos::RandomAccess> > t_dev_const_randomread ;
133 
137  typedef typename t_dev_const_randomread::HostMirror t_host_const_randomread;
138 
140  typedef View< typename traits::data_type ,
141  typename traits::array_layout ,
142  typename traits::device_type ,
143  MemoryUnmanaged> t_dev_um;
144 
146  typedef View< typename t_host::data_type ,
147  typename t_host::array_layout ,
148  typename t_host::device_type ,
149  MemoryUnmanaged> t_host_um;
150 
152  typedef View< typename traits::const_data_type ,
153  typename traits::array_layout ,
154  typename traits::device_type ,
155  MemoryUnmanaged> t_dev_const_um;
156 
158  typedef View<typename t_host::const_data_type,
159  typename t_host::array_layout,
160  typename t_host::device_type,
161  MemoryUnmanaged> t_host_const_um;
162 
164  typedef View< typename t_host::const_data_type ,
165  typename t_host::array_layout ,
166  typename t_host::device_type ,
167  Kokkos::MemoryTraits<Kokkos::Unmanaged|Kokkos::RandomAccess> > t_dev_const_randomread_um ;
168 
172  typedef typename t_dev_const_randomread::HostMirror t_host_const_randomread_um;
173 
175 
177 
178  t_dev d_view;
179  t_host h_view;
180 
182 
184 
185  View<unsigned int,LayoutLeft,typename t_host::execution_space> modified_device;
186  View<unsigned int,LayoutLeft,typename t_host::execution_space> modified_host;
187 
189 
191 
197  DualView () :
198  modified_device (View<unsigned int,LayoutLeft,typename t_host::execution_space> ("DualView::modified_device")),
199  modified_host (View<unsigned int,LayoutLeft,typename t_host::execution_space> ("DualView::modified_host"))
200  {}
201 
211  DualView (const std::string& label,
212  const size_t n0 = 0,
213  const size_t n1 = 0,
214  const size_t n2 = 0,
215  const size_t n3 = 0,
216  const size_t n4 = 0,
217  const size_t n5 = 0,
218  const size_t n6 = 0,
219  const size_t n7 = 0)
220  : d_view (label, n0, n1, n2, n3, n4, n5, n6, n7)
221  , h_view (create_mirror_view (d_view)) // without UVM, host View mirrors
222  , modified_device (View<unsigned int,LayoutLeft,typename t_host::execution_space> ("DualView::modified_device"))
223  , modified_host (View<unsigned int,LayoutLeft,typename t_host::execution_space> ("DualView::modified_host"))
224  {}
225 
227  template<class SS, class LS, class DS, class MS>
228  DualView (const DualView<SS,LS,DS,MS>& src) :
229  d_view (src.d_view),
230  h_view (src.h_view),
231  modified_device (src.modified_device),
232  modified_host (src.modified_host)
233  {}
234 
236  template< class SD, class S1 , class S2 , class S3
237  , class Arg0 , class ... Args >
238  DualView( const DualView<SD,S1,S2,S3> & src
239  , const Arg0 & arg0
240  , Args ... args
241  )
242  : d_view( Kokkos::subview( src.d_view , arg0 , args ... ) )
243  , h_view( Kokkos::subview( src.h_view , arg0 , args ... ) )
244  , modified_device (src.modified_device)
245  , modified_host (src.modified_host)
246  {}
247 
258  DualView (const t_dev& d_view_, const t_host& h_view_) :
259  d_view (d_view_),
260  h_view (h_view_),
261  modified_device (View<unsigned int,LayoutLeft,typename t_host::execution_space> ("DualView::modified_device")),
262  modified_host (View<unsigned int,LayoutLeft,typename t_host::execution_space> ("DualView::modified_host"))
263  {
264  if ( int(d_view.rank) != int(h_view.rank) ||
265  d_view.dimension_0() != h_view.dimension_0() ||
266  d_view.dimension_1() != h_view.dimension_1() ||
267  d_view.dimension_2() != h_view.dimension_2() ||
268  d_view.dimension_3() != h_view.dimension_3() ||
269  d_view.dimension_4() != h_view.dimension_4() ||
270  d_view.dimension_5() != h_view.dimension_5() ||
271  d_view.dimension_6() != h_view.dimension_6() ||
272  d_view.dimension_7() != h_view.dimension_7() ||
273  d_view.stride_0() != h_view.stride_0() ||
274  d_view.stride_1() != h_view.stride_1() ||
275  d_view.stride_2() != h_view.stride_2() ||
276  d_view.stride_3() != h_view.stride_3() ||
277  d_view.stride_4() != h_view.stride_4() ||
278  d_view.stride_5() != h_view.stride_5() ||
279  d_view.stride_6() != h_view.stride_6() ||
280  d_view.stride_7() != h_view.stride_7() ||
281  d_view.span() != h_view.span() ) {
282  Kokkos::Impl::throw_runtime_exception("DualView constructed with incompatible views");
283  }
284  }
285 
287 
289 
311  template< class Device >
312  KOKKOS_INLINE_FUNCTION
313  const typename Impl::if_c<
314  std::is_same<typename t_dev::memory_space,
315  typename Device::memory_space>::value,
316  t_dev,
317  t_host>::type& view () const
318  {
319  return Impl::if_c<
320  std::is_same<
321  typename t_dev::memory_space,
322  typename Device::memory_space>::value,
323  t_dev,
324  t_host >::select (d_view , h_view);
325  }
326 
344  template<class Device>
345  void sync( const typename Impl::enable_if<
346  ( std::is_same< typename traits::data_type , typename traits::non_const_data_type>::value) ||
347  ( std::is_same< Device , int>::value)
348  , int >::type& = 0)
349  {
350  const unsigned int dev =
351  Impl::if_c<
352  std::is_same<
353  typename t_dev::memory_space,
354  typename Device::memory_space>::value ,
355  unsigned int,
356  unsigned int>::select (1, 0);
357 
358  if (dev) { // if Device is the same as DualView's device type
359  if ((modified_host () > 0) && (modified_host () >= modified_device ())) {
360  deep_copy (d_view, h_view);
361  modified_host() = modified_device() = 0;
362  }
363  } else { // hopefully Device is the same as DualView's host type
364  if ((modified_device () > 0) && (modified_device () >= modified_host ())) {
365  deep_copy (h_view, d_view);
366  modified_host() = modified_device() = 0;
367  }
368  }
369  if(std::is_same<typename t_host::memory_space,typename t_dev::memory_space>::value) {
370  t_dev::execution_space::fence();
371  t_host::execution_space::fence();
372  }
373  }
374 
375  template<class Device>
376  void sync ( const typename Impl::enable_if<
377  ( ! std::is_same< typename traits::data_type , typename traits::non_const_data_type>::value ) ||
378  ( std::is_same< Device , int>::value)
379  , int >::type& = 0 )
380  {
381  const unsigned int dev =
382  Impl::if_c<
383  std::is_same<
384  typename t_dev::memory_space,
385  typename Device::memory_space>::value,
386  unsigned int,
387  unsigned int>::select (1, 0);
388  if (dev) { // if Device is the same as DualView's device type
389  if ((modified_host () > 0) && (modified_host () >= modified_device ())) {
390  Impl::throw_runtime_exception("Calling sync on a DualView with a const datatype.");
391  }
392  } else { // hopefully Device is the same as DualView's host type
393  if ((modified_device () > 0) && (modified_device () >= modified_host ())) {
394  Impl::throw_runtime_exception("Calling sync on a DualView with a const datatype.");
395  }
396  }
397  }
398 
399  template<class Device>
400  bool need_sync() const
401  {
402  const unsigned int dev =
403  Impl::if_c<
404  std::is_same<
405  typename t_dev::memory_space,
406  typename Device::memory_space>::value ,
407  unsigned int,
408  unsigned int>::select (1, 0);
409 
410  if (dev) { // if Device is the same as DualView's device type
411  if ((modified_host () > 0) && (modified_host () >= modified_device ())) {
412  return true;
413  }
414  } else { // hopefully Device is the same as DualView's host type
415  if ((modified_device () > 0) && (modified_device () >= modified_host ())) {
416  return true;
417  }
418  }
419  return false;
420  }
426  template<class Device>
427  void modify () {
428  const unsigned int dev =
429  Impl::if_c<
430  std::is_same<
431  typename t_dev::memory_space,
432  typename Device::memory_space>::value,
433  unsigned int,
434  unsigned int>::select (1, 0);
435 
436  if (dev) { // if Device is the same as DualView's device type
437  // Increment the device's modified count.
438  modified_device () = (modified_device () > modified_host () ?
439  modified_device () : modified_host ()) + 1;
440  } else { // hopefully Device is the same as DualView's host type
441  // Increment the host's modified count.
442  modified_host () = (modified_device () > modified_host () ?
443  modified_device () : modified_host ()) + 1;
444  }
445  }
446 
448 
450 
456  void realloc( const size_t n0 = 0 ,
457  const size_t n1 = 0 ,
458  const size_t n2 = 0 ,
459  const size_t n3 = 0 ,
460  const size_t n4 = 0 ,
461  const size_t n5 = 0 ,
462  const size_t n6 = 0 ,
463  const size_t n7 = 0 ) {
464  ::Kokkos::realloc(d_view,n0,n1,n2,n3,n4,n5,n6,n7);
465  h_view = create_mirror_view( d_view );
466 
467  /* Reset dirty flags */
468  modified_device() = modified_host() = 0;
469  }
470 
475  void resize( const size_t n0 = 0 ,
476  const size_t n1 = 0 ,
477  const size_t n2 = 0 ,
478  const size_t n3 = 0 ,
479  const size_t n4 = 0 ,
480  const size_t n5 = 0 ,
481  const size_t n6 = 0 ,
482  const size_t n7 = 0 ) {
483  if(modified_device() >= modified_host()) {
484  /* Resize on Device */
485  ::Kokkos::resize(d_view,n0,n1,n2,n3,n4,n5,n6,n7);
486  h_view = create_mirror_view( d_view );
487 
488  /* Mark Device copy as modified */
489  modified_device() = modified_device()+1;
490 
491  } else {
492  /* Realloc on Device */
493 
494  ::Kokkos::realloc(d_view,n0,n1,n2,n3,n4,n5,n6,n7);
495  t_host temp_view = create_mirror_view( d_view );
496 
497  /* Remap on Host */
498  Kokkos::deep_copy( temp_view , h_view );
499 
500  h_view = temp_view;
501 
502  /* Mark Host copy as modified */
503  modified_host() = modified_host()+1;
504  }
505  }
506 
508 
510 
512  size_t capacity() const {
513  return d_view.span();
514  }
515 
517  template< typename iType>
518  void stride(iType* stride_) const {
519  d_view.stride(stride_);
520  }
521 
522  /* \brief return size of dimension 0 */
523  size_t dimension_0() const {return d_view.dimension_0();}
524  /* \brief return size of dimension 1 */
525  size_t dimension_1() const {return d_view.dimension_1();}
526  /* \brief return size of dimension 2 */
527  size_t dimension_2() const {return d_view.dimension_2();}
528  /* \brief return size of dimension 3 */
529  size_t dimension_3() const {return d_view.dimension_3();}
530  /* \brief return size of dimension 4 */
531  size_t dimension_4() const {return d_view.dimension_4();}
532  /* \brief return size of dimension 5 */
533  size_t dimension_5() const {return d_view.dimension_5();}
534  /* \brief return size of dimension 6 */
535  size_t dimension_6() const {return d_view.dimension_6();}
536  /* \brief return size of dimension 7 */
537  size_t dimension_7() const {return d_view.dimension_7();}
538 
540 };
541 
542 } // namespace Kokkos
543 
544 //----------------------------------------------------------------------------
545 //----------------------------------------------------------------------------
546 //
547 // Partial specializations of Kokkos::subview() for DualView objects.
548 //
549 
550 namespace Kokkos {
551 namespace Impl {
552 
553 template< class D, class A1, class A2, class A3, class ... Args >
554 struct DualViewSubview {
555 
556  typedef typename Kokkos::Experimental::Impl::ViewMapping
557  < void
559  , Args ...
560  >::traits_type dst_traits ;
561 
562  typedef Kokkos::DualView
563  < typename dst_traits::data_type
564  , typename dst_traits::array_layout
565  , typename dst_traits::device_type
566  , typename dst_traits::memory_traits
567  > type ;
568 };
569 
570 } /* namespace Impl */
571 
572 
573 template< class D , class A1 , class A2 , class A3 , class ... Args >
574 typename Impl::DualViewSubview<D,A1,A2,A3,Args...>::type
575 subview( const DualView<D,A1,A2,A3> & src , Args ... args )
576 {
577  return typename
578  Impl::DualViewSubview<D,A1,A2,A3,Args...>::type( src , args ... );
579 }
580 
581 } /* namespace Kokkos */
582 
583 //----------------------------------------------------------------------------
584 //----------------------------------------------------------------------------
585 
586 namespace Kokkos {
587 
588 //
589 // Partial specialization of Kokkos::deep_copy() for DualView objects.
590 //
591 
592 template< class DT , class DL , class DD , class DM ,
593  class ST , class SL , class SD , class SM >
594 void
595 deep_copy (DualView<DT,DL,DD,DM> dst, // trust me, this must not be a reference
596  const DualView<ST,SL,SD,SM>& src )
597 {
598  if (src.modified_device () >= src.modified_host ()) {
599  deep_copy (dst.d_view, src.d_view);
600  dst.template modify<typename DualView<DT,DL,DD,DM>::device_type> ();
601  } else {
602  deep_copy (dst.h_view, src.h_view);
603  dst.template modify<typename DualView<DT,DL,DD,DM>::host_mirror_space> ();
604  }
605 }
606 
607 template< class ExecutionSpace ,
608  class DT , class DL , class DD , class DM ,
609  class ST , class SL , class SD , class SM >
610 void
611 deep_copy (const ExecutionSpace& exec ,
612  DualView<DT,DL,DD,DM> dst, // trust me, this must not be a reference
613  const DualView<ST,SL,SD,SM>& src )
614 {
615  if (src.modified_device () >= src.modified_host ()) {
616  deep_copy (exec, dst.d_view, src.d_view);
617  dst.template modify<typename DualView<DT,DL,DD,DM>::device_type> ();
618  } else {
619  deep_copy (exec, dst.h_view, src.h_view);
620  dst.template modify<typename DualView<DT,DL,DD,DM>::host_mirror_space> ();
621  }
622 }
623 
624 } // namespace Kokkos
625 
626 #endif
std::enable_if< std::is_same< typename Kokkos::View< T, P... >::array_layout, Kokkos::LayoutLeft >::value||std::is_same< typename Kokkos::View< T, P... >::array_layout, Kokkos::LayoutRight >::value >::type resize(Kokkos::View< T, P... > &v, const size_t n0=0, const size_t n1=0, const size_t n2=0, const size_t n3=0, const size_t n4=0, const size_t n5=0, const size_t n6=0, const size_t n7=0)
Resize a view with copying old data to new data at the corresponding indices.
std::enable_if< std::is_same< typename Kokkos::View< T, P... >::array_layout, Kokkos::LayoutLeft >::value||std::is_same< typename Kokkos::View< T, P... >::array_layout, Kokkos::LayoutRight >::value >::type realloc(Kokkos::View< T, P... > &v, const size_t n0=0, const size_t n1=0, const size_t n2=0, const size_t n3=0, const size_t n4=0, const size_t n5=0, const size_t n6=0, const size_t n7=0)
Resize a view with discarding old data.
View
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.
View< typename traits::non_const_data_type, typename traits::array_layout, typename traits::host_mirror_space > HostMirror
Compatible HostMirror view.
Traits class for accessing attributes of a View.