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