NEURON
tqueue.cpp
Go to the documentation of this file.
1 #include <../../nrnconf.h>
2 
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <string.h>
6 #include <stdarg.h>
7 #include <section.h>
8 
9 #include "tqueue.hpp"
10 #include "pool.hpp"
11 
12 #define PROFILE 0
13 #include "profile.h"
14 
15 #define DOCHECK 0
16 
17 #if COLLECT_TQueue_STATISTICS
18 #define STAT(arg) ++arg;
19 #else
20 #define STAT(arg) /**/
21 #endif
22 
23 // splay tree + bin queue limited to fixed step method
24 // for event-sets or priority queues
25 // this starts from the sptqueue.cpp file and adds a bin queue
26 
27 /* Derived from David Brower's c translation of pascal code by
28 Douglas Jones.
29 */
30 /* The original c code is included from this file but note that instead
31 of struct _spblk, we are really using TQItem
32 */
33 
34 #define leftlink left_
35 #define rightlink right_
36 #define uplink parent_
37 #define cnt cnt_
38 #define key t_
39 #include <sptree.hpp>
40 
41 // extern double dt;
42 #define nt_dt nrn_threads->_dt
43 
45 
46 static void prnt(const TQItem* b, int level) {
47  int i;
48  for (i = 0; i < level; ++i) {
49  Printf(" ");
50  }
51  Printf("%g %c %d Q=%p D=%p\n",
52  b->t_,
53  b->data_ ? 'x' : 'o',
54  b->cnt_,
55  fmt::ptr(b),
56  fmt::ptr(b->data_));
57 }
58 
59 TQueue::TQueue(TQItemPool* tp, int mkmut) {
60  MUTCONSTRUCT(mkmut)
61  tpool_ = tp;
62  nshift_ = 0;
63  sptree_ = new SPTree<TQItem>();
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 = sptree_->dequeue()) != nullptr) {
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 (least_) {
94  prnt(least_, 0);
95  }
96  sptree_->apply_all(prnt, nullptr);
97  for (TQItem* q = binq_->first(); q; q = binq_->next(q)) {
98  prnt(q, 0);
99  }
100  MUTUNLOCK
101 }
102 
103 void TQueue::forall_callback(void (*f)(const TQItem*, int)) {
104  MUTLOCK
105  if (least_) {
106  f(least_, 0);
107  }
108  sptree_->apply_all(f, nullptr);
109  for (TQItem* q = binq_->first(); q; q = binq_->next(q)) {
110  f(q, 0);
111  }
112  MUTUNLOCK
113 }
114 
115 void TQueue::check(const char* mes) {}
116 
117 // for Parallel Global Variable Timestep method.
118 // Assume not using bin queue.
120  assert(least_);
121  TQItem* b = sptree_->first();
122  if (b && b->t_ == t) {
123  return b;
124  }
125  return nullptr;
126 }
127 
128 void TQueue::move_least(double tnew) {
129  MUTLOCK
130  move_least_nolock(tnew);
131  MUTUNLOCK
132 }
133 
134 void TQueue::move_least_nolock(double tnew) {
135  TQItem* b = least();
136  if (b) {
137  b->t_ = tnew;
138  TQItem* nl = sptree_->first();
139  if (nl) {
140  if (tnew > nl->t_) {
141  least_ = sptree_->dequeue();
142  sptree_->enqueue(b);
143  }
144  }
145  }
146 }
147 
148 void TQueue::move(TQItem* i, double tnew) {
149  MUTLOCK
150  STAT(nmove)
151  if (i == least_) {
152  move_least_nolock(tnew);
153  } else if (tnew < least_->t_) {
154  sptree_->remove(i);
155  i->t_ = tnew;
157  least_ = i;
158  } else {
159  sptree_->remove(i);
160  i->t_ = tnew;
161  sptree_->enqueue(i);
162  }
163  MUTUNLOCK
164 }
165 
167 #if COLLECT_TQueue_STATISTICS
168  Printf("insertions=%lu moves=%lu removals=%lu calls to least=%lu\n",
169  ninsert,
170  nmove,
171  nrem,
172  nleast);
173  Printf("calls to find=%lu\n", nfind);
174  Printf("comparisons=%d\n", sptree_->get_enqcmps());
175 #else
176  Printf("Turn on COLLECT_TQueue_STATISTICS_ in tqueue.hpp\n");
177 #endif
178 }
179 
180 void TQueue::spike_stat(double* d) {
181 #if COLLECT_TQueue_STATISTICS
182  d[0] = ninsert;
183  d[1] = nmove;
184  d[2] = nrem;
185 // printf("FifoQ spikestat nfenq=%lu nfdeq=%lu nfrem=%lu\n", fifo_->nfenq, fifo_->nfdeq,
186 // fifo_->nfrem);
187 #endif
188 }
189 
190 TQItem* TQueue::insert(double t, void* d) {
191  MUTLOCK
192  STAT(ninsert);
193  TQItem* i = tpool_->alloc();
194  i->data_ = d;
195  i->t_ = t;
196  i->cnt_ = -1;
197  if (t < least_t_nolock()) {
198  if (least()) {
199  sptree_->enqueue(least());
200  }
201  least_ = i;
202  } else {
203  sptree_->enqueue(i);
204  }
205  MUTUNLOCK
206  return i;
207 }
208 
209 TQItem* TQueue::enqueue_bin(double td, void* d) {
210  MUTLOCK
211  STAT(ninsert);
212  TQItem* i = tpool_->alloc();
213  i->data_ = d;
214  i->t_ = td;
215  binq_->enqueue(td, i);
216  MUTUNLOCK
217  return i;
218 }
219 
221  // if lockable then the pool is internally handles locking
222  tpool_->hpfree(q);
223 }
224 
226  MUTLOCK
227  STAT(nrem);
228  if (q) {
229  if (q == least_) {
230  if (!sptree_->empty()) {
231  least_ = sptree_->dequeue();
232  } else {
233  least_ = nullptr;
234  }
235  } else if (q->cnt_ >= 0) {
236  binq_->remove(q);
237  } else {
238  sptree_->remove(q);
239  }
240  tpool_->hpfree(q);
241  }
242  MUTUNLOCK
243 }
244 
246  TQItem* q = 0;
247  MUTLOCK
248  if (least_ && least_->t_ <= tt) {
249  q = least_;
250  STAT(nrem);
251  if (!sptree_->empty()) {
252  least_ = sptree_->dequeue();
253  } else {
254  least_ = nullptr;
255  }
256  }
257  MUTUNLOCK
258  return q;
259 }
260 
262  TQItem* q;
263  MUTLOCK
264  // search only in the splay tree. if this is a bug then fix it.
265  STAT(nfind)
266  if (t == least_t_nolock()) {
267  q = least();
268  } else {
269  q = sptree_->find(t);
270  }
271  MUTUNLOCK
272  return (q);
273 }
274 
276  nbin_ = 1000;
277  bins_ = new TQItem*[nbin_];
278  for (int i = 0; i < nbin_; ++i) {
279  bins_[i] = 0;
280  }
281  qpt_ = 0;
282  tt_ = 0.;
283 #if COLLECT_TQueue_STATISTICS
284  nfenq = nfdeq = nfrem = 0;
285 #endif
286 }
287 
289  for (int i = 0; i < nbin_; ++i) {
290  assert(!bins_[i]);
291  }
292  delete[] bins_;
293 }
294 
295 void BinQ::resize(int size) {
296  // printf("BinQ::resize from %d to %d\n", nbin_, size);
297  int i, j;
298  TQItem* q;
299  assert(size >= nbin_);
300  TQItem** bins = new TQItem*[size];
301  for (i = nbin_; i < size; ++i) {
302  bins[i] = 0;
303  }
304  for (i = 0, j = qpt_; i < nbin_; ++i, ++j) {
305  if (j >= nbin_) {
306  j = 0;
307  }
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_) {
334  idt -= nbin_;
335  }
336  // printf("enqueue idt=%d qpt=%d\n", idt, qpt_);
337  assert(idt < nbin_);
338  q->cnt_ = idt; // only for iteration
339  q->left_ = bins_[idt];
340  bins_[idt] = q;
341 #if COLLECT_TQueue_STATISTICS
342  ++nfenq;
343 #endif
344 }
346  TQItem* q = bins_[qpt_];
347  if (q) {
348  bins_[qpt_] = q->left_;
349 #if COLLECT_TQueue_STATISTICS
350  ++nfdeq;
351 #endif
352  }
353  return q;
354 }
355 
356 /** Iterate in ascending bin order starting at current bin **/
358  for (int i = 0; i < nbin_; ++i) {
359  // start at least time qpt_ up to nbin_, and then wrap
360  // around to 0 and go up to qpt_
361  int j = (qpt_ + i) % nbin_;
362  if (bins_[j]) {
363  return bins_[j];
364  }
365  }
366  return 0;
367 }
369  if (q->left_) {
370  return q->left_;
371  }
372  // next non-empty bin starting at q->cnt_ + 1, until reach
373  // exactly qpt_, possibly wrapping around back to 0 if reach nbin_
374  for (int i = (q->cnt_ + 1) % nbin_; i != qpt_; i = (i + 1) % nbin_) {
375  if (bins_[i]) {
376  return bins_[i];
377  }
378  }
379  return 0;
380 }
381 
383  TQItem *q1, *q2;
384  q1 = bins_[q->cnt_];
385  if (q1 == q) {
386  bins_[q->cnt_] = q->left_;
387  return;
388  }
389  for (q2 = q1->left_; q2; q1 = q2, q2 = q2->left_) {
390  if (q2 == q) {
391  q1->left_ = q->left_;
392  return;
393  }
394  }
395 }
396 
398  MUTCONSTRUCT(mkmut)
399  tpool_ = tp;
400  head_ = nullptr;
401 }
403  remove_all();
405 }
407  MUTLOCK
408  TQItem* q = tpool_->alloc();
409  q->left_ = nullptr;
410  q->right_ = head_;
411  if (head_) {
412  head_->left_ = q;
413  }
414  head_ = q;
415  q->data_ = d;
416  MUTUNLOCK
417  return q;
418 }
420  MUTLOCK
421  if (q->left_) {
422  q->left_->right_ = q->right_;
423  }
424  if (q->right_) {
425  q->right_->left_ = q->left_;
426  }
427  if (q == head_) {
428  head_ = q->right_;
429  }
430  tpool_->hpfree(q);
431  MUTUNLOCK
432  return q->data_;
433 }
435  MUTLOCK
436  for (TQItem* q = first(); q; q = next(q)) {
437  tpool_->hpfree(q);
438  }
439  head_ = nullptr;
440  MUTUNLOCK
441 }
Definition: tqueue.hpp:29
virtual ~BinQ()
Definition: tqueue.cpp:288
BinQ()
Definition: tqueue.cpp:275
void resize(int)
Definition: tqueue.cpp:295
int nfenq
Definition: tqueue.hpp:55
TQItem * next(TQItem *)
Definition: tqueue.cpp:368
double tt_
Definition: tqueue.hpp:58
TQItem * first()
Iterate in ascending bin order starting at current bin.
Definition: tqueue.cpp:357
int qpt_
Definition: tqueue.hpp:59
int nbin_
Definition: tqueue.hpp:59
int nfrem
Definition: tqueue.hpp:55
void enqueue(double tt, TQItem *)
Definition: tqueue.cpp:318
void remove(TQItem *)
Definition: tqueue.cpp:382
TQItem * dequeue()
Definition: tqueue.cpp:345
TQItem ** bins_
Definition: tqueue.hpp:60
int nfdeq
Definition: tqueue.hpp:55
T * alloc()
Definition: pool.hpp:89
void hpfree(T *)
Definition: pool.hpp:105
void apply_all(void(*f)(const T *, int), T *n) const
Definition: sptree.hpp:471
T * find(double key)
Definition: sptree.hpp:456
bool empty() const
Definition: sptree.hpp:124
void remove(T *n)
Definition: sptree.hpp:431
T * first()
Definition: sptree.hpp:413
void enqueue(T *n)
Definition: sptree.hpp:134
T * dequeue()
Definition: sptree.hpp:251
int get_enqcmps() const
Definition: sptree.hpp:129
TQItem * first()
Definition: tqueue.hpp:154
void remove_all()
Definition: tqueue.cpp:434
TQItem * head_
Definition: tqueue.hpp:162
void * remove(TQItem *)
Definition: tqueue.cpp:419
TQItemPool * tpool_
Definition: tqueue.hpp:163
virtual ~SelfQueue()
Definition: tqueue.cpp:402
TQItem * insert(void *)
Definition: tqueue.cpp:406
TQItem * next(TQItem *q)
Definition: tqueue.hpp:157
SelfQueue(TQItemPool *, int mkmut=0)
Definition: tqueue.cpp:397
void statistics()
Definition: tqueue.cpp:166
TQItem * second_least(double t)
Definition: tqueue.cpp:119
unsigned long nleastsrch
Definition: tqueue.hpp:143
void remove(TQItem *)
Definition: tqueue.cpp:225
TQItem * insert(double t, void *data)
Definition: tqueue.cpp:190
TQItem * enqueue_bin(double t, void *data)
Definition: tqueue.cpp:209
SPTree< TQItem > * sptree_
Definition: tqueue.hpp:136
void deleteitem(TQItem *)
Definition: tqueue.cpp:87
double least_t_nolock()
Definition: tqueue.hpp:128
MUTDEC unsigned long nleast
Definition: tqueue.hpp:142
MUTDEC unsigned long ncmplxrem
Definition: tqueue.hpp:142
void check(const char *errmess)
Definition: tqueue.cpp:115
TQItemPool * tpool_
Definition: tqueue.hpp:139
TQItem * least()
Definition: tqueue.hpp:68
void move(TQItem *, double tnew)
Definition: tqueue.cpp:148
unsigned long nmove
Definition: tqueue.hpp:143
void release(TQItem *)
Definition: tqueue.cpp:220
int nshift_
Definition: tqueue.hpp:119
void print()
Definition: tqueue.cpp:91
unsigned long nfastmove
Definition: tqueue.hpp:143
TQItem * atomic_dq(double til)
Definition: tqueue.cpp:245
TQItem * find(double t)
Definition: tqueue.cpp:261
MUTDEC unsigned long nrem
Definition: tqueue.hpp:142
unsigned long nfindsrch
Definition: tqueue.hpp:143
unsigned long ncompare
Definition: tqueue.hpp:143
MUTDEC unsigned long nbal
Definition: tqueue.hpp:142
BinQ * binq_
Definition: tqueue.hpp:137
MUTDEC unsigned long ninsert
Definition: tqueue.hpp:142
TQItem * least_
Definition: tqueue.hpp:138
unsigned long nfind
Definition: tqueue.hpp:143
void move_least_nolock(double tnew)
Definition: tqueue.cpp:134
virtual ~TQueue()
Definition: tqueue.cpp:73
void forall_callback(void(*)(const TQItem *, int))
Definition: tqueue.cpp:103
TQueue(TQItemPool *, int mkmut=0)
Definition: tqueue.cpp:59
void move_least(double tnew)
Definition: tqueue.cpp:128
void spike_stat(double *)
Definition: tqueue.cpp:180
#define i
Definition: md1redef.h:19
#define assert(ex)
Definition: hocassrt.h:24
void(* nrn_binq_enqueue_error_handler)(double, TQItem *)
Definition: tqueue.cpp:44
#define nt_dt
Definition: tqueue.cpp:42
static void prnt(const TQItem *b, int level)
Definition: tqueue.cpp:46
#define STAT(arg)
Definition: tqueue.cpp:18
size_t q
size_t j
#define MUTCONSTRUCT(mkmut)
Definition: nrnmutdec.h:33
#define MUTDESTRUCT
Definition: nrnmutdec.h:34
#define MUTLOCK
Definition: nrnmutdec.h:35
#define MUTUNLOCK
Definition: nrnmutdec.h:36
Definition: tqitem.hpp:3
double t_
Definition: tqitem.hpp:8
int cnt_
Definition: tqitem.hpp:12
void * data_
Definition: tqitem.hpp:7
TQItem * left_
Definition: tqitem.hpp:9
int Printf(const char *fmt, Args... args)
Definition: logger.hpp:18