NEURON
multisend.cpp
Go to the documentation of this file.
1 // included by netpar.cpp
2 
3 /*
4 Overall exchange strategy
5 
6 When a cell spikes, it immediately does a multisend of
7 (int gid, double spiketime) to all the target machines that have
8 cells that need to receive this spike by spiketime + delay
9 I'd like to cycle through a list of mconfig.nconnections so that
10 I don't have to wait for my single connection to complete the previous
11 broadcast when there is a high density of generated spikes but I need
12 to take care of my bus error issues first.
13 
14 In order to minimize the number of nrnmpi_multisend_conserve tests
15 (and potentially abandon them altogether if I can ever guarantee
16 that exchange time is less than half the computation time), I divide the
17 minimum delay integration intervals into two equal subintervals.
18 So if a spike is generated in an even subinterval, I do not have
19 to include it in the conservation check until the end of the next even
20 subinterval.
21 
22 When a spike is received (DMA interrupt) it is placed in even or odd
23 buffers (depending on whether the coded gid is positive or negative)
24 
25 At the end of a computation subinterval the even or odd buffer spikes
26 are enqueued in the priority queue after checking that the number
27 of spikes sent is equal to the number of spikes sent.
28 */
29 // The initial idea behind use_phase2_ is to avoid the large overhead of
30 // initiating a send of the up to 10k list of target hosts when a cell fires.
31 // I.e. when there are a small number of cells on a processor, this causes
32 // load balance problems.
33 // Load balance shuld be better if the send is distributed to a much smaller
34 // set of targets, which, when they receive the spike, pass it on to a neighbor
35 // set.
36 // We expect that TWOPHASE will work best in combination with ENQUEUE=2
37 // which has the greatest amount of overlap between computation
38 // and communication.
39 // Note: the old implementation assumed that input PreSyn did not need
40 // a BGP_DMASend pointer so used the PreSyn.bgp.srchost_ element to
41 // help figure out the target_hosts_ list for the output PreSyn.bgp.dma_send_.
42 // Since bgp.srchost_ is used only for setup, it can be overwritten at phase2
43 // setup time with a bgp.dma_send_ so as to pass on the spike to the
44 // phase2 list of target hosts.
45 
46 // asm/msr.h no longer compiles on my machine.
47 // only for basic testing of logic when not on blue gene/p
48 #define USE_RDTSCL 0
49 
50 // only use if careful not to overrun the buffer during a simulation
51 #if 0 && USE_RDTSCL
52 #define TBUFSIZE (1 << 15)
53 #else
54 #define TBUFSIZE 0
55 #endif
56 
57 #if TBUFSIZE
58 static unsigned long tbuf_[TBUFSIZE];
59 static int itbuf_;
60 #if USE_RDTSCL // but can have many accuracy problems on recent cpus.
61 /* for rdtscl() */
62 //#include <asm/msr.h>
63 #define rdtscl(a) a++
64 static unsigned long t__;
65 #define TBUF \
66  { \
67  rdtscl(t__); \
68  tbuf_[itbuf_++] = t__; \
69  }
70 #else
71 #define TBUF tbuf_[itbuf_++] = (unsigned long) DCMF_Timebase();
72 #endif // not USE_RDTSCLL
73 #else
74 #define TBUF /**/
75 #endif
76 
77 // ENQUEUE 0 means to Multisend_ReceiveBuffer buffer -> PreSyn.send
78 // ENQUEUE 1 means to Multisend_ReceiveBuffer buffer -> psbuf -> PreSyn.send
79 // ENQUEUE 2 means to Multisend_ReceiveBuffer.incoming -> PrySyn.send
80 // Note that ENQUEUE 2 give more overlap between computation and exchange
81 // since the enqueuing takes place during computation except for those
82 // remaining during conservation.
83 #define ENQUEUE 2
84 
85 #if ENQUEUE == 2
86 static unsigned long enq2_find_time_;
87 static unsigned long enq2_enqueue_time_; // includes enq_find_time_
88 #endif
89 
90 #define PHASE2BUFFER_SIZE 2048 // power of 2
91 #define PHASE2BUFFER_MASK (PHASE2BUFFER_SIZE - 1)
92 struct Phase2Buffer {
94  double spiketime;
95 };
96 
97 #include <structpool.h>
98 
100 
101 #define MULTISEND_RECEIVEBUFFER_SIZE 10000
103  public:
105  virtual ~Multisend_ReceiveBuffer();
106  void init(int index);
107  void incoming(int gid, double spiketime);
108  void enqueue();
109  int index_;
110  int size_;
111  int count_;
113  int busy_;
114  int nsend_, nrecv_; // for checking conservation
115  int nsend_cell_; // cells that spiked this interval.
116  unsigned long long timebase_;
119 
120 #if ENQUEUE == 1
121  void enqueue1();
122  void enqueue2();
123 #endif
125  void phase2send();
130 };
131 
132 static int use_phase2_;
133 
135  public:
136  Multisend_Send() = default;
137  virtual ~Multisend_Send();
138  void send(int gid, double t);
143 };
144 
146  public:
150 
151  void send_phase2(int gid, double t, Multisend_ReceiveBuffer*);
154 };
155 
158 // note that if a spike is supposed to be received by multisend_receive_buffer[1]
159 // then during transmission its gid is complemented.
160 
162  busy_ = 0;
163  count_ = 0;
165  buffer_ = new NRNMPI_Spike*[size_];
167  psbuf_ = 0;
168 #if ENQUEUE == 1
169  psbuf_ = new PreSyn*[size_];
170 #endif
173 }
175  assert(busy_ == 0);
176  for (int i = 0; i < count_; ++i) {
177  pool_->hpfree(buffer_[i]);
178  }
179  delete[] buffer_;
180  delete pool_;
181  if (psbuf_)
182  delete[] psbuf_;
183  delete[] phase2_buffer_;
184 }
186  index_ = index;
187  timebase_ = 0;
189  for (int i = 0; i < count_; ++i) {
190  pool_->hpfree(buffer_[i]);
191  }
192  count_ = 0;
195 }
196 void Multisend_ReceiveBuffer::incoming(int gid, double spiketime) {
197  // printf("%d %p.incoming %g %g %d\n", nrnmpi_myid, this, t, spk->spiketime, spk->gid);
198  assert(busy_ == 0);
199  busy_ = 1;
200  if (count_ >= size_) {
201  size_ *= 2;
202  NRNMPI_Spike** newbuf = new NRNMPI_Spike*[size_];
203  for (int i = 0; i < count_; ++i) {
204  newbuf[i] = buffer_[i];
205  }
206  delete[] buffer_;
207  buffer_ = newbuf;
208  if (psbuf_) {
209  delete[] psbuf_;
210  psbuf_ = new PreSyn*[size_];
211  }
212  }
213  NRNMPI_Spike* spk = pool_->alloc();
214  spk->gid = gid;
215  spk->spiketime = spiketime;
216  buffer_[count_++] = spk;
217  if (maxcount_ < count_) {
218  maxcount_ = count_;
219  }
220  ++nrecv_;
221  busy_ = 0;
222 }
224  // printf("%d %p.enqueue count=%d t=%g nrecv=%d nsend=%d\n", nrnmpi_myid, this, t, count_,
225  // nrecv_, nsend_);
226  assert(busy_ == 0);
227  busy_ = 1;
228 #if 1
229  for (int i = 0; i < count_; ++i) {
230  NRNMPI_Spike* spk = buffer_[i];
231  auto iter = gid2in_.find(spk->gid);
232  nrn_assert(iter != gid2in_.end());
233  PreSyn* ps = iter->second;
234  if (use_phase2_ && ps->bgp.multisend_send_phase2_) {
235  // cannot do directly because busy_;
236  // ps->bgp.multisend_send_phase2_->send_phase2(spk->gid, spk->spiketime, this);
240  pb.ps = ps;
241  pb.spiketime = spk->spiketime;
242  }
244  pool_->hpfree(spk);
245  }
246 #endif
247  count_ = 0;
248 #if ENQUEUE != 2
249  nrecv_ = 0;
250  nsend_ = 0;
251  nsend_cell_ = 0;
252 #endif
253  busy_ = 0;
254  phase2send();
255 }
256 
257 #if ENQUEUE == 1
258 void Multisend_ReceiveBuffer::enqueue1() {
259  // printf("%d %lx.enqueue count=%d t=%g nrecv=%d nsend=%d\n", nrnmpi_myid, (long)this, t,
260  // count_, nrecv_, nsend_);
261  assert(busy_ == 0);
262  busy_ = 1;
263  for (int i = 0; i < count_; ++i) {
264  NRNMPI_Spike* spk = buffer_[i];
265  auto iter = gid2in_->find(spk->gid);
266  nrn_assert(iter != gid2in_.end()));
267  PreSyn* ps = iter->second;
268  psbuf_[i] = ps;
269  if (use_phase2_ && ps->bgp.multisend_send_phase2_) {
270  // cannot do directly because busy_;
271  // ps->bgp.multisend_send_phase2_->send_phase2(spk->gid, spk->spiketime, this);
275  pb.ps = ps;
276  pb.spiketime = spk->spiketime;
277  }
278  }
279  busy_ = 0;
280  phase2send();
281 }
282 
283 void Multisend_ReceiveBuffer::enqueue2() {
284  // printf("%d %lx.enqueue count=%d t=%g nrecv=%d nsend=%d\n", nrnmpi_myid, (long)this, t,
285  // count_, nrecv_, nsend_);
286  assert(busy_ == 0);
287  busy_ = 1;
288  for (int i = 0; i < count_; ++i) {
289  NRNMPI_Spike* spk = buffer_[i];
290  PreSyn* ps = psbuf_[i];
292  pool_->hpfree(spk);
293  }
294  count_ = 0;
295  nrecv_ = 0;
296  nsend_ = 0;
297  nsend_cell_ = 0;
298  busy_ = 0;
299 }
300 #endif // ENQUEUE == 1
301 
303  while (phase2_head_ != phase2_tail_) {
306  pb.ps->bgp.multisend_send_phase2_->send_phase2(pb.ps->gid_, pb.spiketime, this);
307  }
308 }
309 
310 // number of DCMF_Multicast_t to cycle through when not using recordreplay
311 #define NSEND 10
312 
313 static int max_ntarget_host;
314 // For one phase sending, max_multisend_targets is max_ntarget_host.
315 // For two phase sending, it is the maximum of all the
316 // ntarget_hosts_phase1 and ntarget_hosts_phase2.
318 
319 double nrn_multisend_receive_time(int type) { // and others
320  double rt = 0.;
321  switch (type) {
322  case 2: // in msend_recv
323  if (!use_multisend_) {
324  return rt;
325  }
326  break;
327  case 3: // in MULTISENDsend::send
328  if (!use_multisend_) {
329  return rt;
330  }
331  rt = 0;
332  break;
333  case 4: // number of extra conservation checks
334  rt = 0.;
335  // and if there is second vector arg then also return the histogram
336 #if TBUFSIZE
337  if (ifarg(3)) {
338  IvocVect* vec = vector_arg(3);
339  vector_resize(vec, itbuf_ + 1);
340  for (int i = 0; i <= itbuf_; ++i) {
341  vector_vec(vec)[i] = double(tbuf_[i]);
342  }
343  vector_vec(vec)[itbuf_] = 0;
344  }
345 #endif
346  break;
347  case 8: // exchange method properties
348  // bit 0: 0 allgather, 1 multisend (MPI_ISend)
349  // bit 1: unused, legacy
350  // bit 2: n_multisend_interval, 0 means one interval, 1 means 2
351  // bit 3: number of phases, 0 means 1 phase, 1 means 2
352  // bit 4: unused (1 used to mean althash used)
353  // bit 5: 1 means enqueue separated into two parts for timeing
354  {
355  int method = use_multisend_ ? 1 : 0;
356  int p = method + 4 * (n_multisend_interval == 2 ? 1 : 0) + 8 * use_phase2_ +
357  16 * (0) // no hash selection, just std::unordered_map
358  + 32 * ENQUEUE;
359  rt = double(p);
360  } break;
361  case 12: // greatest length multisend
362  {
363  rt = double(max_multisend_targets);
364  break;
365  }
366  }
367  return rt;
368 }
369 
370 extern void nrnmpi_multisend_comm();
371 extern void nrnmpi_multisend_multisend(NRNMPI_Spike*, int, int*);
373 extern int nrnmpi_multisend_conserve(int nsend, int nrecv);
374 
375 static void nrn_multisend_init() {
376  for (int i = 0; i < n_multisend_interval; ++i) {
378  }
379  current_rbuf = 0;
381 #if TBUFSIZE
382  itbuf_ = 0;
383 #endif
384 #if ENQUEUE == 2
386 #endif
387 }
388 
389 static int multisend_advance() {
390  NRNMPI_Spike spk;
391  int i = 0;
392  while (nrnmpi_multisend_single_advance(&spk)) {
393  i += 1;
394  int j = 0;
395  if (spk.gid < 0) {
396  spk.gid = ~spk.gid;
397  j = 1;
398  }
400  }
401  nrecv_ += i;
402  return i;
403 }
404 
405 #if NRNMPI
406 void nrn_multisend_advance() {
407  if (use_multisend_) {
409  }
410 #if ENQUEUE == 2
412 #endif
413 }
414 
416  if (target_hosts_) {
417  delete[] target_hosts_;
418  }
419 }
420 
422  if (target_hosts_phase2_) {
423  delete[] target_hosts_phase2_;
424  }
425 }
426 
427 // helps debugging when core dump since otherwise cannot tell where
428 // Multisend_Send::send fails
429 #if 0
430 static void mymulticast(DCMF_Multicast_t* arg) {
431  DCMF_Multicast(arg);
432 }
433 static void myrestart(DCMF_Request_t* arg) {
434  DCMF_Restart(arg);
435 }
436 #endif
437 
438 void Multisend_Send::send(int gid, double t) {
439  if (ntarget_hosts_phase1_) {
440  spk_.gid = gid;
441  spk_.spiketime = t;
444  if (next_rbuf == 1) {
445  spk_.gid = ~spk_.gid;
446  }
447  nsend_ += 1;
448  if (use_multisend_) {
450  }
451  }
452 }
453 
455  if (ntarget_hosts_phase2_) {
456  spk_.gid = gid;
457  spk_.spiketime = t;
458  if (rb->index_ == 1) {
459  spk_.gid = ~spk_.gid;
460  }
461  rb->phase2_nsend_cell_ += 1;
463  if (use_multisend_) {
465  }
466  }
467 }
468 
470  // nrn_spike_exchange();
471  assert(nt == nrn_threads);
472  TBUF
473  double w2;
474  int ncons = 0;
477  double w1 = nrnmpi_wtime();
478  if (use_multisend_) {
480  TBUF
481 #if TBUFSIZE
482 #if ENQUEUE == 2
483  // want the overlap with computation, not conserve
484  unsigned long tfind = enq2_find_time_;
485  unsigned long tsend = enq2_enqueue_time_ - enq2_find_time_;
486 #endif
487  nrnmpi_barrier();
488 #endif
489  TBUF
490  while (nrnmpi_multisend_conserve(s, r) != 0) {
492  ++ncons;
493  }
494  TBUF
495  }
496 #endif
499 #if TBUFSIZE
500  tbuf_[itbuf_++] = (unsigned long) ncons;
501  tbuf_[itbuf_++] = (unsigned long) multisend_receive_buffer[current_rbuf]->nsend_cell_;
502  tbuf_[itbuf_++] = (unsigned long) s;
503  tbuf_[itbuf_++] = (unsigned long) r;
504  tbuf_[itbuf_++] = 0UL;
505  if (use_phase2_) {
506  tbuf_[itbuf_++] =
508  tbuf_[itbuf_++] = (unsigned long) multisend_receive_buffer[current_rbuf]->phase2_nsend_;
509  }
510 #endif
511 #if ENQUEUE == 0
513 #endif
514 #if ENQUEUE == 1
516  TBUF
518 #endif
519 #if ENQUEUE == 2
524  enq2_find_time_ = 0;
525  enq2_enqueue_time_ = 0;
526 #if TBUFSIZE
527  tbuf_[itbuf_++] = tfind;
528  tbuf_[itbuf_++] = tsend;
529 #endif
530 #endif // ENQUEUE == 2
532  wt_ = w1;
533  // printf("%d reverse buffers %g\n", nrnmpi_myid, t);
536  next_rbuf = ((next_rbuf + 1) & 1);
537  }
538  TBUF
539 }
540 
541 void nrn_multisend_send(PreSyn* ps, double t) {
542 #if 0
543  if (nrn_use_localgid_) {
544  nrn_outputevent(ps->localgid_, t);
545  }else{
547  }
548 #endif
549  if (ps->bgp.multisend_send_)
550  ps->bgp.multisend_send_->send(ps->output_index_, t);
551 }
552 
554  if (ps && ps->bgp.multisend_send_) {
555  if (ps->output_index_ >= 0) {
556  delete ps->bgp.multisend_send_;
557  ps->bgp.multisend_send_ = 0;
558  }
559  if (ps->output_index_ < 0) {
560  delete ps->bgp.multisend_send_phase2_;
561  ps->bgp.multisend_send_phase2_ = 0;
562  }
563  }
564 }
565 
566 static void nrn_multisend_cleanup() {
567  for (const auto& iter: gid2out_) {
568  nrn_multisend_cleanup_presyn(iter.second);
569  }
570  for (const auto& iter: gid2in_) {
571  nrn_multisend_cleanup_presyn(iter.second);
572  }
574  delete multisend_receive_buffer[0];
576  }
578  delete multisend_receive_buffer[1];
580  }
581 }
582 
583 #if WORK_AROUND_RECORD_BUG
584 static void ensure_ntarget_gt_3(Multisend_Send* bs) {
585  // work around for bug in RecordReplay
586  if (bs->ntarget_hosts_ > 3) {
587  return;
588  }
589  int nold = bs->ntarget_hosts_;
590  int* old = bs->target_hosts_;
591  bs->target_hosts_ = new int[4];
592  for (int i = 0; i < nold; ++i) {
593  bs->target_hosts_[i] = old[i];
594  }
595  delete[] old;
596  int h = (nrnmpi_myid + 4) % nrnmpi_numprocs;
597  while (bs->ntarget_hosts_ < 4) {
598  int b = 0;
599  for (int i = 0; i < bs->ntarget_hosts_; ++i) {
600  if (h == bs->target_hosts_[i]) {
601  h = (h + 4) % nrnmpi_numprocs;
602  b = 1;
603  break;
604  }
605  }
606  if (b == 0) {
607  bs->target_hosts_[bs->ntarget_hosts_++] = h;
608  h = (h + 1) % nrnmpi_numprocs;
609  }
610  }
612 }
613 #endif
614 
615 #include "multisend_setup.cpp"
616 
619  if (!use_multisend_) {
620  return;
621  }
623  // if (nrnmpi_myid == 0) printf("nrn_multisend_setup()\n");
624  // although we only care about the set of hosts that gid2out_
625  // sends spikes to (source centric). We do not want to send
626  // the entire list of gid2in (which may be 10000 times larger
627  // than gid2out) from every machine to every machine.
628  // so we accomplish the task in two phases the first of which
629  // involves allgather with a total receive buffer size of number
630  // of cells (even that is too large and we will split it up
631  // into chunks). And the second, an
632  // allreduce with receive buffer size of number of hosts.
633  max_ntarget_host = 0;
635 
636  // completely new algorithm does one and two phase.
638 
639  if (!multisend_receive_buffer[0]) {
641  }
644  }
645 }
646 
647 #ifdef USENCS
648 
649 // give me data on which gids of this node send out APs
650 int ncs_multisend_sending_info(int** sendlist2build) {
651  int nsrcgid = 0;
652  for (const auto& iter: gid2out_) {
653  if (iter.second->output_index_ >= 0) {
654  ++nsrcgid;
655  }
656  }
657 
658  *sendlist2build = nsrcgid ? new int[nsrcgid] : 0;
659  int i = 0;
660  for (const auto& iter: gid2out) {
661  PreSyn* ps = iter.second;
662  if (ps->output_index_ >= 0) {
663  (*sendlist2build)[i] = ps->gid_;
664  ++i;
665  }
666  }
667 }
668 }
669 
670 // printf( "Node %d sees first hand %d gids send\n", nrnmpi_myid, nsrcgid );
671 return nsrcgid;
672 }
673 
674 
675 // function to access the sending information of a presyn
676 int ncs_multisend_target_hosts(int gid, int** targetnodes) {
677  auto iter = gid2out_->find(gid);
678  nrn_assert(iter != gid2out_.end());
679  PreSyn* ps = iter->second;
680  if (ps->bgp.multisend_send_) {
681  (*targetnodes) = ps->bgp.multisend_send_->ntarget_hosts_
682  ? new int[ps->bgp.multisend_send_->ntarget_hosts_]
683  : 0;
684  return ps->bgp.multisend_send_->ntarget_hosts_;
685  }
686 
687  return 0;
688 }
689 
690 // iterate over gid2in_ just so I can see what is in there
691 int ncs_multisend_target_info(int** presyngids) {
692  //(*presyngids) = 0;
693 
694  int i, nsrcgid;
695  nsrcgid = 0;
696 
697  // some target PreSyns may not have any input
698  // so initialize all to -1
699  for (const auto& iter: gid2in_) {
700  PreSyn* ps = iter.second;
701  assert(ps->output_index_ < 0);
702  if (ps->bgp.srchost_ != -1) { // has input
703  ++nsrcgid;
704  // printf( "Node %d: Presyn for gid %d has src %d\n", nrnmpi_myid, ps->gid_,
705  // ps->bgp.srchost_ );
706  }
707  }
708 
709  (*presyngids) = nsrcgid ? new int[nsrcgid] : 0;
710 
711  i = 0;
712  for (const auto& iter: gid2in_) {
713  PreSyn* ps = iter.second;
714  assert(ps->output_index_ < 0);
715  if (ps->bgp.srchost_ != -1) { // has input
716  (*presyngids)[i] = ps->gid_;
717  ++i;
718  }
719  }
720 
721  return nsrcgid;
722 }
723 
724 int ncs_multisend_mindelays(int** srchost, double** delays) {
725  int i, nsrcgid = 0;
726 
727  for (const auto& iter: gid2in_) {
728  PreSyn* ps = iter.second;
729  assert(ps->output_index_ < 0);
730  if (ps->bgp.srchost_ != -1) { // has input
731  ++nsrcgid;
732  }
733  }
734 
735  (*delays) = nsrcgid ? new double[nsrcgid] : 0;
736  (*srchost) = nsrcgid ? new int[nsrcgid] : 0;
737 
738  i = 0;
739  for (const auto& iter: gid2in_) {
740  PreSyn* ps = iter.second;
741  assert(ps->output_index_ < 0);
742  if (ps->bgp.srchost_ != -1) { // has input
743  (*delays)[i] = ps->mindelay();
744  (*srchost)[i] = ps->bgp.srchost_;
745  ++i;
746  }
747  }
748 
749  return nsrcgid;
750 }
751 
752 #endif // USENCS
static void nrnmpi_barrier()
void init(int index)
Definition: multisend.cpp:185
void incoming(int gid, double spiketime)
Definition: multisend.cpp:196
unsigned long long timebase_
Definition: multisend.cpp:116
virtual ~Multisend_ReceiveBuffer()
Definition: multisend.cpp:174
NRNMPI_Spike ** buffer_
Definition: multisend.cpp:117
Phase2Buffer * phase2_buffer_
Definition: multisend.cpp:129
Multisend_Send_Phase2()=default
virtual ~Multisend_Send_Phase2()
void send_phase2(int gid, double t, Multisend_ReceiveBuffer *)
Multisend_Send()=default
void send(int gid, double t)
virtual ~Multisend_Send()
int ntarget_hosts_phase1_
Definition: multisend.cpp:142
int * target_hosts_
Definition: multisend.cpp:140
NRNMPI_Spike spk_
Definition: multisend.cpp:141
T * alloc()
Definition: structpool.h:113
void hpfree(T *)
Definition: structpool.h:127
Definition: netcon.h:258
int output_index_
Definition: netcon.h:308
virtual void send(double sendtime, NetCvode *, NrnThread *)
Definition: netcvode.cpp:3016
double mindelay()
Definition: netcvode.cpp:2825
int gid_
Definition: netcon.h:309
#define i
Definition: md1redef.h:19
void vector_resize(IvocVect *v, int n)
Definition: ivocvect.cpp:302
IvocVect * vector_arg(int i)
Definition: ivocvect.cpp:265
#define assert(ex)
Definition: hocassrt.h:24
static int ncons
Definition: kinetic.cpp:456
static double nrnmpi_wtime()
Definition: multisplit.cpp:48
NrnThread * nrn_threads
Definition: multicore.cpp:56
double * vector_vec(IvocVect *v)
Definition: ivocvect.cpp:19
void nrn2ncs_outputevent(int netcon_output_index, double firetime)
bool use_multisend_
Definition: multisend.cpp:53
void nrn_outputevent(unsigned char, double)
void nrn_multisend_receive(NrnThread *)
void nrn_multisend_advance()
bool nrn_use_localgid_
NetCvode * net_cvode_instance
Definition: netcvode.cpp:35
std::map< int, PreSyn * > gid2out
Maps for ouput and input presyns.
Definition: nrn_setup.cpp:159
#define nrn_assert(x)
assert()-like macro, independent of NDEBUG status
Definition: nrn_assert.h:33
size_t p
size_t j
w2
Definition: multisend.cpp:498
#define MULTISEND_RECEIVEBUFFER_SIZE
Definition: multisend.cpp:101
w1
Definition: multisend.cpp:497
Pool< NRNMPI_Spike > SpkPool
Definition: multisend.cpp:99
void nrn_multisend_setup()
Definition: multisend.cpp:617
TBUF void nrn_multisend_send(PreSyn *ps, double t)
Definition: multisend.cpp:541
void nrn_multisend_cleanup_presyn(PreSyn *ps)
Definition: multisend.cpp:553
static Multisend_ReceiveBuffer * multisend_receive_buffer[2]
Definition: multisend.cpp:156
wt1_
Definition: multisend.cpp:531
s
Definition: multisend.cpp:521
void nrnmpi_multisend_comm()
#define PHASE2BUFFER_MASK
Definition: multisend.cpp:91
static void nrn_multisend_init()
Definition: multisend.cpp:375
int nrnmpi_multisend_single_advance(NRNMPI_Spike *)
static void nrn_multisend_cleanup()
Definition: multisend.cpp:566
#define ENQUEUE
Definition: multisend.cpp:83
#define TBUFSIZE
Definition: multisend.cpp:54
static int multisend_advance()
Definition: multisend.cpp:389
static int next_rbuf
Definition: multisend.cpp:157
static int max_multisend_targets
Definition: multisend.cpp:317
static unsigned long enq2_enqueue_time_
Definition: multisend.cpp:87
void nrnmpi_multisend_multisend(NRNMPI_Spike *, int, int *)
#define TBUF
Definition: multisend.cpp:74
wt_
Definition: multisend.cpp:532
int nrnmpi_multisend_conserve(int nsend, int nrecv)
static int current_rbuf
Definition: multisend.cpp:157
static int use_phase2_
Definition: multisend.cpp:132
static int max_ntarget_host
Definition: multisend.cpp:313
static unsigned long enq2_find_time_
Definition: multisend.cpp:86
multisend_receive_buffer[current_rbuf] phase2_nsend_
Definition: multisend.cpp:523
double nrn_multisend_receive_time(int type)
Definition: multisend.cpp:319
multisend_receive_buffer[current_rbuf] phase2_nsend_cell_
Definition: multisend.cpp:522
#define PHASE2BUFFER_SIZE
Definition: multisend.cpp:90
static void setup_presyn_multisend_lists()
static Gid2PreSyn gid2out_
Definition: netpar.cpp:40
static Gid2PreSyn gid2in_
Definition: netpar.cpp:41
static int n_multisend_interval
Definition: netpar.cpp:32
int ifarg(int)
Definition: code.cpp:1607
short index
Definition: cabvars.h:11
short type
Definition: cabvars.h:10
int nrnmpi_myid
#define NULL
Definition: spdefs.h:105
double spiketime
Definition: nrnmpi.h:18
int gid
Definition: nrnmpi.h:17
Represent main neuron object computed by single thread.
Definition: multicore.h:58
PreSyn * ps
Definition: multisend.cpp:93
double spiketime
Definition: multisend.cpp:94