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 //@HEADER
2 // ************************************************************************
3 //
4 // Kokkos v. 4.0
5 // Copyright (2022) National Technology & Engineering
6 // Solutions of Sandia, LLC (NTESS).
7 //
8 // Under the terms of Contract DE-NA0003525 with NTESS,
9 // the U.S. Government retains certain rights in this software.
10 //
11 // Part of Kokkos, under the Apache License v2.0 with LLVM Exceptions.
12 // See https://kokkos.org/LICENSE for license information.
13 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
14 //
15 //@HEADER
16 
17 #ifndef KOKKOS_VECTORIMPORT_HPP
18 #define KOKKOS_VECTORIMPORT_HPP
19 
20 #include <utility>
21 #include <limits>
22 #include <iostream>
23 #include <sstream>
24 #include <stdexcept>
25 
26 #include <Kokkos_Core.hpp>
27 
28 #include <Teuchos_CommHelpers.hpp>
29 
30 namespace Kokkos {
31 namespace Example {
32 
33 template< class CommMessageType , class CommIdentType , class VectorType >
34 class VectorImport ;
35 
36 } // namespace Example
37 } // namespace Kokkos
38 
39 #if ! defined( KOKKOS_ENABLE_MPI )
40 
41 //----------------------------------------------------------------------------
42 //----------------------------------------------------------------------------
43 
44 namespace Kokkos {
45 namespace Example {
46 
47 template< class CommMessageType , class CommIdentType , class VectorType >
48 struct VectorImport {
49 
51  const unsigned count_owned ;
52  const unsigned count_receive ;
53 
54  VectorImport( const Teuchos::RCP<const Teuchos::Comm<int> > arg_comm ,
55  const CommMessageType & ,
56  const CommMessageType & ,
57  const CommIdentType & ,
58  const unsigned arg_count_owned ,
59  const unsigned arg_count_receive )
60  : comm( arg_comm )
61  , count_owned( arg_count_owned )
62  , count_receive( arg_count_receive )
63  {}
64 
65  inline
66  void operator()( const VectorType & ) const {}
67 };
68 
69 
70 } // namespace Example
71 } // namespace Kokkos
72 
73 //----------------------------------------------------------------------------
74 //----------------------------------------------------------------------------
75 
76 #else /* defined( KOKKOS_ENABLE_MPI ) */
77 
79 
80 namespace Kokkos {
81 namespace Example {
82 
83 template< class CommMessageType , class CommIdentType , class VectorType >
84 class VectorImport {
85 private:
86 
87  // rank == 1 or array_layout == LayoutRight
88  static_assert(
89  ( VectorType::rank == 1 ) ||
90  std::is_same< typename VectorType::array_layout , Kokkos::LayoutRight >::value,
91  "Kokkos::Example::VectorImport Assert Fail: rank != 1 or array_layout != LayoutRight" );
92 
93  typedef typename VectorType::HostMirror HostVectorType ;
94  typedef typename CommMessageType::HostMirror HostCommMessageType;
95 
96  enum { ReceiveInPlace =
97  std::is_same< typename VectorType::memory_space ,
98  typename HostVectorType::memory_space >::value };
99 
100  const CommMessageType recv_msg ;
101  const CommMessageType send_msg ;
102  const CommIdentType send_nodeid ;
103  HostCommMessageType host_recv_msg ;
104  HostCommMessageType host_send_msg ;
105  VectorType send_buffer ;
106  HostVectorType host_send_buffer ;
107  HostVectorType host_recv_buffer ;
108  unsigned chunk ;
109 
110 public:
111 
113  const unsigned count_owned ;
114  const unsigned count_receive ;
115 
116  struct Pack {
118  const CommIdentType index ;
119  const VectorType source ;
120  const VectorType buffer ;
121 
122  KOKKOS_INLINE_FUNCTION
123  void operator()( const unsigned i ) const
124  { buffer( i ) = source( index(i) ); }
125 
126  Pack( const CommIdentType & arg_index ,
127  const VectorType & arg_source ,
128  const VectorType & arg_buffer )
129  : index( arg_index )
130  , source( arg_source )
131  , buffer( arg_buffer )
132  {
133  Kokkos::parallel_for( index.extent(0) , *this );
134  execution_space().fence();
135  }
136  };
137 
138  VectorImport( const Teuchos::RCP<const Teuchos::Comm<int> > & arg_comm ,
139  const CommMessageType & arg_recv_msg ,
140  const CommMessageType & arg_send_msg ,
141  const CommIdentType & arg_send_nodeid ,
142  const unsigned arg_count_owned ,
143  const unsigned arg_count_receive )
144  : recv_msg( arg_recv_msg )
145  , send_msg( arg_send_msg )
146  , send_nodeid( arg_send_nodeid )
147  , host_recv_msg()
148  , host_send_msg()
149  , send_buffer()
150  , host_send_buffer()
151  , host_recv_buffer()
152  , comm( arg_comm )
153  , count_owned( arg_count_owned )
154  , count_receive( arg_count_receive )
155  {
156  host_recv_msg = Kokkos::create_mirror_view( recv_msg );
157  host_send_msg = Kokkos::create_mirror_view( send_msg );
158  Kokkos::deep_copy( host_recv_msg , recv_msg );
159  Kokkos::deep_copy( host_send_msg , send_msg );
160  if ( ! ReceiveInPlace ) {
161  host_recv_buffer = HostVectorType("recv_buffer",count_receive);
162  }
163 
164  unsigned send_count = 0 ;
165  for ( unsigned i = 0 ; i < send_msg.extent(0) ; ++i ) { send_count += host_send_msg(i,1); }
166  send_buffer = VectorType("send_buffer",send_count);
167  host_send_buffer = Kokkos::create_mirror_view( send_buffer );
168  }
169 
170  inline
171  void operator()( const VectorType & v ) const
172  {
173  typedef typename VectorType::value_type scalar_type ;
174  typedef typename HostVectorType::value_type host_scalar_type ;
175 
176  const Teuchos::MpiComm<int> & teuchos_mpi_comm = dynamic_cast< const Teuchos::MpiComm<int> & >( *comm );
177 
178  MPI_Comm mpi_comm = * teuchos_mpi_comm.getRawMpiComm();
179 
180  const int mpi_tag = 42 ;
181  const unsigned chunk = v.extent(1);
182 
183  // Subvector for receives
184  const std::pair<unsigned,unsigned> recv_range( count_owned , count_owned + count_receive );
185  const VectorType recv_vector = Kokkos::subview( v , recv_range );
186 
187  std::vector< MPI_Request > recv_request( recv_msg.extent(0) , MPI_REQUEST_NULL );
188 
189  // Post receives
190  if (ReceiveInPlace) {
191  scalar_type * ptr = recv_vector.data();
192 
193  for ( size_t i = 0 ; i < recv_msg.extent(0) ; ++i ) {
194  const int proc = host_recv_msg(i,0);
195  const int count = host_recv_msg(i,1) * chunk ;
196 
197  MPI_Irecv( ptr , count * sizeof(scalar_type) , MPI_BYTE ,
198  proc , mpi_tag , mpi_comm , & recv_request[i] );
199 
200  ptr += count ;
201  }
202  }
203  else {
204  host_scalar_type * ptr = host_recv_buffer.data();
205 
206  for ( size_t i = 0 ; i < recv_msg.extent(0) ; ++i ) {
207  const int proc = host_recv_msg(i,0);
208  const int count = host_recv_msg(i,1) * chunk ;
209 
210  MPI_Irecv( ptr , count * sizeof(host_scalar_type) , MPI_BYTE ,
211  proc , mpi_tag , mpi_comm , & recv_request[i] );
212 
213  ptr += count ;
214  }
215 
216  }
217 
218  MPI_Barrier( mpi_comm );
219 
220  { // Pack and send
221  const Pack pack( send_nodeid , v , send_buffer );
222 
223  Kokkos::deep_copy( host_send_buffer , send_buffer );
224 
225  host_scalar_type * ptr = host_send_buffer.data();
226 
227  for ( size_t i = 0 ; i < send_msg.extent(0) ; ++i ) {
228  const int proc = host_send_msg(i,0);
229  const int count = host_send_msg(i,1) * chunk ;
230 
231  // MPI_Ssend blocks until
232  // (1) a receive is matched for the message and
233  // (2) the send buffer can be re-used.
234  //
235  // It is suggested that MPI_Ssend will have the best performance:
236  // http://www.mcs.anl.gov/research/projects/mpi/sendmode.html .
237 
238  MPI_Ssend( ptr ,
239  count * sizeof(host_scalar_type) , MPI_BYTE ,
240  proc , mpi_tag , mpi_comm );
241 
242  ptr += count ;
243  }
244  }
245 
246  // Wait for receives and verify:
247 
248  for ( size_t i = 0 ; i < recv_msg.extent(0) ; ++i ) {
249  MPI_Status recv_status ;
250  int recv_which = 0 ;
251  int recv_size = 0 ;
252 
253  MPI_Waitany( recv_msg.extent(0) , & recv_request[0] , & recv_which , & recv_status );
254 
255  const int recv_proc = recv_status.MPI_SOURCE ;
256 
257  MPI_Get_count( & recv_status , MPI_BYTE , & recv_size );
258 
259  // Verify message properly received:
260 
261  const int expected_proc = host_recv_msg(recv_which,0);
262  const int expected_size = host_recv_msg(recv_which,1) * chunk * sizeof(scalar_type);
263 
264  if ( ( expected_proc != recv_proc ) ||
265  ( expected_size != recv_size ) ) {
266 
267  int local_rank = 0 ;
268 
269  MPI_Comm_rank( mpi_comm , & local_rank );
270 
271  std::ostringstream msg ;
272  msg << "VectorImport error:"
273  << " P" << local_rank
274  << " received from P" << recv_proc
275  << " size " << recv_size
276  << " expected " << expected_size
277  << " from P" << expected_proc ;
278  throw std::runtime_error( msg.str() );
279  }
280  }
281 
282  // Copy received data to device memory.
283 
284  if ( ! ReceiveInPlace ) { Kokkos::deep_copy( recv_vector , host_recv_buffer ); }
285  }
286 };
287 
288 /*
289 template< class CommMessageType , class CommIdentType ,
290  class S, class L, class D, class M >
291 class VectorImport< CommMessageType, CommIdentType,
292  Kokkos::View<S,L,D,M,Kokkos::Impl::ViewMPVectorContiguous> >
293 {
294 public:
295 
296  typedef Kokkos::Impl::ViewMPVectorContiguous Specialize;
297  typedef Kokkos::View<S,L,D,M,Specialize> VectorType;
298 
299 private:
300 
301  typedef typename VectorType::flat_array_type FlatVectorType;
302  typedef VectorImport<CommMessageType, CommIdentType, FlatVectorType> FlatVectorImportType;
303 
304  FlatVectorImportType flat_import;
305 
306 public:
307 
308  VectorImport( const Teuchos::RCP<const Teuchos::Comm<int> > & arg_comm ,
309  const CommMessageType & arg_recv_msg ,
310  const CommMessageType & arg_send_msg ,
311  const CommIdentType & arg_send_nodeid ,
312  const unsigned arg_count_owned ,
313  const unsigned arg_count_receive ) :
314  flat_import( arg_comm,
315  arg_recv_msg,
316  arg_send_msg,
317  arg_send_nodeid,
318  arg_count_owned,
319  arg_count_receive ) {}
320 
321  inline void operator()( const VectorType & v ) const
322  {
323  FlatVectorType flat_v = v;
324  flat_import(flat_v);
325  }
326 
327 };
328 */
329 
330 } // namespace Example
331 } // namespace Kokkos
332 
333 #endif
334 
335 //----------------------------------------------------------------------------
336 
337 #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)