QUDA  v0.5.0
A library for QCD on GPUs
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
comm_common.cpp
Go to the documentation of this file.
1 #include <unistd.h> // for gethostname()
2 
3 #include <quda_internal.h>
4 #include <comm_quda.h>
5 
6 
7 struct Topology_s {
8  int ndim;
10  int *ranks;
12  int my_rank;
14  // It might be worth adding communicators to allow for efficient reductions:
15  // #if defined(MPI_COMMS)
16  // MPI_Comm comm;
17  // #elif defined(QMP_COMMS)
18  // QMP_communicator_t comm; // currently only supported by qmp-2.4.0-alpha
19  // #endif
20 };
21 
22 
31 static inline int index(int ndim, const int *dims, const int *x)
32 {
33  int idx = x[0];
34  for (int i = 1; i < ndim; i++) {
35  idx = dims[i]*idx + x[i];
36  }
37  return idx;
38 }
39 
40 
41 static inline bool advance_coords(int ndim, const int *dims, int *x)
42 {
43  bool valid = false;
44  for (int i = ndim-1; i >= 0; i--) {
45  if (x[i] < dims[i]-1) {
46  x[i]++;
47  valid = true;
48  break;
49  } else {
50  x[i] = 0;
51  }
52  }
53  return valid;
54 }
55 
56 
57 char *comm_hostname(void)
58 {
59  static bool cached = false;
60  static char hostname[128];
61 
62  if (!cached) {
63  gethostname(hostname, 128);
64  hostname[127] = '\0';
65  cached = true;
66  }
67 
68  return hostname;
69 }
70 
71 
72 static unsigned long int rand_seed = 137;
73 
81 double comm_drand(void)
82 {
83  const double twoneg48 = 0.35527136788005009e-14;
84  const unsigned long int m = 25214903917, a = 11, mask = 281474976710655;
85  rand_seed = (m * rand_seed + a) & mask;
86  return (twoneg48 * rand_seed);
87 }
88 
89 
90 // QudaCommsMap is declared in quda.h:
91 // typedef int (*QudaCommsMap)(const int *coords, void *fdata);
92 
93 Topology *comm_create_topology(int ndim, const int *dims, QudaCommsMap rank_from_coords, void *map_data)
94 {
95  if (ndim > QUDA_MAX_DIM) {
96  errorQuda("ndim exceeds QUDA_MAX_DIM");
97  }
98 
99  Topology *topo = (Topology *) safe_malloc(sizeof(Topology));
100 
101  topo->ndim = ndim;
102 
103  int nodes = 1;
104  for (int i=0; i<ndim; i++) {
105  topo->dims[i] = dims[i];
106  nodes *= dims[i];
107  }
108 
109  topo->ranks = (int *) safe_malloc(nodes*sizeof(int));
110  topo->coords = (int (*)[QUDA_MAX_DIM]) safe_malloc(nodes*sizeof(int[QUDA_MAX_DIM]));
111 
112  int x[QUDA_MAX_DIM];
113  for (int i = 0; i < ndim; i++) {
114  x[i] = 0;
115  }
116 
117  do {
118  int rank = rank_from_coords(x, map_data);
119  topo->ranks[index(ndim, dims, x)] = rank;
120  for (int i=0; i<ndim; i++) {
121  topo->coords[rank][i] = x[i];
122  }
123  } while (advance_coords(ndim, dims, x));
124 
125  int my_rank = comm_rank();
126  topo->my_rank = my_rank;
127  for (int i = 0; i < ndim; i++) {
128  topo->my_coords[i] = topo->coords[my_rank][i];
129  }
130 
131  // initialize the random number generator with a rank-dependent seed
132  rand_seed = 17*my_rank + 137;
133 
134  return topo;
135 }
136 
137 
139 {
140  host_free(topo->ranks);
141  host_free(topo->coords);
142  host_free(topo);
143 }
144 
145 
146 int comm_ndim(const Topology *topo)
147 {
148  return topo->ndim;
149 }
150 
151 
152 const int *comm_dims(const Topology *topo)
153 {
154  return topo->dims;
155 }
156 
157 
158 const int *comm_coords(const Topology *topo)
159 {
160  return topo->my_coords;
161 }
162 
163 
164 const int *comm_coords_from_rank(const Topology *topo, int rank)
165 {
166  return topo->coords[rank];
167 }
168 
169 
170 int comm_rank_from_coords(const Topology *topo, const int *coords)
171 {
172  return topo->ranks[index(topo->ndim, topo->dims, coords)];
173 }
174 
175 
176 static inline int mod(int a, int b)
177 {
178  return ((a % b) + b) % b;
179 }
180 
181 int comm_rank_displaced(const Topology *topo, const int displacement[])
182 {
183  int coords[QUDA_MAX_DIM];
184 
185  for (int i = 0; i < topo->ndim; i++) {
186  coords[i] = mod(comm_coords(topo)[i] + displacement[i], comm_dims(topo)[i]);
187  }
188  return comm_rank_from_coords(topo, coords);
189 }
190 
191 
192 // FIXME: The following routines rely on a "default" topology.
193 // They should probably be reworked or eliminated eventually.
194 
196 
198 {
199  default_topo = topo;
200 }
201 
202 
204 {
205  if (!default_topo) {
206  errorQuda("Default topology has not been declared");
207  }
208  return default_topo;
209 }
210 
211 
212 int comm_dim(int dim)
213 {
215  return comm_dims(topo)[dim];
216 }
217 
218 
219 int comm_coord(int dim)
220 {
222  return comm_coords(topo)[dim];
223 }
224 
225 
229 MsgHandle *comm_declare_send_relative(void *buffer, int dim, int dir, size_t nbytes)
230 {
231  int disp[QUDA_MAX_DIM] = {0};
232  disp[dim] = dir;
233 
234  return comm_declare_send_displaced(buffer, disp, nbytes);
235 }
236 
237 
241 MsgHandle *comm_declare_receive_relative(void *buffer, int dim, int dir, size_t nbytes)
242 {
243  int disp[QUDA_MAX_DIM] = {0};
244  disp[dim] = dir;
245 
246  return comm_declare_receive_displaced(buffer, disp, nbytes);
247 }
248 
249 
250 void comm_finalize(void)
251 {
253  comm_destroy_topology(topo);
255 }
256 
257 
258 static int manual_set_partition[QUDA_MAX_DIM] = {0};
259 
261 {
262  manual_set_partition[dim] = 1;
263 }
264 
265 
267 {
268  return (manual_set_partition[dim] || (comm_dim(dim) > 1));
269 }