Salome HOME
Copyright update 2021
[tools/medcoupling.git] / src / ParaMEDMEM / MPIAccess / MPIAccess.cxx
1 // Copyright (C) 2007-2021  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 #include "MPIAccess/MPIAccess.hxx"
21
22 #include "InterpolationUtils.hxx"
23
24 #include <iostream>
25
26 using namespace std;
27
28 namespace MEDCoupling
29 {
30   /**!
31     \anchor MPIAccess-det
32     \class MPIAccess
33
34     The class \a MPIAccess is the gateway to the MPI library.
35     It is a helper class that gathers the calls to the MPI
36     library that are made in the ParaMEDMEM library. This gathering
37     allows easier gathering of information about the communication
38     in the library. With MPIAccess, tags are managed automatically
39     and asynchronous operations are easier.
40
41     It is typically called after the MPI_Init() call in a program. It is afterwards passed as a parameter to the constructors of ParaMEDMEM objects so that they access the MPI library via the MPIAccess.
42
43     As an example, the following code initializes a processor group made of the zero processor.
44
45     \verbatim
46     #include "MPIAccess.hxx"
47     #include "ProcessorGroup.hxx"
48
49     int main(int argc, char** argv)
50     {
51     //initialization
52     MPI_Init(&argc, &argv);
53     MEDCoupling::CommInterface comm_interface;
54
55     //setting up a processor group with proc 0
56     set<int> procs;
57     procs.insert(0);
58     MEDCoupling::ProcessorGroup group(procs, comm_interface);
59
60     MEDCoupling::MPIAccess mpi_access(group);
61
62     //cleanup
63     MPI_Finalize();
64     }
65     \endverbatim
66   */
67
68
69   /*! Creates a MPIAccess that is based on the processors included in \a ProcessorGroup.
70     This class may be called for easier use of MPI API.
71
72     \param ProcessorGroup MPIProcessorGroup object giving access to group management
73     \param BaseTag and MaxTag define the range of tags to be used.
74     Tags are managed by MPIAccess. They are cyclically incremented.
75     When there is a Send or a Receive operation there is a new RequestId tag returned
76     to the caller. That RequestId may be used to manage the operation Wait, Check of
77     status etc... The MPITag internally managed by MPIAccess is used as "tag" argument
78     in MPI call.
79   */
80
81   MPIAccess::MPIAccess(MPIProcessorGroup * ProcessorGroup, int BaseTag, int MaxTag) :
82     _comm_interface( ProcessorGroup->getCommInterface() ) ,
83     _intra_communicator( ProcessorGroup->getComm() )
84   {
85     void *v ;
86     int mpitagub ;
87     int flag ;
88     //MPI_Comm_get_attr does not run with _IntraCommunicator ???
89     //MPI_Comm_get_attr(*_IntraCommunicator,MPID_TAG_UB,&mpitagub,&flag) ;
90     MPI_Comm_get_attr(MPI_COMM_WORLD,MPI_TAG_UB,&v,&flag) ;
91     mpitagub=*(reinterpret_cast<int*>(v));
92     if ( BaseTag != 0 )
93       BaseTag = (BaseTag/MODULO_TAG)*MODULO_TAG ;
94     if ( MaxTag == 0 )
95       MaxTag = (mpitagub/MODULO_TAG-1)*MODULO_TAG ;
96     MPI_Comm_rank( *_intra_communicator, &_my_rank ) ;
97     if ( !flag | (BaseTag < 0) | (BaseTag >= MaxTag) | (MaxTag > mpitagub) )
98       throw INTERP_KERNEL::Exception("wrong call to MPIAccess constructor");
99
100     _processor_group = ProcessorGroup ;
101     _processor_group_size = _processor_group->size() ;
102     _trace = false ;
103
104     _base_request = -1 ;
105     _max_request = std::numeric_limits<int>::max() ;
106     _request = _base_request ;
107     
108     _base_MPI_tag = BaseTag ;
109     _max_MPI_tag = MaxTag ;
110     
111     _send_request = new int[ _processor_group_size ] ;
112     _recv_request = new int[ _processor_group_size ] ;
113
114     _send_requests.resize( _processor_group_size ) ;
115     _recv_requests.resize( _processor_group_size ) ;
116
117     _send_MPI_tag = new int[ _processor_group_size ] ;
118     _recv_MPI_Tag = new int[ _processor_group_size ] ;
119     int i ;
120     for (i = 0 ; i < _processor_group_size ; i++ )
121       {
122         _send_request[ i ] = _max_request ;
123         _recv_request[ i ] = _max_request ;
124         _send_requests[ i ].resize(0) ;
125         _recv_requests[ i ].resize(0) ;
126         _send_MPI_tag[ i ] = _max_MPI_tag ;
127         _recv_MPI_Tag[ i ] = _max_MPI_tag ;
128       }
129     MPI_Datatype array_of_types[3] ;
130     array_of_types[0] = MPI_DOUBLE ;
131     array_of_types[1] = MPI_DOUBLE ;
132     array_of_types[2] = MPI_INT ;
133     int array_of_blocklengths[3] ;
134     array_of_blocklengths[0] = 1 ;
135     array_of_blocklengths[1] = 1 ;
136     array_of_blocklengths[2] = 1 ;
137     MPI_Aint array_of_displacements[3] ;
138     array_of_displacements[0] = 0 ;
139     array_of_displacements[1] = sizeof(double) ;
140     array_of_displacements[2] = 2*sizeof(double) ;
141     MPI_Type_create_struct(3, array_of_blocklengths, array_of_displacements,
142                     array_of_types, &_MPI_TIME) ;
143     MPI_Type_commit(&_MPI_TIME) ;
144   }
145
146   MPIAccess::~MPIAccess()
147   {
148     delete [] _send_request ;
149     delete [] _recv_request ;
150     delete [] _send_MPI_tag ;
151     delete [] _recv_MPI_Tag ;
152     MPI_Type_free(&_MPI_TIME) ;
153   }
154
155   /*
156     MPIAccess and "RequestIds" :
157     ============================
158
159     . WARNING : In the specification document, the distinction
160     between "MPITags" and "RequestIds" is not clear. "MPITags"
161     are arguments of calls to MPI. "RequestIds" does not concern
162     calls to MPI. "RequestIds" are named "tag"as arguments in/out
163     in the MPIAccess API in the specification documentation.
164     But in the implementation we have the right name RequestId (or
165     RecvRequestId/SendRequestId).
166
167     . When we have a MPI write/read request via MPIAccess, we get
168     an identifier "RequestId".
169     That identifier matches a  structure RequestStruct of
170     MPIAccess. The access to that structure is done with the map
171     "_MapOfRequestStruct".
172     That structure RequestStruct give the possibility to manage
173     the structures MPI_Request and MPI_Status * of MPI. It give
174     also the possibility to get information about that request :
175     target, send/recv, tag, [a]synchronous, type, outcount.
176
177     . That identifier is used to control an asynchronous request
178     via MPIAccess : Wait, Test, Probe, etc...
179
180     . In practise "RequestId" is simply an integer fo the interval
181     [0 , 2**32-1]. There is only one such a cyclic for
182     [I]Sends and [I]Recvs.
183
184     . That "RequestIds" and their associated structures give an easy
185     way to manage asynchronous communications.
186     For example we have mpi_access->Wait( int RequestId ) instead of
187     MPI_Wait(MPI_Request *request, MPI_Status *status).
188
189     . The API of MPIAccess may give the "SendRequestIds" of a "target",
190     the "RecvRequestIds" from a "source" or the "SendRequestIds" of
191     all "targets" or the "RecvRequestIds" of all "sources".
192     That avoid to manage them in Presentation-ParaMEDMEM.
193   */
194
195   int MPIAccess::newRequest( MPI_Datatype datatype, int tag , int destsourcerank ,
196                              bool fromsourcerank , bool asynchronous )
197   {
198     RequestStruct *mpiaccessstruct = new RequestStruct;
199     mpiaccessstruct->MPITag = tag ;
200     mpiaccessstruct->MPIDatatype = datatype ;
201     mpiaccessstruct->MPITarget = destsourcerank ;
202     mpiaccessstruct->MPIIsRecv = fromsourcerank ;
203     MPI_Status *aStatus = new MPI_Status ;
204     mpiaccessstruct->MPIStatus = aStatus ;
205     mpiaccessstruct->MPIAsynchronous = asynchronous ;
206     mpiaccessstruct->MPICompleted = !asynchronous ;
207     mpiaccessstruct->MPIOutCount = -1 ;
208     if ( !asynchronous )
209       {
210         mpiaccessstruct->MPIRequest = MPI_REQUEST_NULL ;
211         mpiaccessstruct->MPIStatus->MPI_SOURCE = destsourcerank ;
212         mpiaccessstruct->MPIStatus->MPI_TAG = tag ;
213         mpiaccessstruct->MPIStatus->MPI_ERROR = MPI_SUCCESS ;
214       }
215     if ( _request == _max_request )
216       _request = _base_request ;
217     _request += 1 ;
218     _map_of_request_struct[_request] = mpiaccessstruct ;
219     if ( fromsourcerank )
220       _recv_request[ destsourcerank ] = _request;
221     else
222       _send_request[ destsourcerank ] = _request;
223     if ( _trace )
224       cout << "NewRequest" << _my_rank << "( " << _request << " ) "
225            << mpiaccessstruct << endl ;
226     return _request ;
227   }
228
229   /*
230     MPIAccess and "tags" (or "MPITags") :
231     =====================================
232
233     . The constructor give the possibility to choose an interval of
234     tags to use : [BaseTag , MaxTag].
235     The default is [ 0 , MPI_TAG_UB], MPI_TAG_UB being the maximum
236     value in an implementation of MPI (minimum 32767 = 2**15-1).
237     On awa with the implementation lam MPI_TAG_UB value is
238     7353944. The norm MPI specify that value is the same in all
239     processes started by mpirun.
240     In the case of the use of the same IntraCommunicator in a process
241     for several distinct data flows (or for several IntraCommunicators
242     with common processes), that permits to avoid ambiguity
243     and may help debug.
244
245     . In MPIAccess the tags have two parts (#define MODULO_TAG 10) :
246     + The last decimal digit decimal correspond to MPI_DataType ( 1 for
247     TimeMessages, 2 for MPI_INT and 3 for MPI_DOUBLE)
248     + The value of other digits correspond to a circular number for each
249     message.
250     + A TimeMessage and the associated DataMessage have the same number
251     (but the types are different and the tags also).
252
253     . For a Send of a message from a process "source" to a process
254     "target", we have _send_MPI_tag[target] in the process
255     source (it contains the last "tag" used for the Send of a
256     message to the process target).
257     And in the process "target" which receive that message, we have
258     _recv_MPI_Tag[source] (it contains the last "tag" used for the Recv
259     of messages from the process source).
260     Naturally in the MPI norm the values of that tags must be the same.
261   */
262   int MPIAccess::newSendTag( MPI_Datatype datatype, int destrank , int method ,
263                              bool asynchronous, int &RequestId )
264   {
265     int tag ;
266     tag = incrTag( _send_MPI_tag[destrank] ) ;
267     tag = valTag( tag, method ) ;
268     _send_MPI_tag[ destrank ] = tag ;
269     RequestId = newRequest( datatype, tag, destrank , false , asynchronous ) ;
270     _send_request[ destrank ] = RequestId ;
271     _send_requests[ destrank ].push_back( RequestId ) ;
272     return tag ;
273   }
274
275   int MPIAccess::newRecvTag( MPI_Datatype datatype, int sourcerank , int method ,
276                              bool asynchronous, int &RequestId )
277   {
278     int tag ;
279     tag = incrTag( _recv_MPI_Tag[sourcerank] ) ;
280     tag = valTag( tag, method ) ;
281     _recv_MPI_Tag[ sourcerank ] = tag ;
282     RequestId = newRequest( datatype, tag , sourcerank , true , asynchronous ) ;
283     _recv_request[ sourcerank ] = RequestId ;
284     _recv_requests[ sourcerank ].push_back( RequestId ) ;
285     return tag ;
286   }
287
288   // Returns the number of all SendRequestIds that may be used to allocate
289   // ArrayOfSendRequests for the call to SendRequestIds
290   int MPIAccess::sendRequestIdsSize()
291   {
292     int size = 0;
293     for (int i = 0 ; i < _processor_group_size ; i++ )
294       size += (int)_send_requests[ i ].size() ;
295     return size ;
296   }
297
298   // Returns in ArrayOfSendRequests with the dimension "size" all the
299   // SendRequestIds
300   int MPIAccess::sendRequestIds(int size, int *ArrayOfSendRequests)
301   {
302     int destrank ;
303     int i = 0 ;
304     for ( destrank = 0 ; destrank < _processor_group_size ; destrank++ )
305       {
306         list< int >::const_iterator iter ;
307         for (iter = _send_requests[ destrank ].begin() ; iter != _send_requests[destrank].end() ; iter++ )
308           ArrayOfSendRequests[i++] = *iter ;
309       }
310     return i ;
311   }
312
313   // Returns the number of all RecvRequestIds that may be used to allocate
314   // ArrayOfRecvRequests for the call to RecvRequestIds
315   int MPIAccess::recvRequestIdsSize()
316   {
317     int size = 0 ;
318     for (int i = 0 ; i < _processor_group_size ; i++ )
319       size += (int)_recv_requests[ i ].size() ;
320     return size ;
321   }
322
323   // Returns in ArrayOfRecvRequests with the dimension "size" all the
324   // RecvRequestIds
325   int MPIAccess::recvRequestIds(int size, int *ArrayOfRecvRequests)
326   {
327     int sourcerank ;
328     int i = 0 ;
329     for ( sourcerank = 0 ; sourcerank < _processor_group_size ; sourcerank++ )
330       {
331         list< int >::const_iterator iter ;
332         for (iter = _recv_requests[ sourcerank ].begin() ; iter != _recv_requests[sourcerank].end() ; iter++ )
333           ArrayOfRecvRequests[i++] = *iter ;
334       }
335     return i ;
336   }
337
338   // Returns in ArrayOfSendRequests with the dimension "size" all the
339   // SendRequestIds to a destination rank
340   int MPIAccess::sendRequestIds(int destrank, int size, int *ArrayOfSendRequests)
341   {
342     if (size < (int)_send_requests[destrank].size() )
343       throw INTERP_KERNEL::Exception("wrong call to MPIAccess::SendRequestIds");
344     int i = 0 ;
345     list< int >::const_iterator iter ;
346     for (iter = _send_requests[ destrank ].begin() ; iter != _send_requests[destrank].end() ; iter++ )
347       ArrayOfSendRequests[i++] = *iter ;
348     return (int)_send_requests[destrank].size() ;
349   }
350
351   // Returns in ArrayOfRecvRequests with the dimension "size" all the
352   // RecvRequestIds from a sourcerank
353   int MPIAccess::recvRequestIds(int sourcerank, int size, int *ArrayOfRecvRequests)
354   {
355     if (size < (int)_recv_requests[sourcerank].size() )
356       throw INTERP_KERNEL::Exception("wrong call to MPIAccess::RecvRequestIds");
357     int i = 0 ;
358     list< int >::const_iterator iter ;
359     _recv_requests[ sourcerank ] ;
360     for (iter = _recv_requests[ sourcerank ].begin() ; iter != _recv_requests[sourcerank].end() ; iter++ )
361       ArrayOfRecvRequests[i++] = *iter ;
362     return (int)_recv_requests[sourcerank].size() ;
363   }
364
365   // Send in synchronous mode count values of type datatype from buffer to target
366   // (returns RequestId identifier even if the corresponding structure is deleted :
367   // it is only in order to have the same signature as the asynchronous mode)
368   int MPIAccess::send(void* buffer, int count, MPI_Datatype datatype, int target, int &RequestId)
369   {
370     int sts = MPI_SUCCESS ;
371     RequestId = -1 ;
372     if ( count )
373       {
374         _MessageIdent aMethodIdent = methodId( datatype ) ;
375         int MPItag = newSendTag( datatype, target , aMethodIdent , false , RequestId ) ;
376         if ( aMethodIdent == _message_time )
377           {
378             TimeMessage *aTimeMsg = (TimeMessage *) buffer ;
379             aTimeMsg->tag = MPItag ;
380           }
381         deleteRequest( RequestId ) ;
382         sts = _comm_interface.send(buffer, count, datatype, target, MPItag,
383                                   *_intra_communicator ) ;
384         if ( _trace )
385           cout << "MPIAccess::Send" << _my_rank << " SendRequestId "
386                << RequestId << " count " << count << " target " << target
387                << " MPItag " << MPItag << endl ;
388       }
389     return sts ;
390   }
391
392   // Receive (read) in synchronous mode count values of type datatype in buffer from source
393   // (returns RequestId identifier even if the corresponding structure is deleted :
394   // it is only in order to have the same signature as the asynchronous mode)
395   // The output argument OutCount is optional : *OutCount <= count
396   int MPIAccess::recv(void* buffer, int count, MPI_Datatype datatype, int source, int &RequestId, int *OutCount)
397   {
398     int sts = MPI_SUCCESS ;
399     RequestId = -1 ;
400     if ( OutCount != NULL )
401       *OutCount = -1 ;
402     if ( count )
403       {
404         _MessageIdent aMethodIdent = methodId( datatype ) ;
405         int MPItag = newRecvTag( datatype, source , aMethodIdent , false , RequestId ) ;
406         sts =  _comm_interface.recv(buffer, count, datatype, source, MPItag,
407                                    *_intra_communicator , MPIStatus( RequestId ) ) ;
408         int outcount = 0 ;
409         if ( sts == MPI_SUCCESS )
410           {
411             MPI_Datatype datatype2 = MPIDatatype( RequestId ) ;
412             _comm_interface.getCount(MPIStatus( RequestId ), datatype2, &outcount ) ;
413             setMPIOutCount( RequestId , outcount ) ;
414             setMPICompleted( RequestId , true ) ;
415             deleteStatus( RequestId ) ;
416           }
417         if ( OutCount != NULL )
418           *OutCount = outcount ;
419         if ( _trace )
420           cout << "MPIAccess::Recv" << _my_rank << " RecvRequestId "
421                << RequestId << " count " << count << " source " << source
422                << " MPItag " << MPItag << endl ;
423         deleteRequest( RequestId ) ;
424       }
425     return sts ;
426   }
427
428   // Send in asynchronous mode count values of type datatype from buffer to target
429   // Returns RequestId identifier.
430   int MPIAccess::ISend(void* buffer, int count, MPI_Datatype datatype, int target, int &RequestId)
431   {
432     int sts = MPI_SUCCESS ;
433     RequestId = -1 ;
434     if ( count )
435       {
436         _MessageIdent aMethodIdent = methodId( datatype ) ;
437         int MPItag = newSendTag( datatype, target , aMethodIdent , true , RequestId ) ;
438         if ( aMethodIdent == _message_time )
439           {
440             TimeMessage *aTimeMsg = (TimeMessage *) buffer ;
441             aTimeMsg->tag = MPItag ;
442           }
443         MPI_Request *aSendRequest = MPIRequest( RequestId ) ;
444         if ( _trace )
445           {
446             cout << "MPIAccess::ISend" << _my_rank << " ISendRequestId "
447                  << RequestId << " count " << count << " target " << target
448                  << " MPItag " << MPItag << endl ;
449             if ( MPItag == 1 )
450               cout << "MPIAccess::ISend" << _my_rank << " time "
451                    << ((TimeMessage *)buffer)->time << " " << ((TimeMessage *)buffer)->deltatime
452                    << endl ;
453           }
454         sts = _comm_interface.Isend(buffer, count, datatype, target, MPItag,
455                                    *_intra_communicator , aSendRequest) ;
456       }
457     return sts ;
458   }
459
460   // Receive (read) in asynchronous mode count values of type datatype in buffer from source
461   // returns RequestId identifier.
462   int MPIAccess::IRecv(void* buffer, int count, MPI_Datatype datatype, int source, int &RequestId)
463   {
464     int sts = MPI_SUCCESS ;
465     RequestId = -1 ;
466     if ( count )
467       {
468         _MessageIdent aMethodIdent = methodId( datatype ) ;
469         int MPItag = newRecvTag( datatype, source , aMethodIdent , true , RequestId ) ;
470         MPI_Request *aRecvRequest = MPIRequest( RequestId ) ;
471         if ( _trace )
472           {
473             cout << "MPIAccess::IRecv" << _my_rank << " IRecvRequestId "
474                  << RequestId << " count " << count << " source " << source
475                  << " MPItag " << MPItag << endl ;
476             if ( MPItag == 1 )
477               cout << "MPIAccess::ISend" << _my_rank << " time "
478                    << ((TimeMessage *)buffer)->time << " " << ((TimeMessage *)buffer)->deltatime
479                    << endl ;
480           }
481         sts = _comm_interface.Irecv(buffer, count, datatype, source, MPItag,
482                                    *_intra_communicator , aRecvRequest) ;
483       }
484     return sts ;
485   }
486
487   // Perform a Send and a Recv in synchronous mode
488   int MPIAccess::sendRecv(void* sendbuf, int sendcount, MPI_Datatype sendtype,
489                           int dest, int &SendRequestId,
490                           void* recvbuf, int recvcount, MPI_Datatype recvtype,
491                           int source, int &RecvRequestId, int *OutCount)
492   {
493     int sts = MPI_SUCCESS ;
494     SendRequestId = -1 ;
495     RecvRequestId = -1 ;
496     if ( recvcount )
497       sts = IRecv(recvbuf, recvcount, recvtype, source, RecvRequestId) ;
498     int outcount = -1 ;
499     if ( _trace )
500       cout << "MPIAccess::SendRecv" << _my_rank << " IRecv RecvRequestId "
501            << RecvRequestId << endl ;
502     if ( sts == MPI_SUCCESS )
503       {
504         if ( sendcount )
505           sts = send(sendbuf, sendcount, sendtype, dest, SendRequestId) ;
506         if ( _trace )
507           cout << "MPIAccess::SendRecv" << _my_rank << " Send SendRequestId "
508                << SendRequestId << endl ;
509         if ( sts == MPI_SUCCESS && recvcount )
510           {
511             sts = wait( RecvRequestId ) ;
512             outcount = MPIOutCount( RecvRequestId ) ;
513             if ( _trace )
514               cout << "MPIAccess::SendRecv" << _my_rank << " IRecv RecvRequestId "
515                    << RecvRequestId << " outcount " << outcount << endl ;
516           }
517       }
518     if ( OutCount != NULL )
519       {
520         *OutCount = outcount ;
521         if ( _trace )
522           cout << "MPIAccess::SendRecv" << _my_rank << " *OutCount = " << *OutCount
523                << endl ;
524       }
525     deleteRequest( RecvRequestId ) ;
526     return sts ;
527   }
528
529   // Perform a Send and a Recv in asynchronous mode
530   int MPIAccess::ISendRecv(void* sendbuf, int sendcount, MPI_Datatype sendtype,
531                            int dest, int &SendRequestId,
532                            void* recvbuf, int recvcount, MPI_Datatype recvtype,
533                            int source, int &RecvRequestId)
534   {
535     int sts = MPI_SUCCESS ;
536     SendRequestId = -1 ;
537     RecvRequestId = -1 ;
538     if ( recvcount )
539       sts = IRecv(recvbuf, recvcount, recvtype, source, RecvRequestId) ;
540     if ( sts == MPI_SUCCESS )
541       if ( sendcount )
542         sts = ISend(sendbuf, sendcount, sendtype, dest, SendRequestId) ;
543     return sts ;
544   }
545
546   // Perform a wait of a Send or Recv asynchronous Request
547   // Do nothing for a synchronous Request
548   // Manage MPI_Request * and MPI_Status * structure
549   int MPIAccess::wait( int RequestId )
550   {
551     int status = MPI_SUCCESS ;
552     if ( !MPICompleted( RequestId ) )
553       {
554         if ( *MPIRequest( RequestId ) != MPI_REQUEST_NULL )
555           {
556             if ( _trace )
557               cout << "MPIAccess::Wait" << _my_rank << " -> wait( " << RequestId
558                    << " ) MPIRequest " << MPIRequest( RequestId ) << " MPIStatus "
559                    << MPIStatus( RequestId ) << " MPITag " << MPITag( RequestId )
560                    << " MPIIsRecv " << MPIIsRecv( RequestId ) << endl ;
561             status = _comm_interface.wait(MPIRequest( RequestId ), MPIStatus( RequestId )) ;
562           }
563         else
564           {
565             if ( _trace )
566               cout << "MPIAccess::Wait" << _my_rank << " MPIRequest == MPI_REQUEST_NULL"
567                    << endl ;
568           }
569         setMPICompleted( RequestId , true ) ;
570         if ( MPIIsRecv( RequestId ) && MPIStatus( RequestId ) )
571           {
572             MPI_Datatype datatype = MPIDatatype( RequestId ) ;
573             int outcount ;
574             status = _comm_interface.getCount(MPIStatus( RequestId ), datatype,
575                                              &outcount ) ;
576             if ( status == MPI_SUCCESS )
577               {
578                 setMPIOutCount( RequestId , outcount ) ;
579                 deleteStatus( RequestId ) ;
580                 if ( _trace )
581                   cout << "MPIAccess::Wait" << _my_rank << " RequestId " << RequestId
582                        << "MPIIsRecv " << MPIIsRecv( RequestId ) << " outcount " << outcount
583                        << endl ;
584               }
585             else
586               {
587                 if ( _trace )
588                   cout << "MPIAccess::Wait" << _my_rank << " MPIIsRecv "
589                        << MPIIsRecv( RequestId ) << " outcount " << outcount << endl ;
590               }
591           }
592         else
593           {
594             if ( _trace )
595               cout << "MPIAccess::Wait" << _my_rank << " MPIIsRecv " << MPIIsRecv( RequestId )
596                    << " MPIOutCount " << MPIOutCount( RequestId ) << endl ;
597           }
598       }
599     if ( _trace )
600       cout << "MPIAccess::Wait" << _my_rank << " RequestId " << RequestId
601            << " Request " << MPIRequest( RequestId )
602            << " Status " << MPIStatus( RequestId ) << " MPICompleted "
603            << MPICompleted( RequestId ) << " MPIOutCount " << MPIOutCount( RequestId )
604            << endl ;
605     return status ;
606   }
607
608   // Perform a "test" of a Send or Recv asynchronous Request
609   // If the request is done, returns true in the flag argument
610   // If the request is not finished, returns false in the flag argument
611   // Do nothing for a synchronous Request
612   // Manage MPI_request * and MPI_status * structure
613   int MPIAccess::test(int RequestId, int &flag)
614   {
615     int status = MPI_SUCCESS ;
616     flag = MPICompleted( RequestId ) ;
617     if ( _trace )
618       cout << "MPIAccess::Test" << _my_rank << " flag " << flag ;
619     if ( MPIIsRecv( RequestId ) )
620       {
621         if ( _trace )
622           cout << " Recv" ;
623       }
624     else
625       {
626         if ( _trace )
627           cout << " Send" ;
628       }
629     if( _trace )
630       cout << "Request" << RequestId << " " << MPIRequest( RequestId )
631            << " Status " << MPIStatus( RequestId ) << endl ;
632     if ( !flag )
633       {
634         if ( *MPIRequest( RequestId ) != MPI_REQUEST_NULL )
635           {
636             if ( _trace )
637               cout << "MPIAccess::Test" << _my_rank << " -> test( " << RequestId
638                    << " ) MPIRequest " << MPIRequest( RequestId )
639                    << " MPIStatus " << MPIStatus( RequestId )
640                    << " MPITag " << MPITag( RequestId )
641                    << " MPIIsRecv " << MPIIsRecv( RequestId ) << endl ;
642             status = _comm_interface.test(MPIRequest( RequestId ), &flag,
643                                          MPIStatus( RequestId )) ;
644           }
645         else
646           {
647             if ( _trace )
648               cout << "MPIAccess::Test" << _my_rank << " MPIRequest == MPI_REQUEST_NULL"
649                    << endl ;
650           }
651         if ( flag )
652           {
653             setMPICompleted( RequestId , true ) ;
654             if ( MPIIsRecv( RequestId ) && MPIStatus( RequestId ) )
655               {
656                 int outcount ;
657                 MPI_Datatype datatype = MPIDatatype( RequestId ) ;
658                 status = _comm_interface.getCount( MPIStatus( RequestId ), datatype,
659                                                   &outcount ) ;
660                 if ( status == MPI_SUCCESS )
661                   {
662                     setMPIOutCount( RequestId , outcount ) ;
663                     deleteStatus( RequestId ) ;
664                     if ( _trace )
665                       cout << "MPIAccess::Test" << _my_rank << " MPIIsRecv "
666                            << MPIIsRecv( RequestId ) << " outcount " << outcount << endl ;
667                   }
668                 else
669                   {
670                     if ( _trace )
671                       cout << "MPIAccess::Test" << _my_rank << " MPIIsRecv "
672                            << MPIIsRecv( RequestId ) << " outcount " << outcount << endl ;
673                   }
674               }
675             else
676               {
677                 if ( _trace )
678                   cout << "MPIAccess::Test" << _my_rank << " MPIIsRecv "
679                        << MPIIsRecv( RequestId ) << " MPIOutCount "
680                        << MPIOutCount( RequestId ) << endl ;
681               }
682           }
683       }
684     if ( _trace )
685       cout << "MPIAccess::Test" << _my_rank << " RequestId " << RequestId
686            << " flag " << flag << " MPICompleted " << MPICompleted( RequestId )
687            << " MPIOutCount " << MPIOutCount( RequestId ) << endl ;
688     return status ;
689   }
690
691   int MPIAccess::waitAny(int count, int *array_of_RequestIds, int &RequestId)
692   {
693     int status = MPI_ERR_OTHER ;
694     RequestId = -1 ;
695     cout << "MPIAccess::WaitAny not yet implemented" << endl ;
696     return status ;
697   }
698
699   int MPIAccess::testAny(int count, int *array_of_RequestIds, int &RequestId, int &flag)
700   {
701     int status = MPI_ERR_OTHER ;
702     RequestId = -1 ;
703     flag = 0 ;
704     cout << "MPIAccess::TestAny not yet implemented" << endl ;
705     return status ;
706   }
707   
708   // Perform a wait of each Send or Recv asynchronous Request of the array 
709   // array_of_RequestIds of size "count".
710   // That array may be filled with a call to SendRequestIdsSize or RecvRequestIdsSize
711   // Do nothing for a synchronous Request
712   // Manage MPI_Request * and MPI_Status * structure
713   int MPIAccess::waitAll(int count, int *array_of_RequestIds)
714   {
715     if ( _trace )
716       cout << "WaitAll" << _my_rank << " : count " << count << endl ;
717     int status ;
718     int retstatus = MPI_SUCCESS ;
719     int i ;
720     for ( i = 0 ; i < count ; i++ )
721       {
722         if ( _trace )
723           cout << "WaitAll" << _my_rank << " " << i << " -> Wait( "
724                << array_of_RequestIds[i] << " )" << endl ;
725         status = wait( array_of_RequestIds[i] ) ;
726         if ( status != MPI_SUCCESS )
727           retstatus = status ;
728       }
729     if ( _trace )
730       cout << "EndWaitAll" << _my_rank << endl ;
731     return retstatus ;
732   }
733
734   // Perform a "test" of each Send or Recv asynchronous Request of the array 
735   // array_of_RequestIds of size "count".
736   // That array may be filled with a call to SendRequestIdsSize or RecvRequestIdsSize
737   // If all requests are done, returns true in the flag argument
738   // If all requests are not finished, returns false in the flag argument
739   // Do nothing for a synchronous Request
740   // Manage MPI_Request * and MPI_Status * structure
741   int MPIAccess::testAll(int count, int *array_of_RequestIds, int &flag)
742   {
743     if ( _trace )
744       cout << "TestAll" << _my_rank << " : count " << count << endl ;
745     int status ;
746     int retstatus = MPI_SUCCESS ;
747     bool retflag = true ;
748     int i ;
749     for ( i = 0 ; i < count ; i++ )
750       {
751         status = test( array_of_RequestIds[i] , flag ) ;
752         retflag = retflag && (flag != 0) ;
753         if ( status != MPI_SUCCESS )
754           retstatus = status ;
755       }
756     flag = retflag ;
757     if ( _trace )
758       cout << "EndTestAll" << _my_rank << endl ;
759     return retstatus ;
760   }
761
762   int MPIAccess::waitSome(int count, int *array_of_RequestIds, int outcount,
763                           int *outarray_of_RequestIds)
764   {
765     int status = MPI_ERR_OTHER ;
766     cout << "MPIAccess::WaitSome not yet implemented" << endl ;
767     return status ;
768   }
769
770   int MPIAccess::testSome(int count, int *array_of_RequestIds, int outcounts,
771                           int *outarray_of_RequestIds)
772   {
773     int status = MPI_ERR_OTHER ;
774     cout << "MPIAccess::TestSome not yet implemented" << endl ;
775     return status ;
776   }
777   
778   // Probe checks if a message is available for read from FromSource rank.
779   // Returns the corresponding source, MPITag, datatype and outcount
780   // Probe is a blocking call which wait until a message is available
781   int MPIAccess::probe(int FromSource, int &source, int &MPITag,
782                        MPI_Datatype &myDatatype, int &outcount)
783   {
784     MPI_Status aMPIStatus ;
785     int sts =  _comm_interface.probe( FromSource, MPI_ANY_TAG,
786                                      *_intra_communicator , &aMPIStatus ) ;
787     if ( sts == MPI_SUCCESS )
788       {
789         source = aMPIStatus.MPI_SOURCE ;
790         MPITag = aMPIStatus.MPI_TAG ;
791         int MethodId = (MPITag % MODULO_TAG) ;
792         myDatatype = datatype( (MEDCoupling::_MessageIdent) MethodId ) ;
793         _comm_interface.getCount(&aMPIStatus, myDatatype, &outcount ) ;
794         if ( _trace )
795           cout << "MPIAccess::Probe" << _my_rank << " FromSource " << FromSource
796                << " source " << source << " MPITag " << MPITag << " MethodId "
797                << MethodId << " datatype " << myDatatype << " outcount " << outcount
798                << endl ;
799       }
800     else
801       {
802         source = -1 ;
803         MPITag = -1 ;
804         myDatatype = 0 ;
805         outcount = -1 ;
806       }
807     return sts ;
808   }
809
810   // IProbe checks if a message is available for read from FromSource rank.
811   // If there is a message available, returns the corresponding source,
812   // MPITag, datatype and outcount with flag = true
813   // If not, returns flag = false
814   int MPIAccess::IProbe(int FromSource, int &source, int &MPITag,
815                         MPI_Datatype &myDataType, int &outcount, int &flag)
816   {
817     MPI_Status aMPIStatus ;
818     int sts =  _comm_interface.Iprobe( FromSource, MPI_ANY_TAG,
819                                       *_intra_communicator , &flag,
820                                       &aMPIStatus ) ;
821     if ( sts == MPI_SUCCESS && flag )
822       {
823         source = aMPIStatus.MPI_SOURCE ;
824         MPITag = aMPIStatus.MPI_TAG ;
825         int MethodId = (MPITag % MODULO_TAG) ;
826         myDataType = datatype( (MEDCoupling::_MessageIdent) MethodId ) ;
827         _comm_interface.getCount(&aMPIStatus, myDataType, &outcount ) ;
828         if ( _trace )
829           cout << "MPIAccess::IProbe" << _my_rank << " FromSource " << FromSource
830                << " source " << source << " MPITag " << MPITag << " MethodId "
831                << MethodId << " datatype " << myDataType << " outcount " << outcount
832                << " flag " << flag << endl ;
833       }
834     else
835       {
836         source = -1 ;
837         MPITag = -1 ;
838         myDataType = 0 ;
839         outcount = -1 ;
840       }
841     return sts ;
842   }
843
844   // Cancel concerns a "posted" asynchronous IRecv
845   // Returns flag = true if the receiving request was successfully canceled
846   // Returns flag = false if the receiving request was finished but not canceled
847   // Use cancel, wait and test_cancelled of the MPI API
848   int MPIAccess::cancel( int RecvRequestId, int &flag )
849   {
850     flag = 0 ;
851     int sts = _comm_interface.cancel( MPIRequest( RecvRequestId ) ) ;
852     if ( sts == MPI_SUCCESS )
853       {
854         sts = _comm_interface.wait( MPIRequest( RecvRequestId ) ,
855                                    MPIStatus( RecvRequestId ) ) ;
856         if ( sts == MPI_SUCCESS )
857           sts = _comm_interface.testCancelled( MPIStatus( RecvRequestId ) , &flag ) ;
858       }
859     return sts ;
860   }
861
862   // Cancel concerns a "pending" receiving message (without IRecv "posted")
863   // Returns flag = true if the message was successfully canceled
864   // Returns flag = false if the receiving request was finished but not canceled
865   // Use Irecv, cancel, wait and test_cancelled of the MPI API
866   int MPIAccess::cancel( int source, int theMPITag, MPI_Datatype datatype, int outcount, int &flag )
867   {
868     int sts ;
869     MPI_Aint extent, lbound ;
870     flag = 0 ;
871     sts =  MPI_Type_get_extent( datatype , &lbound, &extent ) ;
872     if ( sts == MPI_SUCCESS )
873       {
874         void * recvbuf = malloc( extent*outcount ) ;
875         MPI_Request aRecvRequest ;
876         if ( _trace )
877           cout << "MPIAccess::Cancel" << _my_rank << " Irecv extent " << extent
878                << " datatype " << datatype << " source " << source << " theMPITag "
879                << theMPITag << endl ;
880         sts = _comm_interface.Irecv( recvbuf, outcount, datatype, source, theMPITag,
881                                     *_intra_communicator , &aRecvRequest ) ;
882         if ( sts == MPI_SUCCESS )
883           {
884             sts = _comm_interface.cancel( &aRecvRequest ) ;
885             if ( _trace )
886               cout << "MPIAccess::Cancel" << _my_rank << " theMPITag " << theMPITag
887                    << " cancel done" << endl ;
888             if ( sts == MPI_SUCCESS )
889               {
890                 MPI_Status aStatus ;
891                 if ( _trace )
892                   cout << "MPIAccess::Cancel" << _my_rank << " wait" << endl ;
893                 sts = _comm_interface.wait( &aRecvRequest , &aStatus ) ;
894                 if ( sts == MPI_SUCCESS )
895                   {
896                     if ( _trace )
897                       cout << "MPIAccess::Cancel" << _my_rank << " test_cancelled" << endl ;
898                     sts = _comm_interface.testCancelled( &aStatus , &flag ) ;
899                   }
900               }
901           }
902         if ( _trace && datatype == timeType() )
903           cout << "MPIAccess::Cancel" << _my_rank << " time "
904                << ((TimeMessage *) recvbuf)->time << " "
905                << ((TimeMessage *) recvbuf)->deltatime << endl ;
906         free( recvbuf ) ;
907       }
908     if ( _trace )
909       cout << "MPIAccess::Cancel" << _my_rank << " flag " << flag << endl ;
910     return sts ;
911   }
912
913
914   // CancelAll concerns all "pending" receiving message (without IRecv "posted")
915   // CancelAll use IProbe and Cancel (see obove)
916   int MPIAccess::cancelAll()
917   {
918     int sts = MPI_SUCCESS ;
919     int target ;
920     int source ;
921     int MPITag ;
922     MPI_Datatype datatype ;
923     int outcount ;
924     int flag ;
925     for ( target = 0 ; target < _processor_group_size ; target++ )
926       {
927         sts = IProbe(target, source, MPITag, datatype, outcount, flag) ;
928         if ( sts == MPI_SUCCESS && flag )
929           {
930             sts = cancel(source, MPITag, datatype, outcount, flag) ;
931             if ( _trace )
932               cout << "MPIAccess::CancelAll" << _my_rank << " source " << source
933                    << " MPITag " << MPITag << " datatype " << datatype
934                    << " outcount " << outcount << " Cancel flag " << flag << endl ;
935             if ( sts != MPI_SUCCESS )
936               break ;
937           }
938         else if ( sts != MPI_SUCCESS )
939           break ;
940       }
941     return sts ;
942   }
943
944   // Same as barrier of MPI API
945   int MPIAccess::barrier()
946   {
947     int status = _comm_interface.barrier( *_intra_communicator ) ;
948     return status ;
949   }
950
951   // Same as Error_string of MPI API
952   int MPIAccess::errorString(int errorcode, char *string, int *resultlen) const
953   {
954     return _comm_interface.errorString( errorcode, string, resultlen) ;
955   }
956   
957   // Returns source, tag, error and outcount corresponding to receiving RequestId
958   // By default the corresponding structure of RequestId is deleted
959   int MPIAccess::status(int RequestId, int &source, int &tag, int &error,
960                         int &outcount, bool keepRequestStruct)
961   {
962     MPI_Status *myStatus = MPIStatus( RequestId ) ;
963     if ( _trace )
964       cout << "MPIAccess::status" << _my_rank << " RequestId " << RequestId
965            << " status " << myStatus << endl ;
966     if ( myStatus != NULL && MPIAsynchronous( RequestId ) &&
967          MPICompleted( RequestId ) )
968       {
969         if ( MPIIsRecv( RequestId ) )
970           {
971             source = myStatus->MPI_SOURCE ;
972             tag = myStatus->MPI_TAG ;
973             error = myStatus->MPI_ERROR ;
974             MPI_Datatype datatype = MPIDatatype( RequestId ) ;
975             _comm_interface.getCount(myStatus, datatype, &outcount ) ;
976             if ( _trace )
977               cout << "MPIAccess::status" << _my_rank << " RequestId " << RequestId
978                    << " status " << myStatus << " outcount " << outcount << endl ;
979             setMPIOutCount( RequestId , outcount ) ;
980           }
981         else
982           {
983             source = MPITarget( RequestId ) ;
984             tag = MPITag( RequestId ) ;
985             error = 0 ;
986             outcount = MPIOutCount( RequestId ) ;
987           }
988         if ( !keepRequestStruct )
989           deleteRequest( RequestId ) ;
990         return MPI_SUCCESS ;
991       }
992     else
993       {
994         source = MPITarget( RequestId ) ;
995         tag = MPITag( RequestId ) ;
996         error = 0 ;
997         outcount = MPIOutCount( RequestId ) ;
998       }
999     return MPI_SUCCESS ;
1000   }
1001   
1002   int MPIAccess::requestFree( MPI_Request *request )
1003   {
1004     return _comm_interface.requestFree( request ) ;
1005   }
1006   
1007   // Print all information of all known requests for debugging purpose
1008   void MPIAccess::check() const
1009   {
1010     int i = 0 ;
1011     map< int , RequestStruct * >::const_iterator MapOfRequestStructiterator ;
1012     cout << "MPIAccess::Check" << _my_rank << "_map_of_request_struct_size "
1013          << _map_of_request_struct.size() << endl ;
1014     for ( MapOfRequestStructiterator = _map_of_request_struct.begin() ;
1015           MapOfRequestStructiterator != _map_of_request_struct.end() ;
1016           MapOfRequestStructiterator++ )
1017       {
1018         if ( MapOfRequestStructiterator->second != NULL )
1019           {
1020             cout << "    Check" << _my_rank << " " << i << ". Request"
1021                  << MapOfRequestStructiterator->first << "-->" ;
1022             if ( (MapOfRequestStructiterator->second)->MPIAsynchronous )
1023               cout << "I" ;
1024             if ( (MapOfRequestStructiterator->second)->MPIIsRecv )
1025               cout << "Recv from " ;
1026             else
1027               cout << "Send to " ;
1028             cout << (MapOfRequestStructiterator->second)->MPITarget
1029                  << " MPITag " << (MapOfRequestStructiterator->second)->MPITag
1030                  << " DataType " << (MapOfRequestStructiterator->second)->MPIDatatype
1031                  << " Request " << (MapOfRequestStructiterator->second)->MPIRequest
1032                  << " Status " << (MapOfRequestStructiterator->second)->MPIStatus
1033                  << " Completed " << (MapOfRequestStructiterator->second)->MPICompleted
1034                  << endl ;
1035           }
1036         i++ ;
1037       }
1038   }
1039
1040   // Returns the MPI size of a TimeMessage
1041   MPI_Aint MPIAccess::timeExtent() const
1042   {
1043     MPI_Aint aextent, lbound ;
1044     MPI_Type_get_extent( _MPI_TIME , &lbound, &aextent ) ;
1045     return aextent ;
1046   }
1047
1048   // Returns the MPI size of a MPI_INT
1049   MPI_Aint MPIAccess::intExtent() const
1050   {
1051     MPI_Aint aextent, lbound ;
1052     MPI_Type_get_extent( MPI_INT , &lbound, &aextent ) ;
1053     return aextent ;
1054   }
1055
1056   // Returns the MPI size of a MPI_LONG
1057   MPI_Aint MPIAccess::longExtent() const
1058   {
1059     MPI_Aint aextent, lbound ;
1060     MPI_Type_get_extent( MPI_LONG , &lbound, &aextent ) ;
1061     return aextent ;
1062   }
1063
1064   // Returns the MPI size of a MPI_DOUBLE
1065   MPI_Aint MPIAccess::doubleExtent() const
1066   {
1067     MPI_Aint aextent, lbound ;
1068     MPI_Type_get_extent( MPI_DOUBLE , &lbound, &aextent ) ;
1069     return aextent ;
1070   }
1071
1072   // Outputs fields of a TimeMessage structure
1073   ostream & operator<< (ostream & f ,const TimeMessage & aTimeMsg )
1074   {
1075     f << " time " << aTimeMsg.time << " deltatime " << aTimeMsg.deltatime
1076       << " tag " << aTimeMsg.tag ;
1077     return f;
1078   }
1079
1080   // Outputs the DataType coded in a Tag
1081   ostream & operator<< (ostream & f ,const _MessageIdent & methodtype )
1082   {
1083     switch (methodtype)
1084       {
1085       case _message_time :
1086         f << " MethodTime ";
1087         break;
1088       case _message_int :
1089         f << " MPI_INT ";
1090         break;
1091       case _message_double :
1092         f << " MPI_DOUBLE ";
1093         break;
1094       default :
1095         f << " UnknownMethodType ";
1096         break;
1097       }
1098     return f;
1099   }
1100 }