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