NEURON
bgpdmasetup.cpp
Go to the documentation of this file.
1 /*
2 For very large numbers of processors and cells and fanout, it is taking
3 a long time to figure out each cells target list given the input gids
4 (gid2in) on each host. e.g 240 seconds for 2^25 cells, 1k connections
5 per cell, and 128K cores; and 340 seconds for two phase excchange.
6 To reduce this setup time we experiment with a very different algorithm in which
7 we construct a gid target host list on host gid%nhost and copy that list to
8 the source host owning the gid.
9 */
10 
11 #include "oc_ansi.h"
12 
13 #if 0
14 void celldebug(const char* p, Gid2PreSyn& map) {
15  FILE* f;
16  char fname[100];
17  sprintf(fname, "debug.%d", nrnmpi_myid);
18  f = fopen(fname, "a");
19  fprintf(f, "\n%s\n", p);
20  int rank = nrnmpi_myid;
21  fprintf(f, " %2d:", rank);
22  for (const auto& iter: map) {
23  int gid = iter.first;
24  fprintf(f, " %2d", gid);
25  }
26  fprintf(f, "\n");
27  fclose(f);
28 }
29 
30 void alltoalldebug(const char* p, int* s, int* scnt, int* sdispl, int* r, int* rcnt, int* rdispl){
31  FILE* f;
32  char fname[100];
33  sprintf(fname, "debug.%d", nrnmpi_myid);
34  f = fopen(fname, "a");
35  fprintf(f, "\n%s\n", p);
36  int rank = nrnmpi_myid;
37  fprintf(f, " rank %d\n", rank);
38  for (int i=0; i < nrnmpi_numprocs; ++i) {
39  fprintf(f, " s%d : %d %d :", i, scnt[i], sdispl[i]);
40  for (int j = sdispl[i]; j < sdispl[i+1]; ++j) {
41  fprintf(f, " %2d", s[j]);
42  }
43  fprintf(f, "\n");
44  }
45  for (int i=0; i < nrnmpi_numprocs; ++i) {
46  fprintf(f, " r%d : %d %d :", i, rcnt[i], rdispl[i]);
47  for (int j = rdispl[i]; j < rdispl[i+1]; ++j) {
48  fprintf(f, " %2d", r[j]);
49  }
50  fprintf(f, "\n");
51  }
52  fclose(f);
53 }
54 #else
55 void celldebug(const char* p, Gid2PreSyn& map) {}
56 void alltoalldebug(const char* p, int* s, int* scnt, int* sdispl, int* r, int* rcnt, int* rdispl) {}
57 #endif
58 
59 #if 0
60 void phase1debug() {
61  FILE* f;
62  char fname[100];
63  sprintf(fname, "debug.%d", nrnmpi_myid);
64  f = fopen(fname, "a");
65  fprintf(f, "\nphase1debug %d", nrnmpi_myid);
66  for (const auto* iter: gid2out_) {
67  PreSyn* ps = iter.second;
68  fprintf(f, "\n %2d:", ps->gid_);
69  BGP_DMASend* bs = ps->bgp.dma_send_;
70  for (int i=0; i < bs->ntarget_hosts_; ++i) {
71  fprintf(f, " %2d", bs->target_hosts_[i]);
72  }
73  }
74  fprintf(f, "\n");
75  fclose(f);
76 }
77 
78 void phase2debug() {
79  FILE* f;
80  char fname[100];
81  sprintf(fname, "debug.%d", nrnmpi_myid);
82  f = fopen(fname, "a");
83  fprintf(f, "\nphase2debug %d", nrnmpi_myid);
84  for (const auto& iter: gid2in_) {
85  PreSyn* ps = iter.second;
86  fprintf(f, "\n %2d:", ps->gid_);
87  BGP_DMASend_Phase2* bs = ps->bgp.dma_send_phase2_;
88  if (bs) {
89  for (int i=0; i < bs->ntarget_hosts_phase2_; ++i) {
90  fprintf(f, " %2d", bs->target_hosts_phase2_[i]);
91  }
92  }
93  }
94  fprintf(f, "\n");
95  fclose(f);
96 }
97 #endif
98 
99 static void del(int* a) {
100  if (a) {
101  delete[] a;
102  }
103 }
104 
105 static int* newintval(int val, int size) {
106  if (size == 0) {
107  return 0;
108  }
109  int* x = new int[size];
110  for (int i = 0; i < size; ++i) {
111  x[i] = val;
112  }
113  return x;
114 }
115 
116 static int* newoffset(int* acnt, int size) {
117  int* aoff = new int[size + 1];
118  aoff[0] = 0;
119  for (int i = 0; i < size; ++i) {
120  aoff[i + 1] = aoff[i] + acnt[i];
121  }
122  return aoff;
123 }
124 
125 
126 // input scnt, sdispl ; output, newly allocated rcnt, rdispl
127 static void all2allv_helper(int* scnt, int* sdispl, int*& rcnt, int*& rdispl) {
128  int np = nrnmpi_numprocs;
129  int* c = newintval(1, np);
130  rdispl = newoffset(c, np);
131  rcnt = newintval(0, np);
132  nrnmpi_int_alltoallv(scnt, c, rdispl, rcnt, c, rdispl);
133  del(c);
134  del(rdispl);
135  rdispl = newoffset(rcnt, np);
136 }
137 
138 /*
139 define following to 1 if desire space/performance information such as:
140 all2allv_int gidin to intermediate space=1552 total=37345104 time=0.000495835
141 all2allv_int gidout space=528 total=37379376 time=1.641e-05
142 all2allv_int lists space=3088 total=37351312 time=4.4708e-05
143 */
144 #define all2allv_perf 0
145 // input s, scnt, sdispl ; output, newly allocated r, rcnt, rdispl
146 static void
147 all2allv_int(int* s, int* scnt, int* sdispl, int*& r, int*& rcnt, int*& rdispl, const char* dmes) {
148 #if all2allv_perf
149  double tm = nrnmpi_wtime();
150 #endif
151  int np = nrnmpi_numprocs;
152  all2allv_helper(scnt, sdispl, rcnt, rdispl);
153  r = newintval(0, rdispl[np]);
154 
155  nrnmpi_int_alltoallv(s, scnt, sdispl, r, rcnt, rdispl);
156  alltoalldebug(dmes, s, scnt, sdispl, r, rcnt, rdispl);
157 
158  // when finished with r, rcnt, rdispl, caller should del them.
159 #if all2allv_perf
160  if (nrnmpi_myid == 0) {
161  int nb = 4 * nrnmpi_numprocs + sdispl[nrnmpi_numprocs] + rdispl[nrnmpi_numprocs];
162  tm = nrnmpi_wtime() - tm;
163  printf("all2allv_int %s space=%d total=%llu time=%g\n", dmes, nb, nrn_mallinfo(0), tm);
164  }
165 #endif
166 }
167 
168 class TarList {
169  public:
170  TarList();
171  virtual ~TarList();
172  virtual void alloc();
173  int size;
174  int* list;
175  int rank;
176  int* indices; // indices of list for groups of phase2 targets.
177  // If indices is not null, then size is one less than
178  // the size of the indices list where indices[size] = the size of
179  // the list. Indices[0] is 0 and list[indices[i]] is the rank
180  // to send the ith group of phase2 targets.
181 };
182 
183 using Int2TarList = std::unordered_map<int, std::unique_ptr<TarList>>;
184 
186  size = 0;
187  list = 0;
188  rank = -1;
189  indices = 0;
190 }
192  del(list);
193  del(indices);
194 }
195 
197  if (size) {
198  list = new int[size];
199  }
200 }
201 
202 #include <nrnisaac.h>
203 static void* ranstate;
204 
205 static void random_init(int i) {
206  if (!ranstate) {
208  }
210 }
211 
212 static unsigned int get_random() {
214 }
215 
216 static int iran(int i1, int i2) {
217  // discrete uniform random integer from i2 to i2 inclusive. Must
218  // work if i1 == i2
219  if (i1 == i2) {
220  return i1;
221  }
222  int i3 = i1 + get_random() % (i2 - i1 + 1);
223  return i3;
224 }
225 
226 static void phase2organize(TarList* tl) {
227  // copied and modified from old specify_phase2_distribution of bgpdma.cpp
228  int n, nt;
229  nt = tl->size;
230  n = int(sqrt(double(nt)));
231  // change to about 20
232  if (n > 1) { // do not bother if not many connections
233  // equal as possible group sizes
234  tl->indices = new int[n + 1];
235  tl->indices[n] = tl->size;
236  tl->size = n;
237  for (int i = 0; i < n; ++i) {
238  tl->indices[i] = (i * nt) / n;
239  }
240  // Note: not sure the following is true anymore but it could be.
241  // This distribution is very biased (if 0 is a phase1 target
242  // it is always a phase2 sender. So now choose a random
243  // target in the subset and make that the phase2 sender
244  // (need to switch the indices[i] target and the one chosen)
245  for (int i = 0; i < n; ++i) {
246  int i1 = tl->indices[i];
247  int i2 = tl->indices[i + 1] - 1;
248  // need discrete uniform random integer from i1 to i2
249  int i3 = iran(i1, i2);
250  int itar = tl->list[i1];
251  tl->list[i1] = tl->list[i3];
252  tl->list[i3] = itar;
253  }
254  }
255 }
256 
257 /*
258 Setting up target lists uses a lot of temporary memory. It is conceiveable
259 that this can be done prior to creating any cells or connections. I.e.
260 gid2out is presently known from pc.set_gid2node(gid,...). Gid2in is presenly
261 known from NetCon = pc.gid_connect(gid, target) and it is quite a style
262 and hoc network programming change to use something like pc.need_gid(gid)
263 before cells with their synapses are created since one would have to imagine
264 that the hoc network setup code would have to be executed in a virtual
265 or 'abstract' fashion without actually creating, cells, targets, or NetCons.
266 Anyway, to potentially support this in the future, we write setup_target_lists
267 to not use any PreSyn information.
268 */
269 
270 static int setup_target_lists(int**);
271 static void fill_dma_send_lists(int, int*);
272 
273 static void setup_presyn_dma_lists() {
274  // Create and attach BGP_DMASend instances to output Presyn
275  for (const auto& iter: gid2out_) {
276  PreSyn* ps = iter.second;
277  // only ones that generate spikes. eg. multisplit
278  // registers a gid and even associates with a cell piece, but
279  // that piece may not send spikes.
280  if (ps->output_index_ >= 0) {
282  ps->bgp.dma_send_ = new BGP_DMASend();
283  }
284  }
285 
286  // Need to use the bgp union slot for dma_send_phase2_.
287  // Only will be non-NULL if the input is a phase 2 sender.
288  for (const auto& iter: gid2in_) {
289  PreSyn* ps = iter.second;
290  ps->bgp.srchost_ = 0;
291  }
292 
293  int* r;
294  int sz = setup_target_lists(&r);
295  fill_dma_send_lists(sz, r);
296  del(r);
297 
298  // phase1debug();
299  // phase2debug();
300 }
301 
302 static void fill_dma_send_lists(int sz, int* r) {
303  // sequence of gid, size, [totalsize], list
304  // Note that totalsize is there only for output gid's and use_phase2_.
305  // Using this sequence, copy lists to proper phase
306  // 1 and phase 2 lists. (Phase one lists found in gid2out_ and phase
307  // two lists found in gid2in_.
308  for (int i = 0; i < sz;) {
309  int gid = r[i++];
310  int size = r[i++];
311  PreSyn* ps{nullptr};
312  if (use_phase2_) { // look in gid2in first
313  auto iter = gid2in_.find(gid);
314  if (iter != gid2in_.end()) {
315  ps = iter->second;
317  ps->bgp.dma_send_phase2_ = bsp;
318  bsp->ntarget_hosts_phase2_ = size;
319  int* p = newintval(0, size);
320  bsp->target_hosts_phase2_ = p;
321  // printf("%d %d phase2 size=%d\n", nrnmpi_myid, gid, bsp->ntarget_hosts_phase2_);
322  for (int j = 0; j < size; ++j) {
323  p[j] = r[i++];
324  assert(p[j] != nrnmpi_myid);
325  }
326  }
327  }
328  if (!ps) { // phase 1 target list (or whole list if use_phase2 is 0)
329  auto iter = gid2out_.find(gid);
330  nrn_assert(iter != gid2out_.end());
331  ps = iter->second;
332  BGP_DMASend* bs = ps->bgp.dma_send_;
333  bs->ntarget_hosts_phase1_ = size;
334  if (use_phase2_ == 0) {
335  bs->ntarget_hosts_ = size;
336  } else {
337  bs->ntarget_hosts_ = r[i++];
338  }
339  int* p = newintval(0, size);
340  bs->target_hosts_ = p;
341  // printf("%d %d phase1 size=%d\n", nrnmpi_myid, gid, bs->ntarget_hosts_);
342  for (int j = 0; j < size; ++j) {
343  p[j] = r[i++];
344  // There never was a possibility of send2self
345  // because an output presyn is never in gid2in_.
346  assert(p[j] != nrnmpi_myid);
347  }
348  }
349  }
350  // compute max_ntarget_host and max_multisend_targets
351  max_ntarget_host = 0;
353  for (const auto& iter: gid2out_) {
354  PreSyn* ps = iter.second;
355  if (ps->output_index_ >= 0) { // only ones that generate spikes
356  BGP_DMASend* bs = ps->bgp.dma_send_;
357  if (max_ntarget_host < bs->ntarget_hosts_) {
359  }
360  if (max_multisend_targets < bs->NTARGET_HOSTS_PHASE1) {
361  max_multisend_targets = bs->NTARGET_HOSTS_PHASE1;
362  }
363  }
364  }
365  if (use_phase2_)
366  for (const auto& iter: gid2in_) {
367  PreSyn* ps = iter.second;
368  BGP_DMASend_Phase2* bsp = ps->bgp.dma_send_phase2_;
369  if (bsp && max_multisend_targets < bsp->ntarget_hosts_phase2_) {
371  }
372  }
373 }
374 
375 // return is vector and its size. The vector encodes a sequence of
376 // gid, target list size, and target list
377 static int setup_target_lists(int** r_return) {
378  int *s, *r, *scnt, *rcnt, *sdispl, *rdispl;
379  int nhost = nrnmpi_numprocs;
380 
381  celldebug("output gid", gid2out_);
382  celldebug("input gid", gid2in_);
383 
384  // What are the target ranks for a given input gid. All the ranks
385  // with the same input gid send that gid to the intermediate
386  // gid%nhost rank. The intermediate rank can then construct the
387  // list of target ranks for the gids it gets.
388 
389  // scnt is number of input gids from target
390  scnt = newintval(0, nhost);
391  for (const auto& iter: gid2in_) {
392  int gid = iter.first;
393  ++scnt[gid % nhost];
394  }
395 
396  // s are the input gids from target to be sent to the various intermediates
397  sdispl = newoffset(scnt, nhost);
398  s = newintval(0, sdispl[nhost]);
399  for (const auto& iter: gid2in_) {
400  int gid = iter.first;
401  s[sdispl[gid % nhost]++] = gid;
402  }
403  // Restore sdispl for the message.
404  del(sdispl);
405  sdispl = newoffset(scnt, nhost);
406 
407  all2allv_int(s, scnt, sdispl, r, rcnt, rdispl, "gidin to intermediate");
408  del(s);
409  del(scnt);
410  del(sdispl);
411  // r is the gids received by this intermediate rank from all other ranks.
412 
413  // Construct hash table for finding the target rank list for a given gid.
414  Int2TarList gid2tarlist;
415  // Now figure out the size of the target list for each distinct gid in r.
416  for (int i = 0; i < rdispl[nhost]; ++i) {
417  const int gid = r[i];
418  auto& tl = gid2tarlist[gid]; // default-construct a new std::unique_ptr<TarList> if needed
419  if (!tl) {
420  tl.reset(new TarList()); // constructor initialises `size` to zero
421  }
422  ++(tl->size);
423  }
424 
425  // Conceptually, now the intermediate is the mpi source and the gid
426  // sources are the mpi destination in regard to target lists.
427  // It would be possible at this point, but confusing,
428  // to allocate a s[rdispl[nhost]] and figure out scnt and sdispl by
429  // by getting the counts and gids from the ranks that own the source
430  // gids. In this way we could organize s without having to allocate
431  // individual target lists on the intermediate and then allocate
432  // another large s buffer to receive a copy of them. However for
433  // this processing we already require two large buffers for input
434  // gid's so there is no real savings of space.
435  // So let's do the simple obvious sequence and now complete the
436  // target lists.
437 
438  // Allocate the target lists (and set size to 0 (we will recount when filling).
439  for (auto& iter: gid2tarlist) {
440  TarList* tl = iter.second.get();
441  tl->alloc();
442  tl->size = 0;
443  }
444 
445  // fill the target lists
446  for (int rank = 0; rank < nhost; ++rank) {
447  int b = rdispl[rank];
448  int e = rdispl[rank + 1];
449  for (int i = b; i < e; ++i) {
450  const auto iter = gid2tarlist.find(r[i]);
451  if (iter != gid2tarlist.end()) {
452  TarList* tl = iter->second.get();
453  tl->list[tl->size] = rank;
454  tl->size++;
455  }
456  }
457  }
458  del(r);
459  del(rcnt);
460  del(rdispl);
461 
462  // Now the intermediate hosts have complete target lists and
463  // the sources know the intermediate host from the gid2out_ map.
464  // We could potentially organize here for two-phase exchange as well.
465 
466  // Which target lists are desired by the source rank?
467 
468  // Ironically, for round robin distributions, the target lists are
469  // already on the proper source rank so the following code should
470  // be tested for random distributions of gids.
471  // How many on the source rank?
472  scnt = newintval(0, nhost);
473  for (const auto& iter: gid2out_) {
474  PreSyn* ps = iter.second;
475  int gid = iter.first;
476  if (ps->output_index_ >= 0) { // only ones that generate spikes
477  ++scnt[gid % nhost];
478  }
479  }
480  sdispl = newoffset(scnt, nhost);
481 
482  // what are the gids of those target lists
483  s = newintval(0, sdispl[nhost]);
484  for (const auto& iter: gid2out_) {
485  PreSyn* ps = iter.second;
486  int gid = iter.first;
487  if (ps->output_index_ >= 0) { // only ones that generate spikes
488  s[sdispl[gid % nhost]++] = gid;
489  }
490  }
491  // Restore sdispl for the message.
492  del(sdispl);
493  sdispl = newoffset(scnt, nhost);
494  all2allv_int(s, scnt, sdispl, r, rcnt, rdispl, "gidout");
495 
496  // fill in the tl->rank for phase 1 target lists
497  // r is an array of source spiking gids
498  // tl is list associating input gids with list of target ranks.
499  for (int rank = 0; rank < nhost; ++rank) {
500  int b = rdispl[rank];
501  int e = rdispl[rank + 1];
502  for (int i = b; i < e; ++i) {
503  // note that there may be input gids with no corresponding
504  // output gid so that the find may not return true and in
505  // that case the tl->rank remains -1.
506  // For example multisplit gids or simulation of a subset of
507  // cells.
508  const auto iter = gid2tarlist.find(r[i]);
509  if (iter != gid2tarlist.end()) {
510  TarList* tl = iter->second.get();
511  tl->rank = rank;
512  }
513  }
514  }
515  del(s);
516  del(scnt);
517  del(sdispl);
518  del(r);
519  del(rcnt);
520  del(rdispl);
521 
522  if (use_phase2_) {
524  for (const auto& iter: gid2tarlist) {
525  TarList* tl = iter.second.get();
526  if (tl->rank >= 0) { // only if output gid is spike generating
527  phase2organize(tl);
528  }
529  }
530  }
531 
532  // For clarity, use the all2allv_int style of information flow
533  // from source to destination as above (instead of the obsolete
534  // section which was difficult to understand (It was last present at
535  // 672:544c61a730ec))
536  // and also use a uniform code
537  // for copying one and two phase information from a TarList to
538  // develop the s, scnt, and sdispl buffers. That is, a buffer list
539  // section in s for either a one-phase list or the much shorter
540  // (individually) lists for first and second phases, has a
541  // gid, size, totalsize header for each list where totalsize
542  // is only present if the gid is an output gid (for
543  // BGP_DMASend.ntarget_host used for conservation).
544  // Note that totalsize is tl->indices[tl->size]
545 
546  // how much to send to each rank
547  scnt = newintval(0, nhost);
548  for (const auto& iter: gid2tarlist) {
549  TarList* tl = iter.second.get();
550  if (tl->rank < 0) {
551  // When the output gid does not generate spikes, that rank
552  // is not interested if there is a target list for it.
553  // If the output gid dies not exist, there is no rank.
554  // In either case ignore this target list.
555  continue;
556  }
557  if (tl->indices) {
558  // indices[size] is the size of list but size of those
559  // are the sublist phase 2 destination ranks which
560  // don't get sent as part of the phase 2 target list.
561  // Also there is a phase 1 target list of size so there
562  // are altogether size+1 target lists.
563  // (one phase 1 list and size phase 2 lists)
564  scnt[tl->rank] += tl->size + 2; // gid, size, list
565  for (int i = 0; i < tl->size; ++i) {
566  scnt[tl->list[tl->indices[i]]] += tl->indices[i + 1] - tl->indices[i] + 1;
567  // gid, size, list
568  }
569  } else {
570  // gid, list size, list
571  scnt[tl->rank] += tl->size + 2;
572  }
573  if (use_phase2_) {
574  // The phase 1 header has as its third element, the
575  // total list size (needed for conservation);
576  scnt[tl->rank] += 1;
577  }
578  }
579  sdispl = newoffset(scnt, nhost);
580  s = newintval(0, sdispl[nhost]);
581  // what to send to each rank
582  for (const auto& iter: gid2tarlist) {
583  int gid = iter.first;
584  TarList* tl = iter.second.get();
585  if (tl->rank < 0) {
586  continue;
587  }
588  if (tl->indices) {
589  s[sdispl[tl->rank]++] = gid;
590  s[sdispl[tl->rank]++] = tl->size;
591  if (use_phase2_) {
592  s[sdispl[tl->rank]++] = tl->indices[tl->size];
593  }
594  for (int i = 0; i < tl->size; ++i) {
595  s[sdispl[tl->rank]++] = tl->list[tl->indices[i]];
596  }
597  for (int i = 0; i < tl->size; ++i) {
598  int rank = tl->list[tl->indices[i]];
599  s[sdispl[rank]++] = gid;
600  assert(tl->indices[i + 1] > tl->indices[i]);
601  s[sdispl[rank]++] = tl->indices[i + 1] - tl->indices[i] - 1;
602  for (int j = tl->indices[i] + 1; j < tl->indices[i + 1]; ++j) {
603  s[sdispl[rank]++] = tl->list[j];
604  }
605  }
606  } else {
607  // gid, list size, list
608  s[sdispl[tl->rank]++] = gid;
609  s[sdispl[tl->rank]++] = tl->size;
610  if (use_phase2_) {
611  s[sdispl[tl->rank]++] = tl->size;
612  }
613  for (int i = 0; i < tl->size; ++i) {
614  s[sdispl[tl->rank]++] = tl->list[i];
615  }
616  }
617  }
618  del(sdispl);
619  sdispl = newoffset(scnt, nhost);
620  all2allv_int(s, scnt, sdispl, r, rcnt, rdispl, "lists");
621  del(s);
622  del(scnt);
623  del(sdispl);
624 
625  del(rcnt);
626  int sz = rdispl[nhost];
627  del(rdispl);
628  *r_return = r;
629  return sz;
630 }
static void nrnmpi_int_alltoallv(int *s, int *scnt, int *sdispl, int *r, int *rcnt, int *rdispl)
static int max_multisend_targets
Definition: bgpdma.cpp:352
void bgpdma_cleanup_presyn(PreSyn *ps)
Definition: bgpdma.cpp:646
#define NTARGET_HOSTS_PHASE1
Definition: bgpdma.cpp:155
static int use_phase2_
Definition: bgpdma.cpp:154
static int max_ntarget_host
Definition: bgpdma.cpp:348
static void random_init(int i)
static int setup_target_lists(int **)
static unsigned int get_random()
static void del(int *a)
Definition: bgpdmasetup.cpp:99
static void all2allv_int(int *s, int *scnt, int *sdispl, int *&r, int *&rcnt, int *&rdispl, const char *dmes)
static int iran(int i1, int i2)
void alltoalldebug(const char *p, int *s, int *scnt, int *sdispl, int *r, int *rcnt, int *rdispl)
Definition: bgpdmasetup.cpp:56
static int * newoffset(int *acnt, int size)
static int * newintval(int val, int size)
void celldebug(const char *p, Gid2PreSyn &map)
Definition: bgpdmasetup.cpp:55
static void phase2organize(TarList *tl)
static void all2allv_helper(int *scnt, int *sdispl, int *&rcnt, int *&rdispl)
std::unordered_map< int, std::unique_ptr< TarList > > Int2TarList
static void setup_presyn_dma_lists()
static void fill_dma_send_lists(int, int *)
static void * ranstate
int * target_hosts_phase2_
Definition: bgpdma.cpp:176
int ntarget_hosts_phase2_
Definition: bgpdma.cpp:175
int ntarget_hosts_
Definition: bgpdma.cpp:162
int ntarget_hosts_phase1_
Definition: bgpdma.cpp:165
int * target_hosts_
Definition: bgpdma.cpp:163
Definition: netcon.h:255
int output_index_
Definition: netcon.h:306
int gid_
Definition: netcon.h:307
virtual ~TarList()
int * indices
int * list
virtual void alloc()
sprintf(buf, " if (secondorder) {\n" " int _i;\n" " for (_i = 0; _i < %d; ++_i) {\n" " _p[_slist%d[_i]] += dt*_p[_dlist%d[_i]];\n" " }}\n", numeqn, listnum, listnum)
#define c
size_t nrn_mallinfo(int item)
Definition: symbol.cpp:407
#define assert(ex)
Definition: hocassrt.h:32
#define i
Definition: md1redef.h:12
static double map(void *v)
Definition: mlinedit.cpp:47
sqrt
Definition: extdef.h:3
static double nrnmpi_wtime()
Definition: multisplit.cpp:55
#define printf
Definition: mwprefix.h:26
#define fprintf
Definition: mwprefix.h:30
static Gid2PreSyn gid2out_
Definition: netpar.cpp:33
static Gid2PreSyn gid2in_
Definition: netpar.cpp:34
std::unordered_map< int, PreSyn * > Gid2PreSyn
Definition: netpar.cpp:18
#define nrn_assert(ex)
Definition: nrnassrt.h:53
int const size_t const size_t n
Definition: nrngsl.h:11
size_t p
size_t j
uint32_t nrnisaac_uint32_pick(void *v)
Definition: nrnisaac.cpp:34
void * nrnisaac_new(void)
Definition: nrnisaac.cpp:12
void nrnisaac_init(void *v, unsigned long int seed)
Definition: nrnisaac.cpp:23
int nrnmpi_myid
int nrnmpi_numprocs
HOC interpreter function declarations (included by hocdec.h)
static double nhost(void *v)
Definition: ocbbs.cpp:232
#define e
Definition: passive0.cpp:22
FILE * fopen()
static const char * fname(const char *name)
Definition: nrnbbs.cpp:113