source: XIOS/dev/branch_openmp/extern/remap/src/mpi_routing.cpp @ 1328

Last change on this file since 1328 was 1328, checked in by yushan, 6 years ago

dev_omp

File size: 18.5 KB
Line 
1#include "mpi_routing.hpp"
2#include "mpi.hpp"
3#include "node.hpp"
4#include "elt.hpp"
5#include "timerRemap.hpp"
6#include <iostream>
7using namespace ep_lib;
8
9namespace sphereRemap {
10
11const int verbose = 0;
12
13CMPIRouting::CMPIRouting(MPI_Comm comm) : communicator(comm)
14{
15        MPI_Comm_rank(comm, &mpiRank);
16        MPI_Comm_size(comm, &mpiSize);
17}
18
19/* sparse alltoallv when it is known that only a subset of ranks will communicate,
20    but message lengths are *known* to receiver */
21template <typename T>
22void alltoalls_known(const vector<vector<T> >& send, vector<vector<T> >& recv, const vector<int>& ranks, MPI_Comm communicator)
23{
24        vector<MPI_Request> request(ranks.size() * 2);
25        vector<MPI_Status>  status(ranks.size() * 2);
26
27        // communicate data
28        int nbRequest = 0;
29        for (int i = 0; i < ranks.size(); i++)
30                if (recv[i].size())
31                        MPI_Irecv(&recv[i][0], recv[i].size()*sizeof(T), MPI_CHAR, ranks[i], 0, communicator, &request[nbRequest++]);
32        for (int i = 0; i < ranks.size(); i++)
33                if (send[i].size())
34                        MPI_Isend((void *) &send[i][0], send[i].size()*sizeof(T), MPI_CHAR, ranks[i], 0, communicator, &request[nbRequest++]);
35        MPI_Waitall(nbRequest, &request[0], &status[0]);
36}
37
38/* sparse alltoallv when it is known that only a subset of ranks will communicate,
39    but message lengths are *unknown* to receiver */
40template <typename T>
41void alltoalls_unknown(const vector<vector<T> >& send, vector<vector<T> >& recv, const vector<int>& ranks, MPI_Comm communicator)
42{
43        vector<MPI_Request> request(ranks.size() * 2);
44        vector<MPI_Status>  status(ranks.size() * 2);
45
46        // communicate sizes
47        int nbRequest = 0;
48        vector<int> sendSizes(ranks.size());
49        vector<int> recvSizes(ranks.size());
50        for (int i = 0; i < ranks.size(); i++)
51                sendSizes[i] = send[i].size();
52        for (int i = 0; i < ranks.size(); i++)
53                MPI_Irecv(&recvSizes[i], 1, MPI_INT, ranks[i], 0, communicator, &request[nbRequest++]);
54        for (int i = 0; i < ranks.size(); i++)
55                MPI_Isend(&sendSizes[i], 1, MPI_INT, ranks[i], 0, communicator, &request[nbRequest++]);
56        MPI_Waitall(nbRequest, &request[0], &status[0]);
57
58        // allocate
59        for (int i = 0; i < ranks.size(); i++)
60                if (recvSizes[i]) recv[i].resize(recvSizes[i]);
61        // communicate data
62        alltoalls_known(send, recv, ranks, communicator);
63}
64
65void setElementsSendCnt(int route, vector<int>& sendCnt)
66{
67        sendCnt[route]++;
68}
69
70void setElementsSendCnt(const vector<int>& route, vector<int>& sendCnt)
71{
72        for (int i = 0; i < route.size(); i++)
73                sendCnt[route[i]]++;
74}
75
76void setTargetElementIndex(int route, vector<int>& indices, const int *rankToIndex)
77{
78        int index = rankToIndex[route];
79        indices.push_back(index);
80}
81
82void setTargetElementIndex(const vector<int>& route, vector<int>& indices, const int *rankToIndex)
83{
84        for (int i = 0; i < route.size(); i++)
85        {
86                int index = rankToIndex[route[i]];
87                indices.push_back(index);
88        }
89}
90
91template<typename T>
92void CMPIRouting::init(const vector<T>& route, CMPICascade *cascade)
93{
94        vector<int> nbElementSend(mpiSize);
95        int *toSend = new int[mpiSize];
96        int *recvCount = new int[mpiSize];
97        int *targetRankToIndex;
98
99        for (int i = 0; i < route.size(); i++)
100                setElementsSendCnt(route[i], nbElementSend);
101
102        nbTarget = 0;
103vector<int> destRanks;
104        for (int i = 0; i < mpiSize; i++)
105        {
106                if (nbElementSend[i] == 0)
107                        toSend[i] = 0;
108                else
109                {
110destRanks.push_back(i);
111                        toSend[i] = 1;
112                        nbTarget++;
113                }
114                recvCount[i] = 1;
115        }
116//int recvCntDeb = (stree) ? stree->scatter_reduce(destRanks) : -1;
117
118        MPI_Barrier(communicator);
119        CTimer::get("CMPIRouting::init(reduce_scatter)").reset();
120        CTimer::get("CMPIRouting::init(reduce_scatter)").resume();
121        MPI_Reduce_scatter(toSend, &nbSource, recvCount, MPI_INT, MPI_SUM, communicator);
122        CTimer::get("CMPIRouting::init(reduce_scatter)").suspend();
123        CTimer::get("CMPIRouting::init(reduce_scatter)").print();
124
125        MPI_Alloc_mem(nbTarget *sizeof(int), MPI_INFO_NULL, &targetRank);
126        MPI_Alloc_mem(nbSource *sizeof(int), MPI_INFO_NULL, &sourceRank);
127
128        targetRankToIndex = new int[mpiSize];
129        int index = 0;
130        for (int i = 0; i < mpiSize; i++)
131        {
132                if (toSend[i] == 1)
133                {
134                        targetRank[index] = i;
135                        targetRankToIndex[i] = index;
136                        index++;
137                }
138        }
139
140        MPI_Barrier(communicator);
141        CTimer::get("CMPIRouting::init(get_source)").reset();
142        CTimer::get("CMPIRouting::init(get_source)").resume();
143
144        MPI_Request *request = new MPI_Request[nbSource + nbTarget];
145        MPI_Status  *status = new MPI_Status[nbSource + nbTarget];
146
147        int indexRequest = 0;
148        if (verbose) cout << "CMPIRouting::init     nbSource : " << nbSource << " nbTarget : " << nbTarget << endl;
149//      assert(recvCntDeb == -1 || recvCntDeb == nbSource);
150//cout << mpiRank <<  "DEB : " << recvCntDeb << "    nbSource " << nbSource << " nbTarget : " << nbTarget << endl;
151        for (int i = 0; i < nbSource; i++)
152        {
153                #ifdef _usingEP
154                MPI_Irecv(&sourceRank[i], 1, MPI_INT, -2, 0, communicator, &request[indexRequest]);
155                #else
156                MPI_Irecv(&sourceRank[i], 1, MPI_INT, MPI_ANY_SOURCE, 0, communicator, &request[indexRequest]);
157                #endif
158                indexRequest++;
159        }
160        MPI_Barrier(communicator);
161        for (int i = 0; i < nbTarget; i++)
162        {
163                MPI_Isend(&mpiRank, 1, MPI_INT, targetRank[i], 0, communicator, &request[indexRequest]);
164                indexRequest++;
165        }
166        MPI_Waitall(indexRequest, request, status);
167        MPI_Barrier(communicator);  //needed
168        CTimer::get("CMPIRouting::init(get_source)").suspend();
169        CTimer::get("CMPIRouting::init(get_source)").print();
170
171        CTimer::get("CMPIRouting::init(get_source)").reset();
172        CTimer::get("CMPIRouting::init(get_source)").resume();
173
174        indexRequest = 0;
175        for (int i = 0; i < nbSource; i++)
176        {
177                #ifdef _usingEP
178                MPI_Irecv(&sourceRank[i], 1, MPI_INT, -2, 0, communicator, &request[indexRequest]);
179                #else
180                MPI_Irecv(&sourceRank[i], 1, MPI_INT, MPI_ANY_SOURCE, 0, communicator, &request[indexRequest]);
181                #endif
182                indexRequest++;
183        }
184
185        for (int i = 0; i < nbTarget; i++)
186        {
187                MPI_Isend(&mpiRank, 1, MPI_INT, targetRank[i], 0, communicator, &request[indexRequest]);
188                indexRequest++;
189        }
190        MPI_Waitall(indexRequest, request, status);
191        MPI_Barrier(communicator);
192        CTimer::get("CMPIRouting::init(get_source)").suspend();
193        CTimer::get("CMPIRouting::init(get_source)").print();
194
195        CTimer::get("CMPIRouting::init(send_element)").reset();
196        CTimer::get("CMPIRouting::init(send_element)").resume();
197
198        nbTargetElement.resize(nbTarget);
199        nbSourceElement.resize(nbSource);
200
201        for (int i = 0; i < route.size(); i++)
202                setTargetElementIndex(route[i], targetElementIndex, targetRankToIndex);
203
204        for (int i = 0; i < targetElementIndex.size(); i++)
205                nbTargetElement[targetElementIndex[i]]++;
206
207        indexRequest = 0;
208        totalSourceElement = 0;
209        totalTargetElement = 0;
210        for (int i = 0; i < nbSource; i++)
211        {
212                MPI_Irecv(&nbSourceElement[i], 1, MPI_INT, sourceRank[i], 0, communicator, &request[indexRequest]);
213                indexRequest++;
214        }
215
216        for (int i = 0; i < nbTarget; i++)
217        {
218                totalTargetElement += nbTargetElement[i];
219                MPI_Isend(&nbTargetElement[i], 1, MPI_INT, targetRank[i], 0, communicator, &request[indexRequest]);
220                indexRequest++;
221        }
222
223        MPI_Waitall(indexRequest, request, status);
224
225        CTimer::get("CMPIRouting::init(send_element)").suspend();
226        CTimer::get("CMPIRouting::init(send_element)").print();
227
228        totalSourceElement = 0;
229        for (int i = 0; i < nbSource; i++)
230                totalSourceElement += nbSourceElement[i];
231
232        sourceElementIndex.resize(totalSourceElement);
233
234        totalSourceElement = 0;
235        for (int i = 0; i < nbSource; i++)
236        {
237                for (int j = 0; j < nbSourceElement[i]; j++)
238                {
239                        sourceElementIndex[totalSourceElement] = i;
240                        totalSourceElement++;
241                }
242        }
243
244        delete[]  toSend;
245        delete[]  recvCount;
246        delete[]  request;
247        delete[]  status;
248}
249
250
251int CMPIRouting::getTotalSourceElement(void)
252{
253        return totalSourceElement;
254}
255
256template<typename T>
257void CMPIRouting::transferToTarget(T* targetElements, T* sourceElements)
258{
259        char** targetBuffer = new char*[nbTarget];
260        int* indexTargetBuffer = new int[nbTarget];
261
262        for(int i=0;i<nbTarget; i++)
263        {
264                targetBuffer[i] = new char[sizeof(T)*nbTargetElement[i]];
265                indexTargetBuffer[i]= 0;
266        }
267
268        char** sourceBuffer = new char*[nbSource];
269        int* indexSourceBuffer = new int[nbSource];
270
271        for(int i=0;i<nbSource; i++)
272        {
273                sourceBuffer[i] = new char[sizeof(T)*nbSourceElement[i]];
274                indexSourceBuffer[i]= 0;
275        }
276
277        // pack the data
278        int index;
279        for(int i=0;i<totalTargetElement;i++)
280        {
281                index=targetElementIndex[i];
282                *((T*) &(targetBuffer[index][indexTargetBuffer[index]])) = targetElements[i];
283                indexTargetBuffer[index]+=sizeof(T);
284        }
285
286
287        MPI_Request* request=new MPI_Request[nbSource+nbTarget];
288        MPI_Status*  status=new MPI_Status[nbSource+nbTarget];
289        int indexRequest=0;
290
291        MPI_Barrier(communicator);
292        CTimer::get("CMPIRouting::transferToTarget").reset();
293        CTimer::get("CMPIRouting::transferToTarget").resume();
294
295        for(int i=0; i<nbSource; i++)
296        {
297                MPI_Irecv(sourceBuffer[i],nbSourceElement[i]*sizeof(T),MPI_CHAR, sourceRank[i], 0, communicator, &request[indexRequest]);
298                indexRequest++;
299        }
300
301        for(int i=0;i<nbTarget; i++)
302        {
303                MPI_Isend(targetBuffer[i],nbTargetElement[i]*sizeof(T), MPI_CHAR, targetRank[i], 0, communicator, &request[indexRequest]);
304                indexRequest++;
305        }
306
307        MPI_Waitall(indexRequest,request,status);
308
309        CTimer::get("CMPIRouting::transferToTarget").suspend();
310        CTimer::get("CMPIRouting::transferToTarget").print();
311        MPI_Barrier(communicator);
312
313        // unpack the data
314        for(int i=0;i<totalSourceElement;i++)
315        {
316                index=sourceElementIndex[i];
317                sourceElements[i] = *((T*) &(sourceBuffer[index][indexSourceBuffer[index]]));
318                indexSourceBuffer[index]+=sizeof(T);
319        }
320
321        for(int i=0;i<nbTarget; i++) delete[] targetBuffer[i];
322        for(int i=0;i<nbSource; i++) delete[] sourceBuffer[i];
323        delete[] targetBuffer;
324        delete[] indexTargetBuffer;
325        delete[] sourceBuffer;
326        delete[] indexSourceBuffer;
327        delete[] request;
328        delete[] status;
329}
330
331
332template<typename T, typename t_pack, typename t_unpack>
333void CMPIRouting::transferToTarget(T* targetElements, T* sourceElements, t_pack pack, t_unpack unpack)
334{
335        char** targetBuffer = new char*[nbTarget];
336        int* indexTargetBuffer = new int[nbTarget];
337        int* targetMessageSize = new int[nbTarget];
338        int* sourceMessageSize = new int[nbSource];
339        int index;
340
341        // compute target buffer size
342        for (int i = 0; i < nbTarget; i++)
343                targetMessageSize[i] = 0;
344
345        for (int i = 0; i < totalTargetElement; i++)
346        {
347                index = targetElementIndex[i];
348                pack(targetElements[i], NULL, targetMessageSize[index]);
349        }
350
351        MPI_Request *request = new MPI_Request[nbSource + nbTarget];
352        MPI_Status  *status = new MPI_Status[nbSource + nbTarget];
353        int indexRequest = 0;
354
355        MPI_Barrier(communicator);
356        CTimer::get("CMPIRouting::transferToTarget(messageSize)").reset();
357        CTimer::get("CMPIRouting::transferToTarget(messageSize)").resume();
358
359        for(int i=0; i<nbSource; i++)
360        {
361                MPI_Irecv(&sourceMessageSize[i],1,MPI_INT, sourceRank[i], 0, communicator, &request[indexRequest]);
362                indexRequest++;
363        }
364
365        for(int i=0; i<nbTarget; i++)
366        {
367                MPI_Isend(&targetMessageSize[i],1, MPI_INT, targetRank[i], 0, communicator, &request[indexRequest]);
368                indexRequest++;
369        }
370
371        MPI_Waitall(indexRequest,request,status);
372
373        MPI_Barrier(communicator);
374        CTimer::get("CMPIRouting::transferToTarget(messageSize)").suspend();
375        CTimer::get("CMPIRouting::transferToTarget(messageSize)").print();
376
377        for(int i=0; i<nbTarget; i++)
378        {
379                targetBuffer[i] = new char[targetMessageSize[i]];
380                indexTargetBuffer[i] = 0;
381        }
382
383        char** sourceBuffer = new char*[nbSource];
384        int* indexSourceBuffer = new int[nbSource];
385
386        for(int i=0;i<nbSource; i++)
387        {
388                sourceBuffer[i] = new char[sourceMessageSize[i]];
389                indexSourceBuffer[i]= 0;
390        }
391
392        // pack the data
393        for(int i=0; i<totalTargetElement; i++)
394        {
395                index=targetElementIndex[i];
396                pack(targetElements[i], targetBuffer[index], indexTargetBuffer[index] );
397        }
398
399        indexRequest=0;
400
401        MPI_Barrier(communicator);
402        CTimer::get("CMPIRouting::transferToTarget(data)").reset();
403        CTimer::get("CMPIRouting::transferToTarget(data)").resume();
404        for(int i=0; i<nbSource; i++)
405        {
406                MPI_Irecv(sourceBuffer[i],sourceMessageSize[i],MPI_CHAR, sourceRank[i], 0, communicator, &request[indexRequest]);
407                indexRequest++;
408        }
409
410        for(int i=0;i<nbTarget; i++)
411        {
412                MPI_Isend(targetBuffer[i],targetMessageSize[i], MPI_CHAR, targetRank[i], 0, communicator, &request[indexRequest]);
413                indexRequest++;
414        }
415
416        MPI_Waitall(indexRequest,request,status);
417
418        MPI_Barrier(communicator);
419        CTimer::get("CMPIRouting::transferToTarget(data)").suspend();
420        CTimer::get("CMPIRouting::transferToTarget(data)").print();
421
422        // unpack the data
423        for(int i=0; i<totalSourceElement; i++)
424        {
425                index=sourceElementIndex[i];
426                unpack(sourceElements[i], sourceBuffer[index], indexSourceBuffer[index]);
427        }
428
429        for (int i=0; i<nbTarget; i++) delete[] targetBuffer[i];
430        for (int i=0; i<nbSource; i++) delete[] sourceBuffer[i];
431        delete[] targetBuffer;
432        delete[] indexTargetBuffer;
433        delete[] targetMessageSize;
434        delete[] sourceBuffer;
435        delete[] indexSourceBuffer;
436        delete[] sourceMessageSize;
437        delete[] request;
438        delete[] status;
439}
440
441template<typename T>
442void CMPIRouting::transferFromSource(T* targetElements, T* sourceElements)
443{
444        char** targetBuffer = new char*[nbTarget];
445        int* indexTargetBuffer = new int[nbTarget];
446
447        for (int i = 0; i < nbTarget; i++)
448        {
449                targetBuffer[i] = new char[sizeof(T)*nbTargetElement[i]];
450                indexTargetBuffer[i] = 0;
451        }
452
453        char** sourceBuffer = new char*[nbSource];
454        int* indexSourceBuffer = new int[nbSource];
455
456        for (int i = 0; i < nbSource; i++)
457        {
458                sourceBuffer[i] = new char[sizeof(T)*nbSourceElement[i]];
459                indexSourceBuffer[i] = 0;
460        }
461
462        // pack the data
463        int index;
464        for (int i = 0; i < totalSourceElement; i++)
465        {
466                index = sourceElementIndex[i];
467                *((T*) &(sourceBuffer[index][indexSourceBuffer[index]])) = sourceElements[i];
468                indexSourceBuffer[index] += sizeof(T);
469        }
470
471        MPI_Request* request=new MPI_Request[nbSource+nbTarget];
472        MPI_Status*  status=new MPI_Status[nbSource+nbTarget];
473        int indexRequest=0;
474
475        for(int i=0; i<nbSource; i++)
476        {
477                MPI_Isend(sourceBuffer[i],nbSourceElement[i]*sizeof(T),MPI_CHAR, sourceRank[i], 0, communicator, &request[indexRequest]);
478                indexRequest++;
479        }
480
481        for(int i=0;i<nbTarget; i++)
482        {
483                MPI_Irecv(targetBuffer[i],nbTargetElement[i]*sizeof(T), MPI_CHAR, targetRank[i], 0, communicator, &request[indexRequest]);
484                indexRequest++;
485        }
486
487        MPI_Waitall(indexRequest,request,status);
488
489        // unpack the data
490        for(int i=0;i<totalTargetElement;i++)
491        {
492                index=targetElementIndex[i];
493                targetElements[i] = *((T*) &(targetBuffer[index][indexTargetBuffer[index]]));
494                indexTargetBuffer[index]+=sizeof(T);
495        }
496
497        for(int i=0;i<nbTarget; i++) delete[] targetBuffer[i];
498        for(int i=0;i<nbSource; i++) delete[] sourceBuffer[i];
499        delete[] targetBuffer;
500        delete[] indexTargetBuffer;
501        delete[] sourceBuffer;
502        delete[] indexSourceBuffer;
503        delete[] request;
504        delete[] status;
505}
506
507
508/* number of source and target elements is known from previous call to init() */
509template<typename T, typename t_pack, typename t_unpack>
510void CMPIRouting::transferFromSource(T *targetElements, T *sourceElements, t_pack pack, t_unpack unpack)
511{
512        char **targetBuffer = new char*[nbTarget];
513        int *indexTargetBuffer = new int[nbTarget];
514        int *targetMessageSize = new int[nbTarget];
515        int *sourceMessageSize = new int[nbSource];
516        int index;
517
518        // compute target buffer size
519        for (int i = 0; i < nbSource; i++)  sourceMessageSize[i] = 0;
520
521        for (int i = 0; i < totalSourceElement; i++)
522        {
523                index = sourceElementIndex[i];
524                pack(sourceElements[i], NULL, sourceMessageSize[index]);
525        }
526
527        MPI_Request *request = new MPI_Request[nbSource + nbTarget];
528        MPI_Status  *status = new MPI_Status[nbSource + nbTarget];
529        int indexRequest = 0;
530        for (int i = 0; i < nbSource; i++)
531        {
532                MPI_Isend(&sourceMessageSize[i], 1, MPI_INT, sourceRank[i], 0, communicator, &request[indexRequest]);
533                indexRequest++;
534        }
535        for (int i = 0; i < nbTarget; i++)
536        {
537                MPI_Irecv(&targetMessageSize[i], 1, MPI_INT, targetRank[i], 0, communicator, &request[indexRequest]);
538                indexRequest++;
539        }
540        MPI_Waitall(indexRequest, request, status);
541
542        for (int i = 0; i < nbTarget; i++)
543        {
544                targetBuffer[i] = new char[targetMessageSize[i]];
545                indexTargetBuffer[i] = 0;
546        }
547
548        char **sourceBuffer = new char*[nbSource];
549        int *indexSourceBuffer = new int[nbSource];
550
551        for (int i = 0; i < nbSource; i++)
552        {
553                sourceBuffer[i] = new char[sourceMessageSize[i]];
554                indexSourceBuffer[i] = 0;
555        }
556
557
558        // pack the data
559        for (int i = 0; i < totalSourceElement; i++)
560        {
561                index = sourceElementIndex[i];
562                pack(sourceElements[i], sourceBuffer[index], indexSourceBuffer[index] );
563        }
564
565        indexRequest = 0;
566        for (int i = 0; i < nbSource; i++)
567        {
568                MPI_Isend(sourceBuffer[i], sourceMessageSize[i], MPI_CHAR, sourceRank[i], 0, communicator, &request[indexRequest]);
569                indexRequest++;
570        }
571        for (int i = 0; i < nbTarget; i++)
572        {
573                MPI_Irecv(targetBuffer[i], targetMessageSize[i], MPI_CHAR, targetRank[i], 0, communicator, &request[indexRequest]);
574                indexRequest++;
575        }
576        MPI_Waitall(indexRequest, request, status);
577
578        // unpack the data
579        for (int i = 0; i < totalTargetElement; i++)
580        {
581                index = targetElementIndex[i];
582                unpack(targetElements[i], targetBuffer[index], indexTargetBuffer[index]);
583        }
584
585        for (int i = 0; i < nbTarget; i++) delete[] targetBuffer[i];
586        for (int i = 0; i < nbSource; i++) delete[] sourceBuffer[i];
587        delete[] targetBuffer;
588        delete[] indexTargetBuffer;
589        delete[] targetMessageSize;
590        delete[] sourceBuffer;
591        delete[] indexSourceBuffer;
592        delete[] sourceMessageSize;
593        delete[] request;
594        delete[] status;
595}
596
597CMPIRouting::~CMPIRouting()
598{
599};
600
601template void CMPIRouting::init(const std::vector<int>& route, CMPICascade *cascade);
602template void CMPIRouting::init(const std::vector<vector<int> >& route, CMPICascade *cascade);
603
604template void CMPIRouting::transferToTarget(int *targetElements, int *sourceElements);
605template void CMPIRouting::transferToTarget(int *targetElements, int *sourceElements, void (*pack)(int&, char*, int&), void (* unpack)(int&, char *, int&));
606template void CMPIRouting::transferFromSource(int *targetElements, int *sourceElements);
607template void CMPIRouting::transferFromSource(int *targetElements, int *sourceElements, void (*pack)(int&, char*, int&), void (* unpack)(int&, char *, int&));
608
609template void CMPIRouting::transferToTarget(Node* targetElements, Node* sourceElements, void (*pack)(Node&, char*, int&), void (* unpack)(Node&, char *, int&));
610template void CMPIRouting::transferToTarget(Elt **targetElements, Elt **sourceElements, void (*pack)(Elt *, char*, int&), void (* unpack)(Elt *, char *, int&));
611template void CMPIRouting::transferFromSource(std::vector<int> *targetElements, std::vector<int> *sourceElements, void (*pack)(const std::vector<int>&, char*, int&), void (* unpack)(std::vector<int>&, const char *, int&));
612
613struct NES { int cnt; int risc; int rank; };
614
615template void alltoalls_unknown(const std::vector<std::vector<NES> >& send, std::vector<std::vector<NES> >& recv,
616                                const std::vector<int>& ranks, MPI_Comm communicator);
617
618template void alltoalls_known(const std::vector<std::vector<int> >& send, std::vector<std::vector<int> >& recv,
619                              const std::vector<int>& ranks, MPI_Comm communicator);
620
621}
Note: See TracBrowser for help on using the repository browser.