NEURON
nrnmpi.cpp
Go to the documentation of this file.
1 #include <../../nrnconf.h>
2 #include <assert.h>
3 #include "nrnassrt.h"
4 #include <stdio.h>
5 #include <string.h>
6 #include <stdlib.h>
7 #include "nrnpthread.h"
8 
9 /* do not want the redef in the dynamic load case */
10 #include <nrnmpiuse.h>
11 #if NRNMPI_DYNAMICLOAD
12 #include <nrnmpi_dynam.h> /* define all the nrnmpi functions name to f_name */
13 #endif
14 
15 #include <nrnmpi.h>
16 #include <mpispike.h>
17 
18 
19 #if NRNMPI_DYNAMICLOAD
20 #else
21 #include "nrnmpi_def_cinc"
22 #endif
23 
24 extern double nrn_timeus();
25 
26 #if NRNMPI
27 #include <mpi.h>
28 #define asrt(arg) nrn_assert(arg == MPI_SUCCESS)
29 #define USE_HPM 0
30 #if USE_HPM
31 #include <libhpm.h>
32 #endif
33 
34 int nrnmusic;
35 #if NRN_MUSIC
36 MPI_Comm nrnmusic_comm;
37 extern void nrnmusic_init(int* parg, char*** pargv);
38 extern void nrnmusic_terminate();
39 #endif
40 
41 MPI_Comm nrnmpi_world_comm;
42 MPI_Comm nrnmpi_comm;
43 MPI_Comm nrn_bbs_comm;
44 static MPI_Group grp_bbs;
45 static MPI_Group grp_net;
46 
47 extern void nrnmpi_spike_initialize();
48 
49 #define nrnmpidebugleak 0
50 #if nrnmpidebugleak
51 extern void nrnmpi_checkbufleak();
52 #endif
53 
54 static int nrnmpi_under_nrncontrol_;
55 static int nrnmpi_is_setup_;
56 #endif
57 
58 extern "C" void nrnmpi_init(int nrnmpi_under_nrncontrol, int* pargc, char*** pargv) {
59 #if NRNMPI
60  int i, b, flag;
61  if (nrnmpi_use) {
62  return;
63  }
64  nrnmpi_under_nrncontrol_ = nrnmpi_under_nrncontrol;
65  if (nrnmpi_under_nrncontrol_) {
66 #if 0
67 {int i;
68 printf("nrnmpi_init: argc=%d\n", *pargc);
69 for (i=0; i < *pargc; ++i) {
70  printf("%d |%s|\n", i, (*pargv)[i]);
71 }
72 }
73 #endif
74 
75 #if NRN_MUSIC
76  nrnmusic_init(pargc, pargv); /* see src/nrniv/nrnmusic.cpp */
77 #endif
78 
79 #if !ALWAYS_CALL_MPI_INIT
80  /* this is not good. depends on mpirun adding at least one
81  arg that starts with -p4 but that probably is dependent
82  on mpich and the use of the ch_p4 device. We are trying to
83  work around the problem that MPI_Init may change the working
84  directory and so when not invoked under mpirun we would like to
85  NOT call MPI_Init.
86  */
87  b = 0;
88  for (i = 0; i < *pargc; ++i) {
89  if (strncmp("-p4", (*pargv)[i], 3) == 0) {
90  b = 1;
91  break;
92  }
93  if (strcmp("-mpi", (*pargv)[i]) == 0) {
94  b = 1;
95  break;
96  }
97  }
98  if (nrnmpi_under_nrncontrol_ == 2) {
99  b = 1;
100  nrnmpi_under_nrncontrol_ = 1;
101  }
102  if (nrnmusic) {
103  b = 1;
104  }
105  if (!b) {
106  nrnmpi_under_nrncontrol_ = 0;
107  return;
108  }
109 #endif
110  MPI_Initialized(&flag);
111 
112  /* only call MPI_Init if not already initialized */
113  if (!flag) {
114 #if (USE_PTHREAD)
115  int required = MPI_THREAD_SERIALIZED;
116  int provided;
117  asrt(MPI_Init_thread(pargc, pargv, required, &provided));
118  if (required > provided) {
119  nrn_cannot_use_threads_and_mpi = 1;
120  }
121 #else
122  asrt(MPI_Init(pargc, pargv));
123 #endif
124  nrnmpi_under_nrncontrol_ = 1;
125  } else if (!nrnmusic) {
126  nrnmpi_under_nrncontrol_ = 0;
127  }
128 
129 #if NRN_MUSIC
130  if (nrnmusic) {
131  asrt(MPI_Comm_dup(nrnmusic_comm, &nrnmpi_world_comm));
132  } else {
133 #else
134  {
135 #endif
136  asrt(MPI_Comm_dup(MPI_COMM_WORLD, &nrnmpi_world_comm));
137  }
138  }
139  grp_bbs = MPI_GROUP_NULL;
140  grp_net = MPI_GROUP_NULL;
141  asrt(MPI_Comm_dup(nrnmpi_world_comm, &nrnmpi_comm));
142  asrt(MPI_Comm_dup(nrnmpi_world_comm, &nrn_bbs_comm));
143  asrt(MPI_Comm_rank(nrnmpi_world_comm, &nrnmpi_myid_world));
144  asrt(MPI_Comm_size(nrnmpi_world_comm, &nrnmpi_numprocs_world));
147  nrnmpi_spike_initialize();
148  nrnmpi_use = 1;
149 
150  /*begin instrumentation*/
151 #if USE_HPM
152  hpmInit(nrnmpi_myid_world, "mpineuron");
153 #endif
154 #if 0
155 {int i;
156 printf("nrnmpi_init: argc=%d\n", *pargc);
157 for (i=0; i < *pargc; ++i) {
158  printf("%d |%s|\n", i, (*pargv)[i]);
159 }
160 }
161 #endif
162 #if 1
163  if (nrnmpi_myid == 0) {
164  printf("numprocs=%d\n", nrnmpi_numprocs_world);
165  }
166 #endif
167 
168 #endif /* NRNMPI */
169 }
170 
171 double nrnmpi_wtime() {
172 #if NRNMPI
173  if (nrnmpi_use) {
174  return MPI_Wtime();
175  }
176 #endif
177  return nrn_timeus();
178 }
179 
181 #if NRNMPI
182  if (nrnmpi_use) {
183 #if 0
184  printf("%d nrnmpi_terminate\n", nrnmpi_myid_world);
185 #endif
186 #if USE_HPM
187  hpmTerminate(nrnmpi_myid_world);
188 #endif
189  if (nrnmpi_under_nrncontrol_) {
190 #if NRN_MUSIC
191  if (nrnmusic) {
193  } else
194 #endif
195  MPI_Finalize();
196  }
197  nrnmpi_use = 0;
198 #if nrnmpidebugleak
199  nrnmpi_checkbufleak();
200 #endif
201  }
202 #endif /*NRNMPI*/
203 }
204 
205 void nrnmpi_abort(int errcode) {
206 #if NRNMPI
207  int flag;
208  MPI_Initialized(&flag);
209  if (flag) {
210  MPI_Abort(MPI_COMM_WORLD, errcode);
211  } else {
212  abort();
213  }
214 #else
215  abort();
216 #endif
217 }
218 
219 #if NRNMPI
220 void nrnmpi_subworld_size(int n) {
221  /* n is the (desired) size of a subworld (pc.nhost) */
222  /* A subworld (net) is contiguous */
223  /* In case pc.nhost_world/n is not an integer, there are
224  pc.nhost_world/n + 1 subworlds and the last subworld
225  has pc.nhost_world%n ranks. All the other subworlds have n ranks.
226  */
227  if (nrnmpi_use != 1) {
228  return;
229  }
230  if (nrnmpi_comm != MPI_COMM_NULL) {
231  asrt(MPI_Comm_free(&nrnmpi_comm));
232  nrnmpi_comm = MPI_COMM_NULL;
233  }
234  if (nrn_bbs_comm != MPI_COMM_NULL) {
235  asrt(MPI_Comm_free(&nrn_bbs_comm));
236  nrn_bbs_comm = MPI_COMM_NULL;
237  }
238  if (grp_bbs != MPI_GROUP_NULL) {
239  asrt(MPI_Group_free(&grp_bbs));
240  grp_bbs = MPI_GROUP_NULL;
241  }
242  if (grp_net != MPI_GROUP_NULL) {
243  asrt(MPI_Group_free(&grp_net));
244  grp_net = MPI_GROUP_NULL;
245  }
246  MPI_Group wg;
247  asrt(MPI_Comm_group(nrnmpi_world_comm, &wg));
248  int r = nrnmpi_myid_world;
249  /* special cases */
250  if (n == 1) {
251  asrt(MPI_Group_incl(wg, 1, &r, &grp_net));
252  asrt(MPI_Comm_dup(nrnmpi_world_comm, &nrn_bbs_comm));
253  asrt(MPI_Comm_create(nrnmpi_world_comm, grp_net, &nrnmpi_comm));
254  asrt(MPI_Comm_rank(nrnmpi_comm, &nrnmpi_myid));
255  asrt(MPI_Comm_size(nrnmpi_comm, &nrnmpi_numprocs));
256  asrt(MPI_Comm_rank(nrn_bbs_comm, &nrnmpi_myid_bbs));
257  asrt(MPI_Comm_size(nrn_bbs_comm, &nrnmpi_numprocs_bbs));
258  } else if (n == nrnmpi_numprocs_world) {
259  asrt(MPI_Group_incl(wg, 1, &r, &grp_bbs));
260  asrt(MPI_Comm_dup(nrnmpi_world_comm, &nrnmpi_comm));
261  asrt(MPI_Comm_create(nrnmpi_world_comm, grp_bbs, &nrn_bbs_comm));
262  asrt(MPI_Comm_rank(nrnmpi_comm, &nrnmpi_myid));
263  asrt(MPI_Comm_size(nrnmpi_comm, &nrnmpi_numprocs));
264  if (r == 0) {
265  asrt(MPI_Comm_rank(nrn_bbs_comm, &nrnmpi_myid_bbs));
266  asrt(MPI_Comm_size(nrn_bbs_comm, &nrnmpi_numprocs_bbs));
267  } else {
268  nrnmpi_myid_bbs = -1;
269  nrnmpi_numprocs_bbs = -1;
270  }
271  } else {
272  int nw = nrnmpi_numprocs_world;
273  int nb = nw / n; /* nrnmpi_numprocs_bbs */
274  int ib;
275  int range[3];
276  if (nw % n) {
277  nb += 1; /* and the last will have pc.nhost = nw%n */
278  }
279  /* A subworld (net) has contiguous ranks. */
280  /* Every rank is in a specific nrnmpi_comm communicator */
281  ib = r / n;
282  range[0] = ib * n; /* first rank in group */
283  range[1] = range[0] + n - 1; /* last rank in group */
284  if (range[1] >= nw) {
285  range[1] = nw - 1;
286  }
287  range[2] = 1; /* stride */
288  asrt(MPI_Group_range_incl(wg, 1, &range, &grp_net));
289  asrt(MPI_Comm_create(nrnmpi_world_comm, grp_net, &nrnmpi_comm));
290  asrt(MPI_Comm_rank(nrnmpi_comm, &nrnmpi_myid));
291  asrt(MPI_Comm_size(nrnmpi_comm, &nrnmpi_numprocs));
292 
293  /* nrn_bbs_com ranks stride is nrnmpi_numprocs */
294  /* only rank 0 of each subworld participates in nrn_bbs_comm */
295  range[0] = 0; /* first world rank in nrn_bbs_comm */
296  range[1] = (nb - 1) * n; /* last world rank in nrn_bbs_comm */
297  range[2] = n; /* stride */
298  asrt(MPI_Group_range_incl(wg, 1, &range, &grp_bbs));
299  asrt(MPI_Comm_create(nrnmpi_world_comm, grp_bbs, &nrn_bbs_comm));
300  if (r % n == 0) { /* only rank 0 participates in nrn_bbs_comm */
301  asrt(MPI_Comm_rank(nrn_bbs_comm, &nrnmpi_myid_bbs));
302  asrt(MPI_Comm_size(nrn_bbs_comm, &nrnmpi_numprocs_bbs));
303  } else {
304 #if 1
305  nrnmpi_myid_bbs = -1;
306  nrnmpi_numprocs_bbs = -1;
307 #else
308  nrnmpi_myid_bbs = r / n;
309  nrnmpi_numprocs_bbs = nb;
310 #endif
311  }
312  }
313  asrt(MPI_Group_free(&wg));
314 }
315 
316 /* so src/nrnpython/inithoc.cpp does not have to include a c++ mpi.h */
317 int nrnmpi_wrap_mpi_init(int* flag) {
318  return MPI_Initialized(flag);
319 }
320 
321 #endif
#define i
Definition: md1redef.h:12
static int nrnmpi_use
Definition: multisplit.cpp:48
#define printf
Definition: mwprefix.h:26
int const size_t const size_t n
Definition: nrngsl.h:11
void nrnmpi_init(int nrnmpi_under_nrncontrol, int *pargc, char ***pargv)
Definition: nrnmpi.cpp:58
void nrnmpi_abort(int errcode)
Definition: nrnmpi.cpp:205
void nrnmpi_terminate()
Definition: nrnmpi.cpp:180
double nrnmpi_wtime()
Definition: nrnmpi.cpp:171
double nrn_timeus()
Definition: ftime.cpp:61
int nrnmpi_myid
int nrnmpi_numprocs_world
int nrnmpi_numprocs
int nrnmpi_myid_world
int nrnmpi_numprocs_bbs
int nrnmpi_myid_bbs
MPI_Comm nrnmpi_world_comm
void nrnmusic_init(int *, char ***)
Definition: nrnmusic.cpp:189
void nrnmusic_terminate()
Definition: nrnmusic.cpp:209
int nrnmusic
MPI_Comm nrnmusic_comm
MPI_Comm nrnmpi_comm