Bridge++  Ver. 1.1.x
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
layout.cpp
Go to the documentation of this file.
1 
14 #include "layout.h"
15 
16 static const char rcsid[] = "$Id: layout.cpp 942 2013-07-22 06:50:06Z aoym $";
17 
18 // prototype declaration
19 namespace {
20  static int pe_logical_layout(const int ndim, const int *dims, int nproc, int *npe);
21  static int find_primes(const int n, int *p);
22 }
23 
24 // static members
26 int *Communicator_impl::Layout::m_dims = 0; //< lattice extent
27 
28 // logical layout
31 
34 
35 // physical mapping
37 int *Communicator_impl::Layout::m_physical_to_logical = 0; //< map between physical and logical grid
38 
39 // subdimensional-slices
41 
42 
43 // communicator_impl methods
44 
45 int Communicator_impl::Layout::ipe(const int idir)
46 {
47  return m_grid_coord[idir];
48 }
49 
50 
51 int Communicator_impl::Layout::npe(const int idir)
52 {
53  return m_grid_dims[idir];
54 }
55 
56 
58 {
59  for (int i = 0; i < m_ndim; ++i) {
60  dims[i] = m_grid_dims[i];
61  }
62  return EXIT_SUCCESS;
63 }
64 
65 
66 // tag() : identify transfer channel by source rank and direction (incl fw/bw)
67 int Communicator_impl::Layout::tag(int rank, int idir, int ipm)
68 {
69  return 2 * m_ndim * rank + idir + ((ipm > 0) ? 0 : m_ndim);
70 }
71 
72 
74 
92 {
94 
95  // lattice size
96  m_dims = new int [m_ndim];
97 
98  m_dims[0] = CommonParameters::Lx();
99  m_dims[1] = CommonParameters::Ly();
100  m_dims[2] = CommonParameters::Lz();
101  m_dims[3] = CommonParameters::Lt();
102 
103  // suggested logical layout
104  m_grid_dims = new int [m_ndim];
105 
106  m_grid_dims[0] = CommonParameters::NPEx();
107  m_grid_dims[1] = CommonParameters::NPEy();
108  m_grid_dims[2] = CommonParameters::NPEz();
109  m_grid_dims[3] = CommonParameters::NPEt();
110 
111  // suggested local volume
112  int *local_dims = new int [m_ndim];
113 
114  local_dims[0] = CommonParameters::Nx();
115  local_dims[1] = CommonParameters::Ny();
116  local_dims[2] = CommonParameters::Nz();
117  local_dims[3] = CommonParameters::Nt();
118 
119  for (int i = 0; i < m_ndim; ++i) {
120  if (local_dims[i] != 0) { // there is a suggestion of local extent.
121  if (m_grid_dims[i] != 0) {
122  if (m_grid_dims[i] * local_dims[i] != m_dims[i]) {
123  fprintf(stderr, "layout mismatch.\n");
124  abort();
125  } else {
126  // ok. m_grid_dims[i] is as specified.
127  }
128  } else { // use specified local size and find number of divisions.
129  if (m_dims[i] % local_dims[i] != 0) {
130  fprintf(stderr, "layout mismatch. lattice undivisable by local volume.\n");
131  abort();
132  } else {
133  m_grid_dims[i] = m_dims[i] / local_dims[i];
134  }
135  }
136  }
137  }
138 
139  // find logical layout
140  int retv = pe_logical_layout(m_ndim, m_dims, m_grid_size, m_grid_dims);
141 
142  if (retv != EXIT_SUCCESS) {
143  fprintf(stderr, "layout failed.\n");
144  abort();
145  }
146 
147  // physical to logical map
148  physical_map_setup();
149 
150  // find logical coordinate of my rank
151  m_grid_coord = new int [m_ndim];
152  grid_coord(m_grid_coord, m_grid_rank);
153 
154  // find neighbour rank
155  m_ipe_up = new int [m_ndim];
156  m_ipe_dn = new int [m_ndim];
157 
158  int *coord = new int [m_ndim];
159  for (int i = 0; i < m_ndim; ++i) {
160  for (int j = 0; j < m_ndim; ++j) {
161  coord[j] = m_grid_coord[j];
162  }
163 
164  // upward
165  coord[i] = (m_grid_coord[i] + 1) % m_grid_dims[i];
166  grid_rank(&m_ipe_up[i], coord);
167 
168  // downward
169  coord[i] = (m_grid_coord[i] - 1 + m_grid_dims[i]) % m_grid_dims[i];
170  grid_rank(&m_ipe_dn[i], coord);
171  }
172  delete [] coord;
173 
174 
175 #ifdef DEBUG
176  printf("rank %d: up=(%d,%d,%d,%d), dn=(%d,%d,%d,%d)\n",
178  m_ipe_up[0], m_ipe_up[1], m_ipe_up[2], m_ipe_up[3],
179  m_ipe_dn[0], m_ipe_dn[1], m_ipe_dn[2], m_ipe_dn[3]);
180 #endif
181 
182 
183  // subgrid of reduced dimension.
184  subgrid_setup();
185 
186  return EXIT_SUCCESS;
187 }
188 
189 
191 {
192  subgrid_delete();
193 
194  physical_map_delete();
195 
196  delete [] m_dims;
197  delete [] m_grid_dims;
198  delete [] m_grid_coord;
199  delete [] m_ipe_up;
200  delete [] m_ipe_dn;
201 
202  return EXIT_SUCCESS;
203 }
204 
205 
206 // subgrid for communication in reduced dimensional subsets
207 
209 {
210  m_sub_comm = new MPI_Comm [(1 << m_ndim)];
211 
212  for (int imask = 0; imask < (1 << m_ndim); ++imask) {
213  int coord[m_ndim];
214  for (int i = 0; i < m_ndim; ++i) {
215  coord[i] = m_grid_coord[i];
216  }
217 
218  for (int i = 0; i < m_ndim; ++i) {
219  bool mask = ((imask >> i) & 1) == 1 ? true : false;
220  if (!mask) coord[i] = 0;
221  }
222 
223  int rank = 0;
224  grid_rank(coord, &rank);
225 
226 /*
227  printf("split %2d: rank %2d: (%d,%d,%d,%d) -> (%d,%d,%d,%d), %2d\n",
228  imask,
229  m_grid_rank,
230  m_grid_coord[0], m_grid_coord[1], m_grid_coord[2], m_grid_coord[3],
231  coord[0], coord[1], coord[2], coord[3],
232  rank);
233 */
234  MPI_Comm_split(m_comm, rank, 0 /* key */, &m_sub_comm[imask]);
235  }
236 
237  return EXIT_SUCCESS;
238 }
239 
240 
242 {
243  delete [] m_sub_comm;
244 
245  return EXIT_SUCCESS;
246 }
247 
248 
249 namespace { // anonymous namespace
250 // layout
251  static const int prime_table[] =
252  {
253  2, 3, 5, 7, 11, 13, 17, 19,
254  23, 29, 31, 37, 41, 43, 47, 53,
255  59, 61, 67, 71, 73, 79, 83, 89,
256  97, 101, 103, 107, 109, 113, 127, 131,
257  137, 139, 149, 151, 157, 163, 167, 173,
258  179, 181, 191, 193, 197, 199, 211, 223,
259  227, 229, 233, 239, 241, 251, 257, 263,
260  269, 271, 277, 281, 283, 293, 307, 311,
261  };
262 
263  static const int nprime = sizeof(prime_table) / sizeof(int);
264 
265 //* find logical layout
266 //* divide dims_mu into npe_mu x local_mu where prod npe_mu = nproc.
267 //* npe_mu != 0 is kept intact.
268  static int pe_logical_layout(const int ndim, const int *dims, int nproc, int *npe)
269  {
270  int retv = EXIT_SUCCESS;
271 
272  int nfreedim = 0;
273  int nfreeproc = nproc;
274 
275  for (int i = 0; i < ndim; ++i) {
276  if (npe[i] == 0) {
277  ++nfreedim;
278  } else {
279  if (npe[i] < 0) {
280  fprintf(stderr, "illegal value: npe[%d]=%d.\n", i, npe[i]);
281  return EXIT_FAILURE;
282  } else if (nproc % npe[i] != 0) {
283  fprintf(stderr, "illegal value: npe[%d]=%d does not divide NPE=%d.\n", i, npe[i], nproc);
284  return EXIT_FAILURE;
285  } else if (nfreeproc % npe[i] != 0) {
286  fprintf(stderr, "illegal value: NPE=%d is not divisable by %d.\n", nproc, nproc / nfreeproc * npe[i]);
287  return EXIT_FAILURE;
288  } else if (dims[i] % npe[i] != 0) {
289  fprintf(stderr, "illegal value: npe[%d]=%d does not divide L=%d.\n", i, npe[i], dims[i]);
290  return EXIT_FAILURE;
291  } else {
292  nfreeproc /= npe[i];
293  }
294  }
295  }
296 
297  if (nfreeproc < 1) {
298  fprintf(stderr, "impossible layout.\n");
299  return EXIT_FAILURE;
300  } else if (nfreeproc == 1) {
301  for (int i = 0; i < ndim; ++i) {
302  if (npe[i] == 0) npe[i] = 1;
303  }
304  return EXIT_SUCCESS; // complete.
305  } else {
306  if (nfreedim == 0) {
307  fprintf(stderr, "impossible layout. no room to divide.\n");
308  return EXIT_FAILURE;
309  }
310  }
311 
312  // divide nfreeproc to nfreedim npe's.
313  int np = nfreeproc;
314 
315  int *subdims = new int [ndim];
316  int nf = 0;
317  for (int i = 0; i < ndim; ++i) {
318  if (npe[i] == 0) subdims[nf++] = dims[i]; }
319 
320  int *count = new int [nprime];
321  for (int i = 0; i < nprime; ++i) {
322  count[i] = 0;
323  }
324 
325  for (int i = 0; i < nprime; ++i) {
326  int p = prime_table[i];
327  while (np > 1 && np % p == 0)
328  {
329  ++count[i];
330  np /= p;
331  }
332  if (np == 1) break;
333  }
334 
335 // printf("%d = (", nfreeproc);
336 // for (int i=0; i<nprime; ++i) {
337 // printf("%d, ", count[i]);
338 // }
339 // printf(")\n");
340 
341  if (np > 1) {
342  fprintf(stderr, "insufficient prime table.\n");
343  retv = EXIT_FAILURE;
344  goto finalize;
345  }
346 
347 // printf("subdims=(");
348 // for (int i=0; i<nf; ++i) {
349 // printf("%d, ", subdims[i]);
350 // }
351 // printf(")\n");
352 
353  for (int i = nprime - 1; i >= 0; --i) {
354  if (count[i] == 0) continue;
355 
356  int p = prime_table[i];
357 
358  for (int j = 0; j < count[i]; ++j) {
359  int maxsubdim = 0;
360  int maxk = -1;
361  for (int k = 0; k < nf; ++k) {
362  if ((subdims[k] >= maxsubdim) && (subdims[k] % p == 0)) {
363  maxsubdim = subdims[k];
364  maxk = k;
365  }
366  }
367 // printf("prime=%d, maxk=%d, maxsubdim=%d\n", p, maxk, maxsubdim);
368 
369  if (maxk == -1) {
370  fprintf(stderr, "not divisable. %d\n", p);
371  retv = EXIT_FAILURE;
372  goto finalize;
373  }
374 
375  subdims[maxk] /= p;
376  }
377  }
378 
379 /*
380  printf("subdims=(");
381  for (int i=0; i<nf; ++i) {
382  printf("%d, ", subdims[i]);
383  }
384  printf(")\n");
385 */
386  // store
387  for (int i = 0, k = 0; i < ndim; ++i) {
388  if (npe[i] == 0) {
389  npe[i] = dims[i] / subdims[k];
390  ++k;
391  }
392  }
393 
394 finalize:
395  delete [] subdims;
396  delete [] count;
397 
398  return retv;
399  }
400 
401 
402 //* find n primes.
403  static int find_primes(const int n, int *p)
404  {
405  if (n < 1) return EXIT_FAILURE;
406 
407  int i = 0;
408  int k = 2;
409 
410  p[i++] = k++;
411 
412  while (1)
413  {
414  int j;
415  for (j = 0; j < i; ++j) {
416  if (k % p[j] == 0) break;
417  }
418 
419  if (j >= i) { // not divisable by p[0]..p[i-1]. found new prime.
420  p[i++] = k;
421  if (i >= n) return EXIT_FAILURE;
422  }
423 
424  ++k;
425  }
426 
427  return EXIT_SUCCESS;
428  }
429 } // anonymous namespace