NEURON
bbssrv2mpi.cpp
Go to the documentation of this file.
1 #include <../../nrnconf.h>
2 #include "bbsconf.h"
3 #include <nrnmpi.h>
4 #if NRNMPI // to end of file
5 #include <stdio.h>
6 #include <string.h>
7 #include <assert.h>
8 #include "bbssrv2mpi.h"
9 #include "bbssrv.h"
10 #include "bbsimpl.h"
11 #include "hocdec.h" //Printf
12 
13 void nrnbbs_context_wait();
14 
16 
17 #if defined(HAVE_STL)
18 #if defined(HAVE_SSTREAM) // the standard ...
19 #include <map>
20 #include <set>
21 #else
22 #include <pair.h>
23 #include <multimap.h>
24 #include <map.h>
25 #include <set.h>
26 #include <multiset.h>
27 #endif
28 
29 #define debug 0
30 
31 #define MessageList MpiMessageList
32 #define WorkItem MpiWorkItem
33 #define WorkList MpiWorkList
34 #define ReadyList MpiReadyList
35 #define ResultList MpiResultList
36 #define PendingList MpiPendingList
37 #define LookingToDoList MpiLookingToDoList
38 
39 class WorkItem {
40  public:
41  WorkItem(int id, bbsmpibuf* buf, int cid);
42  virtual ~WorkItem();
43  WorkItem* parent_;
44  int id_;
45  bbsmpibuf* buf_;
46  int cid_; // mpi host id
47  bool todo_less_than(const WorkItem*) const;
48 };
49 
50 struct ltstr {
51  bool operator()(const char* s1, const char* s2) const {
52  return strcmp(s1, s2) < 0;
53  }
54 };
55 
56 struct ltint {
57  bool operator()(int i, int j) const {
58  return i < j;
59  }
60 };
61 
62 struct ltWorkItem {
63  bool operator()(const WorkItem* w1, const WorkItem* w2) const {
64  return w1->todo_less_than(w2);
65  }
66 };
67 
68 static char* newstr(const char* s) {
69  char* s1 = new char[strlen(s) + 1];
70  strcpy(s1, s);
71  return s1;
72 }
73 
74 WorkItem::WorkItem(int id, bbsmpibuf* buf, int cid) {
75 #if debug == 2
76  printf("WorkItem %d\n", id);
77 #endif
78  id_ = id;
79  buf_ = buf;
80  cid_ = cid;
81  parent_ = nil;
82 }
83 
84 WorkItem::~WorkItem() {
85 #if debug
86  printf("~WorkItem %d\n", id_);
87 #endif
88 }
89 
90 bool WorkItem::todo_less_than(const WorkItem* w) const {
91  WorkItem* w1 = (WorkItem*) this;
92  WorkItem* w2 = (WorkItem*) w;
93  while (w1->parent_ != w2->parent_) {
94  if (w1->id_ < w2->id_) {
95  w2 = w2->parent_;
96  } else {
97  w1 = w1->parent_;
98  }
99  }
100 #if debug
101  printf("todo_less_than %d < %d return %d\n", this->id_, w->id_, w1->id_ < w2->id_);
102 #endif
103  return w1->id_ < w2->id_;
104 }
105 
106 class MessageList: public std::multimap<const char*, bbsmpibuf*, ltstr> {};
107 class PendingList: public std::multimap<const char*, const int, ltstr> {};
108 class WorkList: public std::map<int, const WorkItem*, ltint> {};
109 class LookingToDoList: public std::set<int, ltint> {};
110 class ReadyList: public std::set<const WorkItem*, ltWorkItem> {};
111 class ResultList: public std::multimap<int, const WorkItem*, ltint> {};
112 #else
113 class MessageList {};
114 class PendingList {};
115 class WorkList {};
116 class LookingToDoList {};
117 class ReadyList {};
118 class ResultList {};
119 #endif
120 
122 #if defined(HAVE_STL)
123  messages_ = new MessageList();
124  work_ = new WorkList();
125  todo_ = new ReadyList();
126  results_ = new ResultList();
127  pending_ = new PendingList();
128  looking_todo_ = new LookingToDoList();
129  send_context_ = new LookingToDoList();
130  next_id_ = FIRSTID;
131  context_buf_ = nil;
133 #endif
134 }
135 
137 #if defined(HAVE_STL)
138  delete todo_;
139  delete results_;
140  delete looking_todo_;
141  printf("~BBSLocalServer not deleting everything\n");
142  // need to unref MessageValue in messages_ and delete WorkItem in work_
143  delete pending_;
144  delete messages_;
145  delete work_;
146  delete send_context_;
147 #endif
148 }
149 
150 bool BBSDirectServer::look_take(const char* key, bbsmpibuf** recv) {
151 #if debug
152  printf("DirectServer::look_take |%s|\n", key);
153 #endif
154  bool b = false;
155 #if defined(HAVE_STL)
156  nrnmpi_unref(*recv);
157  *recv = nil;
158  MessageList::iterator m = messages_->find(key);
159  if (m != messages_->end()) {
160  b = true;
161  *recv = (*m).second;
162  // printf("free %d\n", buf);
163  char* s = (char*) ((*m).first);
164  messages_->erase(m);
165  delete[] s;
166  }
167 #if debug
168  printf("DirectServer::look_take |%s| recv=%p return %d\n", key, (*recv), b);
169 #endif
170 #endif
171  return b;
172 }
173 
174 bool BBSDirectServer::look(const char* key, bbsmpibuf** recv) {
175 #if debug
176  printf("DirectServer::look |%s|\n", key);
177 #endif
178  bool b = false;
179  nrnmpi_unref(*recv);
180  *recv = nil;
181 #if defined(HAVE_STL)
182  MessageList::iterator m = messages_->find(key);
183  if (m != messages_->end()) {
184  b = true;
185  *recv = (*m).second;
186  if (*recv) {
187  nrnmpi_ref(*recv);
188  }
189  }
190 #if debug
191  printf("DirectServer::look |%s| recv=%p return %d\n", key, (*recv), b);
192 #endif
193 #endif
194  return b;
195 }
196 
197 void BBSDirectServer::put_pending(const char* key, int cid) {
198 #if defined(HAVE_STL)
199 #if debug
200  printf("put_pending |%s| %d\n", key, cid);
201 #endif
202  char* s = newstr(key);
203  pending_->insert(std::pair<const char* const, const int>(s, cid));
204 #endif
205 }
206 
207 bool BBSDirectServer::take_pending(const char* key, int* cid) {
208  bool b = false;
209 #if defined(HAVE_STL)
210  PendingList::iterator p = pending_->find(key);
211  if (p != pending_->end()) {
212  *cid = (*p).second;
213 #if debug
214  printf("take_pending |%s| %d\n", key, *cid);
215 #endif
216  char* s = (char*) ((*p).first);
217  pending_->erase(p);
218  delete[] s;
219  b = true;
220  }
221 #endif
222  return b;
223 }
224 
225 void BBSDirectServer::post(const char* key, bbsmpibuf* send) {
226 #if defined(HAVE_STL)
227  int cid;
228 #if debug
229  printf("DirectServer::post |%s| send=%p\n", key, send);
230 #endif
231  if (take_pending(key, &cid)) {
232  nrnmpi_bbssend(cid, TAKE, send);
233  } else {
234  MessageList::iterator m = messages_->insert(
235  std::pair<const char* const, bbsmpibuf*>(newstr(key), send));
236  nrnmpi_ref(send);
237  }
238 #endif
239 }
240 
241 void BBSDirectServer::add_looking_todo(int cid) {
242 #if defined(HAVE_STL)
243  looking_todo_->insert(cid);
244 #endif
245 }
246 
247 void BBSDirectServer::post_todo(int pid, int cid, bbsmpibuf* send) {
248 #if defined(HAVE_STL)
249 #if debug
250  printf("BBSDirectServer::post_todo pid=%d cid=%d send=%p\n", pid, cid, send);
251 #endif
252  WorkItem* w = new WorkItem(next_id_++, send, cid);
253  nrnmpi_ref(send);
254  WorkList::iterator p = work_->find(pid);
255  if (p != work_->end()) {
256  w->parent_ = (WorkItem*) ((*p).second);
257  }
258  work_->insert(std::pair<const int, const WorkItem*>(w->id_, w));
259 #if debug
260  printf("work insert %d\n", w->id_);
261 #endif
262  LookingToDoList::iterator i = looking_todo_->begin();
263  if (i != looking_todo_->end()) {
264  cid = (*i);
265  looking_todo_->erase(i);
266  // the send buffer is correct
267  nrnmpi_bbssend(cid, w->id_ + 1, send);
268  } else {
269 #if debug
270  printf("todo insert\n");
271 #endif
272  todo_->insert(w);
273  }
274 #endif
275 }
276 
277 void BBSDirectServer::context(bbsmpibuf* send) {
278 #if defined(HAVE_STL)
279  int cid, j;
280 #if debug
281  printf("numprocs_bbs=%d\n", nrnmpi_numprocs_bbs);
282 #endif
283  // Previous context may complete after allowing more activity
284  for (j = 0; j < 1000; ++j) {
285  if (remaining_context_cnt_ == 0) {
286  break;
287  }
288  handle();
289  }
290  if (remaining_context_cnt_ > 0) {
291  Printf("some workers did not receive previous context\n");
292  send_context_->erase(send_context_->begin(), send_context_->end());
293  nrnmpi_unref(context_buf_);
294  context_buf_ = nil;
295  }
297  for (j = 1; j < nrnmpi_numprocs_bbs; ++j) {
298  send_context_->insert(j);
299  }
300  LookingToDoList::iterator i = looking_todo_->begin();
301  while (i != looking_todo_->end()) {
302  cid = (*i);
303  looking_todo_->erase(i);
304 #if debug
305  printf("sending context to already waiting %d\n", cid);
306 #endif
307  nrnmpi_bbssend(cid, CONTEXT + 1, send);
308  i = send_context_->find(cid);
309  send_context_->erase(i);
311  i = looking_todo_->begin();
312  }
313  if (remaining_context_cnt_ > 0) {
314  context_buf_ = send;
315  nrnmpi_ref(context_buf_);
316  handle();
317  }
318 #endif
319 }
320 
321 void nrnbbs_context_wait() {
322  if (BBSImpl::is_master_) {
324  }
325 }
326 
328  // printf("context_wait enter %d\n", remaining_context_cnt_);
329  while (remaining_context_cnt_) {
330  handle();
331  }
332  // printf("context_wait exit %d\n", remaining_context_cnt_);
333 }
334 
335 bool BBSDirectServer::send_context(int cid) {
336 #if defined(HAVE_STL)
337  LookingToDoList::iterator i = send_context_->find(cid);
338  if (i != send_context_->end()) {
339  send_context_->erase(i);
340 #if debug
341  printf("sending context to %d\n", cid);
342 #endif
343  nrnmpi_bbssend(cid, CONTEXT + 1, context_buf_);
344  if (--remaining_context_cnt_ <= 0) {
345  nrnmpi_unref(context_buf_);
346  context_buf_ = nil;
347  }
348  return true;
349  }
350 #endif
351  return false;
352 }
353 
354 void BBSDirectServer::post_result(int id, bbsmpibuf* send) {
355 #if defined(HAVE_STL)
356 #if debug
357  printf("DirectServer::post_result id=%d send=%p\n", id, send);
358 #endif
359  WorkList::iterator i = work_->find(id);
360  WorkItem* w = (WorkItem*) ((*i).second);
361  nrnmpi_ref(send);
362  nrnmpi_unref(w->buf_);
363  w->buf_ = send;
364  results_->insert(std::pair<const int, const WorkItem*>(w->parent_ ? w->parent_->id_ : 0, w));
365 #endif
366 }
367 
368 int BBSDirectServer::look_take_todo(bbsmpibuf** recv) {
369 #if defined(HAVE_STL)
370 #if debug
371  printf("DirectServer::look_take_todo\n");
372 #endif
373  nrnmpi_unref(*recv);
374  *recv = nil;
375  ReadyList::iterator i = todo_->begin();
376  if (i != todo_->end()) {
377  WorkItem* w = (WorkItem*) (*i);
378  todo_->erase(i);
379  *recv = w->buf_;
380 #if debug
381  printf("DirectServer::look_take_todo recv %p with keypos=%d return %d\n",
382  *recv,
383  (*recv)->keypos,
384  w->id_);
385 #endif
386  w->buf_ = 0;
387  return w->id_;
388  } else {
389  return 0;
390  }
391 #else
392  return 0;
393 #endif
394 }
395 
396 int BBSDirectServer::look_take_result(int pid, bbsmpibuf** recv) {
397 #if debug
398  printf("DirectServer::look_take_result pid=%d\n", pid);
399 #endif
400 #if defined(HAVE_STL)
401  nrnmpi_unref(*recv);
402  *recv = nil;
403  ResultList::iterator i = results_->find(pid);
404  if (i != results_->end()) {
405  WorkItem* w = (WorkItem*) ((*i).second);
406  results_->erase(i);
407  *recv = w->buf_;
408  int id = w->id_;
409  WorkList::iterator j = work_->find(id);
410  work_->erase(j);
411  delete w;
412 #if debug
413  printf("DirectServer::look_take_result recv=%p return %d\n", *recv, id);
414 #endif
415  return id;
416  } else {
417  return 0;
418  }
419 #else
420  return 0;
421 #endif
422 }
423 
424 #endif // NRNMPI
#define nil
Definition: enter-scope.h:36
#define TAKE
Definition: bbssrv.h:8
#define FIRSTID
Definition: bbssrv.h:23
#define CONTEXT
Definition: bbssrv.h:19
int look_take_result(int parentid)
void add_looking_todo(int cid)
MpiReadyList * todo_
Definition: bbssrv2mpi.h:50
bool look(const char *key)
int context_buf_
Definition: bbslsrv2.h:36
void context(int ncid, int *cids)
bool look_take(const char *key)
MpiLookingToDoList * looking_todo_
Definition: bbssrv2mpi.h:49
static void handle()
void post_todo(int parentid, int cid)
void post(const char *key)
void put_pending(const char *key, int cid)
MpiLookingToDoList * send_context_
Definition: bbssrv2mpi.h:52
virtual ~BBSDirectServer()
static BBSDirectServer * server_
Definition: bbslsrv2.h:18
MpiMessageList * messages_
Definition: bbssrv2mpi.h:46
MpiPendingList * pending_
Definition: bbssrv2mpi.h:47
bool send_context(int cid)
bool take_pending(const char *key, int *cid)
int remaining_context_cnt_
Definition: bbslsrv2.h:37
void post_result(int id)
MpiWorkList * work_
Definition: bbssrv2mpi.h:48
MpiResultList * results_
Definition: bbssrv2mpi.h:51
static bool is_master_
Definition: bbsimpl.h:60
char buf[512]
Definition: init.cpp:13
void send(const char *url)
Definition: hel2mos.cpp:214
void nrnbbs_context_wait()
Definition: datapath.cpp:34
#define id
Definition: md1redef.h:33
#define i
Definition: md1redef.h:12
static double map(void *v)
Definition: mlinedit.cpp:47
#define Printf
Definition: model.h:237
#define printf
Definition: mwprefix.h:26
size_t p
size_t j
int nrnmpi_numprocs_bbs
static N_Vector id_
#define key
Definition: spt2queue.cpp:20