NEURON
mpispike.cpp
Go to the documentation of this file.
1 #include <../../nrnconf.h>
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <stddef.h>
5 #include <assert.h>
6 
7 /* do not want the redef in the dynamic load case */
8 #include <nrnmpiuse.h>
9 
10 #if NRNMPI_DYNAMICLOAD
11 #include <nrnmpi_dynam.h>
12 #endif
13 
14 #include <nrnmpi.h>
15 #include <hocdec.h>
16 
17 #if NRNMPI
18 #include "nrnmpidec.h"
19 #include "nrnmpi_impl.h"
20 #include "mpispike.h"
21 #include <mpi.h>
22 
23 extern void nrnbbs_context_wait();
24 
25 static int np;
26 static int* displs;
27 static int* byteovfl; /* for the compressed transfer method */
28 static MPI_Datatype spike_type;
29 
30 static void pgvts_op(double* in, double* inout, int* len, MPI_Datatype* dptr);
31 static MPI_Op mpi_pgvts_op;
32 
33 static void make_spike_type() {
35  int block_lengths[2];
36  MPI_Aint displacements[2];
37  MPI_Aint addresses[3];
38  MPI_Datatype typelist[2];
39 
40  typelist[0] = MPI_INT;
41  typelist[1] = MPI_DOUBLE;
42 
43  block_lengths[0] = block_lengths[1] = 1;
44 
45  MPI_Get_address(&s, &addresses[0]);
46  MPI_Get_address(&(s.gid), &addresses[1]);
47  MPI_Get_address(&(s.spiketime), &addresses[2]);
48 
49  displacements[0] = addresses[1] - addresses[0];
50  displacements[1] = addresses[2] - addresses[0];
51 
52  MPI_Type_create_struct(2, block_lengths, displacements, typelist, &spike_type);
53  MPI_Type_commit(&spike_type);
54 
55  MPI_Op_create((MPI_User_function*)pgvts_op, 1, &mpi_pgvts_op);
56 }
57 
58 void nrnmpi_spike_initialize() {
59  make_spike_type();
60 }
61 
62 #if nrn_spikebuf_size > 0
63 
64 static MPI_Datatype spikebuf_type;
65 
66 static void make_spikebuf_type() {
67  NRNMPI_Spikebuf s;
68  int block_lengths[3];
69  MPI_Aint displacements[3];
70  MPI_Aint addresses[4];
71  MPI_Datatype typelist[3];
72 
73  typelist[0] = MPI_INT;
74  typelist[1] = MPI_INT;
75  typelist[2] = MPI_DOUBLE;
76 
77  block_lengths[0] = 1;
78  block_lengths[1] = nrn_spikebuf_size;
79  block_lengths[2] = nrn_spikebuf_size;
80 
81  MPI_Get_address(&s, &addresses[0]);
82  MPI_Get_address(&(s.nspike), &addresses[1]);
83  MPI_Get_address(&(s.gid[0]), &addresses[2]);
84  MPI_Get_address(&(s.spiketime[0]), &addresses[3]);
85 
86  displacements[0] = addresses[1] - addresses[0];
87  displacements[1] = addresses[2] - addresses[0];
88  displacements[2] = addresses[3] - addresses[0];
89 
90  MPI_Type_create_struct(3, block_lengths, displacements, typelist, &spikebuf_type);
91  MPI_Type_commit(&spikebuf_type);
92 }
93 #endif
94 
95 int nrnmpi_spike_exchange() {
96  int i, n, novfl, n1;
97  if (!displs) {
98  np = nrnmpi_numprocs;
99  displs = (int*)hoc_Emalloc(np*sizeof(int)); hoc_malchk();
100  displs[0] = 0;
101 #if nrn_spikebuf_size > 0
102  make_spikebuf_type();
103 #endif
104  }
106 #if nrn_spikebuf_size == 0
107  MPI_Allgather(&nout_, 1, MPI_INT, nin_, 1, MPI_INT, nrnmpi_comm);
108  n = nin_[0];
109  for (i=1; i < np; ++i) {
110  displs[i] = n;
111  n += nin_[i];
112  }
113  if (n) {
114  if (icapacity_ < n) {
115  icapacity_ = n + 10;
116  free(spikein_);
118  }
119  MPI_Allgatherv(spikeout_, nout_, spike_type, spikein_, nin_, displs, spike_type, nrnmpi_comm);
120  }
121 #else
122  MPI_Allgather(spbufout_, 1, spikebuf_type, spbufin_, 1, spikebuf_type, nrnmpi_comm);
123  novfl = 0;
124  n = spbufin_[0].nspike;
125  if (n > nrn_spikebuf_size) {
126  nin_[0] = n - nrn_spikebuf_size;
127  novfl += nin_[0];
128  }else{
129  nin_[0] = 0;
130  }
131  for (i=1; i < np; ++i) {
132  displs[i] = novfl;
133  n1 = spbufin_[i].nspike;
134  n += n1;
135  if (n1 > nrn_spikebuf_size) {
136  nin_[i] = n1 - nrn_spikebuf_size;
137  novfl += nin_[i];
138  }else{
139  nin_[i] = 0;
140  }
141  }
142  if (novfl) {
143  if (icapacity_ < novfl) {
144  icapacity_ = novfl + 10;
145  free(spikein_);
147  }
149  MPI_Allgatherv(spikeout_, n1, spike_type, spikein_, nin_, displs, spike_type, nrnmpi_comm);
150  }
151  ovfl_ = novfl;
152 #endif
153  return n;
154 }
155 
156 /*
157 The compressed spike format is restricted to the fixed step method and is
158 a sequence of unsigned char.
159 nspike = buf[0]*256 + buf[1]
160 a sequence of spiketime, localgid pairs. There are nspike of them.
161  spiketime is relative to the last transfer time in units of dt.
162  note that this requires a mindelay < 256*dt.
163  localgid is an unsigned int, unsigned short,
164  or unsigned char in size depending on the range and thus takes
165  4, 2, or 1 byte respectively. To be machine independent we do our
166  own byte coding. When the localgid range is smaller than the true
167  gid range, the gid->PreSyn are remapped into
168  hostid specific maps. If there are not many holes, i.e just about every
169  spike from a source machine is delivered to some cell on a
170  target machine, then instead of a hash map, a vector is used.
171 The allgather sends the first part of the buf and the allgatherv buffer
172 sends any overflow.
173 */
174 int nrnmpi_spike_exchange_compressed() {
175  int i, novfl, n, ntot, idx, bs, bstot; /* n is #spikes, bs is #byte overflow */
176  if (!displs) {
177  np = nrnmpi_numprocs;
178  displs = (int*)hoc_Emalloc(np*sizeof(int)); hoc_malchk();
179  displs[0] = 0;
180  }
181  if (!byteovfl) {
182  byteovfl = (int*)hoc_Emalloc(np*sizeof(int)); hoc_malchk();
183  }
185 
186  MPI_Allgather(spfixout_, ag_send_size_, MPI_BYTE, spfixin_, ag_send_size_, MPI_BYTE, nrnmpi_comm);
187  novfl = 0;
188  ntot = 0;
189  bstot = 0;
190  for (i=0; i < np; ++i) {
191  displs[i] = bstot;
192  idx = i*ag_send_size_;
193  n = spfixin_[idx++]*256;
194  n += spfixin_[idx++];
195  ntot += n;
196  nin_[i] = n;
197  if (n > ag_send_nspike_) {
198  bs = 2 + n*(1 + localgid_size_) - ag_send_size_;
199  byteovfl[i] = bs;
200  bstot += bs;
201  novfl += n - ag_send_nspike_;
202  }else{
203  byteovfl[i] = 0;
204  }
205  }
206  if (novfl) {
207  if (ovfl_capacity_ < novfl) {
208  ovfl_capacity_ = novfl + 10;
209  free(spfixin_ovfl_);
210  spfixin_ovfl_ = (unsigned char*)hoc_Emalloc(ovfl_capacity_ * (1 + localgid_size_)*sizeof(unsigned char)); hoc_malchk();
211  }
212  bs = byteovfl[nrnmpi_myid];
213  /*
214  note that the spfixout_ buffer is one since the overflow
215  is contiguous to the first part. But the spfixin_ovfl_ is
216  completely separate from the spfixin_ since the latter
217  dynamically changes its size during a run.
218  */
219  MPI_Allgatherv(spfixout_ + ag_send_size_, bs, MPI_BYTE, spfixin_ovfl_, byteovfl, displs, MPI_BYTE, nrnmpi_comm);
220  }
221  ovfl_ = novfl;
222  return ntot;
223 }
224 
225 double nrnmpi_mindelay(double m) {
226  double result;
227  if (!nrnmpi_use) { return m; }
229  MPI_Allreduce(&m, &result, 1, MPI_DOUBLE, MPI_MIN, nrnmpi_comm);
230  return result;
231 }
232 
233 int nrnmpi_int_allmax(int x) {
234  int result;
235  if (nrnmpi_numprocs < 2) { return x; }
237  MPI_Allreduce(&x, &result, 1, MPI_INT, MPI_MAX, nrnmpi_comm);
238  return result;
239 }
240 
241 #define ALLTOALLV_SPARSE_TAG 101980
242 
243 /* Code derived from MPI_Alltoallv_sparse in MP-Gadget: https://github.com/MP-Gadget */
244 
245 static int MPI_Alltoallv_sparse(void *sendbuf, int *sendcnts, int *sdispls,
246  MPI_Datatype sendtype, void *recvbuf, int *recvcnts,
247  int *rdispls, MPI_Datatype recvtype, MPI_Comm comm)
248 {
249 
250  int status;
251  int myrank;
252  int nranks;
253  status = MPI_Comm_rank(comm, &myrank);
254  assert(status == MPI_SUCCESS);
255  status = MPI_Comm_size(comm, &nranks);
256  assert(status == MPI_SUCCESS);
257 
258  int rankp;
259  for(rankp = 0; nranks > (1 << rankp); rankp++);
260 
261  ptrdiff_t lb;
262  ptrdiff_t send_elsize;
263  ptrdiff_t recv_elsize;
264 
265  status = MPI_Type_get_extent(sendtype, &lb, &send_elsize);
266  assert(status == MPI_SUCCESS);
267  status = MPI_Type_get_extent(recvtype, &lb, &recv_elsize);
268  assert(status == MPI_SUCCESS);
269 
270  MPI_Request *requests = (MPI_Request*)hoc_Emalloc(nranks * 2 * sizeof(MPI_Request)); hoc_malchk();
271  assert(requests != NULL);
272 
273  int ngrp; int n_requests;
274  n_requests = 0;
275  for(ngrp = 0; ngrp < (1 << rankp); ngrp++)
276  {
277  int target = myrank ^ ngrp;
278 
279  if(target >= nranks) continue;
280  if(recvcnts[target] == 0) continue;
281  status = MPI_Irecv((static_cast<char*>(recvbuf)) + recv_elsize * rdispls[target],
282  recvcnts[target],
283  recvtype, target, ALLTOALLV_SPARSE_TAG, comm, &requests[n_requests++]);
284  assert(status == MPI_SUCCESS);
285  }
286 
287  status = MPI_Barrier(comm);
288  assert(status == MPI_SUCCESS);
289 
290  for(ngrp = 0; ngrp < (1 << rankp); ngrp++)
291  {
292  int target = myrank ^ ngrp;
293  if(target >= nranks) continue;
294  if(sendcnts[target] == 0) continue;
295  status = MPI_Isend((static_cast<char*>(sendbuf)) + send_elsize * sdispls[target],
296  sendcnts[target],
297  sendtype, target, ALLTOALLV_SPARSE_TAG, comm, &requests[n_requests++]);
298  assert(status == MPI_SUCCESS);
299  }
300 
301  status = MPI_Waitall(n_requests, requests, MPI_STATUSES_IGNORE);
302  assert(status == MPI_SUCCESS);
303  free(requests);
304 
305  status = MPI_Barrier(comm);
306  assert(status == MPI_SUCCESS);
307 
308  return MPI_SUCCESS;
309 }
310 
311 
312 extern void nrnmpi_dbl_alltoallv_sparse(double* s, int* scnt, int* sdispl, double* r, int* rcnt, int* rdispl) {
313  MPI_Alltoallv_sparse(s, scnt, sdispl, MPI_DOUBLE, r, rcnt, rdispl, MPI_DOUBLE, nrnmpi_comm);
314 }
315 extern void nrnmpi_int_alltoallv_sparse(int* s, int* scnt, int* sdispl, int* r, int* rcnt, int* rdispl) {
316  MPI_Alltoallv_sparse(s, scnt, sdispl, MPI_INT, r, rcnt, rdispl, MPI_INT, nrnmpi_comm);
317 }
318 
319 extern void nrnmpi_long_alltoallv_sparse(int64_t* s, int* scnt, int* sdispl, int64_t* r, int* rcnt, int* rdispl) {
320  MPI_Alltoallv_sparse(s, scnt, sdispl, MPI_INT64_T, r, rcnt, rdispl, MPI_INT64_T, nrnmpi_comm);
321 }
322 
323 
324 
325 extern void nrnmpi_int_gather(int* s, int* r, int cnt, int root) {
326  MPI_Gather(s, cnt, MPI_INT, r, cnt, MPI_INT, root, nrnmpi_comm);
327 }
328 
329 extern void nrnmpi_int_gatherv(int* s, int scnt,
330  int* r, int* rcnt, int* rdispl, int root) {
331  MPI_Gatherv(s, scnt, MPI_INT,
332  r, rcnt, rdispl, MPI_INT, root, nrnmpi_comm);
333 }
334 
335 extern void nrnmpi_char_gatherv(char* s, int scnt,
336  char* r, int* rcnt, int* rdispl, int root) {
337  MPI_Gatherv(s, scnt, MPI_CHAR,
338  r, rcnt, rdispl, MPI_CHAR, root, nrnmpi_comm);
339 }
340 
341 extern void nrnmpi_int_scatter(int* s, int* r, int cnt, int root) {
342  MPI_Scatter(s, cnt, MPI_INT, r, cnt, MPI_INT, root, nrnmpi_comm);
343 }
344 
345 extern void nrnmpi_char_scatterv(char* s, int* scnt, int* sdispl, char* r, int rcnt, int root) {
346  MPI_Scatterv(s, scnt, sdispl, MPI_CHAR, r, rcnt, MPI_CHAR, root, nrnmpi_comm);
347 }
348 
349 extern void nrnmpi_int_alltoall(int* s, int* r, int n) {
350  MPI_Alltoall(s, n, MPI_INT, r, n, MPI_INT, nrnmpi_comm);
351 }
352 
353 extern void nrnmpi_int_alltoallv(int* s, int* scnt, int* sdispl,
354  int* r, int* rcnt, int* rdispl) {
355  MPI_Alltoallv(s, scnt, sdispl, MPI_INT,
356  r, rcnt, rdispl, MPI_INT, nrnmpi_comm);
357 }
358 
359 extern void nrnmpi_long_alltoallv(int64_t* s, int* scnt, int* sdispl,
360  int64_t* r, int* rcnt, int* rdispl) {
361  MPI_Alltoallv(s, scnt, sdispl, MPI_INT64_T,
362  r, rcnt, rdispl, MPI_INT64_T, nrnmpi_comm);
363 }
364 
365 extern void nrnmpi_dbl_alltoallv(double* s, int* scnt, int* sdispl,
366  double* r, int* rcnt, int* rdispl) {
367  MPI_Alltoallv(s, scnt, sdispl, MPI_DOUBLE,
368  r, rcnt, rdispl, MPI_DOUBLE, nrnmpi_comm);
369 }
370 
371 extern void nrnmpi_char_alltoallv(char* s, int* scnt, int* sdispl,
372  char* r, int* rcnt, int* rdispl) {
373  MPI_Alltoallv(s, scnt, sdispl, MPI_CHAR,
374  r, rcnt, rdispl, MPI_CHAR, nrnmpi_comm);
375 }
376 
377 /* following are for the partrans */
378 
379 void nrnmpi_int_allgather(int* s, int* r, int n) {
380  MPI_Allgather(s, n, MPI_INT, r, n, MPI_INT, nrnmpi_comm);
381 }
382 
383 void nrnmpi_int_allgather_inplace(int* srcdest, int n) {
384  MPI_Allgather(MPI_IN_PLACE, 0, MPI_DATATYPE_NULL, srcdest, n, MPI_INT, nrnmpi_comm);
385 }
386 
387 void nrnmpi_int_allgatherv(int* s, int* r, int* n, int* dspl) {
388  MPI_Allgatherv(s, n[nrnmpi_myid], MPI_INT,
389  r, n, dspl, MPI_INT, nrnmpi_comm);
390 }
391 
392 void nrnmpi_int_allgatherv_inplace(int* srcdest, int* n, int* dspl) {
393  MPI_Allgatherv(MPI_IN_PLACE, 0, MPI_DATATYPE_NULL, srcdest,
394  n, dspl, MPI_INT, nrnmpi_comm);
395 }
396 
397 void nrnmpi_char_allgatherv(char* s, char* r, int* n, int* dspl) {
398  MPI_Allgatherv(s, n[nrnmpi_myid], MPI_CHAR,
399  r, n, dspl, MPI_CHAR, nrnmpi_comm);
400 }
401 
402 void nrnmpi_long_allgatherv(int64_t* s, int64_t* r, int* n, int* dspl) {
403  MPI_Allgatherv(s, n[nrnmpi_myid], MPI_INT64_T,
404  r, n, dspl, MPI_INT64_T, nrnmpi_comm);
405 }
406 
407 void nrnmpi_long_allgatherv_inplace(long* srcdest, int* n, int* dspl) {
408  MPI_Allgatherv(MPI_IN_PLACE, 0, MPI_DATATYPE_NULL, srcdest,
409  n, dspl, MPI_LONG, nrnmpi_comm);
410 }
411 
412 void nrnmpi_dbl_allgatherv(double* s, double* r, int* n, int* dspl) {
413  MPI_Allgatherv(s, n[nrnmpi_myid], MPI_DOUBLE,
414  r, n, dspl, MPI_DOUBLE, nrnmpi_comm);
415 }
416 
417 void nrnmpi_dbl_allgatherv_inplace(double* srcdest, int* n, int* dspl) {
418  MPI_Allgatherv(MPI_IN_PLACE, 0, MPI_DATATYPE_NULL, srcdest,
419  n, dspl, MPI_DOUBLE, nrnmpi_comm);
420 }
421 
422 void nrnmpi_dbl_broadcast(double* buf, int cnt, int root) {
423  MPI_Bcast(buf, cnt, MPI_DOUBLE, root, nrnmpi_comm);
424 }
425 
426 void nrnmpi_int_broadcast(int* buf, int cnt, int root) {
427  MPI_Bcast(buf, cnt, MPI_INT, root, nrnmpi_comm);
428 }
429 
430 void nrnmpi_char_broadcast(char* buf, int cnt, int root) {
431  MPI_Bcast(buf, cnt, MPI_CHAR, root, nrnmpi_comm);
432 }
433 
434 void nrnmpi_char_broadcast_world(char** pstr, int root) {
435  int sz;
436  sz = *pstr ? (strlen(*pstr) + 1) : 0;
437  MPI_Bcast(&sz, 1, MPI_INT, root, nrnmpi_world_comm);
438  if (nrnmpi_myid_world != root) {
439  if (*pstr) { free(*pstr); *pstr = NULL; }
440  if (sz) {
441  *pstr = static_cast<char*>(hoc_Emalloc(sz*sizeof(char))); hoc_malchk();
442  }
443  }
444  if (sz) {
445  MPI_Bcast(*pstr, sz, MPI_CHAR, root, nrnmpi_world_comm);
446  }
447 }
448 
449 int nrnmpi_int_sum_reduce(int in) {
450  int result;
451  MPI_Allreduce(&in, &result, 1, MPI_INT, MPI_SUM, nrnmpi_comm);
452  return result;
453 }
454 
455 void nrnmpi_assert_opstep(int opstep, double t) {
456  /* all machines in comm should have same opstep and same t. */
457  double buf[2];
458  if (nrnmpi_numprocs < 2) { return; }
459  buf[0] = (double)opstep;
460  buf[1] = t;
461  MPI_Bcast(buf, 2, MPI_DOUBLE, 0, nrnmpi_comm);
462  if (opstep != (int)buf[0] || t != buf[1]) {
463  printf("%d opstep=%d %d t=%g t-troot=%g\n", nrnmpi_myid, opstep,
464  (int)buf[0], t, t-buf[1]);
465  hoc_execerror("nrnmpi_assert_opstep failed", (char*)0);
466  }
467 }
468 
469 double nrnmpi_dbl_allmin(double x) {
470  double result;
471  if (nrnmpi_numprocs < 2) { return x; }
472  MPI_Allreduce(&x, &result, 1, MPI_DOUBLE, MPI_MIN, nrnmpi_comm);
473  return result;
474 }
475 
476 static void pgvts_op(double* in, double* inout, int* len, MPI_Datatype* dptr){
477  int i, r=0;
478  assert(*dptr == MPI_DOUBLE);
479  assert(*len == 4);
480  if (in[0] < inout[0]) {
481  /* least time has highest priority */
482  r = 1;
483  }else if (in[0] == inout[0]) {
484  /* when times are equal then */
485  if (in[1] < inout[1]) {
486  /* NetParEvent done last */
487  r = 1;
488  }else if (in[1] == inout[1]) {
489  /* when times and ops are equal then */
490  if (in[2] < inout[2]) {
491  /* init done next to last.*/
492  r = 1;
493  }else if (in[2] == inout[2]) {
494  /* when times, ops, and inits are equal then */
495  if (in[3] < inout[3]) {
496  /* choose lowest rank */
497  r = 1;
498  }
499  }
500  }
501  }
502  if (r) {
503  for (i=0; i < 4; ++i) { inout[i] = in[i]; }
504  }
505 }
506 
507 int nrnmpi_pgvts_least(double* t, int* op, int* init) {
508  int i;
509  double ibuf[4], obuf[4];
510  ibuf[0] = *t;
511  ibuf[1] = (double)(*op);
512  ibuf[2] = (double)(*init);
513  ibuf[3] = (double)nrnmpi_myid;
514  for (i=0; i < 4; ++i) {
515  obuf[i] = ibuf[i];
516  }
517  MPI_Allreduce(ibuf, obuf, 4, MPI_DOUBLE, mpi_pgvts_op, nrnmpi_comm);
518  assert(obuf[0] <= *t);
519  if (obuf[0] == *t) {
520  assert((int)obuf[1] <= *op);
521  if ((int)obuf[1] == *op) {
522  assert((int)obuf[2] <= *init);
523  if ((int)obuf[2] == *init) {
524  assert((int)obuf[3] <= nrnmpi_myid);
525  }
526  }
527  }
528  *t = obuf[0];
529  *op = (int)obuf[1];
530  *init = (int)obuf[2];
531  if (nrnmpi_myid == (int)obuf[3]) {
532  return 1;
533  }
534  return 0;
535 }
536 
537 /* following for splitcell.cpp transfer */
538 void nrnmpi_send_doubles(double* pd, int cnt, int dest, int tag) {
539  MPI_Send(pd, cnt, MPI_DOUBLE, dest, tag, nrnmpi_comm);
540 }
541 
542 void nrnmpi_recv_doubles(double* pd, int cnt, int src, int tag) {
543  MPI_Status status;
544  MPI_Recv(pd, cnt, MPI_DOUBLE, src, tag, nrnmpi_comm, &status);
545 }
546 
547 void nrnmpi_postrecv_doubles(double* pd, int cnt, int src, int tag, void** request) {
548  MPI_Irecv(pd, cnt, MPI_DOUBLE, src, tag, nrnmpi_comm, (MPI_Request*)request);
549 }
550 
551 void nrnmpi_wait(void** request) {
552  MPI_Status status;
553  MPI_Wait((MPI_Request*)request, &status);
554 }
555 
556 void nrnmpi_barrier() {
557  if (nrnmpi_numprocs < 2) { return; }
558  MPI_Barrier(nrnmpi_comm);
559 }
560 
561 double nrnmpi_dbl_allreduce(double x, int type) {
562  double result;
563  MPI_Op t;
564  if (nrnmpi_numprocs < 2) { return x; }
565  if (type == 1) {
566  t = MPI_SUM;
567  }else if (type == 2) {
568  t = MPI_MAX;
569  }else{
570  t = MPI_MIN;
571  }
572  MPI_Allreduce(&x, &result, 1, MPI_DOUBLE, t, nrnmpi_comm);
573  return result;
574 }
575 
576 extern "C" void nrnmpi_dbl_allreduce_vec(double* src, double* dest, int cnt, int type) {
577  int i;
578  MPI_Op t;
579  assert(src != dest);
580  if (nrnmpi_numprocs < 2) {
581  for (i = 0; i < cnt; ++i) {
582  dest[i] = src[i];
583  }
584  return;
585  }
586  if (type == 1) {
587  t = MPI_SUM;
588  }else if (type == 2) {
589  t = MPI_MAX;
590  }else{
591  t = MPI_MIN;
592  }
593  MPI_Allreduce(src, dest, cnt, MPI_DOUBLE, t, nrnmpi_comm);
594  return;
595 }
596 
597 void nrnmpi_longdbl_allreduce_vec(longdbl* src, longdbl* dest, int cnt, int type) {
598  int i;
599  MPI_Op t;
600  assert(src != dest);
601  if (nrnmpi_numprocs < 2) {
602  for (i = 0; i < cnt; ++i) {
603  dest[i] = src[i];
604  }
605  return;
606  }
607  if (type == 1) {
608  t = MPI_SUM;
609  }else if (type == 2) {
610  t = MPI_MAX;
611  }else{
612  t = MPI_MIN;
613  }
614  MPI_Allreduce(src, dest, cnt, MPI_LONG_DOUBLE, t, nrnmpi_comm);
615  return;
616 }
617 
618 void nrnmpi_long_allreduce_vec(long* src, long* dest, int cnt, int type) {
619  int i;
620  MPI_Op t;
621  assert(src != dest);
622  if (nrnmpi_numprocs < 2) {
623  for (i = 0; i < cnt; ++i) {
624  dest[i] = src[i];
625  }
626  return;
627  }
628  if (type == 1) {
629  t = MPI_SUM;
630  }else if (type == 2) {
631  t = MPI_MAX;
632  }else{
633  t = MPI_MIN;
634  }
635  MPI_Allreduce(src, dest, cnt, MPI_LONG, t, nrnmpi_comm);
636  return;
637 }
638 
639 void nrnmpi_dbl_allgather(double* s, double* r, int n) {
640  MPI_Allgather(s, n, MPI_DOUBLE, r, n, MPI_DOUBLE, nrnmpi_comm);
641 }
642 
643 #if BGPDMA
644 
645 static MPI_Comm bgp_comm;
646 
647 void nrnmpi_bgp_comm() {
648  if (!bgp_comm) {
649  MPI_Comm_dup(nrnmpi_comm, &bgp_comm);
650  }
651 }
652 
653 void nrnmpi_bgp_multisend(NRNMPI_Spike* spk, int n, int* hosts) {
654  int i;
655  MPI_Request r;
656  MPI_Status status;
657  for (i=0; i < n; ++i) {
658  MPI_Isend(spk, 1, spike_type, hosts[i], 1, bgp_comm, &r);
659  MPI_Request_free(&r);
660  }
661 }
662 
664  int flag = 0;
665  MPI_Status status;
666  MPI_Iprobe(MPI_ANY_SOURCE, 1, bgp_comm, &flag, &status);
667  if (flag) {
668  MPI_Recv(spk, 1, spike_type, MPI_ANY_SOURCE, 1, bgp_comm, &status);
669  }
670  return flag;
671 }
672 
673 static int iii;
674 int nrnmpi_bgp_conserve(int nsend, int nrecv) {
675  int tcnts[2];
676  tcnts[0] = nsend - nrecv;
677  MPI_Allreduce(tcnts, tcnts+1, 1, MPI_INT, MPI_SUM, bgp_comm);
678  return tcnts[1];
679 }
680 
681 #endif /*BGPDMA*/
682 
683 #endif /*NRNMPI*/
static int nrnmpi_int_allmax(int x)
#define assert(ex)
Definition: hocassrt.h:26
static void nrnmpi_int_allgatherv(int *s, int *r, int *n, int *dspl)
short type
Definition: cabvars.h:10
long double longdbl
Definition: nrnmpidec.h:12
NRNMPI_Spike * spikeout_
MPI_Comm nrnmpi_comm
static void nrnmpi_char_broadcast(char *, int, int)
Definition: ocbbs.cpp:61
static int nrnmpi_use
Definition: multisplit.cpp:48
int nout_
void nrnmpi_bgp_multisend(NRNMPI_Spike *, int, int *)
int ovfl_capacity_
void nrnmpi_bgp_comm()
void nrnbbs_context_wait()
Definition: datapath.cpp:30
NRNMPI_Spike * spikein_
unsigned char * spfixin_ovfl_
return status
int * nin_
int ag_send_size_
static void nrnmpi_postrecv_doubles(double *, int, int, int, void **)
Definition: multisplit.cpp:51
void init()
Definition: init.cpp:169
int const size_t const size_t n
Definition: nrngsl.h:12
#define root
Definition: rbtqueue.cpp:53
unsigned char * spfixin_
int gid
Definition: nrnmpi.h:18
int nrnmpi_myid_world
int nrnmpi_numprocs
_CONST char * s
Definition: system.cpp:74
static void nrnmpi_int_broadcast(int *, int, int)
Definition: ocbbs.cpp:60
static void nrnmpi_barrier()
#define printf
Definition: mwprefix.h:26
int
Definition: nrnmusic.cpp:71
double spiketime
Definition: nrnmpi.h:19
void hoc_execerror(const char *, const char *)
Definition: hoc.cpp:741
#define cnt
Definition: spt2queue.cpp:19
#define nrn_spikebuf_size
Definition: mpispike.h:5
static void nrnmpi_int_alltoallv(int *s, int *scnt, int *sdispl, int *r, int *rcnt, int *rdispl)
static void nrnmpi_send_doubles(double *, int, int, int)
Definition: multisplit.cpp:52
unsigned char * spfixout_
static void nrnmpi_int_allgather(int *s, int *r, int n)
int ag_send_nspike_
void hoc_malchk()
Definition: symbol.cpp:187
int nrnmpi_bgp_conserve(int nsend, int nrecv)
int nrnmpi_myid
static void nrnmpi_dbl_alltoallv(double *s, int *scnt, int *sdispl, double *r, int *rcnt, int *rdispl)
#define i
Definition: md1redef.h:12
static void nrnmpi_dbl_broadcast(double *, int, int)
Definition: ocbbs.cpp:62
char buf[512]
Definition: init.cpp:13
int ovfl_
int localgid_size_
static void nrnmpi_dbl_allgatherv(double *s, double *r, int *n, int *dspl)
MPI_Comm nrnmpi_world_comm
double t
Definition: init.cpp:123
static void nrnmpi_wait(void **)
Definition: multisplit.cpp:53
int nrnmpi_bgp_single_advance(NRNMPI_Spike *)
return NULL
Definition: cabcode.cpp:461
int icapacity_
void * hoc_Emalloc(size_t size)
Definition: symbol.cpp:194