COMBINATORIAL_BLAS  1.6
parUtils.cpp
Go to the documentation of this file.
1 
8 #include "mpi.h"
9 #include "binUtils.h"
10 #include "dtypes.h"
11 #include "parUtils.h"
12 
13 #ifdef __DEBUG__
14 #ifndef __DEBUG_PAR__
15 #define __DEBUG_PAR__
16 #endif
17 #endif
18 
19 namespace par {
20 
21  unsigned int splitCommBinary( MPI_Comm orig_comm, MPI_Comm *new_comm) {
22  int npes, rank;
23 
24  MPI_Group orig_group, new_group;
25 
26  MPI_Comm_size(orig_comm, &npes);
27  MPI_Comm_rank(orig_comm, &rank);
28 
29  unsigned int splitterRank = binOp::getPrevHighestPowerOfTwo(npes);
30 
31  int *ranksAsc, *ranksDesc;
32  //Determine sizes for the 2 groups
33  ranksAsc = new int[splitterRank];
34  ranksDesc = new int[( npes - splitterRank)];
35 
36  int numAsc = 0;
37  int numDesc = ( npes - splitterRank - 1);
38 
39  //This is the main mapping between old ranks and new ranks.
40  for(int i=0; i<npes; i++) {
41  if( static_cast<unsigned int>(i) < splitterRank) {
42  ranksAsc[numAsc] = i;
43  numAsc++;
44  }else {
45  ranksDesc[numDesc] = i;
46  numDesc--;
47  }
48  }//end for i
49 
50  MPI_Comm_group(orig_comm, &orig_group);
51 
52  /* Divide tasks into two distinct groups based upon rank */
53  if (static_cast<unsigned int>(rank) < splitterRank) {
54  MPI_Group_incl(orig_group, splitterRank, ranksAsc, &new_group);
55  }else {
56  MPI_Group_incl(orig_group, (npes-splitterRank), ranksDesc, &new_group);
57  }
58 
59  MPI_Comm_create(orig_comm, new_group, new_comm);
60 
61  delete [] ranksAsc;
62  ranksAsc = NULL;
63 
64  delete [] ranksDesc;
65  ranksDesc = NULL;
66 
67  return splitterRank;
68  }//end function
69 
70  unsigned int splitCommBinaryNoFlip( MPI_Comm orig_comm, MPI_Comm *new_comm) {
71  int npes, rank;
72 
73  MPI_Group orig_group, new_group;
74 
75  MPI_Comm_size(orig_comm, &npes);
76  MPI_Comm_rank(orig_comm, &rank);
77 
78  unsigned int splitterRank = binOp::getPrevHighestPowerOfTwo(npes);
79 
80  int *ranksAsc, *ranksDesc;
81  //Determine sizes for the 2 groups
82  ranksAsc = new int[splitterRank];
83  ranksDesc = new int[( npes - splitterRank)];
84 
85  int numAsc = 0;
86  int numDesc = 0; //( npes - splitterRank - 1);
87 
88  //This is the main mapping between old ranks and new ranks.
89  for(int i = 0; i < npes; i++) {
90  if(static_cast<unsigned int>(i) < splitterRank) {
91  ranksAsc[numAsc] = i;
92  numAsc++;
93  }else {
94  ranksDesc[numDesc] = i;
95  numDesc++;
96  }
97  }//end for i
98 
99  MPI_Comm_group(orig_comm, &orig_group);
100 
101  /* Divide tasks into two distinct groups based upon rank */
102  if (static_cast<unsigned int>(rank) < splitterRank) {
103  MPI_Group_incl(orig_group, splitterRank, ranksAsc, &new_group);
104  }else {
105  MPI_Group_incl(orig_group, (npes-splitterRank), ranksDesc, &new_group);
106  }
107 
108  MPI_Comm_create(orig_comm, new_group, new_comm);
109 
110  delete [] ranksAsc;
111  ranksAsc = NULL;
112 
113  delete [] ranksDesc;
114  ranksDesc = NULL;
115 
116  return splitterRank;
117  }//end function
118 
119  //create Comm groups and remove empty processors...
120  int splitComm2way(bool iAmEmpty, MPI_Comm * new_comm, MPI_Comm comm) {
121 #ifdef __PROFILE_WITH_BARRIER__
122  MPI_Barrier(comm);
123 #endif
124 
125  MPI_Group orig_group, new_group;
126  int size;
127  MPI_Comm_size(comm, &size);
128 
129  bool* isEmptyList = new bool[size];
130  par::Mpi_Allgather<bool>(&iAmEmpty, isEmptyList, 1, comm);
131 
132  int numActive=0, numIdle=0;
133  for(int i = 0; i < size; i++) {
134  if(isEmptyList[i]) {
135  numIdle++;
136  }else {
137  numActive++;
138  }
139  }//end for i
140 
141  int* ranksActive = new int[numActive];
142  int* ranksIdle = new int[numIdle];
143 
144  numActive=0;
145  numIdle=0;
146  for(int i = 0; i < size; i++) {
147  if(isEmptyList[i]) {
148  ranksIdle[numIdle] = i;
149  numIdle++;
150  }else {
151  ranksActive[numActive] = i;
152  numActive++;
153  }
154  }//end for i
155 
156  delete [] isEmptyList;
157  isEmptyList = NULL;
158 
159  /* Extract the original group handle */
160  MPI_Comm_group(comm, &orig_group);
161 
162  /* Divide tasks into two distinct groups based upon rank */
163  if (!iAmEmpty) {
164  MPI_Group_incl(orig_group, numActive, ranksActive, &new_group);
165  }else {
166  MPI_Group_incl(orig_group, numIdle, ranksIdle, &new_group);
167  }
168 
169  /* Create new communicator */
170  MPI_Comm_create(comm, new_group, new_comm);
171 
172  delete [] ranksActive;
173  ranksActive = NULL;
174 
175  delete [] ranksIdle;
176  ranksIdle = NULL;
177 
178  }//end function
179 
180  int splitCommUsingSplittingRank(int splittingRank, MPI_Comm* new_comm,
181  MPI_Comm comm) {
182 #ifdef __PROFILE_WITH_BARRIER__
183  MPI_Barrier(comm);
184 #endif
185 
186  MPI_Group orig_group, new_group;
187  int size;
188  int rank;
189  MPI_Comm_rank(comm, &rank);
190  MPI_Comm_size(comm, &size);
191 
192  int* ranksActive = new int[splittingRank];
193  int* ranksIdle = new int[size - splittingRank];
194 
195  for(int i = 0; i < splittingRank; i++) {
196  ranksActive[i] = i;
197  }
198 
199  for(int i = splittingRank; i < size; i++) {
200  ranksIdle[i - splittingRank] = i;
201  }
202 
203  /* Extract the original group handle */
204  MPI_Comm_group(comm, &orig_group);
205 
206  /* Divide tasks into two distinct groups based upon rank */
207  if (rank < splittingRank) {
208  MPI_Group_incl(orig_group, splittingRank, ranksActive, &new_group);
209  }else {
210  MPI_Group_incl(orig_group, (size - splittingRank), ranksIdle, &new_group);
211  }
212 
213  /* Create new communicator */
214  MPI_Comm_create(comm, new_group, new_comm);
215 
216  delete [] ranksActive;
217  ranksActive = NULL;
218 
219  delete [] ranksIdle;
220  ranksIdle = NULL;
221 
222  }//end function
223 
224  //create Comm groups and remove empty processors...
225  int splitComm2way(const bool* isEmptyList, MPI_Comm * new_comm, MPI_Comm comm) {
226 
227  MPI_Group orig_group, new_group;
228  int size, rank;
229  MPI_Comm_size(comm, &size);
230  MPI_Comm_rank(comm, &rank);
231 
232  int numActive=0, numIdle=0;
233  for(int i = 0; i < size; i++) {
234  if(isEmptyList[i]) {
235  numIdle++;
236  }else {
237  numActive++;
238  }
239  }//end for i
240 
241  int* ranksActive = new int[numActive];
242  int* ranksIdle = new int[numIdle];
243 
244  numActive=0;
245  numIdle=0;
246  for(int i = 0; i < size; i++) {
247  if(isEmptyList[i]) {
248  ranksIdle[numIdle] = i;
249  numIdle++;
250  }else {
251  ranksActive[numActive] = i;
252  numActive++;
253  }
254  }//end for i
255 
256  /* Extract the original group handle */
257  MPI_Comm_group(comm, &orig_group);
258 
259  /* Divide tasks into two distinct groups based upon rank */
260  if (!isEmptyList[rank]) {
261  MPI_Group_incl(orig_group, numActive, ranksActive, &new_group);
262  }else {
263  MPI_Group_incl(orig_group, numIdle, ranksIdle, &new_group);
264  }
265 
266  /* Create new communicator */
267  MPI_Comm_create(comm, new_group, new_comm);
268 
269  delete [] ranksActive;
270  ranksActive = NULL;
271 
272  delete [] ranksIdle;
273  ranksIdle = NULL;
274 
275  return 0;
276  }//end function
277 
278 
279  int AdjustCommunicationPattern(std::vector<int>& send_sizes, std::vector<int>& send_partners,
280  std::vector<int>& recv_sizes, std::vector<int>& recv_partners, MPI_Comm comm)
281  {
282  int npes;
283  int rank;
284  MPI_Comm_rank(comm, &rank);
285  MPI_Comm_size(comm, &npes);
286 
287  unsigned int k = send_sizes.size();
288 
289  // do scans ...
290  DendroIntL lsz[k];
291  DendroIntL gsz[k], gscan[k];
292 
293  for(size_t i = 0; i < send_sizes.size(); ++i) {
294  lsz[i] = send_sizes[i];
295  }
296  par::Mpi_Scan<DendroIntL>( lsz, gscan, k, MPI_SUM, comm);
297 
298  if (rank == npes-1) {
299  for(size_t i = 0; i < k; ++i) {
300  gsz[i] = gscan[i];
301  }
302  }
303  // broadcast from last proc to get total counts, per segment ...
304  par::Mpi_Bcast<DendroIntL>( gsz, k, npes-1, comm);
305 
306  DendroIntL segment_p0[k];
307  for(size_t i = 0; i < k; ++i) {
308  segment_p0[i] = (i*npes)/k;
309  }
310 
311  /*
312  * -- Dividing into k segments, so each segment will have npes/k procs.
313  * -- Each proc will have gsz[i]/(npes/k) elements.
314  * -- rank of proc which will get i-th send_buff is,
315  * -- segment_p0[i] + gscan[i]
316  */
317 
318  // figure out send_partners for k sends
319  // send_partners.clear();
320  for(size_t i = 0; i < k; ++i) {
321  int new_part;
322  int seg_npes = ( (i == k-1) ? npes - segment_p0[i] : segment_p0[i+1]-segment_p0[i] );
323  int overhang = gsz[i] % seg_npes;
324  DendroIntL rank_mid = gscan[i] - lsz[i]/2;
325  if ( rank_mid < overhang*(gsz[i]/seg_npes + 1)) {
326  new_part = segment_p0[i] + rank_mid/(gsz[i]/seg_npes + 1);
327  } else {
328  new_part = segment_p0[i] + (rank_mid - overhang)/(gsz[i]/seg_npes);
329  }
330  send_partners[i] = new_part;
331  }
332 
333  int idx=0;
334  if (send_partners[0] == rank) {
335  send_sizes[0] = 0;
336  }
337  for(size_t i = 1; i < k; ++i)
338  {
339  if (send_partners[i] == rank) {
340  send_sizes[i] = 0;
341  idx = i;
342  continue;
343  }
344  if (send_partners[i] == send_partners[i-1]) {
345  send_sizes[idx] += lsz[i];
346  send_sizes[i]=0;
347  } else {
348  idx = i;
349  }
350  }
351 
352  // let procs know you will be sending to them ...
353 
354  // try MPI one sided comm
355  MPI_Win win;
356  int *rcv;
357  MPI_Alloc_mem(sizeof(int)*npes, MPI_INFO_NULL, &rcv);
358  for(size_t i = 0; i < npes; ++i) rcv[i] = 0;
359 
360  MPI_Win_create(rcv, npes, sizeof(int), MPI_INFO_NULL, MPI_COMM_WORLD, &win);
361 
362 
363  MPI_Win_fence(MPI_MODE_NOPRECEDE, win);
364  for (size_t i = 0; i < send_sizes.size(); i++)
365  {
366  if (send_sizes[i]) {
367  MPI_Put(&(send_sizes[i]), 1, MPI_INT, send_partners[i], rank, 1, MPI_INT, win);
368  }
369  }
370  MPI_Win_fence((MPI_MODE_NOSTORE | MPI_MODE_NOSUCCEED), win);
371  // figure out recv partners and sizes ...
372  recv_sizes.clear(); recv_partners.clear();
373  for(size_t i = 0; i < npes; ++i)
374  {
375  if (rcv[i]) {
376  recv_partners.push_back(i);
377  recv_sizes.push_back(rcv[i]);
378  }
379  }
380 
381  MPI_Win_free(&win);
382  MPI_Free_mem(rcv);
383 
384  return 1;
385  }
386 
387 }// end namespace
388 
A set of parallel utilities.
int getPrevHighestPowerOfTwo(unsigned int n)
Definition: binUtils.cpp:75
Traits to determine MPI_DATATYPE from a C++ datatype.
int size
#define DendroIntL
Definition: parUtils.h:28
int AdjustCommunicationPattern(std::vector< int > &send_sizes, std::vector< int > &send_partners, std::vector< int > &recv_sizes, std::vector< int > &recv_partners, MPI_Comm comm)
Definition: parUtils.cpp:279
unsigned int splitCommBinary(MPI_Comm orig_comm, MPI_Comm *new_comm)
Splits a communication group into two, the first having a power of 2 number of processors and the oth...
Definition: parUtils.cpp:21
Collection of Generic Parallel Functions: Sorting, Partitioning, Searching,...
Definition: dtypes.h:18
int splitCommUsingSplittingRank(int splittingRank, MPI_Comm *new_comm, MPI_Comm orig_comm)
Definition: parUtils.cpp:180
unsigned int splitCommBinaryNoFlip(MPI_Comm orig_comm, MPI_Comm *new_comm)
Splits a communication group into two, the first having a power of 2 number of processors and the oth...
Definition: parUtils.cpp:70
A set of efficient functions that use binary operations to perform some small computations.
int splitComm2way(bool iAmEmpty, MPI_Comm *new_comm, MPI_Comm orig_comm)
Splits a communication group into two, one containing processors that passed a value of &#39;false&#39; for t...
Definition: parUtils.cpp:120
int rank