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 
36 TQItem::~TQItem() {}
37 
38 bool TQItem::check() {
39 #if DOCHECK
40 #endif
41  return true;
42 }
43 
44 static void prnt(const TQItem* b, int level) {
45  int i;
46  for (i = 0; i < level; ++i) {
47  Printf(" ");
48  }
49  Printf("%g %c %d Q=%p D=%p\n", b->t_, b->data_ ? 'x' : 'o', b->cnt_, b, b->data_);
50 }
51 
52 static void chk(TQItem* b, int level) {
53  if (!b->check()) {
54  hoc_execerror("chk failed", errmess_);
55  }
56 }
57 
58 TQueue::TQueue(TQItemPool* tp, int mkmut) {
59  MUTCONSTRUCT(mkmut)
60  tpool_ = tp;
61  nshift_ = 0;
62  sptree_ = new SPTREE<TQItem>;
63  spinit(sptree_);
64  binq_ = new BinQ;
65  least_ = 0;
66 
67 #if COLLECT_TQueue_STATISTICS
68  nmove = ninsert = nrem = nleast = nbal = ncmplxrem = 0;
70 #endif
71 }
72 
74  TQItem *q, *q2;
75  while ((q = spdeq(&sptree_->root)) != nil) {
76  deleteitem(q);
77  }
78  delete sptree_;
79  for (q = binq_->first(); q; q = q2) {
80  q2 = binq_->next(q);
81  remove(q);
82  }
83  delete binq_;
85 }
86 
88  tpool_->hpfree(i);
89 }
90 
91 void TQueue::print() {
92  MUTLOCK
93 #if FAST_LEAST
94  if (least_) {
95  prnt(least_, 0);
96  }
97 #endif
98  spscan(prnt, static_cast<TQItem*>(nil), sptree_);
99  for (TQItem* q = binq_->first(); q; q = binq_->next(q)) {
100  prnt(q, 0);
101  }
102  MUTUNLOCK
103 }
104 
105 void TQueue::forall_callback(void (*f)(const TQItem*, int)) {
106  MUTLOCK
107 #if FAST_LEAST
108  if (least_) {
109  f(least_, 0);
110  }
111 #endif
112  spscan(f, static_cast<TQItem*>(nil), sptree_);
113  for (TQItem* q = binq_->first(); q; q = binq_->next(q)) {
114  f(q, 0);
115  }
116  MUTUNLOCK
117 }
118 
119 void TQueue::check(const char* mes) {}
120 
121 #if FAST_LEAST
122 // for Parallel Global Variable Timestep method.
123 // Assume not using bin queue.
124 TQItem* TQueue::second_least(double t) {
125  assert(least_);
126  TQItem* b = sphead(sptree_);
127  if (b && b->t_ == t) {
128  return b;
129  }
130  return 0;
131 }
132 #endif
133 
134 void TQueue::move_least(double tnew) {
135  MUTLOCK
136  move_least_nolock(tnew);
137  MUTUNLOCK
138 }
139 
140 void TQueue::move_least_nolock(double tnew) {
141  TQItem* b = least();
142  if (b) {
143  b->t_ = tnew;
144  TQItem* nl = sphead(sptree_);
145  if (nl) {
146  if (tnew > nl->t_) {
147  least_ = spdeq(&sptree_->root);
148  spenq(b, sptree_);
149  }
150  }
151  }
152 }
153 
154 void TQueue::move(TQItem* i, double tnew) {
155  MUTLOCK
156  STAT(nmove)
157  if (i == least_) {
158  move_least_nolock(tnew);
159  } else if (tnew < least_->t_) {
160  spdelete(i, sptree_);
161  i->t_ = tnew;
162  spenq(least_, sptree_);
163  least_ = i;
164  } else {
165  spdelete(i, sptree_);
166  i->t_ = tnew;
167  spenq(i, sptree_);
168  }
169  MUTUNLOCK
170 }
171 
172 void TQueue::statistics() {
173 #if COLLECT_TQueue_STATISTICS
174  Printf("insertions=%lu moves=%lu removals=%lu calls to least=%lu\n",
175  ninsert,
176  nmove,
177  nrem,
178  nleast);
179  Printf("calls to find=%lu\n", nfind);
180  Printf("comparisons=%d\n", sptree_->enqcmps);
181 #else
182  Printf("Turn on COLLECT_TQueue_STATISTICS_ in tqueue.h\n");
183 #endif
184 }
185 
186 void TQueue::spike_stat(double* d) {
187 #if COLLECT_TQueue_STATISTICS
188  d[0] = ninsert;
189  d[1] = nmove;
190  d[2] = nrem;
191 // printf("FifoQ spikestat nfenq=%lu nfdeq=%lu nfrem=%lu\n", fifo_->nfenq, fifo_->nfdeq,
192 // 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) {
285  bins_[i] = 0;
286  }
287  qpt_ = 0;
288  tt_ = 0.;
289 #if COLLECT_TQueue_STATISTICS
290  nfenq = nfdeq = nfrem = 0;
291 #endif
292 }
293 
295  for (int i = 0; i < nbin_; ++i) {
296  assert(!bins_[i]);
297  }
298  delete[] bins_;
299 }
300 
301 void BinQ::resize(int size) {
302  // printf("BinQ::resize from %d to %d\n", nbin_, size);
303  int i, j;
304  TQItem* q;
305  assert(size >= nbin_);
306  TQItem** bins = new TQItem*[size];
307  for (i = nbin_; i < size; ++i) {
308  bins[i] = 0;
309  }
310  for (i = 0, j = qpt_; i < nbin_; ++i, ++j) {
311  if (j >= nbin_) {
312  j = 0;
313  }
314  bins[i] = bins_[j];
315  for (q = bins[i]; q; q = q->left_) {
316  q->cnt_ = i;
317  }
318  }
319  delete[] bins_;
320  bins_ = bins;
321  nbin_ = size;
322  qpt_ = 0;
323 }
324 void BinQ::enqueue(double td, TQItem* q) {
325  int idt = (int) ((td - tt_) / nt_dt + 1.e-10);
326  if (idt < 0) {
328  (*nrn_binq_enqueue_error_handler)(td, q);
329  return;
330  } else {
331  assert(idt >= 0);
332  }
333  }
334  if (idt >= nbin_) {
335  resize(idt + 100);
336  }
337  // assert (idt < nbin_);
338  idt += qpt_;
339  if (idt >= nbin_) {
340  idt -= nbin_;
341  }
342  // printf("enqueue idt=%d qpt=%d\n", idt, qpt_);
343  assert(idt < nbin_);
344  q->cnt_ = idt; // only for iteration
345  q->left_ = bins_[idt];
346  bins_[idt] = q;
347 #if COLLECT_TQueue_STATISTICS
348  ++nfenq;
349 #endif
350 }
352  TQItem* q = bins_[qpt_];
353  if (q) {
354  bins_[qpt_] = q->left_;
355 #if COLLECT_TQueue_STATISTICS
356  ++nfdeq;
357 #endif
358  }
359  return q;
360 }
361 
362 /** Iterate in ascending bin order starting at current bin **/
364  for (int i = 0; i < nbin_; ++i) {
365  // start at least time qpt_ up to nbin_, and then wrap
366  // around to 0 and go up to qpt_
367  int j = (qpt_ + i) % nbin_;
368  if (bins_[j]) {
369  return bins_[j];
370  }
371  }
372  return 0;
373 }
375  if (q->left_) {
376  return q->left_;
377  }
378  // next non-empty bin starting at q->cnt_ + 1, until reach
379  // exactly qpt_, possibly wrapping around back to 0 if reach nbin_
380  for (int i = (q->cnt_ + 1) % nbin_; i != qpt_; i = (i + 1) % nbin_) {
381  if (bins_[i]) {
382  return bins_[i];
383  }
384  }
385  return 0;
386 }
387 
389  TQItem *q1, *q2;
390  q1 = bins_[q->cnt_];
391  if (q1 == q) {
392  bins_[q->cnt_] = q->left_;
393  return;
394  }
395  for (q2 = q1->left_; q2; q1 = q2, q2 = q2->left_) {
396  if (q2 == q) {
397  q1->left_ = q->left_;
398  return;
399  }
400  }
401 }
#define nil
Definition: enter-scope.h:36
Definition: sptbinq.h:38
virtual ~BinQ()
Definition: sptbinq.cpp:294
BinQ()
Definition: sptbinq.cpp:281
void resize(int)
Definition: sptbinq.cpp:301
int nfenq
Definition: sptbinq.h:64
TQItem * next(TQItem *)
Definition: sptbinq.cpp:374
double tt_
Definition: sptbinq.h:67
TQItem * first()
Iterate in ascending bin order starting at current bin.
Definition: sptbinq.cpp:363
int qpt_
Definition: sptbinq.h:68
int nbin_
Definition: sptbinq.h:68
int nfrem
Definition: sptbinq.h:64
void enqueue(double tt, TQItem *)
Definition: sptbinq.cpp:324
void remove(TQItem *)
Definition: sptbinq.cpp:388
TQItem * dequeue()
Definition: sptbinq.cpp:351
TQItem ** bins_
Definition: sptbinq.h:69
int nfdeq
Definition: sptbinq.h:64
Definition: bbtqueue.h:6
virtual ~TQItem()
Definition: bbtqueue.cpp:9
double t_
Definition: bbtqueue.h:23
bool check()
Definition: bbtqueue.cpp:30
TQItem * right_
Definition: bbtqueue.h:25
int cnt_
Definition: spt2queue.h:24
TQItem()
Definition: bbtqueue.cpp:3
TQItem * parent_
Definition: bbtqueue.h:26
TQItem * left_
Definition: bbtqueue.h:24
void * data_
Definition: bbtqueue.h:22
unsigned long nbal
Definition: bbtqueue.h:58
void statistics()
Definition: bbtqueue.cpp:477
unsigned long nleastsrch
Definition: bbtqueue.h:59
void remove(TQItem *)
Definition: bbtqueue.cpp:236
TQItem * enqueue_bin(double t, void *data)
Definition: sptbinq.cpp:215
void deleteitem(TQItem *)
Definition: sptbinq.cpp:87
double least_t_nolock()
Definition: sptbinq.h:142
TQItem * least()
Definition: bbtqueue.cpp:140
void check(const char *errmess)
Definition: bbtqueue.cpp:121
TQItemPool * tpool_
Definition: sptbinq.h:153
void move(TQItem *, double tnew)
Definition: bbtqueue.cpp:185
unsigned long nmove
Definition: bbtqueue.h:59
void release(TQItem *)
Definition: sptbinq.cpp:226
TQItem * least_
Definition: bbtqueue.h:54
TQueue()
Definition: bbtqueue.cpp:90
int nshift_
Definition: sptbinq.h:133
unsigned long ninsert
Definition: bbtqueue.h:58
void print()
Definition: bbtqueue.cpp:109
unsigned long nrem
Definition: bbtqueue.h:58
unsigned long nfastmove
Definition: bbtqueue.h:59
SPTREE * sptree_
Definition: spt2queue.h:61
TQItem * atomic_dq(double til)
Definition: sptbinq.cpp:251
TQItem * find(double t)
Definition: bbtqueue.cpp:217
unsigned long nfindsrch
Definition: bbtqueue.h:59
unsigned long ncompare
Definition: bbtqueue.h:59
unsigned long nleast
Definition: bbtqueue.h:58
BinQ * binq_
Definition: sptbinq.h:151
unsigned long nfind
Definition: bbtqueue.h:59
void move_least_nolock(double tnew)
Definition: sptbinq.cpp:140
unsigned long ncmplxrem
Definition: bbtqueue.h:58
virtual ~TQueue()
Definition: bbtqueue.cpp:103
void forall_callback(void(*)(const TQItem *, int))
Definition: bbtqueue.cpp:115
TQItem * insert(double t, void *data_)
Definition: bbtqueue.cpp:394
void move_least(double tnew)
Definition: bbtqueue.cpp:178
void spike_stat(double *)
Definition: spt2queue.cpp:189
double t
Definition: cvodeobj.cpp:59
void hoc_execerror(const char *, const char *)
Definition: hoc.cpp:754
#define assert(ex)
Definition: hocassrt.h:32
void
#define i
Definition: md1redef.h:12
#define STAT
Definition: model.h:117
#define Printf
Definition: model.h:237
size_t q
size_t j
#define MUTCONSTRUCT(mkmut)
Definition: nrnmutdec.h:70
#define MUTDESTRUCT
Definition: nrnmutdec.h:71
#define MUTLOCK
Definition: nrnmutdec.h:72
#define MUTUNLOCK
Definition: nrnmutdec.h:73
void(* nrn_binq_enqueue_error_handler)(double, TQItem *)
Definition: sptbinq.cpp:28
#define nt_dt
Definition: sptbinq.cpp:26
static void prnt(const TQItem *b, int level)
Definition: sptbinq.cpp:44
static void chk(TQItem *b, int level)
Definition: sptbinq.cpp:52
void spscan(void(*f)(const SPBLK *, int), SPBLK *n, SPTREE< SPBLK > *q)
Definition: sptree.h:1035
SPBLK * spdeq(SPBLK **np)
Definition: sptree.h:304
SPBLK * sphead(SPTREE< SPBLK > *q)
Definition: sptree.h:693
SPBLK * spenq(SPBLK *n, SPTREE< SPBLK > *q)
Definition: sptree.h:169
SPBLK * splookup(double key, SPTREE< SPBLK > *q)
Definition: sptree.h:918
void spdelete(SPBLK *n, SPTREE< SPBLK > *q)
Definition: sptree.h:730
void spinit(SPTREE< SPBLK > *q)
Definition: sptree.h:136
int enqcmps
Definition: sptree.h:49
SPBLK * root
Definition: sptree.h:41
static const char * errmess_
Definition: tqueue.cpp:20