Salome HOME
196fd41b6a6bf1eefd4e8140a60ee7842b8f1668
[tools/medcoupling.git] / src / ParaMEDMEM / MPIAccess.hxx
1 // Copyright (C) 2007-2019  CEA/DEN, EDF R&D
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19
20 #ifndef __MPIACCESS_HXX__
21 #define __MPIACCESS_HXX__
22
23 #include "CommInterface.hxx"
24 #include "ProcessorGroup.hxx"
25 #include "MPIProcessorGroup.hxx"
26
27 #include <map>
28 #include <list>
29 #include <vector>
30 #include <iostream>
31
32 namespace MEDCoupling
33 {
34   typedef struct
35   {
36     double time ;
37     double deltatime ;
38     int tag ;
39   } TimeMessage;
40   
41   static MPI_Request mpirequestnull = MPI_REQUEST_NULL ;
42   enum _MessageIdent { _message_unknown, _message_time, _message_int, _message_double } ;
43
44   class MPIAccess
45   {
46   private:
47     struct RequestStruct
48     {
49       int MPITarget ;
50       bool MPIIsRecv ;
51       int MPITag ;
52       bool MPIAsynchronous ;
53       bool MPICompleted ;
54       MPI_Datatype MPIDatatype ;
55       MPI_Request MPIRequest ;
56       MPI_Status *MPIStatus ;
57       int MPIOutCount ;
58     };
59   public:
60     MPIAccess(MPIProcessorGroup * ProcessorGroup, int BaseTag=0, int MaxTag=0) ;
61     virtual ~MPIAccess() ;
62
63     void trace( bool trace = true ) ;
64
65     void deleteRequest( int RequestId ) ;
66     void deleteRequests(int size , int *ArrayOfSendRequests ) ;
67
68     int sendMPITag(int destrank) ;
69     int recvMPITag(int sourcerank) ;
70
71     int sendRequestIdsSize() ;
72     int sendRequestIds(int size, int *ArrayOfSendRequests) ;
73     int recvRequestIdsSize() ;
74     int recvRequestIds(int size, int *ArrayOfRecvRequests) ;
75
76     int sendRequestIdsSize(int destrank) ;
77     int sendRequestIds(int destrank, int size, int *ArrayOfSendRequests) ;
78     int recvRequestIdsSize(int sourcerank) ;
79     int recvRequestIds(int sourcerank, int size, int *ArrayOfRecvRequests) ;
80
81     int send(void* buffer, int count, MPI_Datatype datatype, int target,
82              int &RequestId) ;
83     int ISend(void* buffer, int count, MPI_Datatype datatype, int target,
84               int &RequestId) ;
85     int recv(void* buffer, int count, MPI_Datatype datatype, int source,
86              int &RequestId, int *OutCount=NULL) ;
87     int IRecv(void* buffer, int count, MPI_Datatype datatype, int source,
88               int &RequestId) ;
89     int sendRecv(void* sendbuf, int sendcount, MPI_Datatype sendtype, int dest,
90                  int &SendRequestId, void* recvbuf, int recvcount,
91                  MPI_Datatype recvtype, int source,
92                  int &RecvRequestId, int *OutCount=NULL) ;
93     int ISendRecv(void* sendbuf, int sendcount, MPI_Datatype sendtype, int dest,
94                   int &SendRequestId, void* recvbuf, int recvcount,
95                   MPI_Datatype recvtype, int source, int &RecvRequestId) ;
96
97     int wait(int RequestId) ;
98     int test(int RequestId, int &flag) ;
99     int waitAny(int count, int *array_of_RequestIds, int &RequestId) ;
100     int testAny(int count, int *array_of_RequestIds, int &RequestId, int &flag)  ;
101     int waitAll(int count, int *array_of_RequestIds) ;
102     int testAll(int count, int *array_of_RequestIds, int &flag)  ;
103     int waitSome(int count, int *array_of_RequestIds, int outcount,
104                  int *outarray_of_RequestIds) ;
105     int testSome(int count, int *array_of_RequestIds, int outcounts,
106                  int *outarray_of_RequestIds) ;
107     int probe(int FromSource, int &source, int &MPITag, MPI_Datatype &datatype,
108               int &outcount) ;
109     int IProbe(int FromSource, int &source, int &MPITag, MPI_Datatype &datatype,
110                int &outcount, int &flag) ;
111     int cancel( int RecvRequestId, int &flag ) ; 
112     int cancel( int source, int MPITag, MPI_Datatype datatype, int outcount,
113                 int &flag ) ;
114     int cancelAll() ;
115     int barrier() ;
116     int errorString(int errorcode, char *string, int *resultlen) const ;
117     int status(int RequestId, int &source, int &tag, int &error, int &outcount,
118                bool keepRequestStruct=false) ;
119     int requestFree( MPI_Request *request ) ;
120
121     void check() const ;
122
123     MPI_Datatype timeType() const ;
124     bool isTimeMessage( int MPITag ) const ;
125     MPI_Aint timeExtent() const ;
126     MPI_Aint intExtent() const ;
127     MPI_Aint longExtent() const ;
128     MPI_Aint doubleExtent() const ;
129     MPI_Aint extent( MPI_Datatype datatype ) const ;
130
131     int MPITag( int RequestId ) ;
132     int MPITarget( int RequestId ) ;
133     bool MPIIsRecv( int RequestId ) ;
134     bool MPIAsynchronous( int RequestId ) ;
135     bool MPICompleted( int RequestId ) ;
136     MPI_Datatype MPIDatatype( int RequestId ) ;
137     int MPIOutCount( int RequestId ) ;
138
139   private:
140     int newRequest( MPI_Datatype datatype, int tag , int destsourcerank ,
141                     bool fromsourcerank , bool asynchronous ) ;
142     int newSendTag( MPI_Datatype datatype, int destrank , int method ,
143                     bool asynchronous, int &RequestId ) ;
144     int newRecvTag( MPI_Datatype datatype, int sourcerank , int method ,
145                     bool asynchronous, int &RequestId ) ;
146     int incrTag( int prevtag ) ;
147     int valTag( int tag, int method ) ;
148
149     void deleteSendRecvRequest( int RequestId ) ;
150
151     void deleteStatus( int RequestId ) ;
152
153     MPI_Request *MPIRequest( int RequestId ) ;
154     MPI_Status *MPIStatus( int RequestId ) ;
155     void setMPICompleted( int RequestId , bool completed ) ;
156     void setMPIOutCount( int RequestId , int outcount ) ;
157     void clearMPIStatus( int RequestId ) ;
158
159     _MessageIdent methodId( MPI_Datatype datatype ) const ;
160     MPI_Datatype datatype( _MessageIdent aMethodIdent ) const ;
161   private:
162     const CommInterface &_comm_interface ;
163     const MPI_Comm* _intra_communicator ;
164     MPIProcessorGroup * _processor_group ;
165     int _processor_group_size ;
166     int _my_rank ;
167     bool _trace ;
168     int _base_request ;
169     int _max_request ;
170     int _request ;
171     int * _send_request ;
172     int * _recv_request ;
173     std::vector< std::list< int > > _send_requests ;
174     std::vector< std::list< int > > _recv_requests ;
175     int _base_MPI_tag ;
176     int _max_MPI_tag ;
177     int * _send_MPI_tag ;
178     int * _recv_MPI_Tag ;
179     MPI_Datatype _MPI_TIME ;
180     static const int MODULO_TAG=10;
181     std::map< int , RequestStruct * > _map_of_request_struct ;
182
183   };
184
185   inline void MPIAccess::trace( bool atrace )
186   {
187     _trace = atrace ;
188   }
189
190   // Delete the structure Request corresponding to RequestId identifier after
191   // the deletion of the structures MPI_Request * and MPI_Status *
192   // remove it from _MapOfRequestStruct (erase)
193   inline void MPIAccess::deleteRequest( int RequestId )
194   {
195     struct RequestStruct *aRequestStruct = _map_of_request_struct[ RequestId ] ;
196     if ( aRequestStruct )
197       {
198         if ( _trace )
199           std::cout << "MPIAccess::DeleteRequest" << _my_rank << "( " << RequestId << " ) "
200                     << aRequestStruct << " MPIRequest " << aRequestStruct->MPIRequest
201                     << " MPIIsRecv " << aRequestStruct->MPIIsRecv << std::endl ;
202         if ( _map_of_request_struct[RequestId]->MPIRequest != MPI_REQUEST_NULL )
203           requestFree( &_map_of_request_struct[RequestId]->MPIRequest ) ;
204         deleteSendRecvRequest( RequestId ) ;
205         deleteStatus( RequestId ) ;
206         _map_of_request_struct.erase( RequestId ) ;
207         delete aRequestStruct ;
208       }
209     else
210       {
211         if ( _trace )
212           std::cout << "MPIAccess::DeleteRequest" << _my_rank << "( " << RequestId
213                     << " ) Request not found" << std::endl ;
214       }
215   }
216
217   // Delete all requests of the array ArrayOfSendRequests
218   inline void MPIAccess::deleteRequests(int size , int *ArrayOfSendRequests )
219   {
220     for (int i = 0 ; i < size ; i++ )
221       deleteRequest( ArrayOfSendRequests[i] ) ;
222   }
223
224   // Returns the last MPITag of the destination rank destrank
225   inline int MPIAccess::sendMPITag(int destrank)
226   {
227     return _send_MPI_tag[destrank] ;
228   }
229
230   // Returns the last MPITag of the source rank sourcerank
231   inline int MPIAccess::recvMPITag(int sourcerank)
232   {
233     return _recv_MPI_Tag[sourcerank] ;
234   }
235
236   // Returns the number of all SendRequestIds matching a destination rank. It may be
237   // used to allocate ArrayOfSendRequests for the call to SendRequestIds
238   inline int MPIAccess::sendRequestIdsSize(int destrank)
239   {
240     return (int)_send_requests[destrank].size() ;
241   }
242
243   // Returns the number of all RecvRequestIds matching a source rank. It may be
244   // used to allocate ArrayOfRecvRequests for the call to RecvRequestIds
245   inline int MPIAccess::recvRequestIdsSize(int sourcerank)
246   {
247     return (int)_recv_requests[sourcerank].size() ;
248   }
249
250   // Returns the MPI_Datatype (registered in MPI in the constructor with
251   // MPI_Type_struct and MPI_Type_commit) for TimeMessages
252   inline MPI_Datatype MPIAccess::timeType() const
253   {
254     return _MPI_TIME ;
255   }
256   
257   // Returns true if the tag MPITag corresponds to a TimeMessage
258   inline bool MPIAccess::isTimeMessage( int aMPITag ) const
259   {
260     return ((aMPITag%MODULO_TAG) == _message_time) ;
261   }
262
263   // Returns the MPI size of the MPI_Datatype datatype
264   inline MPI_Aint MPIAccess::extent( MPI_Datatype adatatype ) const
265   {
266     if ( adatatype == _MPI_TIME )
267       return timeExtent() ;
268     if ( adatatype == MPI_INT )
269       return intExtent() ;
270     if ( adatatype == MPI_LONG )
271       return longExtent() ;
272     if ( adatatype == MPI_DOUBLE )
273       return doubleExtent() ;
274     return 0 ;
275   }
276   
277   // Returns the MPITag of the request corresponding to RequestId identifier
278   inline int MPIAccess::MPITag( int RequestId )
279   {
280     struct RequestStruct *aRequestStruct = _map_of_request_struct[ RequestId ] ;
281     if ( aRequestStruct )
282       return aRequestStruct->MPITag ;
283     return -1 ;
284   }
285   
286   // Returns the MPITarget of the request corresponding to RequestId identifier
287   inline int MPIAccess::MPITarget( int RequestId )
288   {
289     struct RequestStruct *aRequestStruct = _map_of_request_struct[ RequestId ] ;
290     if ( aRequestStruct )
291       return aRequestStruct->MPITarget ;
292     return -1 ;
293   }
294
295   // Returns true if the request corresponding to RequestId identifier was [I]Recv
296   inline bool MPIAccess::MPIIsRecv( int RequestId )
297   {
298     struct RequestStruct *aRequestStruct = _map_of_request_struct[ RequestId ] ;
299     if ( aRequestStruct )
300       return aRequestStruct->MPIIsRecv ;
301     return false ;
302   }
303
304   // Returns true if the request corresponding to RequestId identifier was asynchronous
305   inline bool MPIAccess::MPIAsynchronous( int RequestId )
306   {
307     struct RequestStruct *aRequestStruct = _map_of_request_struct[ RequestId ] ;
308     if ( aRequestStruct )
309       return aRequestStruct->MPIAsynchronous ;
310     return false ;
311   }
312   
313   // Returns true if the request corresponding to RequestId identifier was completed
314   inline bool MPIAccess::MPICompleted( int RequestId )
315   {
316     struct RequestStruct *aRequestStruct = _map_of_request_struct[ RequestId ] ;
317     if ( aRequestStruct )
318       return aRequestStruct->MPICompleted;
319     return true ;
320   }
321
322   // Returns the MPI_datatype  of the request corresponding to RequestId identifier
323   inline MPI_Datatype MPIAccess::MPIDatatype( int RequestId )
324   {
325     struct RequestStruct *aRequestStruct = _map_of_request_struct[ RequestId ] ;
326     if ( aRequestStruct )
327       return aRequestStruct->MPIDatatype;
328     return MPI_DATATYPE_NULL;
329   }
330
331   // Returns the size of the receiving message of the request corresponding to
332   // RequestId identifier
333   inline int MPIAccess::MPIOutCount( int RequestId )
334   {
335     struct RequestStruct *aRequestStruct = _map_of_request_struct[ RequestId ] ;
336     if ( aRequestStruct )
337       return aRequestStruct->MPIOutCount;
338     return 0 ;
339   }
340
341   // Increments the previous tag value (cyclically)
342   // Look at MPIAccess::NewSendTag/NewRecvTag in MPIAccess.cxx
343   inline int MPIAccess::incrTag( int prevtag )
344   {
345     int tag;
346     if ( (prevtag % MODULO_TAG) == _message_time )
347       tag = ((prevtag/MODULO_TAG)*MODULO_TAG);
348     else
349       tag = ((prevtag/MODULO_TAG + 1)*MODULO_TAG);
350     if ( tag > _max_MPI_tag )
351       tag = _base_MPI_tag ;
352     return tag ;
353   }
354
355   // Returns the MPITag with the method-type field
356   // Look at MPIAccess::NewSendTag/NewRecvTag in MPIAccess.cxx
357   inline int MPIAccess::valTag( int tag, int method )
358   {
359     return ((tag/MODULO_TAG)*MODULO_TAG) + method;
360   }
361   
362   // Remove a Request identifier from the list _RecvRequests/_SendRequests for
363   // the corresponding target.
364   inline void MPIAccess::deleteSendRecvRequest( int RequestId )
365   {
366     if ( _trace )
367       std::cout << "MPIAccess::DeleteSendRecvRequest" << _my_rank
368                 << "( " << RequestId << " ) " << std::endl ;
369     if ( MPIIsRecv( RequestId ) )
370       _recv_requests[ MPITarget( RequestId ) ].remove( RequestId );
371     else
372       _send_requests[ MPITarget( RequestId ) ].remove( RequestId );
373   }
374
375   // Delete the MPI structure MPI_status * of a ReaquestId
376   inline void MPIAccess::deleteStatus( int RequestId )
377   {
378     if ( _map_of_request_struct[RequestId]->MPIStatus != NULL )
379       {
380         delete _map_of_request_struct[RequestId]->MPIStatus ;
381         clearMPIStatus( RequestId ) ;
382       }
383   }
384
385   // Returns the MPI structure MPI_request * of a RequestId
386   inline MPI_Request * MPIAccess::MPIRequest( int RequestId )
387   {
388     struct RequestStruct *aRequestStruct = _map_of_request_struct[ RequestId ] ;
389     if ( aRequestStruct )
390       return &aRequestStruct->MPIRequest;
391     return &mpirequestnull ;
392   }
393   
394   // Returns the MPI structure MPI_status * of a RequestId
395   inline MPI_Status * MPIAccess::MPIStatus( int RequestId )
396   {
397     struct RequestStruct *aRequestStruct = _map_of_request_struct[ RequestId ];
398     if ( aRequestStruct )
399       return aRequestStruct->MPIStatus;
400     return NULL ;
401   }
402
403   // Set the MPICompleted field of the structure Request corresponding to RequestId
404   // identifier with the value completed
405   inline void MPIAccess::setMPICompleted( int RequestId , bool completed )
406   {
407     struct RequestStruct *aRequestStruct = _map_of_request_struct[ RequestId ] ;
408     if ( aRequestStruct )
409       aRequestStruct->MPICompleted = completed;
410   }
411
412   // Set the MPIOutCount field of the structure Request corresponding to RequestId
413   // identifier with the value outcount
414   inline void MPIAccess::setMPIOutCount( int RequestId , int outcount )
415   {
416     struct RequestStruct *aRequestStruct = _map_of_request_struct[ RequestId ] ;
417     if ( aRequestStruct )
418       aRequestStruct->MPIOutCount = outcount;
419   }
420
421   // Nullify the MPIStatusfield of the structure Request corresponding to RequestId
422   // identifier
423   inline void MPIAccess::clearMPIStatus( int RequestId )
424   {
425     struct RequestStruct *aRequestStruct = _map_of_request_struct[ RequestId ] ;
426     if ( aRequestStruct )
427       aRequestStruct->MPIStatus = NULL ;
428   }
429
430   // Returns the _MessageIdent enum value corresponding to the MPI_Datatype datatype
431   // Look at MPIAccess::NewSendTag/NewRecvTag in MPIAccess.cxx
432   inline _MessageIdent MPIAccess::methodId( MPI_Datatype adatatype ) const
433   {
434     _MessageIdent aMethodIdent ;
435     if ( adatatype == _MPI_TIME )
436       aMethodIdent = _message_time;
437     else if ( adatatype == MPI_INT )
438       aMethodIdent = _message_int ;
439     else if ( adatatype == MPI_DOUBLE )
440       aMethodIdent = _message_double ;
441     else
442       aMethodIdent = _message_unknown ;
443     return aMethodIdent ;
444   }
445   
446   // Returns the MPI_Datatype corresponding to the _MessageIdent enum aMethodIdent
447   inline MPI_Datatype MPIAccess::datatype( _MessageIdent aMethodIdent ) const
448   {
449     MPI_Datatype aDataType ;
450     switch( aMethodIdent )
451       {
452       case _message_time :
453         aDataType = _MPI_TIME ;
454         break ;
455       case _message_int :
456         aDataType = MPI_INT ;
457         break ;
458       case _message_double :
459         aDataType = MPI_DOUBLE ;
460         break ;
461       default :
462         aDataType = (MPI_Datatype) -1 ;
463         break ;
464       }
465     return aDataType ;
466   }
467
468   std::ostream & operator<< (std::ostream &,const _MessageIdent &);
469
470   std::ostream & operator<< (std::ostream &,const TimeMessage &);
471
472 }
473
474 #endif