NEURON
ocbbs.cpp
Go to the documentation of this file.
1 #include <list>
2 #include <InterViews/resource.h>
3 
4 #include "classreg.h"
5 #include "code.h"
6 #include "ivocvect.h"
7 #include "hoclist.h"
8 #include "bbs.h"
9 #include "bbsimpl.h"
10 #include "section.h"
11 #include "membfunc.h"
12 #include "multicore.h"
13 #include "nrnpy.h"
14 #include "utils/profile/profiler_interface.h"
16 #include <nrnmpi.h>
17 #include <cerrno>
18 
19 #undef MD
20 #define MD 2147483647.
21 
22 extern int vector_arg_px(int, double**);
24 extern double t;
26 extern int nrnmpi_spike_compress(int nspike, bool gid_compress, int xchng_meth);
27 extern int nrnmpi_splitcell_connect(int that_host);
28 extern int nrnmpi_multisplit(Section*, double x, int sid, int backbonestyle);
29 extern int nrn_set_timeout(int timeout);
30 extern void nrnmpi_gid_clear(int);
32 extern double nrn_multisend_receive_time(int);
33 extern void nrn_prcellstate(int gid, const char* suffix);
35 #if NRNMPI
36 double nrnmpi_transfer_wait_;
38 #endif
39 #if NRNMPI
40 #include "nrnmpidec.h"
41 #else
42 static void nrnmpi_int_broadcast(int*, int, int) {}
43 static void nrnmpi_char_broadcast(char*, int, int) {}
44 static void nrnmpi_dbl_broadcast(double*, int, int) {}
45 #endif
46 extern double* nrn_mech_wtime_;
47 
49 
50 extern size_t nrncore_write();
51 extern size_t nrnbbcore_register_mapping();
52 extern int nrncore_run(const char*);
53 extern int nrncore_is_enabled();
54 extern int nrncore_is_file_mode();
55 extern int nrncore_psolve(double tstop, int file_mode);
56 
57 class OcBBS final: public BBS, public Resource {
58  public:
59  OcBBS(int nhost_request);
60 
61  public:
62  double retval_ = 0.;
63  int userid_ = 0;
64  int next_local_ = 0;
65 };
66 
68  : BBS(n) {}
69 
70 static bool posting_ = false;
71 static void pack_help(int, OcBBS*);
72 static void unpack_help(int, OcBBS*);
73 static int submit_help(OcBBS*);
74 static char* key_help();
75 
76 void bbs_done() {
77 #if USEBBS
78  Symbol* sym = hoc_lookup("ParallelContext");
79  sym = hoc_which_template(sym);
80  hoc_Item *q, *ql;
81  ql = sym->u.ctemplate->olist;
82  q = ql->next;
83  if (q != ql) {
84  Object* ob = OBJ(q);
85  OcBBS* bbs = (OcBBS*) ob->u.this_pointer;
86  if (bbs->is_master()) {
87  bbs->done();
88  }
89  }
90 #endif
91 }
92 
93 static int submit_help(OcBBS* bbs) {
94  int id, i, firstarg, style;
95  posting_ = true;
96  bbs->pkbegin();
97  i = 1;
98  if (hoc_is_double_arg(i)) {
99  bbs->pkint((id = (int) chkarg(i++, 0, MD)));
100  } else {
101  bbs->pkint((id = --bbs->next_local_));
102  }
103  bbs->pkint(0); // space for working_id
104  if (ifarg(i + 1)) {
105 #if 1
106  int argtypes = 0;
107  int ii = 1;
108  if (hoc_is_str_arg(i)) {
109  style = 1;
110  bbs->pkint(style); // "fname", arg1, ... style
111  bbs->pkstr(gargstr(i++));
112  } else {
113  Object* ob = *hoc_objgetarg(i++);
114  std::vector<char> pname{};
117  }
118  if (!pname.empty()) {
119  style = 3;
120  bbs->pkint(style); // pyfun, arg1, ... style
121  bbs->pkpickle(pname);
122  } else {
123  style = 2;
124  bbs->pkint(style); // [object],"fname", arg1, ... style
125  bbs->pkstr(ob->ctemplate->sym->name);
126  bbs->pkint(ob->index);
127  // printf("ob=%s\n", hoc_object_name(ob));
128  bbs->pkstr(gargstr(i++));
129  }
130  }
131  firstarg = i;
132  for (; ifarg(i); ++i) { // first is least significant
133  if (hoc_is_double_arg(i)) {
134  argtypes += 1 * ii;
135  } else if (hoc_is_str_arg(i)) {
136  argtypes += 2 * ii;
137  } else if (is_vector_arg(i)) { // hoc Vector
138  argtypes += 3 * ii;
139  } else { // must be a PythonObject
140  argtypes += 4 * ii;
141  }
142  ii *= 5;
143  }
144  // printf("submit style %d %s argtypes=%o\n", style, gargstr(firstarg-1), argtypes);
145  bbs->pkint(argtypes);
146  pack_help(firstarg, bbs);
147 #endif
148  } else {
149  if (hoc_is_str_arg(i)) {
150  bbs->pkint(0); // hoc statement style
151  bbs->pkstr(gargstr(i));
152  } else if (neuron::python::methods.po2pickle) {
154  bbs->pkint(3); // pyfun with no arg style
155  bbs->pkpickle(pname);
156  bbs->pkint(0); // argtypes
157  }
158  }
159  posting_ = false;
160  return id;
161 }
162 
163 static double submit(void* v) {
164  int id;
165  OcBBS* bbs = (OcBBS*) v;
166  id = submit_help(bbs);
167  bbs->submit(id);
168  return double(id);
169 }
170 
171 static double context(void* v) {
172  OcBBS* bbs = (OcBBS*) v;
173  submit_help(bbs);
174  // printf("%d context %s %s\n", bbs->myid(), hoc_object_name(*hoc_objgetarg(1)), gargstr(2));
175  bbs->context();
176  return 1.;
177 }
178 
179 static double working(void* v) {
180  OcBBS* bbs = (OcBBS*) v;
181  int id;
182  bool b = bbs->working(id, bbs->retval_, bbs->userid_);
184  if (b) {
185  return double(id);
186  } else {
187  return 0.;
188  }
189 }
190 
191 static double retval(void* v) {
192  OcBBS* bbs = (OcBBS*) v;
193  return bbs->retval_;
194 }
195 
196 static double userid(void* v) {
197  OcBBS* bbs = (OcBBS*) v;
198  return (double) bbs->userid_;
199 }
200 
201 static double nhost(void* v) {
203  return nrnmpi_numprocs;
204 }
205 
206 static double nrn_rank(void* v) {
208  return nrnmpi_myid;
209 }
210 
211 static double nhost_world(void* v) {
213  return nrnmpi_numprocs_world;
214 }
215 
216 static double rank_world(void* v) {
218  return nrnmpi_myid_world;
219 }
220 
221 static double nhost_bbs(void* v) {
223  return nrnmpi_numprocs_bbs;
224 }
225 
226 static double rank_bbs(void* v) {
228  return nrnmpi_myid_bbs;
229 }
230 
231 static double subworlds(void* v) {
232  int n = int(chkarg(1, 1, nrnmpi_numprocs_world));
233 #if NRNMPI
234  nrnmpi_subworld_size(n);
235 #endif
236  return 0.;
237 }
238 
239 static double worker(void* v) {
240  OcBBS* bbs = (OcBBS*) v;
241  bbs->worker();
242  return 0.;
243 }
244 
245 static double master_works(void* v) {
246  OcBBS* bbs = (OcBBS*) v;
247  bbs->master_works(int(chkarg(1, 0, 1)));
248  return 0.;
249 }
250 
251 static double done(void* v) {
252  OcBBS* bbs = (OcBBS*) v;
253  bbs->done();
254  return 0.;
255 }
256 
257 static void pack_help(int i, OcBBS* bbs) {
258  if (!posting_) {
259  bbs->pkbegin();
260  posting_ = true;
261  }
262  for (; ifarg(i); ++i) {
263  if (hoc_is_double_arg(i)) {
264  bbs->pkdouble(*getarg(i));
265  } else if (hoc_is_str_arg(i)) {
266  bbs->pkstr(gargstr(i));
267  } else if (is_vector_arg(i)) {
268  int n;
269  double* px;
270  n = vector_arg_px(i, &px);
271  bbs->pkint(n);
272  bbs->pkvec(n, px);
273  } else { // must be a PythonObject
275  bbs->pkpickle(s);
276  }
277  }
278 }
279 
280 static double pack(void* v) {
281  OcBBS* bbs = (OcBBS*) v;
282  pack_help(1, bbs);
283  return 0.;
284 }
285 
286 static double post(void* v) {
287  OcBBS* bbs = (OcBBS*) v;
288  pack_help(2, bbs);
289  posting_ = false;
290  if (hoc_is_str_arg(1)) {
291  bbs->post(gargstr(1));
292  } else {
293  char key[50];
294  Sprintf(key, "%g", *getarg(1));
295  bbs->post(key);
296  }
297  return 1.;
298 }
299 
300 static void unpack_help(int i, OcBBS* bbs) {
301  for (; ifarg(i); ++i) {
302  if (hoc_is_pdouble_arg(i)) {
303  *hoc_pgetarg(i) = bbs->upkdouble();
304  } else if (hoc_is_str_arg(i)) {
305  char* s = bbs->upkstr();
306  char** ps = hoc_pgargstr(i);
307  hoc_assign_str(ps, s);
308  delete[] s;
309  } else if (is_vector_arg(i)) {
310  Vect* vec = vector_arg(i);
311  int n = bbs->upkint();
312  vec->resize(n);
313  bbs->upkvec(n, vec->data());
314  } else {
315  hoc_execerror("pc.unpack can only unpack str, scalar, or Vector.",
316  "use pc.upkpyobj to unpack a Python Object");
317  }
318  }
319 }
320 
321 static double unpack(void* v) {
322  OcBBS* bbs = (OcBBS*) v;
323  unpack_help(1, bbs);
324  return 1.;
325 }
326 
327 static double upkscalar(void* v) {
328  OcBBS* bbs = (OcBBS*) v;
329  return bbs->upkdouble();
330 }
331 
332 static const char** upkstr(void* v) {
333  OcBBS* bbs = (OcBBS*) v;
334  char* s = bbs->upkstr();
335  char** ps = hoc_pgargstr(1);
336  hoc_assign_str(ps, s);
337  delete[] s;
338  return (const char**) ps;
339 }
340 
341 static Object** upkvec(void* v) {
342  OcBBS* bbs = (OcBBS*) v;
343  Vect* vec;
344  int n = bbs->upkint();
345  if (ifarg(1)) {
346  vec = vector_arg(1);
347  vec->resize(n);
348  } else {
349  vec = new Vect(n);
350  }
351  bbs->upkvec(n, vec->data());
352  return vec->temp_objvar();
353 }
354 
355 static Object** upkpyobj(void* v) {
356  OcBBS* bbs = (OcBBS*) v;
357  std::vector<char> s = bbs->upkpickle();
360  return hoc_temp_objptr(po);
361 }
362 
363 static Object** pyret(void* v) {
364  OcBBS* bbs = (OcBBS*) v;
365  return bbs->pyret();
366 }
370  impl_->pickle_ret_.clear();
371  return hoc_temp_objptr(po);
372 }
373 
374 static Object** py_alltoall_type(int type) {
375  assert(neuron::python::methods.mpi_alltoall_type);
376  // for py_gather, py_broadcast, and py_scatter,
377  // the second arg refers to the root rank of the operation (default 0)
378  int size = 0;
379  if (ifarg(2)) {
380  size = int(chkarg(2, -1, 2.14748e9));
381  }
383  return hoc_temp_objptr(po);
384 }
385 
386 static Object** py_alltoall(void*) {
387  return py_alltoall_type(1);
388 }
389 
390 static Object** py_allgather(void*) {
391  return py_alltoall_type(2);
392 }
393 
394 static Object** py_gather(void*) {
395  return py_alltoall_type(3);
396 }
397 
398 static Object** py_broadcast(void*) {
399  return py_alltoall_type(4);
400 }
401 
402 static Object** py_scatter(void*) {
403  return py_alltoall_type(5);
404 }
405 
406 static char* key_help() {
407  static char key[50];
408  if (hoc_is_str_arg(1)) {
409  return gargstr(1);
410  } else {
411  Sprintf(key, "%g", *getarg(1));
412  return key;
413  }
414 }
415 
416 static double take(void* v) {
417  OcBBS* bbs = (OcBBS*) v;
418  bbs->take(key_help());
419  unpack_help(2, bbs);
420  return 1.;
421 }
422 
423 static double look(void* v) {
424  OcBBS* bbs = (OcBBS*) v;
426  if (bbs->look(key_help())) {
427  unpack_help(2, bbs);
428  return 1.;
429  }
430  return 0.;
431 }
432 
433 static double look_take(void* v) {
434  OcBBS* bbs = (OcBBS*) v;
436  if (bbs->look_take(key_help())) {
437  unpack_help(2, bbs);
438  return 1.;
439  }
440  return 0.;
441 }
442 
443 static double pctime(void* v) {
444  return ((OcBBS*) v)->time();
445 }
446 
447 static double vtransfer_time(void* v) {
448  int mode = ifarg(1) ? int(chkarg(1, 0., 2.)) : 0;
449  if (mode == 2) {
450  return nrnmpi_rtcomp_time_;
451 #if NRNMPI
452  } else if (mode == 1) {
453  return nrnmpi_splitcell_wait_;
454  } else {
455  return nrnmpi_transfer_wait_;
456  }
457 #else
458  }
459  return 0;
460 #endif
461 }
462 
463 static double mech_time(void* v) {
464  if (ifarg(1)) {
465  if (nrn_mech_wtime_) {
466  int i = (int) chkarg(1, 0, n_memb_func - 1);
467  return nrn_mech_wtime_[i];
468  }
469  } else {
470  if (!nrn_mech_wtime_) {
471  nrn_mech_wtime_ = new double[n_memb_func];
472  }
473  for (int i = 0; i < n_memb_func; ++i) {
474  nrn_mech_wtime_[i] = 0.0;
475  }
476  }
477  return 0;
478 }
479 
480 static double prcellstate(void* v) {
481  nrn_prcellstate(int(*hoc_getarg(1)), hoc_gargstr(2));
482  return 0;
483 }
484 
485 static double wait_time(void* v) {
486  double w = ((OcBBS*) v)->wait_time();
487  return w;
488 }
489 
490 static double step_time(void* v) {
491  double w = ((OcBBS*) v)->integ_time();
492 #if NRNMPI
493  w -= nrnmpi_transfer_wait_ + nrnmpi_splitcell_wait_;
494 #endif
495  return w;
496 }
497 
498 static double step_wait(void* v) {
499  if (ifarg(1)) {
500  nrnmpi_step_wait_ = chkarg(1, -1.0, 0.0);
501  }
502  double w = nrnmpi_step_wait_;
503 #if NRNMPI
504  // sadly, no calculation of transfer and multisplit barrier times.
505 #endif
506  if (w < 0.) {
507  w = 0.0;
508  }
509  return w;
510 }
511 
512 static double send_time(void* v) {
513  int arg = ifarg(1) ? int(chkarg(1, 0, 20)) : 0;
514  if (arg) {
515  return nrn_multisend_receive_time(arg);
516  }
517  return ((OcBBS*) v)->send_time();
518 }
519 
520 static double event_time(void* v) {
521  return 0.;
522 }
523 
524 static double integ_time(void* v) {
525  return 0.;
526 }
527 
528 static double set_gid2node(void* v) {
529  OcBBS* bbs = (OcBBS*) v;
530  bbs->set_gid2node(int(chkarg(1, 0, MD)), int(chkarg(2, 0, MD)));
531  return 0.;
532 }
533 
534 static double gid_exists(void* v) {
535  OcBBS* bbs = (OcBBS*) v;
537  return int(bbs->gid_exists(int(chkarg(1, 0, MD))));
538 }
539 
540 static double cell(void* v) {
541  OcBBS* bbs = (OcBBS*) v;
542  bbs->cell();
543  return 0.;
544 }
545 
546 static double threshold(void* v) {
547  OcBBS* bbs = (OcBBS*) v;
548  return bbs->threshold();
549 }
550 
551 static double spcompress(void* v) {
552  int nspike = -1;
553  bool gid_compress = true;
554  int xchng_meth = 0;
555  if (ifarg(1)) {
556  nspike = (int) chkarg(1, -1, MD);
557  }
558  if (ifarg(2)) {
559  gid_compress = (chkarg(2, 0, 1) ? true : false);
560  }
561  if (ifarg(3)) {
562  xchng_meth = (int) chkarg(3, 0, 15);
563  }
564  return (double) nrnmpi_spike_compress(nspike, gid_compress, xchng_meth);
565 }
566 
567 static double splitcell_connect(void* v) {
568  int that_host = (int) chkarg(1, 0, nrnmpi_numprocs - 1);
569  // also needs a currently accessed section that is the root of this_tree
570  nrnmpi_splitcell_connect(that_host);
571  return 0.;
572 }
573 
574 static double multisplit(void* v) {
575  double x = -1.;
576  Section* sec = NULL;
577  int sid = -1;
578  int backbone_style = 2;
579  if (ifarg(1)) {
580  nrn_seg_or_x_arg(1, &sec, &x);
581  sid = (int) chkarg(2, 0, (double) (0x7fffffff));
582  }
583  if (ifarg(3)) {
584  backbone_style = (int) chkarg(3, 0, 2);
585  }
586  // also needs a currently accessed section
587  nrnmpi_multisplit(sec, x, sid, backbone_style);
588  return 0.;
589 }
590 
591 static double set_timeout(void* v) {
592  int arg = 0;
593  if (ifarg(1)) {
594  arg = int(chkarg(1, 0, 10000));
595  }
596  arg = nrn_set_timeout(arg);
597  return double(arg);
598 }
599 
600 static double set_mpiabort_on_error(void*) {
601  double ret = double(nrn_mpiabort_on_error_);
602  if (ifarg(1)) {
603  nrn_mpiabort_on_error_ = int(chkarg(1, 0, 1));
604  }
605  return ret;
606 }
607 
608 static double gid_clear(void* v) {
609  int arg = 0;
610  if (ifarg(1)) {
611  arg = int(chkarg(1, 0, 4));
612  }
613  nrnmpi_gid_clear(arg);
614  return 0.;
615 }
616 
617 static double outputcell(void* v) {
618  OcBBS* bbs = (OcBBS*) v;
619  int gid = int(chkarg(1, 0., MD));
620  bbs->outputcell(gid);
621  return 0.;
622 }
623 
624 static double spike_record(void* v) {
625  OcBBS* bbs = (OcBBS*) v;
626  IvocVect* spikevec = vector_arg(2);
627  IvocVect* gidvec = vector_arg(3);
628  if (hoc_is_object_arg(1) && is_vector_arg(1)) {
629  IvocVect* gids = vector_arg(1);
630  bbs->spike_record(gids, spikevec, gidvec);
631  } else {
632  int gid = int(chkarg(1, -1., MD));
633  bbs->spike_record(gid, spikevec, gidvec);
634  }
635  return 0.;
636 }
637 
638 static double psolve(void* v) {
640  OcBBS* bbs = (OcBBS*) v;
641  double tstop = chkarg(1, t, 1e9);
642  int enabled = nrncore_is_enabled();
643  int file_mode = nrncore_is_file_mode();
644  if (enabled == 1) {
645  nrncore_psolve(tstop, file_mode);
646  } else if (enabled == 0) {
647  // Classic case
648  bbs->netpar_solve(tstop);
649  }
651  return double(enabled);
652 }
653 
654 static double set_maxstep(void* v) {
655  OcBBS* bbs = (OcBBS*) v;
656  return bbs->netpar_mindelay(chkarg(1, 1e-6, 1e9));
657 }
658 
659 static double spike_stat(void* v) {
660  OcBBS* bbs = (OcBBS*) v;
661  int nsend, nsendmax, nrecv, nrecv_useful;
663  nsend = nsendmax = nrecv = nrecv_useful = 0;
664  bbs->netpar_spanning_statistics(&nsend, &nsendmax, &nrecv, &nrecv_useful);
665  if (ifarg(1)) {
666  *hoc_pgetarg(1) = nsend;
667  }
668  if (ifarg(2)) {
669  *hoc_pgetarg(2) = nrecv;
670  }
671  if (ifarg(3)) {
672  *hoc_pgetarg(3) = nrecv_useful;
673  }
674  return double(nsendmax);
675 }
676 
677 static double maxhist(void* v) {
678  OcBBS* bbs = (OcBBS*) v;
679  IvocVect* vec = ifarg(1) ? vector_arg(1) : nullptr;
680  if (vec) {
681  hoc_obj_ref(vec->obj_);
682  }
683  vec = bbs->netpar_max_histogram(vec);
684  if (vec) {
685  hoc_obj_unref(vec->obj_);
686  }
687  return 0.;
688 }
689 
690 static double source_var(void*) { // &source_variable, source_global_index
691  // At BEFORE BREAKPOINT, the value of variable is sent to the
692  // target machine(s). This can only be executed on the
693  // source machine (where source_variable exists).
695  return 0.;
696 }
697 
698 static double target_var(void*) { // &target_variable, source_global_index
699  // At BEFORE BREAKPOINT, the value of the target_variable is set
700  // to the value of the source variable associated
701  // with the source_global_index. This can only be executed on the
702  // target machine (where target_variable exists).
704  return 0.;
705 }
706 
707 static double setup_transfer(void*) { // after all source/target and before init and run
709  return 0.;
710 }
711 
712 static double barrier(void*) {
713  // return wait time
714  double t = 0.;
715 #if NRNMPI
716  if (nrnmpi_numprocs > 1) {
717  t = nrnmpi_wtime();
718  nrnmpi_barrier();
719  t = nrnmpi_wtime() - t;
720  }
721  errno = 0;
722 #endif
723  return t;
724 }
725 
726 static double allreduce(void*) {
727  // type 1,2,3 sum, max, min
728  if (hoc_is_object_arg(1)) {
729  Vect* vec = vector_arg(1);
730  int n = vec->size();
731  if (n == 0) {
732  return 0.0;
733  }
734 #if NRNMPI
735  if (nrnmpi_numprocs > 1) {
736  int type = (int) chkarg(2, 1, 3);
737  double* px = vector_vec(vec);
738  double* dest = new double[n];
739  nrnmpi_dbl_allreduce_vec(px, dest, n, type);
740  for (int i = 0; i < n; ++i) {
741  px[i] = dest[i];
742  }
743  delete[] dest;
744  }
745  errno = 0;
746 #endif
747  return 0.;
748  } else {
749  double val = *getarg(1);
750 #if NRNMPI
751  if (nrnmpi_numprocs > 1) {
752  int type = (int) chkarg(2, 1, 3);
753  val = nrnmpi_dbl_allreduce(val, type);
754  }
755  errno = 0;
756 #endif
757  return val;
758  }
759 }
760 
761 static double allgather(void*) {
762  double val = *getarg(1);
763  Vect* vec = vector_arg(2);
765  double* px = vector_vec(vec);
766 
767 #if NRNMPI
768  if (nrnmpi_numprocs > 1) {
769  nrnmpi_dbl_allgather(&val, px, 1);
770  errno = 0;
771  } else {
772  px[0] = val;
773  }
774 #else
775  px[0] = val;
776 #endif
777  return 0.;
778 }
779 
780 // This function takes 3 arguments:
781 // - vsrc (In)
782 // - vscnt (In)
783 // - vdest (Out)
784 static double alltoall(void*) {
785  int np = nrnmpi_numprocs;
786  const Vect* vsrc = vector_arg(1);
787  const Vect* vscnt = vector_arg(2);
788  Vect* vdest = vector_arg(3);
789  std::size_t ns = vsrc->size();
790  if (vscnt->size() != np) {
791  hoc_execerror("size of source counts vector is not nhost", nullptr);
792  }
793  const std::vector<int> scnt(vscnt->begin(), vscnt->end()); // cast from double to int
794  std::vector<int> sdispl(np + 1);
795  for (int i = 0; i < np; ++i) {
796  sdispl[i + 1] = sdispl[i] + scnt[i];
797  }
798  if (ns != sdispl[np]) {
799  hoc_execerror("sum of source counts is not the size of the src vector", nullptr);
800  }
801  if (nrnmpi_numprocs > 1) {
802 #if NRNMPI
803  std::vector<int> rcnt(np);
804  std::vector<int> c(np, 1);
805  std::vector<int> rdispl(np + 1);
806  std::iota(rdispl.begin(), rdispl.end(), 0);
807 
809  scnt.data(), c.data(), rdispl.data(), rcnt.data(), c.data(), rdispl.data());
810  for (int i = 0; i < np; ++i) {
811  rdispl[i + 1] = rdispl[i] + rcnt[i];
812  }
813  vdest->resize(rdispl[np]);
815  vsrc->data(), scnt.data(), sdispl.data(), vdest->data(), rcnt.data(), rdispl.data());
816 #endif
817  } else {
818  vdest->resize(ns);
819  std::copy(vsrc->begin(), vsrc->end(), vdest->begin());
820  }
821  return 0.;
822 }
823 
824 static double broadcast(void*) {
825  int srcid = int(chkarg(2, 0, nrnmpi_numprocs - 1));
826  int cnt = 0;
827 #if NRNMPI
828  if (nrnmpi_numprocs > 1) {
829  if (hoc_is_str_arg(1)) {
830  char* s;
831  if (srcid == nrnmpi_myid) {
832  s = gargstr(1);
833  cnt = strlen(s) + 1;
834  }
835  nrnmpi_int_broadcast(&cnt, 1, srcid);
836  if (srcid != nrnmpi_myid) {
837  s = new char[cnt];
838  }
839  nrnmpi_char_broadcast(s, cnt, srcid);
840  if (srcid != nrnmpi_myid) {
842  delete[] s;
843  }
844  } else {
845  Vect* vec = vector_arg(1);
846  if (srcid == nrnmpi_myid) {
847  cnt = vec->size();
848  }
849  nrnmpi_int_broadcast(&cnt, 1, srcid);
850  if (srcid != nrnmpi_myid) {
851  vec->resize(cnt);
852  }
853  nrnmpi_dbl_broadcast(vector_vec(vec), cnt, srcid);
854  }
855  } else {
856 #else
857  {
858 #endif
859  if (hoc_is_str_arg(1)) {
860  cnt = strlen(gargstr(1));
861  } else {
862  cnt = vector_arg(1)->size();
863  }
864  }
865  return double(cnt);
866 }
867 
868 static double nthrd(void*) {
869  bool ip{true};
871  if (ifarg(1)) {
872  if (ifarg(2)) {
873  ip = bool(chkarg(2, 0, 1));
874  }
875  nrn_threads_create(int(chkarg(1, 1, 1e5)), ip);
876  }
877  return double(nrn_nthread);
878 }
879 
880 static double number_of_worker_threads(void*) {
882  return nof_worker_threads();
883 }
884 
885 static double partition(void*) {
886  Object* ob = 0;
887  int it;
888  if (ifarg(2)) {
889  ob = *hoc_objgetarg(2);
890  if (ob) {
891  check_obj_type(ob, "SectionList");
892  }
893  }
894  if (ifarg(1)) {
895  it = (int) chkarg(1, 0, nrn_nthread - 1);
896  nrn_thread_partition(it, ob);
897  } else {
898  for (it = 0; it < nrn_nthread; ++it) {
899  nrn_thread_partition(it, ob);
900  }
901  }
902  return 0.0;
903 }
904 
905 static Object** get_partition(void*) {
906  return nrn_get_thread_partition(int(chkarg(1, 0, nrn_nthread - 1)));
907  ;
908 }
909 
910 static double thread_stat(void*) {
911  // nrn_thread_stat was called here but didn't do anything
912  return 0.0;
913 }
914 
915 static double thread_busywait(void*) {
916  int old = nrn_allow_busywait(int(chkarg(1, 0, 1)));
917  return double(old);
918 }
919 
920 static double thread_how_many_proc(void*) {
922  int i = nrn_how_many_processors();
923  return double(i);
924 }
925 
926 static double optimize_node_order(void*) {
928  if (ifarg(1)) {
930  }
931  return double(neuron::interleave_permute_type);
932 }
933 
934 static double sec_in_thread(void*) {
936  Section* sec = chk_access();
937  return double(sec->pnode[0]->_nt->id);
938 }
939 
940 static double thread_ctime(void*) {
941  int i;
942 #if 1
943  if (ifarg(1)) {
944  i = int(chkarg(1, 0, nrn_nthread));
945  return nrn_threads[i]._ctime;
946  } else {
947  for (i = 0; i < nrn_nthread; ++i) {
948  nrn_threads[i]._ctime = 0.0;
949  }
950  }
951 #endif
952  return 0.0;
953 }
954 
955 static double nrn_thread_t(void*) {
956  int i;
957  i = int(chkarg(1, 0, nrn_nthread));
958  return nrn_threads[i]._t;
959 }
960 
961 static double thread_dt(void*) {
962  int i;
963  i = int(chkarg(1, 0, nrn_nthread));
964  return nrn_threads[i]._dt;
965 }
966 
967 static double nrncorewrite_argvec(void*) {
968  if (ifarg(2) && !(hoc_is_object_arg(2) && is_vector_arg(2))) {
969  hoc_execerror("nrnbbcore_write: optional second arg is not a Vector", nullptr);
970  }
971  return double(nrncore_write());
972 }
973 
974 static double print_memory_stats(void*) {
976 
977 #if NRNMPI
978  neuron::container::MemoryStats memory_stats;
979  nrnmpi_memory_stats(memory_stats, local_memory_usage);
980  nrnmpi_print_memory_stats(memory_stats);
981 #else
983 #endif
984 
985  return 1.0;
986 }
987 
988 static double nrncorewrite_argappend(void*) {
989  if (ifarg(2) && !hoc_is_double_arg(2)) {
991  "nrncore_write: optional second arg is not a number (True or False append flag)",
992  nullptr);
993  }
994  return double(nrncore_write());
995 }
996 
997 static double nrncorerun(void*) {
998  if (ifarg(2)) {
999  nrn_trajectory_request_per_time_step_ = chkarg(2, 0., 1.) != 0.0;
1000  }
1001  return double(nrncore_run(gargstr(1)));
1002 }
1003 
1004 static double nrnbbcore_register_mapping(void*) {
1005  return double(nrnbbcore_register_mapping());
1006 }
1007 
1008 static Object** gid2obj(void* v) {
1009  OcBBS* bbs = (OcBBS*) v;
1010  return bbs->gid2obj(int(chkarg(1, 0, MD)));
1011 }
1012 
1013 static Object** gid2cell(void* v) {
1014  OcBBS* bbs = (OcBBS*) v;
1015  return bbs->gid2cell(int(chkarg(1, 0, MD)));
1016 }
1017 
1018 static Object** gid_connect(void* v) {
1019  OcBBS* bbs = (OcBBS*) v;
1020  return bbs->gid_connect(int(chkarg(1, 0, MD)));
1021 }
1022 
1023 static Member_func members[] = {{"submit", submit},
1024  {"working", working},
1025  {"retval", retval},
1026  {"userid", userid},
1027  {"pack", pack},
1028  {"post", post},
1029  {"unpack", unpack},
1030  {"upkscalar", upkscalar},
1031  {"take", take},
1032  {"look", look},
1033  {"look_take", look_take},
1034  {"runworker", worker},
1035  {"master_works_on_jobs", master_works},
1036  {"done", done},
1037  {"id", nrn_rank},
1038  {"nhost", nhost},
1039  {"id_world", rank_world},
1040  {"nhost_world", nhost_world},
1041  {"id_bbs", rank_bbs},
1042  {"nhost_bbs", nhost_bbs},
1043  {"subworlds", subworlds},
1044  {"context", context},
1045 
1046  {"time", pctime},
1047  {"wait_time", wait_time},
1048  {"step_time", step_time},
1049  {"step_wait", step_wait},
1050  {"send_time", send_time},
1051  {"event_time", event_time},
1052  {"integ_time", integ_time},
1053  {"vtransfer_time", vtransfer_time},
1054  {"mech_time", mech_time},
1055  {"timeout", set_timeout},
1056  {"mpiabort_on_error", set_mpiabort_on_error},
1057 
1058  {"set_gid2node", set_gid2node},
1059  {"gid_exists", gid_exists},
1060  {"outputcell", outputcell},
1061  {"cell", cell},
1062  {"threshold", threshold},
1063  {"spike_record", spike_record},
1064  {"psolve", psolve},
1065  {"set_maxstep", set_maxstep},
1066  {"spike_statistics", spike_stat},
1067  {"max_histogram", maxhist},
1068  {"spike_compress", spcompress},
1069  {"gid_clear", gid_clear},
1070  {"prcellstate", prcellstate},
1071 
1072  {"source_var", source_var},
1073  {"target_var", target_var},
1074  {"setup_transfer", setup_transfer},
1075  {"splitcell_connect", splitcell_connect},
1076  {"multisplit", multisplit},
1077 
1078  {"barrier", barrier},
1079  {"allreduce", allreduce},
1080  {"allgather", allgather},
1081  {"alltoall", alltoall},
1082  {"broadcast", broadcast},
1083 
1084  {"nthread", nthrd},
1085  {"nworker", number_of_worker_threads},
1086  {"partition", partition},
1087  {"thread_stat", thread_stat},
1088  {"thread_busywait", thread_busywait},
1089  {"thread_how_many_proc", thread_how_many_proc},
1090  {"optimize_node_order", optimize_node_order},
1091  {"sec_in_thread", sec_in_thread},
1092  {"thread_ctime", thread_ctime},
1093  {"dt", thread_dt},
1094  {"t", nrn_thread_t},
1095 
1096  {"nrnbbcore_write", nrncorewrite_argvec},
1097  {"nrncore_write", nrncorewrite_argappend},
1098  {"nrnbbcore_register_mapping", nrnbbcore_register_mapping},
1099  {"nrncore_run", nrncorerun},
1100  {"print_memory_stats", print_memory_stats},
1101 
1102  {0, 0}};
1103 
1104 static Member_ret_str_func retstr_members[] = {{"upkstr", upkstr}, {0, 0}};
1105 
1107  {"gid2obj", gid2obj},
1108  {"gid2cell", gid2cell},
1109  {"gid_connect", gid_connect},
1110  {"get_partition", get_partition},
1111  {"upkpyobj", upkpyobj},
1112  {"pyret", pyret},
1113  {"py_alltoall", py_alltoall},
1114  {"py_allgather", py_allgather},
1115  {"py_gather", py_gather},
1116  {"py_broadcast", py_broadcast},
1117  {"py_scatter", py_scatter},
1118  {0, 0}};
1119 
1120 static void* cons(Object*) {
1121  // not clear at moment what is best way to handle nested context
1122  int i = -1;
1123  if (ifarg(1)) {
1124  i = int(chkarg(1, 0, 10000));
1125  }
1126  OcBBS* bbs = new OcBBS(i);
1127  bbs->ref();
1128  return bbs;
1129 }
1130 
1131 static void destruct(void* v) {
1132  OcBBS* bbs = (OcBBS*) v;
1133  bbs->unref();
1134 }
1135 
1137  class2oc("ParallelContext", cons, destruct, members, retobj_members, retstr_members);
1138 }
1139 
1140 // A BBS message is something to execute.
1141 // This helper execute depending of the style of the message.
1142 // style == 0:
1143 // This is a string that is a hoc statement, execute it with `hoc_obj_run`.
1144 // Return `nullptr`, set `size` argument to 0.
1145 // Not listen to `exec`.
1146 // No arguments.
1147 // style == 1:
1148 // This is a function name as a string followed by a list of arguments.
1149 // Return `nullptr` and set `size` to 0.
1150 // Dry run if `exec` is false.
1151 // style == 2:
1152 // From a template, find a object with an id and inside this object find a member
1153 // with a name as a string. Execute this member with arguments.
1154 // Return `nullptr` and set `size` to 0.
1155 // Dry run if `exec` is false.
1156 // style == 3:
1157 // A python pickle (https://docs.python.org/3/library/pickle.html) followed by arguments.
1158 // Return a string that is of size `size`.
1159 // Dry run if `exec` is false.
1160 std::vector<char> BBSImpl::execute_helper(int id, bool exec) {
1161  int subworld = (nrnmpi_numprocs > 1 && nrnmpi_numprocs_bbs < nrnmpi_numprocs_world);
1162  int style = upkint();
1163  if (subworld) {
1164  assert(nrnmpi_myid == 0);
1165  int info[2];
1166  info[0] = id;
1167  info[1] = style;
1168  nrnmpi_int_broadcast(info, 2, 0);
1169  }
1170  std::vector<char> rs{};
1171  switch (style) {
1172  case 0: {
1173  char* statement = upkstr();
1174  if (subworld) {
1175  int size = strlen(statement) + 1;
1176  nrnmpi_int_broadcast(&size, 1, 0);
1177  nrnmpi_char_broadcast(statement, size, 0);
1178  }
1179  hoc_obj_run(statement, nullptr);
1180  delete[] statement;
1181  } break;
1182  default: {
1183  std::vector<char> python_pickle{}; // Only for style == 3
1184  Symbol* fname = nullptr;
1185  Object* ob = nullptr;
1186  std::list<char*> sarg; // Store the strings pointer to delete[] them later
1187  // Use a list because, we push pointers of the object into
1188  // the hoc stack
1189  int narg = 0; // total number of args
1190  if (style == 2) { // object first
1191  char* template_name = upkstr();
1192  int object_index = upkint(); // object index
1193  Symbol* sym = hoc_lookup(template_name);
1194  if (sym) {
1195  sym = hoc_which_template(sym);
1196  }
1197  if (!sym) {
1198  hoc_execerror(template_name, "is not a template");
1199  }
1200  hoc_Item *q, *ql;
1201  ql = sym->u.ctemplate->olist;
1202  ITERATE(q, ql) {
1203  ob = OBJ(q);
1204  if (ob->index == object_index) {
1205  break;
1206  }
1207  ob = nullptr;
1208  }
1209  if (!ob) {
1210  fprintf(stderr,
1211  "%s[%d] is not an Object in this process\n",
1212  template_name,
1213  object_index);
1214  hoc_execerror("ParallelContext execution error", nullptr);
1215  }
1216  delete[] template_name;
1217  char* fname_str = upkstr();
1218  fname = hoc_table_lookup(fname_str, sym->u.ctemplate->symtable);
1219  if (!fname) {
1220  fprintf(stderr, "%s not a function in %s\n", fname_str, hoc_object_name(ob));
1221  hoc_execerror("ParallelContext execution error", nullptr);
1222  }
1223  delete[] fname_str;
1224  if (subworld) {
1225  hoc_execerror("with subworlds, this submit style not implemented", nullptr);
1226  }
1227  } else if (style == 3) { // Python callable
1228  python_pickle = upkpickle();
1229  if (subworld) {
1230  int size = static_cast<int>(python_pickle.size());
1231  nrnmpi_int_broadcast(&size, 1, 0);
1232  nrnmpi_char_broadcast(python_pickle.data(), size, 0);
1233  }
1234  } else {
1235  char* fname_str = upkstr();
1236  if (subworld) {
1237  int size = strlen(fname_str) + 1;
1238  nrnmpi_int_broadcast(&size, 1, 0);
1239  nrnmpi_char_broadcast(fname_str, size, 0);
1240  }
1241  fname = hoc_lookup(fname_str);
1242  if (!fname) {
1243  fprintf(stderr, "%s not a function in %s\n", fname_str, hoc_object_name(ob));
1244  hoc_execerror("ParallelContext execution error", nullptr);
1245  }
1246  delete[] fname_str;
1247  }
1248 
1249  int argtypes = upkint(); // first is least signif
1250  if (subworld) {
1251  // printf("%d exec argtypes = %d\n", nrnmpi_myid_world, argtypes);
1252  nrnmpi_int_broadcast(&argtypes, 1, 0);
1253  }
1254  for (int i = 0, j = argtypes; (i = j % 5) != 0; j /= 5) {
1255  ++narg;
1256  if (i == 1) {
1257  double x = upkdouble();
1258  if (subworld) {
1259  nrnmpi_dbl_broadcast(&x, 1, 0);
1260  }
1261  hoc_pushx(x);
1262  } else if (i == 2) {
1263  sarg.push_back(upkstr());
1264  if (subworld) {
1265  int size = strlen(sarg.back()) + 1;
1266  nrnmpi_int_broadcast(&size, 1, 0);
1267  nrnmpi_char_broadcast(sarg.back(), size, 0);
1268  }
1269  hoc_pushstr(&(sarg.back()));
1270  } else if (i == 3) {
1271  int n = upkint();
1272  if (subworld) {
1273  nrnmpi_int_broadcast(&n, 1, 0);
1274  }
1275  Vect* vec = new Vect(n);
1276  upkvec(n, vec->data());
1277  if (subworld) {
1278  nrnmpi_dbl_broadcast(vec->data(), n, 0);
1279  }
1280  hoc_pushobj(vec->temp_objvar());
1281  } else { // PythonObject
1282  auto s = upkpickle();
1283  int size = static_cast<int>(s.size());
1284  if (subworld) {
1285  nrnmpi_int_broadcast(&size, 1, 0);
1286  nrnmpi_char_broadcast(s.data(), size, 0);
1287  }
1291  }
1292  }
1293  if (style == 3) {
1295  if (exec) {
1296  rs = neuron::python::methods.call_picklef(python_pickle, narg);
1297  }
1298  hoc_ac_ = 0.;
1299  } else {
1300  if (exec) {
1301  hoc_ac_ = hoc_call_objfunc(fname, narg, ob);
1302  } else {
1303  hoc_ac_ = 0.;
1304  }
1305  }
1306  for (auto& arg: sarg) {
1307  delete[] arg;
1308  }
1309  } break;
1310  }
1311  return rs;
1312 }
1313 
1315  // execute the same thing that execute_worker is executing. This
1316  // is done for all the nrnmpi_myid_bbs == -1 workers associated with
1317  // the specific nrnmpi_myid == 0 with nrnmpi_myid_bbs >= 0.
1318  // All the nrnmpi/mpispike.cpp functions can be used since the
1319  // proper communicators for a subworld are used by those functions.
1320  // The broadcast functions are particularly useful and those are
1321  // how execute_worker passes messages into here.
1322 
1323  // printf("%d enter subworld_worker_execute\n", nrnmpi_myid_world);
1324  int info[2];
1325  // wait for something to do
1326  nrnmpi_int_broadcast(info, 2, 0);
1327  // info[0] = -1 means it was from a pc.context. Also -2 means
1328  // DONE.
1329  // printf("%d subworld_worker_execute info %d %d\n", nrnmpi_myid_world, info[0], info[1]);
1330  int id = info[0];
1331  if (id == -2) { // DONE, so quit.
1332  done();
1333  }
1334  hoc_ac_ = double(id);
1335  int style = info[1];
1336  if (style == 0) { // hoc statement form
1337  int size;
1338  nrnmpi_int_broadcast(&size, 1, 0); // includes terminator
1339  char* s = new char[size];
1340  nrnmpi_char_broadcast(s, size, 0);
1341  hoc_obj_run(s, nullptr);
1342  delete[] s;
1343  // printf("%d leave subworld_worker_execute\n", nrnmpi_myid_world);
1344  return;
1345  }
1346  int i, j;
1347  int npickle;
1348  std::vector<char> s{};
1349  Symbol* fname = 0;
1350  Object* ob = nullptr;
1351  char* sarg[20]; // up to 20 arguments may be strings
1352  int ns = 0; // number of args that are strings
1353  int narg = 0; // total number of args
1354 
1355  if (style == 3) { // python callable
1356  nrnmpi_int_broadcast(&npickle, 1, 0);
1357  s.resize(npickle);
1358  nrnmpi_char_broadcast(s.data(), npickle, 0);
1359  } else if (style == 1) { // hoc function
1360  int size;
1361  nrnmpi_int_broadcast(&size, 1, 0); // includes terminator
1362  // printf("%d subworld hoc function string size = %d\n", nrnmpi_myid_world, size);
1363  s.resize(size);
1364  nrnmpi_char_broadcast(s.data(), size, 0);
1365  fname = hoc_lookup(s.data());
1366  if (!fname) {
1367  return;
1368  } // error raised by sender
1369  } else {
1370  return; // no others implemented, error raised by sender
1371  }
1372 
1373  // now get the args
1374  int argtypes;
1375  nrnmpi_int_broadcast(&argtypes, 1, 0);
1376  // printf("%d subworld argtypes = %d\n", nrnmpi_myid_world, argtypes);
1377  for (j = argtypes; (i = j % 5) != 0; j /= 5) {
1378  ++narg;
1379  if (i == 1) { // double
1380  double x;
1381  nrnmpi_dbl_broadcast(&x, 1, 0);
1382  // printf("%d subworld scalar = %g\n", nrnmpi_myid_world, x);
1383  hoc_pushx(x);
1384  } else if (i == 2) { // string
1385  int size;
1386  nrnmpi_int_broadcast(&size, 1, 0);
1387  sarg[ns] = new char[size];
1388  nrnmpi_char_broadcast(sarg[ns], size, 0);
1389  hoc_pushstr(sarg + ns);
1390  ns++;
1391  } else if (i == 3) { // Vector
1392  int n;
1393  nrnmpi_int_broadcast(&n, 1, 0);
1394  Vect* vec = new Vect(n);
1395  nrnmpi_dbl_broadcast(vec->data(), n, 0);
1396  hoc_pushobj(vec->temp_objvar());
1397  } else { // PythonObject
1398  int n;
1399  nrnmpi_int_broadcast(&n, 1, 0);
1400  std::vector<char> s(n);
1401  nrnmpi_char_broadcast(s.data(), n, 0);
1404  }
1405  }
1406 
1407  if (style == 3) {
1409  assert(!rs.empty());
1410  } else {
1411  // printf("%d subworld hoc call %s narg=%d\n", nrnmpi_myid_world, fname->name, narg);
1412  hoc_call_objfunc(fname, narg, ob);
1413  // printf("%d subworld return from hoc call %s\n", nrnmpi_myid_world, fname->name);
1414  }
1415  for (i = 0; i < ns; ++i) {
1416  delete[] sarg[i];
1417  }
1418 }
1419 
1420 void BBSImpl::return_args(int id) {
1421  // the message has been set up by the subclass
1422  // perhaps it would be better to do this directly
1423  // and avoid the meaningless create and delete.
1424  // but then they all would have to know this format
1425  char* s;
1426  // printf("BBSImpl::return_args(%d):\n", id);
1427  upkint(); // userid
1428  /* int wid = */ upkint();
1429  int style = upkint();
1430  // printf("message userid=%d style=%d\n", i, style);
1431  switch (style) {
1432  case 0:
1433  s = upkstr(); // the statement
1434  // printf("statement |%s|\n", s);
1435  delete[] s;
1436  break;
1437  case 2: // obj first
1438  s = upkstr(); // template name
1439  upkint(); // instance index
1440  // printf("object %s[%d]\n", s, i);
1441  delete[] s;
1442  // fall through
1443  case 1:
1444  s = upkstr(); // fname
1445  upkint(); // arg manifest
1446  // printf("fname=|%s| manifest=%o\n", s, i);
1447  delete[] s;
1448  break;
1449  case 3:
1450  auto pickle = upkpickle(); // pickled callable
1451  upkint(); // arg manifest
1452  break;
1453  }
1454  // now only args are left and ready to unpack.
1455 }
static void nrnmpi_dbl_alltoallv(const double *s, const int *scnt, const int *sdispl, double *r, int *rcnt, int *rdispl)
static void nrnmpi_int_alltoallv(const int *s, const int *scnt, const int *sdispl, int *r, int *rcnt, int *rdispl)
static void nrnmpi_barrier()
Section * chk_access()
Definition: cabcode.cpp:449
Definition: bbs.h:7
bool look_take(const char *)
Definition: bbs.cpp:430
Object ** gid2cell(int)
Definition: netpar.cpp:1167
void spike_record(int, IvocVect *, IvocVect *)
Definition: netpar.cpp:1113
Object ** gid_connect(int)
Definition: netpar.cpp:1193
void master_works(int flag)
Definition: bbs.cpp:327
std::vector< char > upkpickle()
Definition: bbs.cpp:174
void set_gid2node(int, int)
Definition: netpar.cpp:947
void pkstr(const char *)
Definition: bbs.cpp:210
Object ** pyret()
Definition: ocbbs.cpp:367
void upkvec(int n, double *px)
Definition: bbs.cpp:159
void netpar_solve(double)
Definition: netpar.cpp:1251
void pkdouble(double)
Definition: bbs.cpp:196
void pkint(int)
Definition: bbs.cpp:189
void pkvec(int n, double *px)
Definition: bbs.cpp:203
void done()
Definition: bbs.cpp:458
int upkint()
Definition: bbs.cpp:143
bool working(int &id, double &x, int &userid)
Definition: bbs.cpp:323
bool is_master()
Definition: bbs.cpp:96
Object ** gid2obj(int)
Definition: netpar.cpp:1163
void pkbegin()
Definition: bbs.cpp:182
IvocVect * netpar_max_histogram(IvocVect *)
Definition: netpar.cpp:1429
int gid_exists(int)
Definition: netpar.cpp:1053
void post(const char *)
Definition: bbs.cpp:423
void worker()
Definition: bbs.cpp:392
bool look(const char *)
Definition: bbs.cpp:438
void cell()
Definition: netpar.cpp:1070
void netpar_spanning_statistics(int *, int *, int *, int *)
Definition: netpar.cpp:1419
int submit(int userid)
Definition: bbs.cpp:296
void pkpickle(const std::vector< char > &)
Definition: bbs.cpp:217
BBSImpl * impl_
Definition: bbs.h:73
void outputcell(int)
Definition: netpar.cpp:1104
char * upkstr()
Definition: bbs.cpp:166
void take(const char *)
Definition: bbs.cpp:446
double netpar_mindelay(double maxdelay)
Definition: netpar.cpp:1411
double threshold()
Definition: netpar.cpp:1057
double upkdouble()
Definition: bbs.cpp:151
void context()
Definition: bbs.cpp:314
virtual int upkint()=0
virtual void return_args(int userid)
Definition: ocbbs.cpp:1420
std::vector< char > execute_helper(int id, bool exec=true)
Definition: ocbbs.cpp:1160
virtual void upkvec(int, double *)=0
virtual char * upkstr()=0
virtual std::vector< char > upkpickle()=0
void subworld_worker_execute()
Definition: ocbbs.cpp:1314
std::vector< char > pickle_ret_
Definition: bbsimpl.h:59
virtual double upkdouble()=0
virtual void done()
Definition: bbs.cpp:464
auto begin() const -> std::vector< double >::const_iterator
Definition: ivocvect.h:64
double const * data() const
Definition: ivocvect.h:34
size_t size() const
Definition: ivocvect.h:42
Object ** temp_objvar()
Definition: ivocvect.cpp:349
auto end() const -> std::vector< double >::const_iterator
Definition: ivocvect.h:68
Object * obj_
Definition: ivocvect.h:101
void resize(size_t n)
Definition: ivocvect.h:46
Definition: ocbbs.cpp:57
OcBBS(int nhost_request)
Definition: ocbbs.cpp:67
int userid_
Definition: ocbbs.cpp:63
int next_local_
Definition: ocbbs.cpp:64
double retval_
Definition: ocbbs.cpp:62
virtual void ref() const
Definition: resource.cpp:42
virtual void unref() const
Definition: resource.cpp:47
void class2oc(const char *, ctor_f *cons, dtor_f *destruct, Member_func *, Member_ret_obj_func *, Member_ret_str_func *)
Definition: hoc_oop.cpp:1631
Symbol * hoc_table_lookup(const char *, Symlist *)
Definition: symbol.cpp:48
char * gargstr(int narg)
Definition: code2.cpp:227
HocReturnType hoc_return_type_code
Definition: code.cpp:42
#define cnt
Definition: tqueue.hpp:44
#define key
Definition: tqueue.hpp:45
#define v
Definition: md1redef.h:11
#define sec
Definition: md1redef.h:20
#define id
Definition: md1redef.h:41
#define i
Definition: md1redef.h:19
double chkarg(int, double low, double high)
Definition: code2.cpp:626
int hoc_is_object_arg(int narg)
Definition: code.cpp:876
void hoc_pushstr(char **d)
Definition: code.cpp:800
double * hoc_getarg(int narg)
Definition: code.cpp:1641
void vector_resize(IvocVect *v, int n)
Definition: ivocvect.cpp:302
int vector_arg_px(int, double **)
Definition: ivocvect.cpp:396
void hoc_pushobj(Object **d)
Definition: code.cpp:784
char * hoc_gargstr(int)
int hoc_is_str_arg(int narg)
Definition: code.cpp:872
void hoc_assign_str(char **cpp, const char *buf)
Definition: code.cpp:2263
double hoc_call_objfunc(Symbol *s, int narg, Object *ob)
Definition: hoc_oop.cpp:384
int hoc_is_double_arg(int narg)
Definition: code.cpp:864
void check_obj_type(Object *obj, const char *type_name)
Definition: hoc_oop.cpp:2098
IvocVect * vector_arg(int i)
Definition: ivocvect.cpp:265
double hoc_ac_
Definition: hoc_init.cpp:222
void hoc_obj_ref(Object *obj)
Definition: hoc_oop.cpp:1844
char * hoc_object_name(Object *ob)
Definition: hoc_oop.cpp:73
int is_vector_arg(int i)
Definition: ivocvect.cpp:378
double * hoc_pgetarg(int narg)
Definition: oc_ansi.h:253
Symbol * hoc_lookup(const char *)
Definition: symbol.cpp:59
int hoc_is_pdouble_arg(int narg)
Definition: code.cpp:868
void bbs_done()
Definition: ocbbs.cpp:76
void hoc_obj_unref(Object *obj)
Definition: hoc_oop.cpp:1881
int nrn_mpiabort_on_error_
Definition: hoc.cpp:80
char ** hoc_pgargstr(int narg)
Definition: code.cpp:1623
static int c
Definition: hoc.cpp:169
#define assert(ex)
Definition: hocassrt.h:24
#define getarg
Definition: hocdec.h:17
#define OBJ(q)
Definition: hoclist.h:88
Object ** hoc_objgetarg(int)
Definition: code.cpp:1614
static int narg()
Definition: ivocvect.cpp:121
int hoc_obj_run(const char *, Object *)
Definition: hoc_oop.cpp:315
void hoc_pushx(double)
Definition: code.cpp:779
IvocVect Vect
Definition: ivocvect.h:134
#define ITERATE(itm, lst)
Definition: model.h:18
static double nrnmpi_splitcell_wait_
Definition: multisplit.cpp:36
static double nrnmpi_wtime()
Definition: multisplit.cpp:48
static void phase_end(const char *name)
static void phase_begin(const char *name)
NrnThread * nrn_threads
Definition: multicore.cpp:56
void nrn_threads_create(int n)
Definition: multicore.cpp:102
double * vector_vec(IvocVect *v)
Definition: ivocvect.cpp:19
static int np
Definition: mpispike.cpp:25
int nrn_nthread
Definition: multicore.cpp:55
void hoc_execerror(const char *s1, const char *s2)
Definition: nrnoc_aux.cpp:39
void print_memory_usage(const MemoryUsage &usage)
MemoryUsage local_memory_usage()
Gather memory usage of this process.
impl_ptrs methods
Collection of pointers to functions with python-version-specific implementations.
Definition: nrnpy.cpp:21
int Sprintf(char(&buf)[N], const char *fmt, Args &&... args)
Redirect sprintf to snprintf if the buffer size can be deduced.
Definition: wrap_sprintf.h:14
int ii
Definition: cellorder.cpp:631
if(ncell==0)
Definition: cellorder.cpp:785
int interleave_permute_type
Definition: cellorder.cpp:42
int nrn_optimize_node_order(int type)
Select node ordering for optimum gaussian elimination.
Definition: cellorder.cpp:336
static List * info
static char suffix[256]
Definition: nocpout.cpp:135
void nrn_seg_or_x_arg(int iarg, Section **psec, double *px)
Definition: point.cpp:170
int const size_t const size_t n
Definition: nrngsl.h:10
size_t q
size_t j
s
Definition: multisend.cpp:521
int ifarg(int)
Definition: code.cpp:1607
short type
Definition: cabvars.h:10
int n_memb_func
Definition: init.cpp:448
int nrn_allow_busywait(int b)
Definition: multicore.cpp:1032
Object ** nrn_get_thread_partition(int it)
Definition: multicore.cpp:921
int nrn_how_many_processors()
Definition: multicore.cpp:1038
void nrn_thread_partition(int it, Object *sl)
Definition: multicore.cpp:899
std::size_t nof_worker_threads()
Definition: multicore.cpp:1048
std::vector< char > call_picklef(const std::vector< char > &fname, int narg)
Definition: nrnpy_p2h.cpp:601
static std::vector< char > pickle(PyObject *p)
Definition: nrnpy_p2h.cpp:525
static Object * pickle2po(const std::vector< char > &s)
Definition: nrnpy_p2h.cpp:551
static std::vector< char > po2pickle(Object *ho)
Definition: nrnpy_p2h.cpp:534
static char * sarg
Definition: nrnversion.cpp:17
int nrnmpi_myid
int nrnmpi_numprocs_world
int nrnmpi_myid_world
int nrnmpi_numprocs_bbs
int nrnmpi_myid_bbs
static double spike_record(void *v)
Definition: ocbbs.cpp:624
static double spike_stat(void *v)
Definition: ocbbs.cpp:659
int nrncore_run(const char *)
int nrn_set_timeout(int timeout)
Definition: netpar.cpp:1244
static double step_time(void *v)
Definition: ocbbs.cpp:490
static double partition(void *)
Definition: ocbbs.cpp:885
size_t nrnbbcore_register_mapping()
For BBP use case, we want to write section-segment mapping to gid_3.dat file.
static Object ** upkpyobj(void *v)
Definition: ocbbs.cpp:355
static double print_memory_stats(void *)
Definition: ocbbs.cpp:974
static double nhost(void *v)
Definition: ocbbs.cpp:201
static double nthrd(void *)
Definition: ocbbs.cpp:868
static Object ** upkvec(void *v)
Definition: ocbbs.cpp:341
void ParallelContext_reg()
Definition: ocbbs.cpp:1136
Symbol * hoc_which_template(Symbol *)
Definition: hoc_oop.cpp:1492
static double userid(void *v)
Definition: ocbbs.cpp:196
static double nrncorerun(void *)
Definition: ocbbs.cpp:997
void nrn_prcellstate(int gid, const char *suffix)
static double pctime(void *v)
Definition: ocbbs.cpp:443
static double thread_dt(void *)
Definition: ocbbs.cpp:961
static bool posting_
Definition: ocbbs.cpp:70
double nrn_multisend_receive_time(int)
Definition: multisend.cpp:319
static double prcellstate(void *v)
Definition: ocbbs.cpp:480
static void unpack_help(int, OcBBS *)
Definition: ocbbs.cpp:300
static double nhost_world(void *v)
Definition: ocbbs.cpp:211
static double look_take(void *v)
Definition: ocbbs.cpp:433
double nrnmpi_step_wait_
Definition: ocbbs.cpp:34
static double working(void *v)
Definition: ocbbs.cpp:179
static double send_time(void *v)
Definition: ocbbs.cpp:512
static double alltoall(void *)
Definition: ocbbs.cpp:784
static double wait_time(void *v)
Definition: ocbbs.cpp:485
int nrncore_is_enabled()
static double outputcell(void *v)
Definition: ocbbs.cpp:617
static double master_works(void *v)
Definition: ocbbs.cpp:245
static double done(void *v)
Definition: ocbbs.cpp:251
static Object ** gid2cell(void *v)
Definition: ocbbs.cpp:1013
static double event_time(void *v)
Definition: ocbbs.cpp:520
static Member_ret_str_func retstr_members[]
Definition: ocbbs.cpp:1104
static double thread_stat(void *)
Definition: ocbbs.cpp:910
static Member_func members[]
Definition: ocbbs.cpp:1023
int nrncore_is_file_mode()
double * nrn_mech_wtime_
Definition: treeset.cpp:38
static void * cons(Object *)
Definition: ocbbs.cpp:1120
static double set_gid2node(void *v)
Definition: ocbbs.cpp:528
static void pack_help(int, OcBBS *)
Definition: ocbbs.cpp:257
static double nrncorewrite_argvec(void *)
Definition: ocbbs.cpp:967
int nrncore_psolve(double tstop, int file_mode)
static double rank_bbs(void *v)
Definition: ocbbs.cpp:226
static void destruct(void *v)
Definition: ocbbs.cpp:1131
static double retval(void *v)
Definition: ocbbs.cpp:191
static Object ** py_gather(void *)
Definition: ocbbs.cpp:394
static double context(void *v)
Definition: ocbbs.cpp:171
static Object ** py_alltoall_type(int type)
Definition: ocbbs.cpp:374
static double spcompress(void *v)
Definition: ocbbs.cpp:551
static void nrnmpi_dbl_broadcast(double *, int, int)
Definition: ocbbs.cpp:44
static double nrn_thread_t(void *)
Definition: ocbbs.cpp:955
static double thread_how_many_proc(void *)
Definition: ocbbs.cpp:920
static double thread_ctime(void *)
Definition: ocbbs.cpp:940
static double splitcell_connect(void *v)
Definition: ocbbs.cpp:567
static double gid_clear(void *v)
Definition: ocbbs.cpp:608
static double source_var(void *)
Definition: ocbbs.cpp:690
static void nrnmpi_char_broadcast(char *, int, int)
Definition: ocbbs.cpp:43
static double setup_transfer(void *)
Definition: ocbbs.cpp:707
static char * key_help()
Definition: ocbbs.cpp:406
static Object ** py_broadcast(void *)
Definition: ocbbs.cpp:398
static double allgather(void *)
Definition: ocbbs.cpp:761
static double threshold(void *v)
Definition: ocbbs.cpp:546
static double nhost_bbs(void *v)
Definition: ocbbs.cpp:221
static double integ_time(void *v)
Definition: ocbbs.cpp:524
static double sec_in_thread(void *)
Definition: ocbbs.cpp:934
static double thread_busywait(void *)
Definition: ocbbs.cpp:915
double t
Definition: cvodeobj.cpp:57
static double take(void *v)
Definition: ocbbs.cpp:416
static double step_wait(void *v)
Definition: ocbbs.cpp:498
static Object ** pyret(void *v)
Definition: ocbbs.cpp:363
static double subworlds(void *v)
Definition: ocbbs.cpp:231
static double vtransfer_time(void *v)
Definition: ocbbs.cpp:447
static double pack(void *v)
Definition: ocbbs.cpp:280
size_t nrncore_write()
double nrnmpi_rtcomp_time_
Definition: ocbbs.cpp:31
static double cell(void *v)
Definition: ocbbs.cpp:540
static double mech_time(void *v)
Definition: ocbbs.cpp:463
static void nrnmpi_int_broadcast(int *, int, int)
Definition: ocbbs.cpp:42
static Object ** py_alltoall(void *)
Definition: ocbbs.cpp:386
static double set_timeout(void *v)
Definition: ocbbs.cpp:591
void nrnmpi_gid_clear(int)
Definition: netpar.cpp:988
static double multisplit(void *v)
Definition: ocbbs.cpp:574
#define MD
Definition: ocbbs.cpp:20
int nrnmpi_spike_compress(int nspike, bool gid_compress, int xchng_meth)
Definition: netpar.cpp:1483
static double nrncorewrite_argappend(void *)
Definition: ocbbs.cpp:988
static double post(void *v)
Definition: ocbbs.cpp:286
static double rank_world(void *v)
Definition: ocbbs.cpp:216
static double gid_exists(void *v)
Definition: ocbbs.cpp:534
static double set_maxstep(void *v)
Definition: ocbbs.cpp:654
static Member_ret_obj_func retobj_members[]
Definition: ocbbs.cpp:1106
static double submit(void *v)
Definition: ocbbs.cpp:163
static double optimize_node_order(void *)
Definition: ocbbs.cpp:926
static double worker(void *v)
Definition: ocbbs.cpp:239
static Object ** gid_connect(void *v)
Definition: ocbbs.cpp:1018
static Object ** py_allgather(void *)
Definition: ocbbs.cpp:390
static double nrn_rank(void *v)
Definition: ocbbs.cpp:206
static double target_var(void *)
Definition: ocbbs.cpp:698
static double broadcast(void *)
Definition: ocbbs.cpp:824
void nrnmpi_target_var()
static Object ** gid2obj(void *v)
Definition: ocbbs.cpp:1008
void nrnmpi_setup_transfer()
Definition: partrans.cpp:620
int nrnmpi_multisplit(Section *, double x, int sid, int backbonestyle)
Definition: multisplit.cpp:300
static double barrier(void *)
Definition: ocbbs.cpp:712
bool nrn_trajectory_request_per_time_step_
Definition: netcvode.cpp:106
static Object ** py_scatter(void *)
Definition: ocbbs.cpp:402
static int submit_help(OcBBS *)
Definition: ocbbs.cpp:93
static double unpack(void *v)
Definition: ocbbs.cpp:321
static const char ** upkstr(void *v)
Definition: ocbbs.cpp:332
static Object ** get_partition(void *)
Definition: ocbbs.cpp:905
static double number_of_worker_threads(void *)
Definition: ocbbs.cpp:880
int nrnmpi_splitcell_connect(int that_host)
Definition: splitcell.cpp:48
static double upkscalar(void *v)
Definition: ocbbs.cpp:327
static double maxhist(void *v)
Definition: ocbbs.cpp:677
void nrnmpi_source_var()
static double look(void *v)
Definition: ocbbs.cpp:423
static double psolve(void *v)
Definition: ocbbs.cpp:638
static double allreduce(void *)
Definition: ocbbs.cpp:726
static double set_mpiabort_on_error(void *)
Definition: ocbbs.cpp:600
static const char ** pname(void *v)
Definition: ocpointer.cpp:64
#define NULL
Definition: spdefs.h:105
Object ** hoc_temp_objptr(Object *)
Definition: code.cpp:151
Definition: hocdec.h:173
void * this_pointer
Definition: hocdec.h:178
int index
Definition: hocdec.h:175
cTemplate * ctemplate
Definition: hocdec.h:180
union Object::@47 u
Definition: model.h:47
union Symbol::@28 u
cTemplate * ctemplate
Definition: hocdec.h:126
char * name
Definition: model.h:61
Symbol * sym
Definition: hocdec.h:147
Symlist * symtable
Definition: hocdec.h:148
hoc_List * olist
Definition: hocdec.h:155
hoc_Item * next
Definition: hoclist.h:44
Overall SoA datastructures related memory usage.
std::vector< char >(* call_picklef)(const std::vector< char > &, int narg)
Definition: nrnpy.h:28
std::vector< char >(* po2pickle)(Object *)
Definition: nrnpy.h:49
Object *(* mpi_alltoall_type)(int, int)
Definition: nrnpy.h:44
Object *(* pickle2po)(const std::vector< char > &)
Definition: nrnpy.h:47