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  --po->refcount;
361  return hoc_temp_objptr(po);
362 }
363 
364 static Object** pyret(void* v) {
365  OcBBS* bbs = (OcBBS*) v;
366  return bbs->pyret();
367 }
371  impl_->pickle_ret_.clear();
372  --po->refcount;
373  return hoc_temp_objptr(po);
374 }
375 
376 static Object** py_alltoall_type(int type) {
377  assert(neuron::python::methods.mpi_alltoall_type);
378  // for py_gather, py_broadcast, and py_scatter,
379  // the second arg refers to the root rank of the operation (default 0)
380  int size = 0;
381  if (ifarg(2)) {
382  size = int(chkarg(2, -1, 2.14748e9));
383  }
385  return hoc_temp_objptr(po);
386 }
387 
388 static Object** py_alltoall(void*) {
389  return py_alltoall_type(1);
390 }
391 
392 static Object** py_allgather(void*) {
393  return py_alltoall_type(2);
394 }
395 
396 static Object** py_gather(void*) {
397  return py_alltoall_type(3);
398 }
399 
400 static Object** py_broadcast(void*) {
401  return py_alltoall_type(4);
402 }
403 
404 static Object** py_scatter(void*) {
405  return py_alltoall_type(5);
406 }
407 
408 static char* key_help() {
409  static char key[50];
410  if (hoc_is_str_arg(1)) {
411  return gargstr(1);
412  } else {
413  Sprintf(key, "%g", *getarg(1));
414  return key;
415  }
416 }
417 
418 static double take(void* v) {
419  OcBBS* bbs = (OcBBS*) v;
420  bbs->take(key_help());
421  unpack_help(2, bbs);
422  return 1.;
423 }
424 
425 static double look(void* v) {
426  OcBBS* bbs = (OcBBS*) v;
428  if (bbs->look(key_help())) {
429  unpack_help(2, bbs);
430  return 1.;
431  }
432  return 0.;
433 }
434 
435 static double look_take(void* v) {
436  OcBBS* bbs = (OcBBS*) v;
438  if (bbs->look_take(key_help())) {
439  unpack_help(2, bbs);
440  return 1.;
441  }
442  return 0.;
443 }
444 
445 static double pctime(void* v) {
446  return ((OcBBS*) v)->time();
447 }
448 
449 static double vtransfer_time(void* v) {
450  int mode = ifarg(1) ? int(chkarg(1, 0., 2.)) : 0;
451  if (mode == 2) {
452  return nrnmpi_rtcomp_time_;
453 #if NRNMPI
454  } else if (mode == 1) {
455  return nrnmpi_splitcell_wait_;
456  } else {
457  return nrnmpi_transfer_wait_;
458  }
459 #else
460  }
461  return 0;
462 #endif
463 }
464 
465 static double mech_time(void* v) {
466  if (ifarg(1)) {
467  if (nrn_mech_wtime_) {
468  int i = (int) chkarg(1, 0, n_memb_func - 1);
469  return nrn_mech_wtime_[i];
470  }
471  } else {
472  if (!nrn_mech_wtime_) {
473  nrn_mech_wtime_ = new double[n_memb_func];
474  }
475  for (int i = 0; i < n_memb_func; ++i) {
476  nrn_mech_wtime_[i] = 0.0;
477  }
478  }
479  return 0;
480 }
481 
482 static double prcellstate(void* v) {
483  nrn_prcellstate(int(*hoc_getarg(1)), hoc_gargstr(2));
484  return 0;
485 }
486 
487 static double wait_time(void* v) {
488  double w = ((OcBBS*) v)->wait_time();
489  return w;
490 }
491 
492 static double step_time(void* v) {
493  double w = ((OcBBS*) v)->integ_time();
494 #if NRNMPI
495  w -= nrnmpi_transfer_wait_ + nrnmpi_splitcell_wait_;
496 #endif
497  return w;
498 }
499 
500 static double step_wait(void* v) {
501  if (ifarg(1)) {
502  nrnmpi_step_wait_ = chkarg(1, -1.0, 0.0);
503  }
504  double w = nrnmpi_step_wait_;
505 #if NRNMPI
506  // sadly, no calculation of transfer and multisplit barrier times.
507 #endif
508  if (w < 0.) {
509  w = 0.0;
510  }
511  return w;
512 }
513 
514 static double send_time(void* v) {
515  int arg = ifarg(1) ? int(chkarg(1, 0, 20)) : 0;
516  if (arg) {
517  return nrn_multisend_receive_time(arg);
518  }
519  return ((OcBBS*) v)->send_time();
520 }
521 
522 static double event_time(void* v) {
523  return 0.;
524 }
525 
526 static double integ_time(void* v) {
527  return 0.;
528 }
529 
530 static double set_gid2node(void* v) {
531  OcBBS* bbs = (OcBBS*) v;
532  bbs->set_gid2node(int(chkarg(1, 0, MD)), int(chkarg(2, 0, MD)));
533  return 0.;
534 }
535 
536 static double gid_exists(void* v) {
537  OcBBS* bbs = (OcBBS*) v;
539  return int(bbs->gid_exists(int(chkarg(1, 0, MD))));
540 }
541 
542 static double cell(void* v) {
543  OcBBS* bbs = (OcBBS*) v;
544  bbs->cell();
545  return 0.;
546 }
547 
548 static double threshold(void* v) {
549  OcBBS* bbs = (OcBBS*) v;
550  return bbs->threshold();
551 }
552 
553 static double spcompress(void* v) {
554  int nspike = -1;
555  bool gid_compress = true;
556  int xchng_meth = 0;
557  if (ifarg(1)) {
558  nspike = (int) chkarg(1, -1, MD);
559  }
560  if (ifarg(2)) {
561  gid_compress = (chkarg(2, 0, 1) ? true : false);
562  }
563  if (ifarg(3)) {
564  xchng_meth = (int) chkarg(3, 0, 15);
565  }
566  return (double) nrnmpi_spike_compress(nspike, gid_compress, xchng_meth);
567 }
568 
569 static double splitcell_connect(void* v) {
570  int that_host = (int) chkarg(1, 0, nrnmpi_numprocs - 1);
571  // also needs a currently accessed section that is the root of this_tree
572  nrnmpi_splitcell_connect(that_host);
573  return 0.;
574 }
575 
576 static double multisplit(void* v) {
577  double x = -1.;
578  Section* sec = NULL;
579  int sid = -1;
580  int backbone_style = 2;
581  if (ifarg(1)) {
582  nrn_seg_or_x_arg(1, &sec, &x);
583  sid = (int) chkarg(2, 0, (double) (0x7fffffff));
584  }
585  if (ifarg(3)) {
586  backbone_style = (int) chkarg(3, 0, 2);
587  }
588  // also needs a currently accessed section
589  nrnmpi_multisplit(sec, x, sid, backbone_style);
590  return 0.;
591 }
592 
593 static double set_timeout(void* v) {
594  int arg = 0;
595  if (ifarg(1)) {
596  arg = int(chkarg(1, 0, 10000));
597  }
598  arg = nrn_set_timeout(arg);
599  return double(arg);
600 }
601 
602 static double set_mpiabort_on_error(void*) {
603  double ret = double(nrn_mpiabort_on_error_);
604  if (ifarg(1)) {
605  nrn_mpiabort_on_error_ = int(chkarg(1, 0, 1));
606  }
607  return ret;
608 }
609 
610 static double gid_clear(void* v) {
611  int arg = 0;
612  if (ifarg(1)) {
613  arg = int(chkarg(1, 0, 4));
614  }
615  nrnmpi_gid_clear(arg);
616  return 0.;
617 }
618 
619 static double outputcell(void* v) {
620  OcBBS* bbs = (OcBBS*) v;
621  int gid = int(chkarg(1, 0., MD));
622  bbs->outputcell(gid);
623  return 0.;
624 }
625 
626 static double spike_record(void* v) {
627  OcBBS* bbs = (OcBBS*) v;
628  IvocVect* spikevec = vector_arg(2);
629  IvocVect* gidvec = vector_arg(3);
630  if (hoc_is_object_arg(1) && is_vector_arg(1)) {
631  IvocVect* gids = vector_arg(1);
632  bbs->spike_record(gids, spikevec, gidvec);
633  } else {
634  int gid = int(chkarg(1, -1., MD));
635  bbs->spike_record(gid, spikevec, gidvec);
636  }
637  return 0.;
638 }
639 
640 static double psolve(void* v) {
642  OcBBS* bbs = (OcBBS*) v;
643  double tstop = chkarg(1, t, 1e9);
644  int enabled = nrncore_is_enabled();
645  int file_mode = nrncore_is_file_mode();
646  if (enabled == 1) {
647  nrncore_psolve(tstop, file_mode);
648  } else if (enabled == 0) {
649  // Classic case
650  bbs->netpar_solve(tstop);
651  }
653  return double(enabled);
654 }
655 
656 static double set_maxstep(void* v) {
657  OcBBS* bbs = (OcBBS*) v;
658  return bbs->netpar_mindelay(chkarg(1, 1e-6, 1e9));
659 }
660 
661 static double spike_stat(void* v) {
662  OcBBS* bbs = (OcBBS*) v;
663  int nsend, nsendmax, nrecv, nrecv_useful;
665  nsend = nsendmax = nrecv = nrecv_useful = 0;
666  bbs->netpar_spanning_statistics(&nsend, &nsendmax, &nrecv, &nrecv_useful);
667  if (ifarg(1)) {
668  *hoc_pgetarg(1) = nsend;
669  }
670  if (ifarg(2)) {
671  *hoc_pgetarg(2) = nrecv;
672  }
673  if (ifarg(3)) {
674  *hoc_pgetarg(3) = nrecv_useful;
675  }
676  return double(nsendmax);
677 }
678 
679 static double maxhist(void* v) {
680  OcBBS* bbs = (OcBBS*) v;
681  IvocVect* vec = ifarg(1) ? vector_arg(1) : nullptr;
682  if (vec) {
683  hoc_obj_ref(vec->obj_);
684  }
685  vec = bbs->netpar_max_histogram(vec);
686  if (vec) {
687  hoc_obj_unref(vec->obj_);
688  }
689  return 0.;
690 }
691 
692 static double source_var(void*) { // &source_variable, source_global_index
693  // At BEFORE BREAKPOINT, the value of variable is sent to the
694  // target machine(s). This can only be executed on the
695  // source machine (where source_variable exists).
697  return 0.;
698 }
699 
700 static double target_var(void*) { // &target_variable, source_global_index
701  // At BEFORE BREAKPOINT, the value of the target_variable is set
702  // to the value of the source variable associated
703  // with the source_global_index. This can only be executed on the
704  // target machine (where target_variable exists).
706  return 0.;
707 }
708 
709 static double setup_transfer(void*) { // after all source/target and before init and run
711  return 0.;
712 }
713 
714 static double barrier(void*) {
715  // return wait time
716  double t = 0.;
717 #if NRNMPI
718  if (nrnmpi_numprocs > 1) {
719  t = nrnmpi_wtime();
720  nrnmpi_barrier();
721  t = nrnmpi_wtime() - t;
722  }
723  errno = 0;
724 #endif
725  return t;
726 }
727 
728 static double allreduce(void*) {
729  // type 1,2,3 sum, max, min
730  if (hoc_is_object_arg(1)) {
731  Vect* vec = vector_arg(1);
732  int n = vec->size();
733  if (n == 0) {
734  return 0.0;
735  }
736 #if NRNMPI
737  if (nrnmpi_numprocs > 1) {
738  int type = (int) chkarg(2, 1, 3);
739  double* px = vector_vec(vec);
740  double* dest = new double[n];
741  nrnmpi_dbl_allreduce_vec(px, dest, n, type);
742  for (int i = 0; i < n; ++i) {
743  px[i] = dest[i];
744  }
745  delete[] dest;
746  }
747  errno = 0;
748 #endif
749  return 0.;
750  } else {
751  double val = *getarg(1);
752 #if NRNMPI
753  if (nrnmpi_numprocs > 1) {
754  int type = (int) chkarg(2, 1, 3);
755  val = nrnmpi_dbl_allreduce(val, type);
756  }
757  errno = 0;
758 #endif
759  return val;
760  }
761 }
762 
763 static double allgather(void*) {
764  double val = *getarg(1);
765  Vect* vec = vector_arg(2);
767  double* px = vector_vec(vec);
768 
769 #if NRNMPI
770  if (nrnmpi_numprocs > 1) {
771  nrnmpi_dbl_allgather(&val, px, 1);
772  errno = 0;
773  } else {
774  px[0] = val;
775  }
776 #else
777  px[0] = val;
778 #endif
779  return 0.;
780 }
781 
782 // This function takes 3 arguments:
783 // - vsrc (In)
784 // - vscnt (In)
785 // - vdest (Out)
786 static double alltoall(void*) {
787  int np = nrnmpi_numprocs;
788  const Vect* vsrc = vector_arg(1);
789  const Vect* vscnt = vector_arg(2);
790  Vect* vdest = vector_arg(3);
791  std::size_t ns = vsrc->size();
792  if (vscnt->size() != np) {
793  hoc_execerror("size of source counts vector is not nhost", nullptr);
794  }
795  const std::vector<int> scnt(vscnt->begin(), vscnt->end()); // cast from double to int
796  std::vector<int> sdispl(np + 1);
797  for (int i = 0; i < np; ++i) {
798  sdispl[i + 1] = sdispl[i] + scnt[i];
799  }
800  if (ns != sdispl[np]) {
801  hoc_execerror("sum of source counts is not the size of the src vector", nullptr);
802  }
803  if (nrnmpi_numprocs > 1) {
804 #if NRNMPI
805  std::vector<int> rcnt(np);
806  std::vector<int> c(np, 1);
807  std::vector<int> rdispl(np + 1);
808  std::iota(rdispl.begin(), rdispl.end(), 0);
809 
811  scnt.data(), c.data(), rdispl.data(), rcnt.data(), c.data(), rdispl.data());
812  for (int i = 0; i < np; ++i) {
813  rdispl[i + 1] = rdispl[i] + rcnt[i];
814  }
815  vdest->resize(rdispl[np]);
817  vsrc->data(), scnt.data(), sdispl.data(), vdest->data(), rcnt.data(), rdispl.data());
818 #endif
819  } else {
820  vdest->resize(ns);
821  std::copy(vsrc->begin(), vsrc->end(), vdest->begin());
822  }
823  return 0.;
824 }
825 
826 static double broadcast(void*) {
827  int srcid = int(chkarg(2, 0, nrnmpi_numprocs - 1));
828  int cnt = 0;
829 #if NRNMPI
830  if (nrnmpi_numprocs > 1) {
831  if (hoc_is_str_arg(1)) {
832  char* s;
833  if (srcid == nrnmpi_myid) {
834  s = gargstr(1);
835  cnt = strlen(s) + 1;
836  }
837  nrnmpi_int_broadcast(&cnt, 1, srcid);
838  if (srcid != nrnmpi_myid) {
839  s = new char[cnt];
840  }
841  nrnmpi_char_broadcast(s, cnt, srcid);
842  if (srcid != nrnmpi_myid) {
844  delete[] s;
845  }
846  } else {
847  Vect* vec = vector_arg(1);
848  if (srcid == nrnmpi_myid) {
849  cnt = vec->size();
850  }
851  nrnmpi_int_broadcast(&cnt, 1, srcid);
852  if (srcid != nrnmpi_myid) {
853  vec->resize(cnt);
854  }
855  nrnmpi_dbl_broadcast(vector_vec(vec), cnt, srcid);
856  }
857  } else {
858 #else
859  {
860 #endif
861  if (hoc_is_str_arg(1)) {
862  cnt = strlen(gargstr(1));
863  } else {
864  cnt = vector_arg(1)->size();
865  }
866  }
867  return double(cnt);
868 }
869 
870 static double nthrd(void*) {
871  bool ip{true};
873  if (ifarg(1)) {
874  if (ifarg(2)) {
875  ip = bool(chkarg(2, 0, 1));
876  }
877  nrn_threads_create(int(chkarg(1, 1, 1e5)), ip);
878  }
879  return double(nrn_nthread);
880 }
881 
882 static double number_of_worker_threads(void*) {
884  return nof_worker_threads();
885 }
886 
887 static double partition(void*) {
888  Object* ob = 0;
889  int it;
890  if (ifarg(2)) {
891  ob = *hoc_objgetarg(2);
892  if (ob) {
893  check_obj_type(ob, "SectionList");
894  }
895  }
896  if (ifarg(1)) {
897  it = (int) chkarg(1, 0, nrn_nthread - 1);
898  nrn_thread_partition(it, ob);
899  } else {
900  for (it = 0; it < nrn_nthread; ++it) {
901  nrn_thread_partition(it, ob);
902  }
903  }
904  return 0.0;
905 }
906 
907 static Object** get_partition(void*) {
908  return nrn_get_thread_partition(int(chkarg(1, 0, nrn_nthread - 1)));
909  ;
910 }
911 
912 static double thread_stat(void*) {
913  // nrn_thread_stat was called here but didn't do anything
914  return 0.0;
915 }
916 
917 static double thread_busywait(void*) {
918  int old = nrn_allow_busywait(int(chkarg(1, 0, 1)));
919  return double(old);
920 }
921 
922 static double thread_how_many_proc(void*) {
924  int i = nrn_how_many_processors();
925  return double(i);
926 }
927 
928 static double optimize_node_order(void*) {
930  if (ifarg(1)) {
932  }
933  return double(neuron::interleave_permute_type);
934 }
935 
936 static double sec_in_thread(void*) {
938  Section* sec = chk_access();
939  return double(sec->pnode[0]->_nt->id);
940 }
941 
942 static double thread_ctime(void*) {
943  int i;
944 #if 1
945  if (ifarg(1)) {
946  i = int(chkarg(1, 0, nrn_nthread));
947  return nrn_threads[i]._ctime;
948  } else {
949  for (i = 0; i < nrn_nthread; ++i) {
950  nrn_threads[i]._ctime = 0.0;
951  }
952  }
953 #endif
954  return 0.0;
955 }
956 
957 static double nrn_thread_t(void*) {
958  int i;
959  i = int(chkarg(1, 0, nrn_nthread));
960  return nrn_threads[i]._t;
961 }
962 
963 static double thread_dt(void*) {
964  int i;
965  i = int(chkarg(1, 0, nrn_nthread));
966  return nrn_threads[i]._dt;
967 }
968 
969 static double nrncorewrite_argvec(void*) {
970  if (ifarg(2) && !(hoc_is_object_arg(2) && is_vector_arg(2))) {
971  hoc_execerror("nrnbbcore_write: optional second arg is not a Vector", nullptr);
972  }
973  return double(nrncore_write());
974 }
975 
976 static double print_memory_stats(void*) {
978 
979 #if NRNMPI
980  neuron::container::MemoryStats memory_stats;
981  nrnmpi_memory_stats(memory_stats, local_memory_usage);
982  nrnmpi_print_memory_stats(memory_stats);
983 #else
985 #endif
986 
987  return 1.0;
988 }
989 
990 static double nrncorewrite_argappend(void*) {
991  if (ifarg(2) && !hoc_is_double_arg(2)) {
993  "nrncore_write: optional second arg is not a number (True or False append flag)",
994  nullptr);
995  }
996  return double(nrncore_write());
997 }
998 
999 static double nrncorerun(void*) {
1000  if (ifarg(2)) {
1001  nrn_trajectory_request_per_time_step_ = chkarg(2, 0., 1.) != 0.0;
1002  }
1003  return double(nrncore_run(gargstr(1)));
1004 }
1005 
1006 static double nrnbbcore_register_mapping(void*) {
1007  return double(nrnbbcore_register_mapping());
1008 }
1009 
1010 static Object** gid2obj(void* v) {
1011  OcBBS* bbs = (OcBBS*) v;
1012  return bbs->gid2obj(int(chkarg(1, 0, MD)));
1013 }
1014 
1015 static Object** gid2cell(void* v) {
1016  OcBBS* bbs = (OcBBS*) v;
1017  return bbs->gid2cell(int(chkarg(1, 0, MD)));
1018 }
1019 
1020 static Object** gid_connect(void* v) {
1021  OcBBS* bbs = (OcBBS*) v;
1022  return bbs->gid_connect(int(chkarg(1, 0, MD)));
1023 }
1024 
1025 static Member_func members[] = {{"submit", submit},
1026  {"working", working},
1027  {"retval", retval},
1028  {"userid", userid},
1029  {"pack", pack},
1030  {"post", post},
1031  {"unpack", unpack},
1032  {"upkscalar", upkscalar},
1033  {"take", take},
1034  {"look", look},
1035  {"look_take", look_take},
1036  {"runworker", worker},
1037  {"master_works_on_jobs", master_works},
1038  {"done", done},
1039  {"id", nrn_rank},
1040  {"nhost", nhost},
1041  {"id_world", rank_world},
1042  {"nhost_world", nhost_world},
1043  {"id_bbs", rank_bbs},
1044  {"nhost_bbs", nhost_bbs},
1045  {"subworlds", subworlds},
1046  {"context", context},
1047 
1048  {"time", pctime},
1049  {"wait_time", wait_time},
1050  {"step_time", step_time},
1051  {"step_wait", step_wait},
1052  {"send_time", send_time},
1053  {"event_time", event_time},
1054  {"integ_time", integ_time},
1055  {"vtransfer_time", vtransfer_time},
1056  {"mech_time", mech_time},
1057  {"timeout", set_timeout},
1058  {"mpiabort_on_error", set_mpiabort_on_error},
1059 
1060  {"set_gid2node", set_gid2node},
1061  {"gid_exists", gid_exists},
1062  {"outputcell", outputcell},
1063  {"cell", cell},
1064  {"threshold", threshold},
1065  {"spike_record", spike_record},
1066  {"psolve", psolve},
1067  {"set_maxstep", set_maxstep},
1068  {"spike_statistics", spike_stat},
1069  {"max_histogram", maxhist},
1070  {"spike_compress", spcompress},
1071  {"gid_clear", gid_clear},
1072  {"prcellstate", prcellstate},
1073 
1074  {"source_var", source_var},
1075  {"target_var", target_var},
1076  {"setup_transfer", setup_transfer},
1077  {"splitcell_connect", splitcell_connect},
1078  {"multisplit", multisplit},
1079 
1080  {"barrier", barrier},
1081  {"allreduce", allreduce},
1082  {"allgather", allgather},
1083  {"alltoall", alltoall},
1084  {"broadcast", broadcast},
1085 
1086  {"nthread", nthrd},
1087  {"nworker", number_of_worker_threads},
1088  {"partition", partition},
1089  {"thread_stat", thread_stat},
1090  {"thread_busywait", thread_busywait},
1091  {"thread_how_many_proc", thread_how_many_proc},
1092  {"optimize_node_order", optimize_node_order},
1093  {"sec_in_thread", sec_in_thread},
1094  {"thread_ctime", thread_ctime},
1095  {"dt", thread_dt},
1096  {"t", nrn_thread_t},
1097 
1098  {"nrnbbcore_write", nrncorewrite_argvec},
1099  {"nrncore_write", nrncorewrite_argappend},
1100  {"nrnbbcore_register_mapping", nrnbbcore_register_mapping},
1101  {"nrncore_run", nrncorerun},
1102  {"print_memory_stats", print_memory_stats},
1103 
1104  {0, 0}};
1105 
1106 static Member_ret_str_func retstr_members[] = {{"upkstr", upkstr}, {0, 0}};
1107 
1109  {"gid2obj", gid2obj},
1110  {"gid2cell", gid2cell},
1111  {"gid_connect", gid_connect},
1112  {"get_partition", get_partition},
1113  {"upkpyobj", upkpyobj},
1114  {"pyret", pyret},
1115  {"py_alltoall", py_alltoall},
1116  {"py_allgather", py_allgather},
1117  {"py_gather", py_gather},
1118  {"py_broadcast", py_broadcast},
1119  {"py_scatter", py_scatter},
1120  {0, 0}};
1121 
1122 static void* cons(Object*) {
1123  // not clear at moment what is best way to handle nested context
1124  int i = -1;
1125  if (ifarg(1)) {
1126  i = int(chkarg(1, 0, 10000));
1127  }
1128  OcBBS* bbs = new OcBBS(i);
1129  bbs->ref();
1130  return bbs;
1131 }
1132 
1133 static void destruct(void* v) {
1134  OcBBS* bbs = (OcBBS*) v;
1135  bbs->unref();
1136 }
1137 
1139  class2oc("ParallelContext", cons, destruct, members, retobj_members, retstr_members);
1140 }
1141 
1142 // A BBS message is something to execute.
1143 // This helper execute depending of the style of the message.
1144 // style == 0:
1145 // This is a string that is a hoc statement, execute it with `hoc_obj_run`.
1146 // Return `nullptr`, set `size` argument to 0.
1147 // Not listen to `exec`.
1148 // No arguments.
1149 // style == 1:
1150 // This is a function name as a string followed by a list of arguments.
1151 // Return `nullptr` and set `size` to 0.
1152 // Dry run if `exec` is false.
1153 // style == 2:
1154 // From a template, find a object with an id and inside this object find a member
1155 // with a name as a string. Execute this member with arguments.
1156 // Return `nullptr` and set `size` to 0.
1157 // Dry run if `exec` is false.
1158 // style == 3:
1159 // A python pickle (https://docs.python.org/3/library/pickle.html) followed by arguments.
1160 // Return a string that is of size `size`.
1161 // Dry run if `exec` is false.
1162 std::vector<char> BBSImpl::execute_helper(int id, bool exec) {
1163  int subworld = (nrnmpi_numprocs > 1 && nrnmpi_numprocs_bbs < nrnmpi_numprocs_world);
1164  int style = upkint();
1165  if (subworld) {
1166  assert(nrnmpi_myid == 0);
1167  int info[2];
1168  info[0] = id;
1169  info[1] = style;
1170  nrnmpi_int_broadcast(info, 2, 0);
1171  }
1172  std::vector<char> rs{};
1173  switch (style) {
1174  case 0: {
1175  char* statement = upkstr();
1176  if (subworld) {
1177  int size = strlen(statement) + 1;
1178  nrnmpi_int_broadcast(&size, 1, 0);
1179  nrnmpi_char_broadcast(statement, size, 0);
1180  }
1181  hoc_obj_run(statement, nullptr);
1182  delete[] statement;
1183  } break;
1184  default: {
1185  std::vector<char> python_pickle{}; // Only for style == 3
1186  Symbol* fname = nullptr;
1187  Object* ob = nullptr;
1188  std::list<char*> sarg; // Store the strings pointer to delete[] them later
1189  // Use a list because, we push pointers of the object into
1190  // the hoc stack
1191  int narg = 0; // total number of args
1192  if (style == 2) { // object first
1193  char* template_name = upkstr();
1194  int object_index = upkint(); // object index
1195  Symbol* sym = hoc_lookup(template_name);
1196  if (sym) {
1197  sym = hoc_which_template(sym);
1198  }
1199  if (!sym) {
1200  hoc_execerror(template_name, "is not a template");
1201  }
1202  hoc_Item *q, *ql;
1203  ql = sym->u.ctemplate->olist;
1204  ITERATE(q, ql) {
1205  ob = OBJ(q);
1206  if (ob->index == object_index) {
1207  break;
1208  }
1209  ob = nullptr;
1210  }
1211  if (!ob) {
1212  fprintf(stderr,
1213  "%s[%d] is not an Object in this process\n",
1214  template_name,
1215  object_index);
1216  hoc_execerror("ParallelContext execution error", nullptr);
1217  }
1218  delete[] template_name;
1219  char* fname_str = upkstr();
1220  fname = hoc_table_lookup(fname_str, sym->u.ctemplate->symtable);
1221  if (!fname) {
1222  fprintf(stderr, "%s not a function in %s\n", fname_str, hoc_object_name(ob));
1223  hoc_execerror("ParallelContext execution error", nullptr);
1224  }
1225  delete[] fname_str;
1226  if (subworld) {
1227  hoc_execerror("with subworlds, this submit style not implemented", nullptr);
1228  }
1229  } else if (style == 3) { // Python callable
1230  python_pickle = upkpickle();
1231  if (subworld) {
1232  int size = static_cast<int>(python_pickle.size());
1233  nrnmpi_int_broadcast(&size, 1, 0);
1234  nrnmpi_char_broadcast(python_pickle.data(), size, 0);
1235  }
1236  } else {
1237  char* fname_str = upkstr();
1238  if (subworld) {
1239  int size = strlen(fname_str) + 1;
1240  nrnmpi_int_broadcast(&size, 1, 0);
1241  nrnmpi_char_broadcast(fname_str, size, 0);
1242  }
1243  fname = hoc_lookup(fname_str);
1244  if (!fname) {
1245  fprintf(stderr, "%s not a function in %s\n", fname_str, hoc_object_name(ob));
1246  hoc_execerror("ParallelContext execution error", nullptr);
1247  }
1248  delete[] fname_str;
1249  }
1250 
1251  int argtypes = upkint(); // first is least signif
1252  if (subworld) {
1253  // printf("%d exec argtypes = %d\n", nrnmpi_myid_world, argtypes);
1254  nrnmpi_int_broadcast(&argtypes, 1, 0);
1255  }
1256  for (int i = 0, j = argtypes; (i = j % 5) != 0; j /= 5) {
1257  ++narg;
1258  if (i == 1) {
1259  double x = upkdouble();
1260  if (subworld) {
1261  nrnmpi_dbl_broadcast(&x, 1, 0);
1262  }
1263  hoc_pushx(x);
1264  } else if (i == 2) {
1265  sarg.push_back(upkstr());
1266  if (subworld) {
1267  int size = strlen(sarg.back()) + 1;
1268  nrnmpi_int_broadcast(&size, 1, 0);
1269  nrnmpi_char_broadcast(sarg.back(), size, 0);
1270  }
1271  hoc_pushstr(&(sarg.back()));
1272  } else if (i == 3) {
1273  int n = upkint();
1274  if (subworld) {
1275  nrnmpi_int_broadcast(&n, 1, 0);
1276  }
1277  Vect* vec = new Vect(n);
1278  upkvec(n, vec->data());
1279  if (subworld) {
1280  nrnmpi_dbl_broadcast(vec->data(), n, 0);
1281  }
1282  hoc_pushobj(vec->temp_objvar());
1283  } else { // PythonObject
1284  auto s = upkpickle();
1285  int size = static_cast<int>(s.size());
1286  if (subworld) {
1287  nrnmpi_int_broadcast(&size, 1, 0);
1288  nrnmpi_char_broadcast(s.data(), size, 0);
1289  }
1292  --po->refcount;
1294  }
1295  }
1296  if (style == 3) {
1298  if (exec) {
1299  rs = neuron::python::methods.call_picklef(python_pickle, narg);
1300  }
1301  hoc_ac_ = 0.;
1302  } else {
1303  if (exec) {
1304  hoc_ac_ = hoc_call_objfunc(fname, narg, ob);
1305  } else {
1306  hoc_ac_ = 0.;
1307  }
1308  }
1309  for (auto& arg: sarg) {
1310  delete[] arg;
1311  }
1312  } break;
1313  }
1314  return rs;
1315 }
1316 
1318  // execute the same thing that execute_worker is executing. This
1319  // is done for all the nrnmpi_myid_bbs == -1 workers associated with
1320  // the specific nrnmpi_myid == 0 with nrnmpi_myid_bbs >= 0.
1321  // All the nrnmpi/mpispike.cpp functions can be used since the
1322  // proper communicators for a subworld are used by those functions.
1323  // The broadcast functions are particularly useful and those are
1324  // how execute_worker passes messages into here.
1325 
1326  // printf("%d enter subworld_worker_execute\n", nrnmpi_myid_world);
1327  int info[2];
1328  // wait for something to do
1329  nrnmpi_int_broadcast(info, 2, 0);
1330  // info[0] = -1 means it was from a pc.context. Also -2 means
1331  // DONE.
1332  // printf("%d subworld_worker_execute info %d %d\n", nrnmpi_myid_world, info[0], info[1]);
1333  int id = info[0];
1334  if (id == -2) { // DONE, so quit.
1335  done();
1336  }
1337  hoc_ac_ = double(id);
1338  int style = info[1];
1339  if (style == 0) { // hoc statement form
1340  int size;
1341  nrnmpi_int_broadcast(&size, 1, 0); // includes terminator
1342  char* s = new char[size];
1343  nrnmpi_char_broadcast(s, size, 0);
1344  hoc_obj_run(s, nullptr);
1345  delete[] s;
1346  // printf("%d leave subworld_worker_execute\n", nrnmpi_myid_world);
1347  return;
1348  }
1349  int i, j;
1350  int npickle;
1351  std::vector<char> s{};
1352  Symbol* fname = 0;
1353  Object* ob = nullptr;
1354  char* sarg[20]; // up to 20 arguments may be strings
1355  int ns = 0; // number of args that are strings
1356  int narg = 0; // total number of args
1357 
1358  if (style == 3) { // python callable
1359  nrnmpi_int_broadcast(&npickle, 1, 0);
1360  s.resize(npickle);
1361  nrnmpi_char_broadcast(s.data(), npickle, 0);
1362  } else if (style == 1) { // hoc function
1363  int size;
1364  nrnmpi_int_broadcast(&size, 1, 0); // includes terminator
1365  // printf("%d subworld hoc function string size = %d\n", nrnmpi_myid_world, size);
1366  s.resize(size);
1367  nrnmpi_char_broadcast(s.data(), size, 0);
1368  fname = hoc_lookup(s.data());
1369  if (!fname) {
1370  return;
1371  } // error raised by sender
1372  } else {
1373  return; // no others implemented, error raised by sender
1374  }
1375 
1376  // now get the args
1377  int argtypes;
1378  nrnmpi_int_broadcast(&argtypes, 1, 0);
1379  // printf("%d subworld argtypes = %d\n", nrnmpi_myid_world, argtypes);
1380  for (j = argtypes; (i = j % 5) != 0; j /= 5) {
1381  ++narg;
1382  if (i == 1) { // double
1383  double x;
1384  nrnmpi_dbl_broadcast(&x, 1, 0);
1385  // printf("%d subworld scalar = %g\n", nrnmpi_myid_world, x);
1386  hoc_pushx(x);
1387  } else if (i == 2) { // string
1388  int size;
1389  nrnmpi_int_broadcast(&size, 1, 0);
1390  sarg[ns] = new char[size];
1391  nrnmpi_char_broadcast(sarg[ns], size, 0);
1392  hoc_pushstr(sarg + ns);
1393  ns++;
1394  } else if (i == 3) { // Vector
1395  int n;
1396  nrnmpi_int_broadcast(&n, 1, 0);
1397  Vect* vec = new Vect(n);
1398  nrnmpi_dbl_broadcast(vec->data(), n, 0);
1399  hoc_pushobj(vec->temp_objvar());
1400  } else { // PythonObject
1401  int n;
1402  nrnmpi_int_broadcast(&n, 1, 0);
1403  std::vector<char> s(n);
1404  nrnmpi_char_broadcast(s.data(), n, 0);
1406  --po->refcount;
1408  }
1409  }
1410 
1411  if (style == 3) {
1413  assert(!rs.empty());
1414  } else {
1415  // printf("%d subworld hoc call %s narg=%d\n", nrnmpi_myid_world, fname->name, narg);
1416  hoc_call_objfunc(fname, narg, ob);
1417  // printf("%d subworld return from hoc call %s\n", nrnmpi_myid_world, fname->name);
1418  }
1419  for (i = 0; i < ns; ++i) {
1420  delete[] sarg[i];
1421  }
1422 }
1423 
1424 void BBSImpl::return_args(int id) {
1425  // the message has been set up by the subclass
1426  // perhaps it would be better to do this directly
1427  // and avoid the meaningless create and delete.
1428  // but then they all would have to know this format
1429  char* s;
1430  // printf("BBSImpl::return_args(%d):\n", id);
1431  upkint(); // userid
1432  /* int wid = */ upkint();
1433  int style = upkint();
1434  // printf("message userid=%d style=%d\n", i, style);
1435  switch (style) {
1436  case 0:
1437  s = upkstr(); // the statement
1438  // printf("statement |%s|\n", s);
1439  delete[] s;
1440  break;
1441  case 2: // obj first
1442  s = upkstr(); // template name
1443  upkint(); // instance index
1444  // printf("object %s[%d]\n", s, i);
1445  delete[] s;
1446  // fall through
1447  case 1:
1448  s = upkstr(); // fname
1449  upkint(); // arg manifest
1450  // printf("fname=|%s| manifest=%o\n", s, i);
1451  delete[] s;
1452  break;
1453  case 3:
1454  auto pickle = upkpickle(); // pickled callable
1455  upkint(); // arg manifest
1456  break;
1457  }
1458  // now only args are left and ready to unpack.
1459 }
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:368
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:1424
std::vector< char > execute_helper(int id, bool exec=true)
Definition: ocbbs.cpp:1162
virtual void upkvec(int, double *)=0
virtual char * upkstr()=0
virtual std::vector< char > upkpickle()=0
void subworld_worker_execute()
Definition: ocbbs.cpp:1317
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:626
static double spike_stat(void *v)
Definition: ocbbs.cpp:661
int nrncore_run(const char *)
int nrn_set_timeout(int timeout)
Definition: netpar.cpp:1244
static double step_time(void *v)
Definition: ocbbs.cpp:492
static double partition(void *)
Definition: ocbbs.cpp:887
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:976
static double nhost(void *v)
Definition: ocbbs.cpp:201
static double nthrd(void *)
Definition: ocbbs.cpp:870
static Object ** upkvec(void *v)
Definition: ocbbs.cpp:341
void ParallelContext_reg()
Definition: ocbbs.cpp:1138
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:999
void nrn_prcellstate(int gid, const char *suffix)
static double pctime(void *v)
Definition: ocbbs.cpp:445
static double thread_dt(void *)
Definition: ocbbs.cpp:963
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:482
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:435
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:514
static double alltoall(void *)
Definition: ocbbs.cpp:786
static double wait_time(void *v)
Definition: ocbbs.cpp:487
int nrncore_is_enabled()
static double outputcell(void *v)
Definition: ocbbs.cpp:619
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:1015
static double event_time(void *v)
Definition: ocbbs.cpp:522
static Member_ret_str_func retstr_members[]
Definition: ocbbs.cpp:1106
static double thread_stat(void *)
Definition: ocbbs.cpp:912
static Member_func members[]
Definition: ocbbs.cpp:1025
int nrncore_is_file_mode()
double * nrn_mech_wtime_
Definition: treeset.cpp:38
static void * cons(Object *)
Definition: ocbbs.cpp:1122
static double set_gid2node(void *v)
Definition: ocbbs.cpp:530
static void pack_help(int, OcBBS *)
Definition: ocbbs.cpp:257
static double nrncorewrite_argvec(void *)
Definition: ocbbs.cpp:969
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:1133
static double retval(void *v)
Definition: ocbbs.cpp:191
static Object ** py_gather(void *)
Definition: ocbbs.cpp:396
static double context(void *v)
Definition: ocbbs.cpp:171
static Object ** py_alltoall_type(int type)
Definition: ocbbs.cpp:376
static double spcompress(void *v)
Definition: ocbbs.cpp:553
static void nrnmpi_dbl_broadcast(double *, int, int)
Definition: ocbbs.cpp:44
static double nrn_thread_t(void *)
Definition: ocbbs.cpp:957
static double thread_how_many_proc(void *)
Definition: ocbbs.cpp:922
static double thread_ctime(void *)
Definition: ocbbs.cpp:942
static double splitcell_connect(void *v)
Definition: ocbbs.cpp:569
static double gid_clear(void *v)
Definition: ocbbs.cpp:610
static double source_var(void *)
Definition: ocbbs.cpp:692
static void nrnmpi_char_broadcast(char *, int, int)
Definition: ocbbs.cpp:43
static double setup_transfer(void *)
Definition: ocbbs.cpp:709
static char * key_help()
Definition: ocbbs.cpp:408
static Object ** py_broadcast(void *)
Definition: ocbbs.cpp:400
static double allgather(void *)
Definition: ocbbs.cpp:763
static double threshold(void *v)
Definition: ocbbs.cpp:548
static double nhost_bbs(void *v)
Definition: ocbbs.cpp:221
static double integ_time(void *v)
Definition: ocbbs.cpp:526
static double sec_in_thread(void *)
Definition: ocbbs.cpp:936
static double thread_busywait(void *)
Definition: ocbbs.cpp:917
double t
Definition: cvodeobj.cpp:57
static double take(void *v)
Definition: ocbbs.cpp:418
static double step_wait(void *v)
Definition: ocbbs.cpp:500
static Object ** pyret(void *v)
Definition: ocbbs.cpp:364
static double subworlds(void *v)
Definition: ocbbs.cpp:231
static double vtransfer_time(void *v)
Definition: ocbbs.cpp:449
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:542
static double mech_time(void *v)
Definition: ocbbs.cpp:465
static void nrnmpi_int_broadcast(int *, int, int)
Definition: ocbbs.cpp:42
static Object ** py_alltoall(void *)
Definition: ocbbs.cpp:388
static double set_timeout(void *v)
Definition: ocbbs.cpp:593
void nrnmpi_gid_clear(int)
Definition: netpar.cpp:988
static double multisplit(void *v)
Definition: ocbbs.cpp:576
#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:990
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:536
static double set_maxstep(void *v)
Definition: ocbbs.cpp:656
static Member_ret_obj_func retobj_members[]
Definition: ocbbs.cpp:1108
static double submit(void *v)
Definition: ocbbs.cpp:163
static double optimize_node_order(void *)
Definition: ocbbs.cpp:928
static double worker(void *v)
Definition: ocbbs.cpp:239
static Object ** gid_connect(void *v)
Definition: ocbbs.cpp:1020
static Object ** py_allgather(void *)
Definition: ocbbs.cpp:392
static double nrn_rank(void *v)
Definition: ocbbs.cpp:206
static double target_var(void *)
Definition: ocbbs.cpp:700
static double broadcast(void *)
Definition: ocbbs.cpp:826
void nrnmpi_target_var()
static Object ** gid2obj(void *v)
Definition: ocbbs.cpp:1010
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:714
bool nrn_trajectory_request_per_time_step_
Definition: netcvode.cpp:106
static Object ** py_scatter(void *)
Definition: ocbbs.cpp:404
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:907
static double number_of_worker_threads(void *)
Definition: ocbbs.cpp:882
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:679
void nrnmpi_source_var()
static double look(void *v)
Definition: ocbbs.cpp:425
static double psolve(void *v)
Definition: ocbbs.cpp:640
static double allreduce(void *)
Definition: ocbbs.cpp:728
static double set_mpiabort_on_error(void *)
Definition: ocbbs.cpp:602
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
int refcount
Definition: hocdec.h:174
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