NEURON
bbs.cpp
Go to the documentation of this file.
1 #include <../../nrnconf.h>
2 #include "nrnmpi.h"
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <InterViews/resource.h>
6 #include "oc2iv.h"
7 #include "bbs.h"
8 #include "bbslocal.h"
9 #if defined(NRNMPI)
10 #include "bbsdirect.h"
11 #include "bbsrcli.h"
12 #endif
13 
14 extern int nrn_global_argc;
15 extern char** nrn_global_argv;
16 extern double nrn_timeus();
17 
18 bool BBSImpl::is_master_ = false;
19 bool BBSImpl::started_ = false;
20 bool BBSImpl::done_ = false;
21 bool BBSImpl::master_works_ = true;
22 
23 #undef debug
24 #define debug BBSImpl::debug_
25 
26 int BBSImpl::debug_ = 0;
27 int BBSImpl::mytid_;
28 
29 static int etaskcnt;
30 static double total_exec_time;
31 static double worker_take_time;
32 
34  init(-1);
35 }
36 
37 BBS::BBS(int n) {
38  init(n);
39 }
40 
41 #if NRNMPI
42 void BBS::init(int) {
43  if (nrnmpi_use == 0) {
44  BBSImpl::is_master_ = true;
45  impl_ = new BBSLocal();
46  return;
47  }
48  if (!BBSImpl::started_) {
49  BBSImpl::is_master_ = (nrnmpi_myid_bbs == 0) ? true : false;
51  }
52  // Just as with PVM which stored buffers on the bulletin board
53  // so we have the following files to store MPI_PACKED buffers
54  // on the bulletin board. It would be possible to factor out
55  // the pvm stuff and we may do that later but for now we
56  // start with copies of the four files that worked for PVM
57  // and convert to the nrnmpi functions implemented in
58  // ../nrnmpi
59  // The four files are
60  // bbsclimpi.cpp - mpi remote client BBSClient from bbsrcli.cpp
61  // bbsdirectmpi.cpp - mpi master client BBSDirect from bbsdirect.cpp
62  // bbssrvmpi.cpp - mpi server portion to remote client from master bbs
63  // BBSDirectServer derived from bbssrv.cpp
64  // bbslsrvmpi.cpp - mpi master bbs portion of BBSDirectServer
65  // derived from bbslsrv2.cpp
66  // We reuse the .h files of these.
67  if (BBSImpl::is_master_) {
68  impl_ = new BBSDirect();
69  } else {
70  impl_ = new BBSClient();
71  }
72 }
73 #else // !NRNMPI
74 void BBS::init(int) {
75  if (!BBSImpl::started_) {
76  BBSImpl::is_master_ = true;
78  }
79  impl_ = new BBSLocal();
80 }
81 #endif // !NRNMPI
82 
85  wait_time_ = 0.;
86  send_time_ = 0.;
87  integ_time_ = 0.;
88  working_id_ = 0;
89  n_ = 0;
90 }
91 
93  delete impl_;
94 }
95 
97  return BBSImpl::is_master_;
98 }
99 
100 int BBS::nhost() {
101  return nrnmpi_numprocs;
102 }
103 
104 int BBS::myid() {
105  return nrnmpi_myid;
106 }
107 
109  return is_master_;
110 }
111 
112 double BBS::time() {
113  return impl_->time();
114 }
115 
116 double BBSImpl::time() {
117 #if NRNMPI
118  return nrnmpi_wtime();
119 #else
120  return nrn_timeus();
121 #endif
122 }
123 
124 double BBS::wait_time() {
125  return impl_->wait_time_;
126 }
127 double BBS::integ_time() {
128  return impl_->integ_time_;
129 }
130 double BBS::send_time() {
131  return impl_->send_time_;
132 }
133 void BBS::add_wait_time(double st) {
134  impl_->wait_time_ += impl_->time() - st;
135 }
136 
137 void BBS::perror(const char* s) {
138  impl_->perror(s);
139 }
140 
141 void BBSImpl::perror(const char*) {}
142 
143 int BBS::upkint() {
144  int i = impl_->upkint();
145  if (debug) {
146  printf("upkint %d\n", i);
147  }
148  return i;
149 }
150 
151 double BBS::upkdouble() {
152  double d = impl_->upkdouble();
153  if (debug) {
154  printf("upkdouble %g\n", d);
155  }
156  return d;
157 }
158 
159 void BBS::upkvec(int n, double* px) {
160  impl_->upkvec(n, px);
161  if (debug) {
162  printf("upkvec %d\n", n);
163  }
164 }
165 
166 char* BBS::upkstr() {
167  char* s = impl_->upkstr();
168  if (debug) {
169  printf("upkstr |%s|\n", s);
170  }
171  return s;
172 }
173 
174 std::vector<char> BBS::upkpickle() {
175  auto s = impl_->upkpickle();
176  if (debug) {
177  printf("upkpickle %lu |%s|\n", s.size(), s.data());
178  }
179  return s;
180 }
181 
182 void BBS::pkbegin() {
183  if (debug) {
184  printf("pkbegin\n");
185  }
186  impl_->pkbegin();
187 }
188 
189 void BBS::pkint(int i) {
190  if (debug) {
191  printf("pkint %d\n", i);
192  }
193  impl_->pkint(i);
194 }
195 
196 void BBS::pkdouble(double x) {
197  if (debug) {
198  printf("pkdouble %g\n", x);
199  }
200  impl_->pkdouble(x);
201 }
202 
203 void BBS::pkvec(int n, double* px) {
204  if (debug) {
205  printf("pkdouble %d\n", n);
206  }
207  impl_->pkvec(n, px);
208 }
209 
210 void BBS::pkstr(const char* s) {
211  if (debug) {
212  printf("pkstr |%s|\n", s);
213  }
214  impl_->pkstr(s);
215 }
216 
217 void BBS::pkpickle(const std::vector<char>& s) {
218  if (debug) {
219  printf("pkpickle %lu |%s|\n", s.size(), s.data());
220  }
221  impl_->pkpickle(s);
222 }
223 
224 #if 0
225 // for now all todo messages are of the three item form
226 // tid
227 // gid
228 // id
229 // "stmt"
230 // the latter should set hoc_ac_ if the return value is important
231 // right now every arg must be literal, we'll handle variables later.
232 // eg the following should work.
233 // n = 1000 x = 0 for i=1,n { x += i } hoc_ac_ = x
234 // although it may makes sense to send the result directly to the
235 // tid for now we just put it back onto the mailbox in the form
236 // message: "result tid gid" with two items, i.e. id, hoc_ac_
237 // Modified 11/30/09. To allow a return of a (pickled) PythonObject
238 // for the case when the execution is for a Python Callable the return
239 // message result now has three items, i.e. id, rtype, hoc_ac or pickled
240 // PyObject. rtype = 0 means hoc_ac, rtype = 1 means pickled PyObject.
241 // execute_helper returns the pickle string or (char*)0.
242 #endif
243 #if 0
244 // the todo management has been considerably modified to support
245 // a priority queue style for the order in which tasks are executed.
246 // Now the server manages the task id. Given a task id, it knows the
247 // parent task id.
248 // The working_id is always non-trivial on worker machines, and is
249 // only 0 on the master when dealing with a submission at the top level
250 // post_todo(working_id_) message is the statement, here the working_id is
251 // the parent of the future stmt task.
252 // take_todo: message is the statement. return is the id of this task
253 // post_result(id) message is return value.
254 // the result will be retrieved relative to the submitting working_id_
255 // look_take_result(working_id_) message is the return value. the return
256 // value of this call is the id of the task that computed the return.
257 #endif
258 
259 // BBSImpl::execute_helper() in ocbbs.cpp
260 
261 void BBSImpl::execute(int id) { // assumes a "_todo" message in receive buffer
262  ++etaskcnt;
263  double st, et;
264  int userid;
265  int save_id = working_id_;
266  int save_n = n_;
267  working_id_ = id;
268  n_ = 0;
269  st = time();
270  if (debug_) {
271  printf("execute begin %g: working_id_=%d\n", st, working_id_);
272  }
273  userid = upkint();
274  int wid = upkint();
275  hoc_ac_ = double(id);
276  auto rs = execute_helper(id); // builds and execute hoc statement
277  et = time() - st;
278  total_exec_time += et;
279  if (debug) {
280  printf("execute end elapsed %g: working_id_=%d hoc_ac_=%g\n", et, working_id_, hoc_ac_);
281  }
282  pkbegin();
283  pkint(userid);
284  pkint(wid);
285  pkint(!rs.empty() ? 1 : 0);
286  if (rs.empty()) {
287  pkdouble(hoc_ac_);
288  } else {
289  pkpickle(rs);
290  }
291  working_id_ = save_id;
292  n_ = save_n;
293  post_result(id);
294 }
295 
296 int BBS::submit(int userid) {
297  return impl_->submit(userid);
298 }
299 
301  // userid was the first item packed
302  ++n_;
303  if (debug) {
304  printf("submit n_= %d for working_id=%d userid=%d\n", n_, working_id_, userid);
305  }
306  if (userid < 0) {
307  save_args(userid);
308  } else {
310  }
311  return userid;
312 }
313 
314 void BBS::context() {
315  impl_->context();
316 }
317 
319  printf("can't execute BBS::context on a worker\n");
320  exit(1);
321 }
322 
323 bool BBS::working(int& id, double& x, int& userid) {
324  return impl_->working(id, x, userid);
325 }
326 
327 void BBS::master_works(int flag) {
328  if (impl_->is_master() && nrnmpi_numprocs_bbs > 1) {
329  impl_->master_works_ = flag ? true : false;
330  }
331 }
332 
334  assert(0);
335  return 0;
336 }
337 
338 bool BBSImpl::working(int& id, double& x, int& userid) {
339  int cnt = 0;
340  int rtype;
341  double t;
342  if (n_ <= 0) {
343  if (debug) {
344  printf("working n_=%d: return false\n", n_);
345  }
346  return false;
347  }
348  if (debug) {
349  t = time();
350  }
351  for (;;) {
352  ++cnt;
353  if (master_works_) {
355  } else {
357  }
358  if (id != 0) {
359  userid = upkint();
360  /* int wid = */ upkint();
361  rtype = upkint();
362  if (rtype == 0) {
363  x = upkdouble();
364  } else {
365  assert(rtype == 1);
366  x = 0.0;
368  }
369  --n_;
370  if (debug) {
371  printf("working n_=%d: after %d try elapsed %g sec got result for %d id=%d x=%g\n",
372  n_,
373  cnt,
374  time() - t,
375  working_id_,
376  id,
377  x);
378  }
379  if (userid < 0) {
381  }
382  return true;
383  } else if ((id = look_take_todo()) != 0) {
384  if (debug) {
385  printf("working: no result for %d but did get _todo id=%d\n", working_id_, id);
386  }
387  execute(id);
388  }
389  }
390 };
391 
392 void BBS::worker() {
394  impl_->worker();
395 }
396 
398  // forever request and execute commands
399  double st, et;
400  int id;
401  if (debug) {
402  printf("%d BBS::worker is_master=%d nrnmpi_myid = %d\n",
404  is_master(),
405  nrnmpi_myid);
406  }
407  if (!is_master()) {
408  if (nrnmpi_myid_bbs == -1) { // wait for message from
409  for (;;) { // the proper nrnmpi_myid == 0
411  }
412  }
413  for (;;) {
414  st = time();
415  id = take_todo();
416  et = time() - st;
417  worker_take_time += et;
418  execute(id);
419  }
420  }
421 }
422 
423 void BBS::post(const char* key) {
424  if (debug) {
425  printf("post: |%s|\n", key);
426  }
427  impl_->post(key);
428 }
429 
430 bool BBS::look_take(const char* key) {
431  bool b = impl_->look_take(key);
432  if (debug) {
433  printf("look_take |%s| return %d\n", key, b);
434  }
435  return b;
436 }
437 
438 bool BBS::look(const char* key) {
439  bool b = impl_->look(key);
440  if (debug) {
441  printf("look |%s| return %d\n", key, b);
442  }
443  return b;
444 }
445 
446 void BBS::take(const char* key) { // blocking
447  double t;
448  if (debug) {
449  t = time();
450  printf("begin take |%s| at %g\n", key, t);
451  }
452  impl_->take(key);
453  if (debug) {
454  printf("end take |%s| elapsed %g from %g\n", key, time() - t, t);
455  }
456 }
457 
458 void BBS::done() {
459  if (impl_->runworker_called_) {
460  impl_->done();
461  }
462 }
463 
465  if (done_) {
466  return;
467  }
468  done_ = true;
469 }
470 
472  if (started_) {
473  return;
474  }
475  started_ = 1;
476 }
#define debug
Definition: bbs.cpp:24
int nrn_global_argc
Definition: hoc.cpp:45
static int etaskcnt
Definition: bbs.cpp:29
char ** nrn_global_argv
Definition: hoc.cpp:46
static double total_exec_time
Definition: bbs.cpp:30
static double worker_take_time
Definition: bbs.cpp:31
double nrn_timeus()
Definition: ftime.cpp:27
bool look_take(const char *)
Definition: bbs.cpp:430
int myid()
Definition: bbs.cpp:104
virtual ~BBS()
Definition: bbs.cpp:92
void master_works(int flag)
Definition: bbs.cpp:327
std::vector< char > upkpickle()
Definition: bbs.cpp:174
double send_time()
Definition: bbs.cpp:130
int nhost()
Definition: bbs.cpp:100
void pkstr(const char *)
Definition: bbs.cpp:210
void upkvec(int n, double *px)
Definition: bbs.cpp:159
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
double integ_time()
Definition: bbs.cpp:127
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
void init(int)
Definition: bbs.cpp:74
void pkbegin()
Definition: bbs.cpp:182
void perror(const char *)
Definition: bbs.cpp:137
void post(const char *)
Definition: bbs.cpp:423
void worker()
Definition: bbs.cpp:392
double wait_time()
Definition: bbs.cpp:124
void add_wait_time(double)
Definition: bbs.cpp:133
bool look(const char *)
Definition: bbs.cpp:438
int submit(int userid)
Definition: bbs.cpp:296
double time()
Definition: bbs.cpp:112
void pkpickle(const std::vector< char > &)
Definition: bbs.cpp:217
BBSImpl * impl_
Definition: bbs.h:73
char * upkstr()
Definition: bbs.cpp:166
void take(const char *)
Definition: bbs.cpp:446
BBS()
Definition: bbs.cpp:33
double upkdouble()
Definition: bbs.cpp:151
void context()
Definition: bbs.cpp:314
virtual int upkint()=0
int working_id_
Definition: bbsimpl.h:55
virtual bool look_take(const char *)=0
static bool is_master_
Definition: bbsimpl.h:60
virtual void return_args(int userid)
Definition: ocbbs.cpp:1420
double send_time_
Definition: bbsimpl.h:58
static int mytid_
Definition: bbsimpl.h:62
BBSImpl()
Definition: bbs.cpp:83
virtual void post_result(int id)=0
static int debug_
Definition: bbsimpl.h:63
virtual void pkpickle(const std::vector< char > &)=0
std::vector< char > execute_helper(int id, bool exec=true)
Definition: ocbbs.cpp:1160
virtual void save_args(int userid)=0
int n_
Definition: bbsimpl.h:55
virtual int take_todo()=0
double integ_time_
Definition: bbsimpl.h:57
virtual int submit(int userid)
Definition: bbs.cpp:300
virtual void worker()
Definition: bbs.cpp:397
static bool master_works_
Definition: bbsimpl.h:64
virtual void pkbegin()=0
virtual void pkstr(const char *)=0
virtual void execute(int id)
Definition: bbs.cpp:261
virtual void upkvec(int, double *)=0
static bool started_
Definition: bbsimpl.h:61
int runworker_called_
Definition: bbsimpl.h:54
virtual int look_take_result(int pid)=0
virtual char * upkstr()=0
double wait_time_
Definition: bbsimpl.h:56
virtual void perror(const char *)
Definition: bbs.cpp:141
virtual void pkvec(int, double *)=0
virtual std::vector< char > upkpickle()=0
virtual void pkint(int)=0
void subworld_worker_execute()
Definition: ocbbs.cpp:1314
virtual bool is_master()
Definition: bbs.cpp:108
virtual double time()
Definition: bbs.cpp:116
static bool done_
Definition: bbsimpl.h:61
virtual int look_take_todo()=0
virtual void post_todo(int parentid)=0
virtual bool working(int &id, double &x, int &userid)
Definition: bbs.cpp:338
virtual void post(const char *)=0
virtual void take(const char *)=0
std::vector< char > pickle_ret_
Definition: bbsimpl.h:59
virtual double upkdouble()=0
virtual bool look(const char *)=0
virtual void start()
Definition: bbs.cpp:471
virtual void pkdouble(double)=0
virtual void done()
Definition: bbs.cpp:464
virtual void context()
Definition: bbs.cpp:318
virtual int master_take_result(int pid)
Definition: bbs.cpp:333
#define cnt
Definition: tqueue.hpp:44
#define key
Definition: tqueue.hpp:45
#define id
Definition: md1redef.h:41
#define i
Definition: md1redef.h:19
double hoc_ac_
Definition: hoc_init.cpp:222
#define assert(ex)
Definition: hocassrt.h:24
printf
Definition: extdef.h:5
static double nrnmpi_wtime()
Definition: multisplit.cpp:48
static int nrnmpi_use
Definition: multisplit.cpp:41
int const size_t const size_t n
Definition: nrngsl.h:10
s
Definition: multisend.cpp:521
int nrnmpi_myid
int nrnmpi_myid_world
int nrnmpi_numprocs_bbs
int nrnmpi_myid_bbs
static double userid(void *v)
Definition: ocbbs.cpp:196