Stokhos Package Browser (Single Doxygen Collection)  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
MPAssembly/VectorImport.hpp
Go to the documentation of this file.
1 /*
2 //@HEADER
3 // ************************************************************************
4 //
5 // Kokkos: Manycore Performance-Portable Multidimensional Arrays
6 // Copyright (2012) 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_VECTORIMPORT_HPP
45 #define KOKKOS_VECTORIMPORT_HPP
46 
47 #include <utility>
48 #include <limits>
49 #include <iostream>
50 #include <sstream>
51 #include <stdexcept>
52 
53 #include <Kokkos_Core.hpp>
54 
55 #include <Teuchos_CommHelpers.hpp>
56 
57 namespace Kokkos {
58 namespace Example {
59 
60 template< class CommMessageType , class CommIdentType , class VectorType >
61 class VectorImport ;
62 
63 } // namespace Example
64 } // namespace Kokkos
65 
66 #if ! defined( KOKKOS_ENABLE_MPI )
67 
68 //----------------------------------------------------------------------------
69 //----------------------------------------------------------------------------
70 
71 namespace Kokkos {
72 namespace Example {
73 
74 template< class CommMessageType , class CommIdentType , class VectorType >
75 struct VectorImport {
76 
78  const unsigned count_owned ;
79  const unsigned count_receive ;
80 
81  VectorImport( const Teuchos::RCP<const Teuchos::Comm<int> > arg_comm ,
82  const CommMessageType & ,
83  const CommMessageType & ,
84  const CommIdentType & ,
85  const unsigned arg_count_owned ,
86  const unsigned arg_count_receive )
87  : comm( arg_comm )
88  , count_owned( arg_count_owned )
89  , count_receive( arg_count_receive )
90  {}
91 
92  inline
93  void operator()( const VectorType & ) const {}
94 };
95 
96 
97 } // namespace Example
98 } // namespace Kokkos
99 
100 //----------------------------------------------------------------------------
101 //----------------------------------------------------------------------------
102 
103 #else /* defined( KOKKOS_ENABLE_MPI ) */
104 
106 
107 namespace Kokkos {
108 namespace Example {
109 
110 template< class CommMessageType , class CommIdentType , class VectorType >
111 class VectorImport {
112 private:
113 
114  // rank == 1 or array_layout == LayoutRight
115  static_assert(
116  ( VectorType::rank == 1 ) ||
117  std::is_same< typename VectorType::array_layout , Kokkos::LayoutRight >::value,
118  "Kokkos::Example::VectorImport Assert Fail: rank != 1 or array_layout != LayoutRight" );
119 
120  typedef typename VectorType::HostMirror HostVectorType ;
121  typedef typename CommMessageType::HostMirror HostCommMessageType;
122 
123  enum { ReceiveInPlace =
124  std::is_same< typename VectorType::memory_space ,
125  typename HostVectorType::memory_space >::value };
126 
127  const CommMessageType recv_msg ;
128  const CommMessageType send_msg ;
129  const CommIdentType send_nodeid ;
130  HostCommMessageType host_recv_msg ;
131  HostCommMessageType host_send_msg ;
132  VectorType send_buffer ;
133  HostVectorType host_send_buffer ;
134  HostVectorType host_recv_buffer ;
135  unsigned chunk ;
136 
137 public:
138 
140  const unsigned count_owned ;
141  const unsigned count_receive ;
142 
143  struct Pack {
145  const CommIdentType index ;
146  const VectorType source ;
147  const VectorType buffer ;
148 
149  KOKKOS_INLINE_FUNCTION
150  void operator()( const unsigned i ) const
151  { buffer( i ) = source( index(i) ); }
152 
153  Pack( const CommIdentType & arg_index ,
154  const VectorType & arg_source ,
155  const VectorType & arg_buffer )
156  : index( arg_index )
157  , source( arg_source )
158  , buffer( arg_buffer )
159  {
160  Kokkos::parallel_for( index.extent(0) , *this );
161  execution_space().fence();
162  }
163  };
164 
165  VectorImport( const Teuchos::RCP<const Teuchos::Comm<int> > & arg_comm ,
166  const CommMessageType & arg_recv_msg ,
167  const CommMessageType & arg_send_msg ,
168  const CommIdentType & arg_send_nodeid ,
169  const unsigned arg_count_owned ,
170  const unsigned arg_count_receive )
171  : recv_msg( arg_recv_msg )
172  , send_msg( arg_send_msg )
173  , send_nodeid( arg_send_nodeid )
174  , host_recv_msg()
175  , host_send_msg()
176  , send_buffer()
177  , host_send_buffer()
178  , host_recv_buffer()
179  , comm( arg_comm )
180  , count_owned( arg_count_owned )
181  , count_receive( arg_count_receive )
182  {
183  host_recv_msg = Kokkos::create_mirror_view( recv_msg );
184  host_send_msg = Kokkos::create_mirror_view( send_msg );
185  Kokkos::deep_copy( host_recv_msg , recv_msg );
186  Kokkos::deep_copy( host_send_msg , send_msg );
187  if ( ! ReceiveInPlace ) {
188  host_recv_buffer = HostVectorType("recv_buffer",count_receive);
189  }
190 
191  unsigned send_count = 0 ;
192  for ( unsigned i = 0 ; i < send_msg.extent(0) ; ++i ) { send_count += host_send_msg(i,1); }
193  send_buffer = VectorType("send_buffer",send_count);
194  host_send_buffer = Kokkos::create_mirror_view( send_buffer );
195  }
196 
197  inline
198  void operator()( const VectorType & v ) const
199  {
200  typedef typename VectorType::value_type scalar_type ;
201  typedef typename HostVectorType::value_type host_scalar_type ;
202 
203  const Teuchos::MpiComm<int> & teuchos_mpi_comm = dynamic_cast< const Teuchos::MpiComm<int> & >( *comm );
204 
205  MPI_Comm mpi_comm = * teuchos_mpi_comm.getRawMpiComm();
206 
207  const int mpi_tag = 42 ;
208  const unsigned chunk = v.extent(1);
209 
210  // Subvector for receives
211  const std::pair<unsigned,unsigned> recv_range( count_owned , count_owned + count_receive );
212  const VectorType recv_vector = Kokkos::subview( v , recv_range );
213 
214  std::vector< MPI_Request > recv_request( recv_msg.extent(0) , MPI_REQUEST_NULL );
215 
216  // Post receives
217  if (ReceiveInPlace) {
218  scalar_type * ptr = recv_vector.data();
219 
220  for ( size_t i = 0 ; i < recv_msg.extent(0) ; ++i ) {
221  const int proc = host_recv_msg(i,0);
222  const int count = host_recv_msg(i,1) * chunk ;
223 
224  MPI_Irecv( ptr , count * sizeof(scalar_type) , MPI_BYTE ,
225  proc , mpi_tag , mpi_comm , & recv_request[i] );
226 
227  ptr += count ;
228  }
229  }
230  else {
231  host_scalar_type * ptr = host_recv_buffer.data();
232 
233  for ( size_t i = 0 ; i < recv_msg.extent(0) ; ++i ) {
234  const int proc = host_recv_msg(i,0);
235  const int count = host_recv_msg(i,1) * chunk ;
236 
237  MPI_Irecv( ptr , count * sizeof(host_scalar_type) , MPI_BYTE ,
238  proc , mpi_tag , mpi_comm , & recv_request[i] );
239 
240  ptr += count ;
241  }
242 
243  }
244 
245  MPI_Barrier( mpi_comm );
246 
247  { // Pack and send
248  const Pack pack( send_nodeid , v , send_buffer );
249 
250  Kokkos::deep_copy( host_send_buffer , send_buffer );
251 
252  host_scalar_type * ptr = host_send_buffer.data();
253 
254  for ( size_t i = 0 ; i < send_msg.extent(0) ; ++i ) {
255  const int proc = host_send_msg(i,0);
256  const int count = host_send_msg(i,1) * chunk ;
257 
258  // MPI_Ssend blocks until
259  // (1) a receive is matched for the message and
260  // (2) the send buffer can be re-used.
261  //
262  // It is suggested that MPI_Ssend will have the best performance:
263  // http://www.mcs.anl.gov/research/projects/mpi/sendmode.html .
264 
265  MPI_Ssend( ptr ,
266  count * sizeof(host_scalar_type) , MPI_BYTE ,
267  proc , mpi_tag , mpi_comm );
268 
269  ptr += count ;
270  }
271  }
272 
273  // Wait for receives and verify:
274 
275  for ( size_t i = 0 ; i < recv_msg.extent(0) ; ++i ) {
276  MPI_Status recv_status ;
277  int recv_which = 0 ;
278  int recv_size = 0 ;
279 
280  MPI_Waitany( recv_msg.extent(0) , & recv_request[0] , & recv_which , & recv_status );
281 
282  const int recv_proc = recv_status.MPI_SOURCE ;
283 
284  MPI_Get_count( & recv_status , MPI_BYTE , & recv_size );
285 
286  // Verify message properly received:
287 
288  const int expected_proc = host_recv_msg(recv_which,0);
289  const int expected_size = host_recv_msg(recv_which,1) * chunk * sizeof(scalar_type);
290 
291  if ( ( expected_proc != recv_proc ) ||
292  ( expected_size != recv_size ) ) {
293 
294  int local_rank = 0 ;
295 
296  MPI_Comm_rank( mpi_comm , & local_rank );
297 
298  std::ostringstream msg ;
299  msg << "VectorImport error:"
300  << " P" << local_rank
301  << " received from P" << recv_proc
302  << " size " << recv_size
303  << " expected " << expected_size
304  << " from P" << expected_proc ;
305  throw std::runtime_error( msg.str() );
306  }
307  }
308 
309  // Copy received data to device memory.
310 
311  if ( ! ReceiveInPlace ) { Kokkos::deep_copy( recv_vector , host_recv_buffer ); }
312  }
313 };
314 
315 /*
316 template< class CommMessageType , class CommIdentType ,
317  class S, class L, class D, class M >
318 class VectorImport< CommMessageType, CommIdentType,
319  Kokkos::View<S,L,D,M,Kokkos::Impl::ViewMPVectorContiguous> >
320 {
321 public:
322 
323  typedef Kokkos::Impl::ViewMPVectorContiguous Specialize;
324  typedef Kokkos::View<S,L,D,M,Specialize> VectorType;
325 
326 private:
327 
328  typedef typename VectorType::flat_array_type FlatVectorType;
329  typedef VectorImport<CommMessageType, CommIdentType, FlatVectorType> FlatVectorImportType;
330 
331  FlatVectorImportType flat_import;
332 
333 public:
334 
335  VectorImport( const Teuchos::RCP<const Teuchos::Comm<int> > & arg_comm ,
336  const CommMessageType & arg_recv_msg ,
337  const CommMessageType & arg_send_msg ,
338  const CommIdentType & arg_send_nodeid ,
339  const unsigned arg_count_owned ,
340  const unsigned arg_count_receive ) :
341  flat_import( arg_comm,
342  arg_recv_msg,
343  arg_send_msg,
344  arg_send_nodeid,
345  arg_count_owned,
346  arg_count_receive ) {}
347 
348  inline void operator()( const VectorType & v ) const
349  {
350  FlatVectorType flat_v = v;
351  flat_import(flat_v);
352  }
353 
354 };
355 */
356 
357 } // namespace Example
358 } // namespace Kokkos
359 
360 #endif
361 
362 //----------------------------------------------------------------------------
363 
364 #endif /* #ifndef KOKKOS_VECTORIMPORT_HPP */
Kokkos::DefaultExecutionSpace execution_space
void operator()(const VectorType &) const
const Teuchos::RCP< const Teuchos::Comm< int > > comm
void deep_copy(const Stokhos::CrsMatrix< ValueType, DstDevice, Layout > &dst, const Stokhos::CrsMatrix< ValueType, SrcDevice, Layout > &src)
VectorImport(const Teuchos::RCP< const Teuchos::Comm< int > > arg_comm, const CommMessageType &, const CommMessageType &, const CommIdentType &, const unsigned arg_count_owned, const unsigned arg_count_receive)
Stokhos::CrsMatrix< ValueType, Device, Layout >::HostMirror create_mirror_view(const Stokhos::CrsMatrix< ValueType, Device, Layout > &A)