NEURON
bgpdma.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 DCMF_Multicast 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_bgp_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 
30 extern "C" {
31 
32 extern IvocVect* vector_arg(int);
33 extern void vector_resize(IvocVect*, int);
34 
35 } // extern "C"
36 extern void (*nrntimeout_call)();
37 
38 
39 // The initial idea behind use_phase2_ is to avoid the large overhead of
40 // initiating a send of the up to 10k list of target hosts when a cell fires.
41 // I.e. when there are a small number of cells on a processor, this causes
42 // load balance problems.
43 // Load balance shuld be better if the send is distributed to a much smaller
44 // set of targets, which, when they receive the spike, pass it on to a neighbor
45 // set.
46 // We expect that TWOPHASE will work best in combination with ENQUEUE=2
47 // which has the greatest amount of overlap between computation
48 // and communication.
49 // Note: the old implementation assumed that input PreSyn did not need
50 // a BGP_DMASend pointer so used the PreSyn.bgp.srchost_ element to
51 // help figure out the target_hosts_ list for the output PreSyn.bgp.dma_send_.
52 // Since bgp.srchost_ is used only for setup, it can be overwritten at phase2
53 // setup time with a bgp.dma_send_ so as to pass on the spike to the
54 // phase2 list of target hosts.
55 
56 #if !defined(DCMFTICK)
57 #define DCMFTICK 0
58 #define DCMFTIMEBASE 0
59 #endif
60 
61 static unsigned long long dmasend_time_;
62 static int n_xtra_cons_check_;
63 #define MAXNCONS 10
64 #if MAXNCONS
65 static int xtra_cons_hist_[MAXNCONS + 1];
66 #endif
67 
68 // asm/msr.h no longer compiles on my machine.
69 // only for basic testing of logic when not on blue gene/p
70 #define USE_RDTSCL 0
71 
72 // only use if careful not to overrun the buffer during a simulation
73 #if 0 && USE_RDTSCL
74 #define TBUFSIZE (1 << 15)
75 #else
76 #define TBUFSIZE 0
77 #endif
78 
79 #if TBUFSIZE
80 static unsigned long tbuf_[TBUFSIZE];
81 static int itbuf_;
82 #if USE_RDTSCL // but can have many accuracy problems on recent cpus.
83 /* for rdtscl() */
84 //#include <asm/msr.h>
85 #define rdtscl(a) a++
86 static unsigned long t__;
87 #define TBUF \
88  { \
89  rdtscl(t__); \
90  tbuf_[itbuf_++] = t__; \
91  }
92 #else
93 #define TBUF tbuf_[itbuf_++] = (unsigned long) DCMF_Timebase();
94 #endif // not USE_RDTSCLL
95 #else
96 #define TBUF /**/
97 #endif
98 
99 // ENQUEUE 0 means to BGP_ReceiveBuffer buffer -> PreSyn.send
100 // ENQUEUE 1 means to BGP_ReceiveBuffer buffer -> psbuf -> PreSyn.send
101 // ENQUEUE 2 means to BGP_ReceiveBuffer.incoming -> PrySyn.send
102 // Note that ENQUEUE 2 give more overlap between computation and exchange
103 // since the enqueuing takes place during computation except for those
104 // remaining during conservation.
105 #define ENQUEUE 2
106 
107 #if ENQUEUE == 2
108 static unsigned long enq2_find_time_;
109 static unsigned long enq2_enqueue_time_; // includes enq_find_time_
110 #endif
111 
112 #define PHASE2BUFFER_SIZE 2048 // power of 2
113 #define PHASE2BUFFER_MASK (PHASE2BUFFER_SIZE - 1)
114 struct Phase2Buffer {
116  double spiketime;
117 };
118 
119 #include <structpool.h>
120 
122 
123 #define BGP_RECEIVEBUFFER_SIZE 10000
125  public:
127  virtual ~BGP_ReceiveBuffer();
128  void init(int index);
129  void incoming(int gid, double spiketime);
130  void enqueue();
131  int index_;
132  int size_;
133  int count_;
135  int busy_;
136  int nsend_, nrecv_; // for checking conservation
137  int nsend_cell_; // cells that spiked this interval.
138  unsigned long long timebase_;
141 
142 #if ENQUEUE == 1
143  void enqueue1();
144  void enqueue2();
145 #endif
147  void phase2send();
152 };
153 
154 static int use_phase2_;
155 #define NTARGET_HOSTS_PHASE1 ntarget_hosts_phase1_
156 
157 class BGP_DMASend {
158  public:
159  BGP_DMASend();
160  virtual ~BGP_DMASend();
161  void send(int gid, double t);
166 };
167 
169  public:
171  virtual ~BGP_DMASend_Phase2();
173 
174  void send_phase2(int gid, double t, BGP_ReceiveBuffer*);
177 };
178 
181 #if BGP_INTERVAL == 2
182 // note that if a spike is supposed to be received by bgp_receive_buffer[1]
183 // then during transmission its gid is complemented.
184 #endif
185 
187  busy_ = 0;
188  count_ = 0;
190  buffer_ = new NRNMPI_Spike*[size_];
192  psbuf_ = 0;
193 #if ENQUEUE == 1
194  psbuf_ = new PreSyn*[size_];
195 #endif
198 }
200  assert(busy_ == 0);
201  for (int i = 0; i < count_; ++i) {
202  pool_->hpfree(buffer_[i]);
203  }
204  delete[] buffer_;
205  delete pool_;
206  if (psbuf_)
207  delete[] psbuf_;
208  delete[] phase2_buffer_;
209 }
211  index_ = index;
212  timebase_ = 0;
214  for (int i = 0; i < count_; ++i) {
215  pool_->hpfree(buffer_[i]);
216  }
217  count_ = 0;
220 }
221 void BGP_ReceiveBuffer::incoming(int gid, double spiketime) {
222  // printf("%d %p.incoming %g %g %d\n", nrnmpi_myid, this, t, spk->spiketime, spk->gid);
223  assert(busy_ == 0);
224  busy_ = 1;
225  if (count_ >= size_) {
226  size_ *= 2;
227  NRNMPI_Spike** newbuf = new NRNMPI_Spike*[size_];
228  for (int i = 0; i < count_; ++i) {
229  newbuf[i] = buffer_[i];
230  }
231  delete[] buffer_;
232  buffer_ = newbuf;
233  if (psbuf_) {
234  delete[] psbuf_;
235  psbuf_ = new PreSyn*[size_];
236  }
237  }
238  NRNMPI_Spike* spk = pool_->alloc();
239  spk->gid = gid;
240  spk->spiketime = spiketime;
241  buffer_[count_++] = spk;
242  if (maxcount_ < count_) {
243  maxcount_ = count_;
244  }
245  ++nrecv_;
246  busy_ = 0;
247 }
249  // printf("%d %p.enqueue count=%d t=%g nrecv=%d nsend=%d\n", nrnmpi_myid, this, t, count_,
250  // nrecv_, nsend_);
251  assert(busy_ == 0);
252  busy_ = 1;
253 #if 1
254  for (int i = 0; i < count_; ++i) {
255  NRNMPI_Spike* spk = buffer_[i];
256 #if ENQUEUE == 2
257  unsigned long long tb = DCMFTIMEBASE;
258 #endif
259 
260  auto iter = gid2in_.find(spk->gid);
261  nrn_assert(iter != gid2in_.end());
262  PreSyn* ps = iter->second;
263  if (use_phase2_ && ps->bgp.dma_send_phase2_) {
264  // cannot do directly because busy_;
265  // ps->bgp.dma_send_phase2_->send_phase2(spk->gid, spk->spiketime, this);
269  pb.ps = ps;
270  pb.spiketime = spk->spiketime;
271  }
272 #if ENQUEUE == 2
273  enq2_find_time_ += (unsigned long) (DCMFTIMEBASE - tb);
274 #endif
276  pool_->hpfree(spk);
277 #if ENQUEUE == 2
278  enq2_enqueue_time_ += (unsigned long) (DCMFTIMEBASE - tb);
279 #endif
280  }
281 #endif
282  count_ = 0;
283 #if ENQUEUE != 2
284  nrecv_ = 0;
285  nsend_ = 0;
286  nsend_cell_ = 0;
287 #endif
288  busy_ = 0;
289  phase2send();
290 }
291 
292 #if ENQUEUE == 1
293 void BGP_ReceiveBuffer::enqueue1() {
294  // printf("%d %lx.enqueue count=%d t=%g nrecv=%d nsend=%d\n", nrnmpi_myid, (long)this, t,
295  // count_, nrecv_, nsend_);
296  assert(busy_ == 0);
297  busy_ = 1;
298  for (int i = 0; i < count_; ++i) {
299  NRNMPI_Spike* spk = buffer_[i];
300  auto iter = gid2in_->find(spk->gid);
301  nrn_assert(iter != gid2in_.end()));
302  PreSyn* ps = iter->second;
303  psbuf_[i] = ps;
304  if (use_phase2_ && ps->bgp.dma_send_phase2_) {
305  // cannot do directly because busy_;
306  // ps->bgp.dma_send_phase2_->send_phase2(spk->gid, spk->spiketime, this);
310  pb.ps = ps;
311  pb.spiketime = spk->spiketime;
312  }
313  }
314  busy_ = 0;
315  phase2send();
316 }
317 
318 void BGP_ReceiveBuffer::enqueue2() {
319  // printf("%d %lx.enqueue count=%d t=%g nrecv=%d nsend=%d\n", nrnmpi_myid, (long)this, t,
320  // count_, nrecv_, nsend_);
321  assert(busy_ == 0);
322  busy_ = 1;
323  for (int i = 0; i < count_; ++i) {
324  NRNMPI_Spike* spk = buffer_[i];
325  PreSyn* ps = psbuf_[i];
327  pool_->hpfree(spk);
328  }
329  count_ = 0;
330  nrecv_ = 0;
331  nsend_ = 0;
332  nsend_cell_ = 0;
333  busy_ = 0;
334 }
335 #endif // ENQUEUE == 1
336 
338  while (phase2_head_ != phase2_tail_) {
341  pb.ps->bgp.dma_send_phase2_->send_phase2(pb.ps->gid_, pb.spiketime, this);
342  }
343 }
344 
345 // number of DCMF_Multicast_t to cycle through when not using recordreplay
346 #define NSEND 10
347 
348 static int max_ntarget_host;
349 // For one phase sending, max_multisend_targets is max_ntarget_host.
350 // For two phase sending, it is the maximum of all the
351 // ntarget_hosts_phase1 and ntarget_hosts_phase2.
353 
354 double nrn_bgp_receive_time(int type) { // and others
355  double rt = 0.;
356  switch (type) {
357  case 2: // in msend_recv
358  if (!use_bgpdma_) {
359  return rt;
360  }
361  for (int i = 0; i < n_bgp_interval; ++i) {
363  }
364  break;
365  case 3: // in BGP_DMAsend::send
366  if (!use_bgpdma_) {
367  return rt;
368  }
369  rt = dmasend_time_ * DCMFTICK;
370  break;
371  case 4: // number of extra conservation checks
372  rt = double(n_xtra_cons_check_);
373  // and if there is second vector arg then also return the histogram
374 #if MAXNCONS
375  if (ifarg(2) && use_bgpdma_) {
376  IvocVect* vec = vector_arg(2);
377  vector_resize(vec, MAXNCONS + 1);
378  for (int i = 0; i <= MAXNCONS; ++i) {
379  vector_vec(vec)[i] = double(xtra_cons_hist_[i]);
380  }
381  }
382 #endif // MAXNCONS
383 #if TBUFSIZE
384  if (ifarg(3)) {
385  IvocVect* vec = vector_arg(3);
386  vector_resize(vec, itbuf_ + 1);
387  for (int i = 0; i <= itbuf_; ++i) {
388  vector_vec(vec)[i] = double(tbuf_[i]);
389  }
390  vector_vec(vec)[itbuf_] = DCMFTICK;
391  }
392 #endif
393  break;
394  case 8: // exchange method properties
395  // bit 0: 0 allgather, 1 multisend (MPI_ISend)
396  // bit 1: unused, legacy
397  // bit 2: n_bgp_interval, 0 means one interval, 1 means 2
398  // bit 3: number of phases, 0 means 1 phase, 1 means 2
399  // bit 4: unused (1 used to mean althash used)
400  // bit 5: 1 means enqueue separated into two parts for timeing
401  {
402  int method = use_bgpdma_ ? 1 : 0;
403  int p = method + 4 * (n_bgp_interval == 2 ? 1 : 0) + 8 * use_phase2_ +
404  16 * (0) // no hash selection, just std::unordered_map
405  + 32 * ENQUEUE;
406  rt = double(p);
407  } break;
408  case 12: // greatest length multisend
409  {
410  rt = double(max_multisend_targets);
411  break;
412  }
413  }
414  return rt;
415 }
416 
417 extern void nrnmpi_bgp_comm();
418 extern void nrnmpi_bgp_multisend(NRNMPI_Spike*, int, int*);
420 extern int nrnmpi_bgp_conserve(int nsend, int nrecv);
421 
422 static void bgp_dma_init() {
423  for (int i = 0; i < n_bgp_interval; ++i) {
425  }
426  current_rbuf = 0;
428 #if TBUFSIZE
429  itbuf_ = 0;
430 #endif
431  dmasend_time_ = 0;
432 #if ENQUEUE == 2
434 #endif
435  n_xtra_cons_check_ = 0;
436 #if MAXNCONS
437  for (int i = 0; i <= MAXNCONS; ++i) {
438  xtra_cons_hist_[i] = 0;
439  }
440 #endif // MAXNCONS
441 }
442 
443 static int bgp_advance() {
444  NRNMPI_Spike spk;
445  int i = 0;
446  while (nrnmpi_bgp_single_advance(&spk)) {
447  i += 1;
448  int j = 0;
449 #if BGP_INTERVAL == 2
450  if (spk.gid < 0) {
451  spk.gid = ~spk.gid;
452  j = 1;
453  }
454 #endif
456  }
457  nrecv_ += i;
458  return i;
459 }
460 
461 #if BGPDMA
462 void nrnbgp_messager_advance() {
463 #if BGPDMA & 1
464  if (use_bgpdma_) {
465  bgp_advance();
466  }
467 #endif
468 #if ENQUEUE == 2
470 #endif
471 }
472 #endif
473 
475  ntarget_hosts_ = 0;
478 }
479 
481  if (target_hosts_) {
482  delete[] target_hosts_;
483  }
484 }
485 
489 }
490 
492  if (target_hosts_phase2_) {
493  delete[] target_hosts_phase2_;
494  }
495 }
496 
497 // helps debugging when core dump since otherwise cannot tell where
498 // BGP_DMASend::send fails
499 #if 0
500 static void mymulticast(DCMF_Multicast_t* arg) {
501  DCMF_Multicast(arg);
502 }
503 static void myrestart(DCMF_Request_t* arg) {
504  DCMF_Restart(arg);
505 }
506 #endif
507 
508 void BGP_DMASend::send(int gid, double t) {
509  unsigned long long tb = DCMFTIMEBASE;
510  if (NTARGET_HOSTS_PHASE1) {
511  spk_.gid = gid;
512  spk_.spiketime = t;
513 #if BGP_INTERVAL == 2
516  if (next_rbuf == 1) {
517  spk_.gid = ~spk_.gid;
518  }
519 #else
522 #endif
523  nsend_ += 1;
524 #if BGPDMA & 1
525  if (use_bgpdma_) {
527  }
528 #endif
529  }
530  dmasend_time_ += DCMFTIMEBASE - tb;
531 }
532 
534  unsigned long long tb = DCMFTIMEBASE;
535  if (ntarget_hosts_phase2_) {
536  spk_.gid = gid;
537  spk_.spiketime = t;
538 #if BGP_INTERVAL == 2
539  if (rb->index_ == 1) {
540  spk_.gid = ~spk_.gid;
541  }
542 #endif
543  rb->phase2_nsend_cell_ += 1;
545 #if BGPDMA & 1
546  if (use_bgpdma_) {
548  }
549 #endif
550  }
551  dmasend_time_ += DCMFTIMEBASE - tb;
552 }
553 
555  // nrn_spike_exchange();
556  assert(nt == nrn_threads);
557  TBUF double w1, w2;
558  int ncons = 0;
561 #if ENQUEUE == 2 && TBUFSIZE
562  unsigned long tfind, tsend;
563 #endif
564  w1 = nrnmpi_wtime();
565 #if BGPDMA & 1
566  if (use_bgpdma_) {
567  nrnbgp_messager_advance();
568  TBUF
569 #if ENQUEUE == 2 && TBUFSIZE
570  // want the overlap with computation, not conserve
571  tfind = enq2_find_time_;
573 #endif
574 #if TBUFSIZE
575  nrnmpi_barrier();
576 #endif
577  TBUF while (nrnmpi_bgp_conserve(s, r) != 0) {
578  nrnbgp_messager_advance();
579  ++ncons;
580  }
581  TBUF
582  }
583 #endif
584  w1 = nrnmpi_wtime() - w1;
585  w2 = nrnmpi_wtime();
586 #if TBUFSIZE
587  tbuf_[itbuf_++] = (unsigned long) ncons;
588  tbuf_[itbuf_++] = (unsigned long) bgp_receive_buffer[current_rbuf]->nsend_cell_;
589  tbuf_[itbuf_++] = (unsigned long) s;
590  tbuf_[itbuf_++] = (unsigned long) r;
591  tbuf_[itbuf_++] = (unsigned long) dmasend_time_;
592  if (use_phase2_) {
593  tbuf_[itbuf_++] = (unsigned long) bgp_receive_buffer[current_rbuf]->phase2_nsend_cell_;
594  tbuf_[itbuf_++] = (unsigned long) bgp_receive_buffer[current_rbuf]->phase2_nsend_;
595  }
596 #endif
597 #if (BGPMDA & 2) && MAXNCONS
598  if (ncons > MAXNCONS) {
599  ncons = MAXNCONS;
600  }
602 #endif // MAXNCONS
603 #if ENQUEUE == 0
605 #endif
606 #if ENQUEUE == 1
607  bgp_receive_buffer[current_rbuf]->enqueue1();
608  TBUF bgp_receive_buffer[current_rbuf]->enqueue2();
609 #endif
610 #if ENQUEUE == 2
615  enq2_find_time_ = 0;
616  enq2_enqueue_time_ = 0;
617 #if TBUFSIZE
618  tbuf_[itbuf_++] = tfind;
619  tbuf_[itbuf_++] = tsend;
620 #endif
621 #endif // ENQUEUE == 2
622  wt1_ = nrnmpi_wtime() - w2;
623  wt_ = w1;
624 #if BGP_INTERVAL == 2
625  // printf("%d reverse buffers %g\n", nrnmpi_myid, t);
626  if (n_bgp_interval == 2) {
628  next_rbuf = ((next_rbuf + 1) & 1);
629  }
630 #endif
631  TBUF
632 }
633 
634 void bgp_dma_send(PreSyn* ps, double t) {
635 #if 0
636  if (nrn_use_localgid_) {
637  nrn_outputevent(ps->localgid_, t);
638  }else{
639  nrn2ncs_outputevent(ps->output_index_, t);
640  }
641 #endif
642  if (ps->bgp.dma_send_)
643  ps->bgp.dma_send_->send(ps->output_index_, t);
644 }
645 
647  if (ps && ps->bgp.dma_send_) {
648  if (ps->output_index_ >= 0) {
649  delete ps->bgp.dma_send_;
650  ps->bgp.dma_send_ = 0;
651  }
652  if (ps->output_index_ < 0) {
653  delete ps->bgp.dma_send_phase2_;
654  ps->bgp.dma_send_phase2_ = 0;
655  }
656  }
657 }
658 
659 static void bgpdma_cleanup() {
660  nrntimeout_call = 0;
661  for (const auto& iter: gid2out_) {
662  bgpdma_cleanup_presyn(iter.second);
663  }
664  for (const auto& iter: gid2in_) {
665  bgpdma_cleanup_presyn(iter.second);
666  }
667  if (!use_bgpdma_ && bgp_receive_buffer[1]) {
668  delete bgp_receive_buffer[0];
670  }
671 #if BGP_INTERVAL == 2
672  if ((!use_bgpdma_ || n_bgp_interval != 2) && bgp_receive_buffer[1]) {
673  delete bgp_receive_buffer[1];
675  }
676 #endif
677 }
678 
679 #ifndef BGPTIMEOUT
680 #define BGPTIMEOUT 0
681 #endif
682 
683 #if BGPTIMEOUT
684 static void bgptimeout() {
685  printf("%d timeout %d %d %d\n",
686  nrnmpi_myid,
687  current_rbuf,
690 }
691 #endif
692 
693 #if WORK_AROUND_RECORD_BUG
694 static void ensure_ntarget_gt_3(BGP_DMASend* bs) {
695  // work around for bug in RecordReplay
696  if (bs->ntarget_hosts_ > 3) {
697  return;
698  }
699  int nold = bs->ntarget_hosts_;
700  int* old = bs->target_hosts_;
701  bs->target_hosts_ = new int[4];
702  for (int i = 0; i < nold; ++i) {
703  bs->target_hosts_[i] = old[i];
704  }
705  delete[] old;
706  int h = (nrnmpi_myid + 4) % nrnmpi_numprocs;
707  while (bs->ntarget_hosts_ < 4) {
708  int b = 0;
709  for (int i = 0; i < bs->ntarget_hosts_; ++i) {
710  if (h == bs->target_hosts_[i]) {
711  h = (h + 4) % nrnmpi_numprocs;
712  b = 1;
713  break;
714  }
715  }
716  if (b == 0) {
717  bs->target_hosts_[bs->ntarget_hosts_++] = h;
718  h = (h + 1) % nrnmpi_numprocs;
719  }
720  }
722 }
723 #endif
724 
725 #define FASTSETUP 1
726 #if FASTSETUP
727 #include "bgpdmasetup.cpp"
728 #endif
729 
731  bgpdma_cleanup();
732  if (!use_bgpdma_) {
733  return;
734  }
735  // not sure this is useful for debugging when stuck in a collective.
736 #if BGPTIMEOUT
737  nrntimeout_call = bgptimeout;
738 #endif
739  nrnmpi_bgp_comm();
740  // if (nrnmpi_myid == 0) printf("bgp_dma_setup()\n");
741  // although we only care about the set of hosts that gid2out_
742  // sends spikes to (source centric). We do not want to send
743  // the entire list of gid2in (which may be 10000 times larger
744  // than gid2out) from every machine to every machine.
745  // so we accomplish the task in two phases the first of which
746  // involves allgather with a total receive buffer size of number
747  // of cells (even that is too large and we will split it up
748  // into chunks). And the second, an
749  // allreduce with receive buffer size of number of hosts.
750  max_ntarget_host = 0;
752 
753 #if FASTSETUP
754  // completely new algorithm does one and two phase.
756 #else // obsolete
757  // see 672:544c61a730ec
758 #error "FASTSETUP required"
759 #endif // obsolete (not FASTSETUP)
760 
761  if (!bgp_receive_buffer[0]) {
763  }
764 #if BGP_INTERVAL == 2
765  if (n_bgp_interval == 2 && !bgp_receive_buffer[1]) {
767  }
768 #endif
769 }
770 
771 #ifdef USENCS
772 
773 // give me data on which gids of this node send out APs
774 int ncs_bgp_sending_info(int** sendlist2build) {
775  int nsrcgid = 0;
776  for (const auto& iter: gid2out_) {
777  if (iter.second->output_index_ >= 0) {
778  ++nsrcgid;
779  }
780  }
781 
782  *sendlist2build = nsrcgid ? new int[nsrcgid] : 0;
783  int i = 0;
784  for (const auto& iter: gid2out) {
785  PreSyn* ps = iter.second;
786  if (ps->output_index_ >= 0) {
787  (*sendlist2build)[i] = ps->gid_;
788  ++i;
789  }
790  }
791 }
792 }
793 
794 // printf( "Node %d sees first hand %d gids send\n", nrnmpi_myid, nsrcgid );
795 return nsrcgid;
796 }
797 
798 
799 // function to access the sending information of a presyn
800 int ncs_bgp_target_hosts(int gid, int** targetnodes) {
801  auto iter = gid2out_->find(gid);
802  nrn_assert(iter != gid2out_.end());
803  PreSyn* ps = iter->second;
804  if (ps->bgp.dma_send_) {
805  (*targetnodes) = ps->bgp.dma_send_->ntarget_hosts_
806  ? new int[ps->bgp.dma_send_->ntarget_hosts_]
807  : 0;
808  return ps->bgp.dma_send_->ntarget_hosts_;
809  }
810 
811  return 0;
812 }
813 
814 // iterate over gid2in_ just so I can see what is in there
815 int ncs_bgp_target_info(int** presyngids) {
816  //(*presyngids) = 0;
817 
818  int i, nsrcgid;
819  nsrcgid = 0;
820 
821  // some target PreSyns may not have any input
822  // so initialize all to -1
823  for (const auto& iter: gid2in_) {
824  PreSyn* ps = iter.second;
825  assert(ps->output_index_ < 0);
826  if (ps->bgp.srchost_ != -1) { // has input
827  ++nsrcgid;
828  // printf( "Node %d: Presyn for gid %d has src %d\n", nrnmpi_myid, ps->gid_,
829  // ps->bgp.srchost_ );
830  }
831  }
832 
833  (*presyngids) = nsrcgid ? new int[nsrcgid] : 0;
834 
835  i = 0;
836  for (const auto& iter: gid2in_) {
837  PreSyn* ps = iter.second;
838  assert(ps->output_index_ < 0);
839  if (ps->bgp.srchost_ != -1) { // has input
840  (*presyngids)[i] = ps->gid_;
841  ++i;
842  }
843  }
844 
845  return nsrcgid;
846 }
847 
848 int ncs_bgp_mindelays(int** srchost, double** delays) {
849  int i, nsrcgid = 0;
850 
851  for (const auto& iter: gid2in_) {
852  PreSyn* ps = iter.second;
853  assert(ps->output_index_ < 0);
854  if (ps->bgp.srchost_ != -1) { // has input
855  ++nsrcgid;
856  }
857  }
858 
859  (*delays) = nsrcgid ? new double[nsrcgid] : 0;
860  (*srchost) = nsrcgid ? new int[nsrcgid] : 0;
861 
862  i = 0;
863  for (const auto& iter: gid2in_) {
864  PreSyn* ps = iter.second;
865  assert(ps->output_index_ < 0);
866  if (ps->bgp.srchost_ != -1) { // has input
867  (*delays)[i] = ps->mindelay();
868  (*srchost)[i] = ps->bgp.srchost_;
869  ++i;
870  }
871  }
872 
873  return nsrcgid;
874 }
875 
876 #endif // USENCS
static void nrnmpi_barrier()
void bgp_dma_receive(NrnThread *nt)
Definition: bgpdma.cpp:554
void bgp_dma_setup()
Definition: bgpdma.cpp:730
void nrnmpi_bgp_multisend(NRNMPI_Spike *, int, int *)
#define BGP_RECEIVEBUFFER_SIZE
Definition: bgpdma.cpp:123
Pool< NRNMPI_Spike > SpkPool
Definition: bgpdma.cpp:121
void vector_resize(IvocVect *, int)
#define PHASE2BUFFER_MASK
Definition: bgpdma.cpp:113
static unsigned long enq2_enqueue_time_
Definition: bgpdma.cpp:109
void(* nrntimeout_call)()
#define DCMFTICK
Definition: bgpdma.cpp:57
#define ENQUEUE
Definition: bgpdma.cpp:105
#define TBUFSIZE
Definition: bgpdma.cpp:76
static unsigned long long dmasend_time_
Definition: bgpdma.cpp:61
static int next_rbuf
Definition: bgpdma.cpp:180
double nrn_bgp_receive_time(int type)
Definition: bgpdma.cpp:354
static BGP_ReceiveBuffer * bgp_receive_buffer[BGP_INTERVAL]
Definition: bgpdma.cpp:179
#define DCMFTIMEBASE
Definition: bgpdma.cpp:58
static int max_multisend_targets
Definition: bgpdma.cpp:352
static void bgpdma_cleanup()
Definition: bgpdma.cpp:659
void bgpdma_cleanup_presyn(PreSyn *ps)
Definition: bgpdma.cpp:646
static void bgp_dma_init()
Definition: bgpdma.cpp:422
static int n_xtra_cons_check_
Definition: bgpdma.cpp:62
#define TBUF
Definition: bgpdma.cpp:96
#define NTARGET_HOSTS_PHASE1
Definition: bgpdma.cpp:155
static int current_rbuf
Definition: bgpdma.cpp:180
void bgp_dma_send(PreSyn *ps, double t)
Definition: bgpdma.cpp:634
IvocVect * vector_arg(int)
Definition: ivocvect.cpp:397
static int use_phase2_
Definition: bgpdma.cpp:154
int nrnmpi_bgp_conserve(int nsend, int nrecv)
#define MAXNCONS
Definition: bgpdma.cpp:63
static int max_ntarget_host
Definition: bgpdma.cpp:348
static unsigned long enq2_find_time_
Definition: bgpdma.cpp:108
void nrnmpi_bgp_comm()
static int bgp_advance()
Definition: bgpdma.cpp:443
static int xtra_cons_hist_[MAXNCONS+1]
Definition: bgpdma.cpp:65
int nrnmpi_bgp_single_advance(NRNMPI_Spike *)
#define PHASE2BUFFER_SIZE
Definition: bgpdma.cpp:112
static void setup_presyn_dma_lists()
short index
Definition: cabvars.h:10
short type
Definition: cabvars.h:9
int * target_hosts_phase2_
Definition: bgpdma.cpp:176
int ntarget_hosts_phase2_
Definition: bgpdma.cpp:175
virtual ~BGP_DMASend_Phase2()
Definition: bgpdma.cpp:491
NRNMPI_Spike spk_
Definition: bgpdma.cpp:172
void send_phase2(int gid, double t, BGP_ReceiveBuffer *)
Definition: bgpdma.cpp:533
void send(int gid, double t)
Definition: bgpdma.cpp:508
int ntarget_hosts_
Definition: bgpdma.cpp:162
int ntarget_hosts_phase1_
Definition: bgpdma.cpp:165
NRNMPI_Spike spk_
Definition: bgpdma.cpp:164
virtual ~BGP_DMASend()
Definition: bgpdma.cpp:480
int * target_hosts_
Definition: bgpdma.cpp:163
NRNMPI_Spike ** buffer_
Definition: bgpdma.cpp:139
virtual ~BGP_ReceiveBuffer()
Definition: bgpdma.cpp:199
unsigned long long timebase_
Definition: bgpdma.cpp:138
PreSyn ** psbuf_
Definition: bgpdma.cpp:146
SpkPool * pool_
Definition: bgpdma.cpp:140
void incoming(int gid, double spiketime)
Definition: bgpdma.cpp:221
void init(int index)
Definition: bgpdma.cpp:210
void phase2send()
Definition: bgpdma.cpp:337
int phase2_nsend_cell_
Definition: bgpdma.cpp:150
Phase2Buffer * phase2_buffer_
Definition: bgpdma.cpp:151
T * alloc()
Definition: structpool.h:114
void hpfree(T *)
Definition: structpool.h:128
Definition: netcon.h:255
int output_index_
Definition: netcon.h:306
virtual void send(double sendtime, NetCvode *, NrnThread *)
Definition: netcvode.cpp:3252
double mindelay()
Definition: netcvode.cpp:3051
int gid_
Definition: netcon.h:307
double t
Definition: cvodeobj.cpp:59
NetCvode * net_cvode_instance
Definition: cvodestb.cpp:27
#define assert(ex)
Definition: hocassrt.h:32
void
int ifarg(int)
Definition: code.cpp:1581
double * vector_vec(Vect *v)
Definition: ivocvect.cpp:328
static int ncons
Definition: kinetic.cpp:509
#define i
Definition: md1redef.h:12
NrnThread * nrn_threads
Definition: multicore.cpp:47
static double nrnmpi_wtime()
Definition: multisplit.cpp:55
#define printf
Definition: mwprefix.h:26
#define BGP_INTERVAL
Definition: netpar.cpp:27
static Gid2PreSyn gid2out_
Definition: netpar.cpp:33
static Gid2PreSyn gid2in_
Definition: netpar.cpp:34
static int n_bgp_interval
Definition: netpar.cpp:29
#define nrn_assert(ex)
Definition: nrnassrt.h:53
size_t p
size_t j
int nrnmpi_myid
int nrnmpi_numprocs
#define arg
Definition: redef.h:28
#define NULL
Definition: sptree.h:16
double spiketime
Definition: nrnmpi.h:19
int gid
Definition: nrnmpi.h:18
Represent main neuron object computed by single thread.
Definition: multicore.h:58
PreSyn * ps
Definition: bgpdma.cpp:115
double spiketime
Definition: bgpdma.cpp:116