QUDA  1.0.0
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
layout_hyper.c
Go to the documentation of this file.
1 /******** layout_hyper.c *********/
2 /* adapted from SciDAC QDP Data Parallel API */
3 /* Includes new entry "get_sites_on_node" */
4 /* adapted from MIMD version 6 */
5 
6 /* ROUTINES WHICH DETERMINE THE DISTRIBUTION OF SITES ON NODES */
7 
8 /* This version divides the lattice by factors of prime numbers in any of the
9  four directions. It prefers to divide the longest dimensions,
10  which mimimizes the area of the surfaces. Similarly, it prefers
11  to divide dimensions which have already been divided, thus not
12  introducing more off-node directions.
13 
14  S. Gottlieb, May 18, 1999
15  The code will start trying to divide with the largest prime factor
16  and then work its way down to 2. The current maximum prime is 53.
17  The array of primes "prime[]" may be extended if necessary.
18 
19  This requires that the lattice volume be divisible by the number
20  of nodes. Each dimension must be divisible by a suitable factor
21  such that the product of the four factors is the number of nodes.
22 
23  3/29/00 EVENFIRST is the rule now. CD.
24  12/10/00 Fixed so k = MAXPRIMES-1 DT
25 */
26 
27 /*
28  setup_layout() sets up layout
29  node_number() returns the node number on which a site lives
30  node_index() returns the index of the site on the node
31  get_coords() gives lattice coords from node & index
32 */
33 
34 
35 #include <stdlib.h>
36 #include <stdio.h>
37 #include <qmp.h>
38 #include <layout_hyper.h>
39 
40 //#include <qio_util.h>
41 
42 /* The following globals are required:
43 
44  QMP_get_logical_topology()
45  QMP_logical_topology_is_declared()
46  this_node
47  QMP_abort()
48 
49 */
50 
51 static int *squaresize = NULL; /* dimensions of hypercubes */
52 static int *nsquares = NULL; /* number of hypercubes in each direction */
53 static int ndim;
54 static int *size1[2] = {NULL, NULL}, *size2 = NULL;
55 static int prime[] = {2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53};
56 static int sites_on_node;
57 static int *mcoord = NULL;
58 
59 #define MAXPRIMES (sizeof(prime)/sizeof(int))
60 
61 // MAC this function assumes that the QMP geometry has been predetermined
62 static void setup_qmp_fixed(int len[], int nd, int numnodes) {
63  int i;
64 
65  //Added by M. Cheng to fix seg fault on single-node case where
66  //QMP topology is not yet declared.
67 
68  if(QMP_get_number_of_nodes() == 1) {
69  for (i=0; i<ndim; i++) {
70  nsquares[i] = 1;
71  squaresize[i] = len[i]/nsquares[i];
72  }
73  } else {
74  for (i=0; i<ndim; i++) {
75  nsquares[i] = QMP_get_logical_dimensions()[i];
76  squaresize[i] = len[i]/nsquares[i];
77  }
78  }
79 
80 }
81 
82 static void setup_qmp_grid(int len[], int nd, int numnodes){
83  int ndim2, i;
84  const int *nsquares2;
85 
86  ndim2 = QMP_get_allocated_number_of_dimensions();
87  nsquares2 = QMP_get_allocated_dimensions();
88  for(i=0; i<ndim; i++) {
89  if(i<ndim2) nsquares[i] = nsquares2[i];
90  else nsquares[i] = 1;
91  }
92 
93  for(i=0; i<ndim; i++) {
94  if(len[i]%nsquares[i] != 0) {
95  printf("LATTICE SIZE DOESN'T FIT GRID\n");
96  QMP_abort(0);
97  }
98  squaresize[i] = len[i]/nsquares[i];
99  }
100 }
101 
102 static void setup_hyper_prime(int len[], int nd, int numnodes)
103 {
104  int i, j, k, n;
105 
106  /* Figure out dimensions of rectangle */
107  for(i=0; i<ndim; ++i) {
108  squaresize[i] = len[i];
109  nsquares[i] = 1;
110  }
111 
112  n = numnodes; /* remaining number of nodes to be factored */
113  k = MAXPRIMES-1;
114  while(n>1) {
115  /* figure out which prime to divide by starting with largest */
116  while( (n%prime[k]!=0) && (k>0) ) --k;
117 
118  /* figure out which direction to divide */
119  /* find largest divisible dimension of h-cubes */
120  /* if one direction with largest dimension has already been
121  divided, divide it again. Otherwise divide first direction
122  with largest dimension. */
123  j = -1;
124  for(i=0; i<ndim; i++) {
125  if(squaresize[i]%prime[k]==0) {
126  if( (j<0) || (squaresize[i]>squaresize[j]) ) {
127  j = i;
128  } else if(squaresize[i]==squaresize[j]) {
129  if((nsquares[j]==1)&&(nsquares[i]!=1)) j = i;
130  }
131  }
132  }
133 
134  /* This can fail if we run out of prime factors in the dimensions */
135  if(j<0) {
136  if(this_node==0) {
137  fprintf(stderr, "LAYOUT: Not enough prime factors in lattice dimensions\n");
138  }
139  QMP_abort(1);
140  exit(1);
141  }
142 
143  /* do the surgery */
144  n /= prime[k];
145  squaresize[j] /= prime[k];
146  nsquares[j] *= prime[k];
147  }
148 }
149 
150 int setup_layout(int len[], int nd, int numnodes){
151  int i;
152 
153  ndim = nd;
154 
155  if (squaresize) free(squaresize);
156  squaresize = (int *) malloc(ndim*sizeof(int));
157 
158  if (nsquares) free(nsquares);
159  nsquares = (int *) malloc(ndim*sizeof(int));
160 
161  if (mcoord) free(mcoord);
162  mcoord = (int *) malloc(ndim*sizeof(int));
163 
164  /*
165  The miniminum surface area partitioning is disabled and QUDA
166  expects it to be determined by the user or calling application, but
167  this functionality is included for possible future use.
168  */
169 
170  int create_geom = 0;
171  if (create_geom) {
172  if(QMP_get_msg_passing_type()==QMP_GRID) {
173  printf("grid\n");
174  setup_qmp_grid(len, ndim, numnodes);
175  } else {
176  printf("prime\n"); setup_hyper_prime(len, ndim, numnodes);
177  }
178  } else {
179  setup_qmp_fixed(len, ndim, numnodes); // use the predetermined geometry
180  }
181 
182  /* setup QMP logical topology */
183  if(!QMP_logical_topology_is_declared()) {
184  if(QMP_declare_logical_topology(nsquares, ndim)!=0)
185  return 1;
186  }
187 
188  sites_on_node = 1;
189  for(i=0; i<ndim; ++i) {
191  }
192 
193  if (size1[0]) free(size1[0]);
194  size1[0] = (int*)malloc(2*(ndim+1)*sizeof(int));
195  size1[1] = size1[0] + ndim + 1;
196 
197  if (size2) free(size2);
198  size2 = (int*)malloc((ndim+1)*sizeof(int));
199 
200  size1[0][0] = 1;
201  size1[1][0] = 0;
202  size2[0] = 1;
203  for(i=1; i<=ndim; i++) {
204  size1[0][i] = size2[i-1]*(squaresize[i-1]/2)
205  + size1[0][i-1]*(squaresize[i-1]%2);
206  size1[1][i] = size2[i-1]*(squaresize[i-1]/2)
207  + size1[1][i-1]*(squaresize[i-1]%2);
208  size2[i] = size1[0][i] + size1[1][i];
209  //printf("%i\t%i\t%i\n", size1[0][i], size1[1][i], size2[i]);
210  }
211  return 0;
212 }
213 
214 int node_number(const int x[])
215 {
216  int i;
217 
218  for(i=0; i<ndim; i++) {
219  mcoord[i] = x[i]/squaresize[i];
220  }
221  return QMP_get_node_number_from(mcoord);
222 }
223 
224 int node_index(const int x[])
225 {
226  int i, r=0, p=0;
227 
228  for(i=ndim-1; i>=0; --i) {
229  r = r*squaresize[i] + (x[i]%squaresize[i]);
230  p += x[i];
231  }
232 
233  if( p%2==0 ) { /* even site */
234  r /= 2;
235  } else {
236  r = (r+sites_on_node)/2;
237  }
238  return r;
239 }
240 
241 void get_coords(int x[], int node, int index)
242 {
243  int i, s, si;
244  int *m;
245 
246  si = index;
247 
248  m = QMP_get_logical_coordinates_from(node);
249 
250  s = 0;
251  for(i=0; i<ndim; ++i) {
252  x[i] = m[i] * squaresize[i];
253  s += x[i];
254  }
255  s &= 1;
256 
257  if(index>=size1[s][ndim]) {
258  index -= size1[s][ndim];
259  s ^= 1;
260  }
261 
262  for(i=ndim-1; i>0; i--) {
263  x[i] += 2*(index/size2[i]);
264  index %= size2[i];
265  if(index>=size1[s][i]) {
266  index -= size1[s][i];
267  s ^= 1;
268  x[i]++;
269  }
270  }
271  x[0] += 2*index + s;
272 
273  free(m);
274 
275  /* Check the result */
276  if(node_index(x)!=si) {
277  if(this_node==0) {
278  fprintf(stderr,"get_coords: error in layout!\n");
279  for(i=0; i<ndim; i++) {
280  fprintf(stderr,"%i\t%i\t%i\n", size1[0][i], size1[1][i], size2[i]);
281  }
282  fprintf(stderr,"%i\t%i", node, si);
283  for(i=0; i<ndim; i++) fprintf(stderr,"\t%i", x[i]);
284  fprintf(stderr,"\n");
285  }
286  QMP_abort(1);
287  exit(1);
288  }
289 }
290 
291 /* The number of sites on the specified node */
292 int num_sites(int node){
293  return sites_on_node;
294 }
static int * mcoord
Definition: layout_hyper.c:57
#define MAXPRIMES
Definition: layout_hyper.c:59
void get_coords(int x[], int node, int index)
Definition: layout_hyper.c:241
static void setup_hyper_prime(int len[], int nd, int numnodes)
Definition: layout_hyper.c:102
int this_node
Definition: qio_field.cpp:9
static void setup_qmp_fixed(int len[], int nd, int numnodes)
Definition: layout_hyper.c:62
static int ndim
Definition: layout_hyper.c:53
static int * size2
Definition: layout_hyper.c:54
static int sites_on_node
Definition: layout_hyper.c:56
static int * nsquares
Definition: layout_hyper.c:52
static int * size1[2]
Definition: layout_hyper.c:54
static int index(int ndim, const int *dims, const int *x)
Definition: comm_common.cpp:32
int setup_layout(int len[], int nd, int numnodes)
Definition: layout_hyper.c:150
__shared__ float s[]
int node_index(const int x[])
Definition: layout_hyper.c:224
int node_number(const int x[])
Definition: layout_hyper.c:214
static int prime[]
Definition: layout_hyper.c:55
static int * squaresize
Definition: layout_hyper.c:51
int num_sites(int node)
Definition: layout_hyper.c:292
static void setup_qmp_grid(int len[], int nd, int numnodes)
Definition: layout_hyper.c:82