QUDA v0.4.0
A library for QCD on GPUs
|
00001 /******** layout_hyper.c *********/ 00002 /* adapted from SciDAC QDP Data Parallel API */ 00003 /* Includes new entry "get_sites_on_node" */ 00004 /* adapted from MIMD version 6 */ 00005 00006 /* ROUTINES WHICH DETERMINE THE DISTRIBUTION OF SITES ON NODES */ 00007 00008 /* This version divides the lattice by factors of prime numbers in any of the 00009 four directions. It prefers to divide the longest dimensions, 00010 which mimimizes the area of the surfaces. Similarly, it prefers 00011 to divide dimensions which have already been divided, thus not 00012 introducing more off-node directions. 00013 00014 S. Gottlieb, May 18, 1999 00015 The code will start trying to divide with the largest prime factor 00016 and then work its way down to 2. The current maximum prime is 53. 00017 The array of primes "prime[]" may be extended if necessary. 00018 00019 This requires that the lattice volume be divisible by the number 00020 of nodes. Each dimension must be divisible by a suitable factor 00021 such that the product of the four factors is the number of nodes. 00022 00023 3/29/00 EVENFIRST is the rule now. CD. 00024 12/10/00 Fixed so k = MAXPRIMES-1 DT 00025 */ 00026 00027 /* 00028 setup_layout() sets up layout 00029 node_number() returns the node number on which a site lives 00030 node_index() returns the index of the site on the node 00031 get_coords() gives lattice coords from node & index 00032 */ 00033 00034 00035 #include <stdlib.h> 00036 #include <stdio.h> 00037 #include <qmp.h> 00038 #include <layout_hyper.h> 00039 00040 //#include <qio_util.h> 00041 00042 /* The following globals are required: 00043 00044 QMP_get_logical_topology() 00045 QMP_logical_topology_is_declared() 00046 this_node 00047 QMP_abort() 00048 00049 */ 00050 00051 static int *squaresize; /* dimensions of hypercubes */ 00052 static int *nsquares; /* number of hypercubes in each direction */ 00053 static int ndim; 00054 static int *size1[2], *size2; 00055 static int prime[] = {2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53}; 00056 static int sites_on_node; 00057 static int *mcoord; 00058 00059 #define MAXPRIMES (sizeof(prime)/sizeof(int)) 00060 00061 // MAC this function assumes that the QMP geometry has been predetermined 00062 static void setup_qmp_fixed(int len[], int nd, int numnodes) { 00063 int i; 00064 00065 for (i=0; i<ndim; i++) { 00066 nsquares[i] = QMP_get_logical_dimensions()[i]; 00067 squaresize[i] = len[i]/nsquares[i]; 00068 } 00069 00070 } 00071 00072 static void setup_qmp_grid(int len[], int nd, int numnodes){ 00073 int ndim2, i; 00074 const int *nsquares2; 00075 00076 ndim2 = QMP_get_allocated_number_of_dimensions(); 00077 nsquares2 = QMP_get_allocated_dimensions(); 00078 for(i=0; i<ndim; i++) { 00079 if(i<ndim2) nsquares[i] = nsquares2[i]; 00080 else nsquares[i] = 1; 00081 } 00082 00083 for(i=0; i<ndim; i++) { 00084 if(len[i]%nsquares[i] != 0) { 00085 printf("LATTICE SIZE DOESN'T FIT GRID\n"); 00086 QMP_abort(0); 00087 } 00088 squaresize[i] = len[i]/nsquares[i]; 00089 } 00090 } 00091 00092 static void setup_hyper_prime(int len[], int nd, int numnodes) 00093 { 00094 int i, j, k, n; 00095 00096 /* Figure out dimensions of rectangle */ 00097 for(i=0; i<ndim; ++i) { 00098 squaresize[i] = len[i]; 00099 nsquares[i] = 1; 00100 } 00101 00102 n = numnodes; /* remaining number of nodes to be factored */ 00103 k = MAXPRIMES-1; 00104 while(n>1) { 00105 /* figure out which prime to divide by starting with largest */ 00106 while( (n%prime[k]!=0) && (k>0) ) --k; 00107 00108 /* figure out which direction to divide */ 00109 /* find largest divisible dimension of h-cubes */ 00110 /* if one direction with largest dimension has already been 00111 divided, divide it again. Otherwise divide first direction 00112 with largest dimension. */ 00113 j = -1; 00114 for(i=0; i<ndim; i++) { 00115 if(squaresize[i]%prime[k]==0) { 00116 if( (j<0) || (squaresize[i]>squaresize[j]) ) { 00117 j = i; 00118 } else if(squaresize[i]==squaresize[j]) { 00119 if((nsquares[j]==1)&&(nsquares[i]!=1)) j = i; 00120 } 00121 } 00122 } 00123 00124 /* This can fail if we run out of prime factors in the dimensions */ 00125 if(j<0) { 00126 if(this_node==0) { 00127 fprintf(stderr, "LAYOUT: Not enough prime factors in lattice dimensions\n"); 00128 } 00129 QMP_abort(1); 00130 exit(1); 00131 } 00132 00133 /* do the surgery */ 00134 n /= prime[k]; 00135 squaresize[j] /= prime[k]; 00136 nsquares[j] *= prime[k]; 00137 } 00138 } 00139 00140 int setup_layout(int len[], int nd, int numnodes){ 00141 int i; 00142 00143 ndim = nd; 00144 squaresize = (int *) malloc(ndim*sizeof(int)); 00145 nsquares = (int *) malloc(ndim*sizeof(int)); 00146 mcoord = (int *) malloc(ndim*sizeof(int)); 00147 00148 /* 00149 MAC: The miniminum surface area partitioning is disabled and QUDA 00150 expects it to be determined by the user or calling application, but 00151 this functionality is included for possible future use. 00152 */ 00153 00154 #if 0 00155 if(QMP_get_msg_passing_type()==QMP_GRID) { 00156 printf("grid\n"); 00157 setup_qmp_grid(len, ndim, numnodes); 00158 } else { 00159 printf("prime\n"); setup_hyper_prime(len, ndim, numnodes); 00160 } 00161 #else 00162 setup_qmp_fixed(len, ndim, numnodes); // use the predetermined geometry 00163 #endif 00164 00165 /* setup QMP logical topology */ 00166 if(!QMP_logical_topology_is_declared()) { 00167 if(QMP_declare_logical_topology(nsquares, ndim)!=0) 00168 return 1; 00169 } 00170 00171 sites_on_node = 1; 00172 for(i=0; i<ndim; ++i) { 00173 sites_on_node *= squaresize[i]; 00174 } 00175 00176 size1[0] = (int*)malloc(2*(ndim+1)*sizeof(int)); 00177 size1[1] = size1[0] + ndim + 1; 00178 size2 = (int*)malloc((ndim+1)*sizeof(int)); 00179 00180 size1[0][0] = 1; 00181 size1[1][0] = 0; 00182 size2[0] = 1; 00183 for(i=1; i<=ndim; i++) { 00184 size1[0][i] = size2[i-1]*(squaresize[i-1]/2) 00185 + size1[0][i-1]*(squaresize[i-1]%2); 00186 size1[1][i] = size2[i-1]*(squaresize[i-1]/2) 00187 + size1[1][i-1]*(squaresize[i-1]%2); 00188 size2[i] = size1[0][i] + size1[1][i]; 00189 //printf("%i\t%i\t%i\n", size1[0][i], size1[1][i], size2[i]); 00190 } 00191 return 0; 00192 } 00193 00194 int node_number(const int x[]) 00195 { 00196 int i; 00197 00198 for(i=0; i<ndim; i++) { 00199 mcoord[i] = x[i]/squaresize[i]; 00200 } 00201 return QMP_get_node_number_from(mcoord); 00202 } 00203 00204 int node_index(const int x[]) 00205 { 00206 int i, r=0, p=0; 00207 00208 for(i=ndim-1; i>=0; --i) { 00209 r = r*squaresize[i] + (x[i]%squaresize[i]); 00210 p += x[i]; 00211 } 00212 00213 if( p%2==0 ) { /* even site */ 00214 r /= 2; 00215 } else { 00216 r = (r+sites_on_node)/2; 00217 } 00218 return r; 00219 } 00220 00221 void get_coords(int x[], int node, int index) 00222 { 00223 int i, s, si; 00224 int *m; 00225 00226 si = index; 00227 00228 m = QMP_get_logical_coordinates_from(node); 00229 00230 s = 0; 00231 for(i=0; i<ndim; ++i) { 00232 x[i] = m[i] * squaresize[i]; 00233 s += x[i]; 00234 } 00235 s &= 1; 00236 00237 if(index>=size1[s][ndim]) { 00238 index -= size1[s][ndim]; 00239 s ^= 1; 00240 } 00241 00242 for(i=ndim-1; i>0; i--) { 00243 x[i] += 2*(index/size2[i]); 00244 index %= size2[i]; 00245 if(index>=size1[s][i]) { 00246 index -= size1[s][i]; 00247 s ^= 1; 00248 x[i]++; 00249 } 00250 } 00251 x[0] += 2*index + s; 00252 00253 free(m); 00254 00255 /* Check the result */ 00256 if(node_index(x)!=si) { 00257 if(this_node==0) { 00258 fprintf(stderr,"get_coords: error in layout!\n"); 00259 for(i=0; i<ndim; i++) { 00260 fprintf(stderr,"%i\t%i\t%i\n", size1[0][i], size1[1][i], size2[i]); 00261 } 00262 fprintf(stderr,"%i\t%i", node, si); 00263 for(i=0; i<ndim; i++) fprintf(stderr,"\t%i", x[i]); 00264 fprintf(stderr,"\n"); 00265 } 00266 QMP_abort(1); 00267 exit(1); 00268 } 00269 } 00270 00271 /* The number of sites on the specified node */ 00272 int num_sites(int node){ 00273 return sites_on_node; 00274 }