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