NEURON
sptbinq.cpp
Go to the documentation of this file.
1 // splay tree + bin queue limited to fixed step method
2 // for event-sets or priority queues
3 // this starts from the sptqueue.cpp file and adds a bin queue
4 
5 /* Derived from David Brower's c translation of pascal code by
6 Douglas Jones.
7 */
8 /* The original c code is included from this file but note that instead
9 of struct _spblk, we are really using TQItem
10 */
11 
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <stdarg.h>
16 #include <section.h>
17 
18 #define leftlink left_
19 #define rightlink right_
20 #define uplink parent_
21 #define cnt cnt_
22 #define key t_
23 #include <sptree.h>
24 
25 //extern double dt;
26 #define nt_dt nrn_threads->_dt
27 
29 
31  left_ = 0;
32  right_ = 0;
33  parent_ = 0;
34 }
35 
37 }
38 
39 bool TQItem::check() {
40 #if DOCHECK
41 #endif
42  return true;
43 }
44 
45 static void prnt(const TQItem* b, int level) {
46  int i;
47  for (i=0; i < level; ++i) {
48  Printf(" ");
49  }
50  Printf("%g %c %d Q=%p D=%p\n", b->t_, b->data_?'x':'o', b->cnt_, b, b->data_);
51 }
52 
53 static void chk(TQItem* b, int level) {
54  if (!b->check()) {
55  hoc_execerror("chk failed", errmess_);
56  }
57 }
58 
59 TQueue::TQueue(TQItemPool* tp, int mkmut) {
60  MUTCONSTRUCT(mkmut)
61  tpool_ = tp;
62  nshift_ = 0;
63  sptree_ = new SPTREE<TQItem>;
64  spinit(sptree_);
65  binq_ = new BinQ;
66  least_ = 0;
67 
68 #if COLLECT_TQueue_STATISTICS
69  nmove = ninsert = nrem = nleast = nbal = ncmplxrem = 0;
70  nfastmove = ncompare = nleastsrch = nfind = nfindsrch = 0;
71 #endif
72 }
73 
75  TQItem* q, *q2;
76  while((q = spdeq(&sptree_->root)) != nil) {
77  deleteitem(q);
78  }
79  delete sptree_;
80  for (q = binq_->first(); q; q = q2) {
81  q2 = binq_->next(q);
82  remove(q);
83  }
84  delete binq_;
86 }
87 
89  tpool_->hpfree(i);
90 }
91 
92 void TQueue::print() {
93  MUTLOCK
94 #if FAST_LEAST
95  if (least_) {
96  prnt(least_, 0);
97  }
98 #endif
99  spscan(prnt, static_cast<TQItem*>(nil), sptree_);
100  for (TQItem* q = binq_->first(); q; q = binq_->next(q)) {
101  prnt(q, 0);
102  }
103  MUTUNLOCK
104 }
105 
106 void TQueue::forall_callback(void(*f)(const TQItem*, int)) {
107  MUTLOCK
108 #if FAST_LEAST
109  if (least_) {
110  f(least_, 0);
111  }
112 #endif
113  spscan(f, static_cast<TQItem*>(nil), sptree_);
114  for (TQItem* q = binq_->first(); q; q = binq_->next(q)) {
115  f(q, 0);
116  }
117  MUTUNLOCK
118 }
119 
120 void TQueue::check(const char* mes) {
121 }
122 
123 #if FAST_LEAST
124 // for Parallel Global Variable Timestep method.
125 // Assume not using bin queue.
126 TQItem* TQueue::second_least(double t) {
127  assert(least_);
128  TQItem* b = sphead(sptree_);
129  if (b && b->t_ == t) {
130  return b;
131  }
132  return 0;
133 }
134 #endif
135 
136 void TQueue::move_least(double tnew) {
137  MUTLOCK
138  move_least_nolock(tnew);
139  MUTUNLOCK
140 }
141 
142 void TQueue::move_least_nolock(double tnew) {
143  TQItem* b = least();
144  if (b) {
145  b->t_ = tnew;
146  TQItem* nl = sphead(sptree_);
147  if (nl) {
148  if (tnew > nl->t_) {
149  least_ = spdeq(&sptree_->root);
150  spenq(b, sptree_);
151  }
152  }
153  }
154 }
155 
156 void TQueue::move(TQItem* i, double tnew) {
157  MUTLOCK
158  STAT(nmove)
159  if (i == least_) {
160  move_least_nolock(tnew);
161  }else if (tnew < least_->t_) {
162  spdelete(i, sptree_);
163  i->t_ = tnew;
164  spenq(least_, sptree_);
165  least_ = i;
166  }else{
167  spdelete(i, sptree_);
168  i->t_ = tnew;
169  spenq(i, sptree_);
170  }
171  MUTUNLOCK
172 }
173 
174 void TQueue::statistics() {
175 #if COLLECT_TQueue_STATISTICS
176  Printf("insertions=%lu moves=%lu removals=%lu calls to least=%lu\n",
177  ninsert, nmove, nrem, nleast);
178  Printf("calls to find=%lu\n",
179  nfind);
180  Printf("comparisons=%d\n",
181  sptree_->enqcmps);
182 #else
183  Printf("Turn on COLLECT_TQueue_STATISTICS_ in tqueue.h\n");
184 #endif
185 }
186 
187 void TQueue::spike_stat(double* d) {
188 #if COLLECT_TQueue_STATISTICS
189  d[0] = ninsert;
190  d[1] = nmove;
191  d[2] = nrem;
192 //printf("FifoQ spikestat nfenq=%lu nfdeq=%lu nfrem=%lu\n", fifo_->nfenq, fifo_->nfdeq, fifo_->nfrem);
193 #endif
194 }
195 
196 TQItem* TQueue::insert(double t, void* d) {
197  MUTLOCK
198  STAT(ninsert);
199  TQItem* i = tpool_->alloc();
200  i->data_ = d;
201  i->t_ = t;
202  i->cnt_ = -1;
203  if (t < least_t_nolock()) {
204  if (least()) {
205  spenq(least(), sptree_);
206  }
207  least_ = i;
208  }else{
209  spenq(i, sptree_);
210  }
211  MUTUNLOCK
212  return i;
213 }
214 
215 TQItem* TQueue::enqueue_bin(double td, void* d) {
216  MUTLOCK
217  STAT(ninsert);
218  TQItem* i = tpool_->alloc();
219  i->data_ = d;
220  i->t_ = td;
221  binq_->enqueue(td, i);
222  MUTUNLOCK
223  return i;
224 }
225 
227  // if lockable then the pool is internally handles locking
228  tpool_->hpfree(q);
229 }
230 
231 void TQueue::remove(TQItem* q) {
232  MUTLOCK
233  STAT(nrem);
234  if (q) {
235  if (q == least_) {
236  if (sptree_->root) {
237  least_ = spdeq(&sptree_->root);
238  }else{
239  least_ = nil;
240  }
241  }else if (q->cnt_ >= 0) {
242  binq_->remove(q);
243  }else{
244  spdelete(q, sptree_);
245  }
246  tpool_->hpfree(q);
247  }
248  MUTUNLOCK
249 }
250 
252  TQItem* q = 0;
253  MUTLOCK
254  if (least_ && least_->t_ <= tt) {
255  q = least_;
256  STAT(nrem);
257  if (sptree_->root) {
258  least_ = spdeq(&sptree_->root);
259  }else{
260  least_ = nil;
261  }
262  }
263  MUTUNLOCK
264  return q;
265 }
266 
267 TQItem* TQueue::find(double t) {
268  TQItem* q;
269  MUTLOCK
270  // search only in the splay tree. if this is a bug then fix it.
271  STAT(nfind)
272  if (t == least_t_nolock()) {
273  q = least();
274  }else{
275  q = splookup(t, sptree_);
276  }
277  MUTUNLOCK
278  return(q);
279 }
280 
282  nbin_ = 1000;
283  bins_ = new TQItem*[nbin_];
284  for (int i=0; i < nbin_; ++i) { bins_[i] = 0; }
285  qpt_ = 0;
286  tt_ = 0.;
287 #if COLLECT_TQueue_STATISTICS
288  nfenq = nfdeq = nfrem = 0;
289 #endif
290 }
291 
293  for (int i=0; i < nbin_; ++i) {
294  assert(!bins_[i]);
295  }
296  delete [] bins_;
297 }
298 
299 void BinQ::resize(int size) {
300  //printf("BinQ::resize from %d to %d\n", nbin_, size);
301  int i, j;
302  TQItem* q;
303  assert(size >= nbin_);
304  TQItem** bins = new TQItem*[size];
305  for (i=nbin_; i < size; ++i) { bins[i] = 0; }
306  for (i=0, j=qpt_; i < nbin_; ++i, ++j) {
307  if (j >= nbin_) { j = 0; }
308  bins[i] = bins_[j];
309  for (q = bins[i]; q; q = q->left_) {
310  q->cnt_ = i;
311  }
312  }
313  delete [] bins_;
314  bins_ = bins;
315  nbin_ = size;
316  qpt_ = 0;
317 }
318 void BinQ::enqueue(double td, TQItem* q) {
319  int idt = (int)((td - tt_)/nt_dt + 1.e-10);
320  if (idt < 0) {
322  (*nrn_binq_enqueue_error_handler)(td, q);
323  return;
324  }else{
325  assert(idt >= 0);
326  }
327  }
328  if (idt >= nbin_) {
329  resize(idt + 100);
330  }
331  //assert (idt < nbin_);
332  idt += qpt_;
333  if (idt >= nbin_) { idt -= nbin_; }
334 //printf("enqueue idt=%d qpt=%d\n", idt, qpt_);
335  assert (idt < nbin_);
336  q->cnt_ = idt; // only for iteration
337  q->left_ = bins_[idt];
338  bins_[idt] = q;
339 #if COLLECT_TQueue_STATISTICS
340  ++nfenq;
341 #endif
342 }
344  TQItem* q = bins_[qpt_];
345  if (q) {
346  bins_[qpt_] = q->left_;
347 #if COLLECT_TQueue_STATISTICS
348  ++nfdeq;
349 #endif
350  }
351  return q;
352 }
353 
354 /** Iterate in ascending bin order starting at current bin **/
356  for (int i = 0; i < nbin_; ++i) {
357  // start at least time qpt_ up to nbin_, and then wrap
358  // around to 0 and go up to qpt_
359  int j = (qpt_ + i)%nbin_;
360  if (bins_[j]) {
361  return bins_[j];
362  }
363  }
364  return 0;
365 }
367  if (q->left_) { return q->left_; }
368  // next non-empty bin starting at q->cnt_ + 1, until reach
369  // exactly qpt_, possibly wrapping around back to 0 if reach nbin_
370  for (int i = (q->cnt_ + 1)%nbin_; i != qpt_; i = (i + 1)%nbin_) {
371  if (bins_[i]) {
372  return bins_[i];
373  }
374  }
375  return 0;
376 }
377 
379  TQItem* q1, *q2;
380  q1 = bins_[q->cnt_];
381  if (q1 == q) {
382  bins_[q->cnt_] = q->left_;
383  return;
384  }
385  for (q2 = q1->left_; q2; q1 = q2, q2 = q2->left_) {
386  if (q2 == q) {
387  q1->left_ = q->left_;
388  return;
389  }
390  }
391 }
#define Printf
Definition: model.h:252
#define assert(ex)
Definition: hocassrt.h:26
SPBLK * spdeq(SPBLK **np)
Definition: sptree.h:320
void spdelete(SPBLK *n, SPTREE< SPBLK > *q)
Definition: sptree.h:772
void print()
Definition: bbtqueue.cpp:114
TQItem * find(double t)
Definition: bbtqueue.cpp:220
TQItem()
Definition: bbtqueue.cpp:3
void enqueue(double tt, TQItem *)
Definition: sptbinq.cpp:318
#define MUTLOCK
Definition: nrnmutdec.h:32
void
SPBLK * sphead(SPTREE< SPBLK > *q)
Definition: sptree.h:731
void resize(int)
Definition: sptbinq.cpp:299
#define MUTUNLOCK
Definition: nrnmutdec.h:33
double t_
Definition: bbtqueue.h:18
TQItem * enqueue_bin(double t, void *data)
Definition: sptbinq.cpp:215
Definition: bbtqueue.h:6
static void chk(TQItem *b, int level)
Definition: sptbinq.cpp:53
void spinit(SPTREE< SPBLK > *q)
Definition: sptree.h:139
bool check()
Definition: bbtqueue.cpp:30
void statistics()
Definition: bbtqueue.cpp:474
void forall_callback(void(*)(const TQItem *, int))
Definition: bbtqueue.cpp:120
TQItem * atomic_dq(double til)
Definition: sptbinq.cpp:251
TQItem * first()
Iterate in ascending bin order starting at current bin.
Definition: sptbinq.cpp:355
virtual ~TQItem()
Definition: bbtqueue.cpp:9
void remove(TQItem *)
Definition: sptbinq.cpp:378
#define nt_dt
Definition: sptbinq.cpp:26
virtual ~BinQ()
Definition: sptbinq.cpp:292
int
Definition: nrnmusic.cpp:71
void spike_stat(double *)
Definition: spt2queue.cpp:170
void hoc_execerror(const char *, const char *)
Definition: hoc.cpp:741
TQItem * insert(double t, void *data_)
Definition: bbtqueue.cpp:391
size_t j
static void deleteitem(TQItem *i)
Definition: bbtqueue.cpp:18
#define nil
Definition: enter-scope.h:36
TQItem * dequeue()
Definition: sptbinq.cpp:343
static double resize(void *v)
TQItem * left_
Definition: bbtqueue.h:19
static void prnt(const TQItem *b, int level)
Definition: sptbinq.cpp:45
#define MUTCONSTRUCT(mkmut)
Definition: nrnmutdec.h:30
SPBLK * splookup(double key, SPTREE< SPBLK > *q)
Definition: sptree.h:975
void move_least(double tnew)
Definition: bbtqueue.cpp:181
void spscan(void(*f)(const SPBLK *, int), SPBLK *n, SPTREE< SPBLK > *q)
Definition: sptree.h:1102
void deleteitem(TQItem *)
Definition: sptbinq.cpp:88
static const char * errmess_
Definition: tqueue.cpp:20
TQItem * parent_
Definition: bbtqueue.h:21
virtual ~TQueue()
Definition: bbtqueue.cpp:107
#define i
Definition: md1redef.h:12
#define MUTDESTRUCT
Definition: nrnmutdec.h:31
void release(TQItem *)
Definition: sptbinq.cpp:226
void move_least_nolock(double tnew)
Definition: sptbinq.cpp:142
#define STAT
Definition: model.h:117
static double least(void *v)
Definition: tqueue.cpp:33
SPBLK * spenq(SPBLK *n, SPTREE< SPBLK > *q)
Definition: sptree.h:176
void * data_
Definition: bbtqueue.h:17
void check(const char *errmess)
Definition: bbtqueue.cpp:126
Definition: sptbinq.h:36
void remove(TQItem *)
Definition: bbtqueue.cpp:239
double t
Definition: init.cpp:123
size_t q
BinQ()
Definition: sptbinq.cpp:281
int cnt_
Definition: spt2queue.h:23
TQueue()
Definition: bbtqueue.cpp:94
void move(TQItem *, double tnew)
Definition: bbtqueue.cpp:188
TQItem * right_
Definition: bbtqueue.h:20
TQItem * next(TQItem *)
Definition: sptbinq.cpp:366
void(* nrn_binq_enqueue_error_handler)(double, TQItem *)
Definition: sptbinq.cpp:28