SIMLIB/C++  3.07
calendar.cc
Go to the documentation of this file.
1 /////////////////////////////////////////////////////////////////////////////
2 //! \file calendar.cc Calendar queue implementation
3 //
4 // Copyright (c) 1991-2008 Petr Peringer
5 //
6 // This library is licensed under GNU Library GPL. See the file COPYING.
7 //
8 
9 /// Implementation of class CalendarList
10 /// <br> interface is static - using global functions in SQS namespace
11 ///
12 /// <br> uses double-linked list and dynamic calendar queue [brown1988]
13 //
14 // FIXME: Warning: experimental code, needs improvements
15 // TODO: improve interface
16 // TODO: reference-counting entities?
17 
18 ////////////////////////////////////////////////////////////////////////////
19 // interface
20 //
21 
22 #include "simlib.h"
23 #include "internal.h"
24 #include <cmath>
25 #include <cstring>
26 
27 //#define MEASURE // comment this to switch off
28 #ifdef MEASURE
29 
30 // this is for measuring performance of operations only
31 namespace {
32 #include "rdtsc.h" // RDTSC instruction on i586+ FIXME
33 
34 static unsigned long long T_MEASURE;
35 
36 inline void START_T() {
37  T_MEASURE = rdtsc();
38 }
39 
40 inline double STOP_T() {
41  T_MEASURE = rdtsc() - T_MEASURE;
42  // here can be unit conversion code
43  // iuse CPU clocks for now
44  return (double)T_MEASURE;
45 }
46 
47 enum {
48  OP_RESIZE=1,
49  OP_ESTIMATE=2,
50  OP_SWITCH2CQ=4,
51  OP_SWITCH2LIST=8,
52 };
53 int OP_MEASURE = 0;
54 
55 } // local namespace
56 #endif
57 
58 ////////////////////////////////////////////////////////////////////////////
59 // implementation
60 //
61 
62 namespace simlib3 {
63 
65 
66 /// common interface for all calendar (PES) implementations
67 class Calendar { // abstract base class
68  public:
69  bool Empty() const { return _size == 0; }
70  unsigned Size() const { return _size; }
71  /// enqueue
72  virtual void ScheduleAt(Entity *e, double t) = 0;
73  /// dequeue first
74  virtual Entity * GetFirst() = 0;
75  /// dequeue
76  virtual Entity * Get(Entity *e) = 0;
77  /// remove all scheduled entities
78  virtual void clear(bool destroy_entities=false) = 0;
79  virtual const char* Name() =0;
80 #ifndef NDEBUG
81  /// for debugging only
82  virtual void debug_print() = 0; // print the calendar contents
83 #endif
84  /// time of activation of first item
85  double MinTime() const { return mintime; }
86  protected:
87  /// set cache for faster access
88  void SetMinTime(double t) { mintime=t; }
89 
90  ///////////////////////////////////////////////////////////////////////////
91  // data
92  protected:
93  unsigned _size; //!< number of scheduled items
94  private:
95  double mintime; //!< activation time of first event
96  ///////////////////////////////////////////////////////////////////////////
97  // singleton:
98  public:
99  static Calendar * instance(); //!< create/get single instance (singleton)
100  /// check if the instance exists
101  static bool instance_exists() {
102  return _instance != 0;
103  }
104  protected:
105  Calendar(): _size(0), mintime(SIMLIB_MAXTIME) {}
106  virtual ~Calendar() {} //!< clear is called in derived class dtr
107  static void delete_instance(); //!< destroy single instance
108  private:
109  static Calendar * _instance; //!< pointer to single instance
110  ///////////////////////////////////////////////////////////////////////////
111  friend void SetCalendar(const char *name); // sets _instance
112 };
113 
114 /////////////////////////////////////////////////////////////////////////////
115 /// calendar item - PRIVATE for any implementation
116 /// <br> we use double-linked circular list
117 struct EventNoticeLinkBase { // base class with list pointers only
118  // used as list head in CalendarList and as part of list items
119  EventNoticeLinkBase * pred; //!< previous object in list
120  EventNoticeLinkBase * succ; //!< next object in list
121 
122  EventNoticeLinkBase() : pred(this), succ(this) {}
123 
124  /// remove from calendar list
125  void remove() {
126  pred->succ = succ;
127  succ->pred = pred;
128  pred = succ = this; // NOT linked
129  }
130 
131  /// insert at position p
133  // todo: move this test (it is not needed always)
134  if(pred != this)
135  remove(); // is in calendar, remove first
136  // --- insert before item s
137  succ = p;
138  pred = p->pred;
139  pred->succ = this;
140  p->pred = this;
141  }
142 };
143 
144 /// activation record
146  /// which entity is scheduled
148  /// activation time of entity
149  double time;
150  /// priority at the time of scheduling
152 
153  EventNotice(Entity *p, double t) :
154  //inherited: pred(this), succ(this), // == NOT linked
155  entity(p), // which entity
156  time(t), // activation time
157  priority(p->Priority) // current scheduling priority
158  {
159  create_reverse_link();
160  }
161 
162  /// create link from entity to activation record
164  entity->_evn = this; // reverse link to this activation record
165  }
166  /// delete link from entity to activation record
168  entity->_evn = 0; // unlink reverse link
169  }
170 
172  if(pred != this) {
173  remove(); // remove from calendar
174  delete_reverse_link();
175  }
176  }
177 
178  /// set new values to existing (unlinked) record
179  void Set(Entity *e, double t) {
180  pred=succ=this;
181  entity = e; // which entity
182  time = t; // activation time
183  priority = e->Priority; // current scheduling priority
184  create_reverse_link();
185  }
186 
187  static EventNotice *Create(Entity *p, double t);
188  static void Destroy(EventNotice *en);
189 
190  private:
191  EventNotice(const EventNotice&); // disable
192  EventNotice &operator=(const EventNotice&);
193 };
194 
195 
196 // TODO: update interface to be compatible with std:: allocators
197 /// allocate activation records fast
198 // TODO: use std::list
200  static const unsigned MAXSIZELIMIT = 1000000;
201  EventNoticeLinkBase *l; // single-linked list of freed items
202  unsigned freed;
203  public:
204  EventNoticeAllocator(): l(0), freed(0) {}
206  clear(); // delete freelist
207  }
208 
209  /// free EventNotice, add to freelist for future allocation
210  void free(EventNotice *en) {
211  if(en->pred!=en) { // if scheduled
212  en->remove(); // unlink from calendar list
213  en->delete_reverse_link();
214  }
215  if(freed>MAXSIZELIMIT) // limit the size of freelist
216  delete en;
217  else {
218  // add to freelist
219  en->succ=l;
220  l=en;
221  freed++;
222  }
223  }
224  /// EventNotice allocation or reuse from freelist
225  EventNotice *alloc(Entity *p, double t) {
226  if(l==0)
227  return new EventNotice(p, t);
228  else {
229  // get from freelist
230  freed--;
231  EventNotice *ptr = static_cast<EventNotice *>(l);
232  l = l->succ;
233  ptr->Set(p,t);
234  return ptr;
235  }
236  }
237  /// clear: delete all free-list items
238  void clear() {
239  while(l!=0) {
240  EventNotice *p = static_cast<EventNotice*>(l);
241  l=l->succ;
242  delete p;
243  }
244  }
245 } allocator; // global allocator TODO: improve -> singleton
246 
247 
248 
249 ////////////////////////////////////////////////////////////////////////////
250 /// class CalendarListImplementation --- sorted list
251 // +-----------------------------------------------------+
252 // | +---+ +---+ +---+ |
253 // +-->| |<-- ............ -->| |<---->| |<--+
254 // +--+---+---------------------+ +---+ +---+
255 // | CalendarListImplementation | |EvN| |EvN|
256 // +----------------------------+ +---+ +---+
257 // double-linked circular list (should be faster than std::list)
258 // items sorted by: 1) time
259 // 2) priority
260 // 3) FIFO
261 //
262 // no checking
263 //
265  EventNoticeLinkBase l; //!< head of circular list
266  public:
267  class iterator { //!< bidirectional iterator
269  public:
270  iterator(EventNoticeLinkBase *pos) : p(pos) {}
271  // prefix version only
272  iterator &operator++() { p = p->succ; return *this; }
273  iterator &operator--() { p = p->pred; return *this; }
274  // implicit operator= and copy constructor are OK
276  // access to activation record
277  return static_cast<EventNotice *>(p);
278  }
279  bool operator != (iterator q) { return p!=q.p; }
280  bool operator == (iterator q) { return p==q.p; }
281  }; // iterator
282  iterator begin() { return l.succ; }
283  iterator end() { return &l; }
284  bool empty() { return begin() == end(); }
285  ///////////////////////////////////////////////////////////
286 
287  double first_time() { return (*begin())->time; }
288  EventNotice *first() { return *begin(); }
289 
290 private:
291  /// search --- linear search for insert position
293  if(empty())
294  return end();
295  double t = en->time;
296  iterator evn = --end(); // search from back
297  while(evn!=end() && (*evn)->time > t) { // search time
298  --evn;
299  }
300  Entity::Priority_t prio = en->priority;
301  while(evn!=end() && (*evn)->time==t && // equal time...
302  (*evn)->priority < prio) { // ...search priority
303  --evn;
304  }
305  ++evn;
306  return evn; // return insert position or end()
307  }
308 
309 public:
310  /// enqueue operation
311  void insert(Entity *e, double t) {
312  EventNotice *evn = EventNotice::Create(e,t);
313  iterator pos = search(evn);
314  evn->insert(*pos); // insert before pos
315  }
316 
317  /// special dequeue operation for rescheduling
318  Entity *remove(Entity *e) {
319  EventNotice::Destroy(e->GetEventNotice()); // disconnect, remove item
320  return e;
321  }
322 
323  /// dequeue operation
325  Entity *e = first()->entity;
326  EventNotice::Destroy(first()); // disconnect, remove item
327  return e;
328  }
329 
331  /// remove all items
332  /// @param destroy deallocates entities if true
333  void clear(bool destroy) {
334  while (!empty()) {
335  Entity *e = remove_first();
336  if (destroy && e->isAllocated()) delete e; // delete entity
337  }
338  }
340  clear(true);
341  allocator.clear(); // clear freelist
342  }
343 #ifndef NDEBUG
344  /// print of calendar contents - FOR DEBUGGING ONLY
345  void debug_print();
346 #endif
347 
348  /// fast special operations for list swap (Dangerous!):
350  EventNotice *en = first();
351  en->remove(); // disconnect only, no other changes
352  return en;
353  }
354  /// fast special enqueue operation
356  iterator pos = search(evn);
357  evn->insert(*pos); // insert before pos
358  }
359 };
360 
361 ////////////////////////////////////////////////////////////////////////////
362 /// class CalendarList --- list implementation of calendar
363 //
364 class CalendarList : public Calendar {
366  public:
367  /// enqueue
368  virtual void ScheduleAt(Entity *p, double t) override;
369 
370  /// dequeue
371  virtual Entity *Get(Entity *p) override; // remove process p from calendar
372  /// dequeue first entity
373  virtual Entity *GetFirst() override;
374  /// remove all
375  virtual void clear(bool destroy=false) override; // remove/destroy all items
376 
377  /// create calendar instance
378  // TODO: we need this only if calendar use is allowed before Init()
379  static CalendarList * create() { // create instance
380  Dprintf(("CalendarList::create()"));
381  CalendarList *cal = new CalendarList;
382  SIMLIB_atexit(delete_instance); // last SIMLIB module cleanup calls it
383  //else SIMLIB_error(DuplicateCalendar);
384  return cal;
385  }
386  virtual const char* Name() override { return "CalendarList"; }
387 
388  private:
390  Dprintf(("CalendarList::CalendarList()"));
391  SetMinTime( SIMLIB_MAXTIME ); // empty
392  }
394  Dprintf(("CalendarList::~CalendarList()"));
395  clear(true);
396  }
397 
398 public:
399 #ifndef NDEBUG
400  virtual void debug_print() override; // print of calendar contents - FOR DEBUGGING ONLY
401 #endif
402 };
403 
404 
405 ////////////////////////////////////////////////////////////////////////////
406 // CalendarList implementation
407 //
408 
409 
410 
411 ////////////////////////////////////////////////////////////////////////////
412 /// creates new EventNotice,
414 {
415  EventNotice *evn = e->GetEventNotice();
416 
417  if(evn) { // Entity is scheduled already --- REUSE EventNotice
418  evn->remove(); // remove from calendar list, should stay connected
419  evn->time = t; // change activation time
420  evn->priority = e->Priority; // use current scheduling priority
421 // Dprintf(("EventNotice::Create(entity=%p, time=%g, [priority=%d]): %p [RECYCLED]",
422 // evn->entity, evn->time, evn->priority, this));
423  }
424  else {
425  evn = allocator.alloc(e,t);
426 // Dprintf(("EventNotice::Create(entity=%p, time=%g, [priority=%d]): %p [NEW]",
427 // evn->entity, evn->time, evn->priority, this));
428  }
429  return evn;
430 }
431 
432 ////////////////////////////////////////////////////////////////////////////
433 /// delete EventNotice, if inserted in calendar remove it first
434 //
436 {
437  allocator.free(en); // disconnect, remove item
438 }
439 
440 ////////////////////////////////////////////////////////////////////////////
441 /// schedule entity e at time t
443 {
444 // Dprintf(("CalendarList::ScheduleAt(%s,%g)", e->Name().c_str(), t));
445  if(t<Time)
447  l.insert(e,t);
448  ++_size;
449  // update mintime:
450  if(t < MinTime())
451  SetMinTime(l.first_time());
452 }
453 
454 ////////////////////////////////////////////////////////////////////////////
455 /// delete first entity
457 {
458 // Dprintf(("CalendarList::GetFirst(): size=%u", Size()));
459 
460  if(Empty())
462 
463  Entity *e = l.remove_first();
464  --_size;
465 
466  if(Empty())
468  else
469  SetMinTime(l.first_time());
470  return e;
471 }
472 
473 ////////////////////////////////////////////////////////////////////////////
474 /// remove entity e from calendar
476 {
477 // Dprintf(("CalendarList::Get(e=%s): size=%u",e->Name().c_str(), Size()));
478 
479  if(Empty())
480  SIMLIB_error(EmptyCalendar); // internal --> TODO:remove
481  if(e->Idle())
483 
484  l.remove(e);
485  --_size;
486 
487  if(Empty())
489  else
490  SetMinTime(l.first_time());
491  return e;
492 }
493 
494 ////////////////////////////////////////////////////////////////////////////
495 /// remove all event notices, and optionally destroy them
496 //
497 // FIXME: TODO analyze possible problems with call in destructor
498 //
499 void CalendarList::clear(bool destroy)
500 {
501  Dprintf(("CalendarList::clear(destroy=%s)", destroy?"true":"false"));
502  l.clear(destroy);
503  _size = 0;
505 }
506 
507 
508 
509 
510 
511 
512 
513 
514 
515 
516 
517 
518 
519 
520 
521 
522 
523 
524 
525 
526 
527 
528 
529 
530 
531 /////////////////////////////////////////////////////////////////////////////
532 // CalendarQueue tunable parameters:
533 
534 // when to switch from list to calendar queue
535 const unsigned LIST_MAX = 512; // TODO:tune parameter: 64-1024
536 const unsigned MINBUCKETS = LIST_MAX>4?LIST_MAX:4; // should be power of 2 and >=4
537 const unsigned LIST_MIN = LIST_MAX/2; // TODO:tune parameter
538 
539 // average bucket list length
540 const double COEF_PAR = 1.5; // TODO:tune parameter: cca 1.5
541 
542 // bucket width = MUL_PAR * average delta t
543 const double MUL_PAR = 1.0; // TODO:tune parameter: 1.0--5.0
544 
545 ////////////////////////////////////////////////////////////////////////////
546 /// CQ implementation of calendar
547 class CalendarQueue : public Calendar {
549  BucketList *buckets; // bucket array
550  BucketList list; // list for small number of items
551  unsigned nbuckets; // current number of buckets
552  unsigned hi_bucket_mark; // high bucket threshold for resize
553  unsigned low_bucket_mark; // low bucket threshold for resize
554  unsigned nextbucket; // next bucket to check for first item
555 
556  unsigned numop; // number of operations performed from last tuning
557  double bucket_width; // parameter: width of each bucket
558  double buckettop; // top time of current bucket
559  double last_dequeue_time; // for deleta computation
560  double sumdelta; // sum for bucket_width estimation
561  unsigned ndelta; // count
562 
563  private:
564  bool list_impl() { return buckets==NULL; }
565 
566  /// Convert time to bucket number
567  inline int time2bucket (double t) {
568  return static_cast<int>(fmod(t/bucket_width, static_cast<double>(nbuckets)));
569  }
570 
571  /// Compute bucket top limit
572  // the *1.5 is good for bucket number >= 3
573  // XXXX++++++--XXXX X = time can be in bucket 1
574  // 1111222233331111
575  inline double time2bucket_top(double t) {
576  return t + 1.5*bucket_width;
577  }
578 
579  double estimate_bucket_width();
580  void switchtocq();
581  void switchtolist();
582 
583  public:
584  /// enqueue
585  virtual void ScheduleAt(Entity *p, double t) override;
586 
587  /// dequeue
588  virtual Entity *Get(Entity *p) override; // remove process p from calendar
589  /// dequeue first
590  virtual Entity *GetFirst() override;
591  /// remove all
592  virtual void clear(bool destroy=false) override; // remove/destroy all items
593 
594  /// create calendar instance
595  // TODO: we need this only if calendar use is allowed before Init()
596  static CalendarQueue * create() { // create instance
597  Dprintf(("CalendarQueue::create()"));
598  CalendarQueue *l = new CalendarQueue;
599  SIMLIB_atexit(delete_instance); // last SIMLIB module cleanup calls it
600  //TODO:SIMLIB_error(DuplicateCalendar);
601  return l;
602  }
603 
604  virtual const char* Name() override { return "CalendarQueue"; }
605  private:
606  CalendarQueue();
607  ~CalendarQueue();
608 
609  void Resize(int grow=0); // grow/shrink operation
610  void SearchMinTime(double starttime); // search for new minimum
611 
612 public:
613 #ifndef NDEBUG
614  virtual void debug_print() override; // print of calendar contents - FOR DEBUGGING ONLY
615  void visualize(const char *msg);
616 #endif
617 }; // CalendarQueue
618 
619 
620 // TODO: tune this parameter
621 #define MAX_OP (Size()/2)
622 
623 /////////////////////////////////////////////////////////////////////////////
624 /// Initialize calendar queue
626  buckets(0), // ptr to bucketarray
627  nbuckets(0), // number of buckets
628 
629  hi_bucket_mark(0), // high bucket threshold
630  low_bucket_mark(0), // low bucket threshold
631 
632  nextbucket(0), // next bucket to check
633  numop(0), // number of operations from last tuning
634  bucket_width(0.0), // width of each bucket
635  buckettop(0.0), // high time limit of current bucket
636  last_dequeue_time(-1.0),
637  sumdelta(0.0), ndelta(0) // statistics
638 {
639  Dprintf(("CalendarQueue::CalendarQueue()"));
640  SetMinTime( SIMLIB_MAXTIME ); // empty
641  // init: Allocate initial buckets
642  // Resize();
643 }
644 
645 /// schedule
647 {
648  Dprintf(("CalendarQueue::ScheduleAt(%s,%g)", e->Name().c_str(), t));
649  if(t<Time)
651 
652  // if overgrown
653  if(_size>LIST_MAX && list_impl())
654  switchtocq();
655 
656  if(list_impl()) {
657  // insert at right position
658  list.insert(e,t);
659  }
660  else {
661  // if too many items, resize bucket array
662  if(_size + 1 > hi_bucket_mark)
663  Resize(+1);
664 
665  if(++numop > MAX_OP) // tune each MAX_OP edit operations
666  Resize();
667 
668  // select bucket
669  BucketList &bp = buckets[time2bucket(t)];
670  // insert at right position
671  bp.insert(e,t);
672  }
673  ++_size;
674  // update mintime
675  if (MinTime() > t) {
676  SetMinTime(t);
677  }
678 }
679 
680 
681 ////////////////////////////////////////////////////////////////////////////
682 /// dequeue
684 {
685 // Dprintf(("CalendarQueue::GetFirst()"));
686  if(Empty())
688 
689  if(_size<LIST_MIN && !list_impl())
690  switchtolist();
691 
692  if(list_impl()) {
693  Entity * e = list.remove_first();
694  // update size
695  --_size;
696  if(Empty())
698  else
700  return e;
701  }
702 
703  // else
704 
705  // get statistics for tuning
706  double min_time = MinTime();
707  if(last_dequeue_time >= 0.0) {
708  double diff = min_time - last_dequeue_time;
709  if(diff>0.0) {
710  sumdelta += diff;
711  ndelta++;
712  }
713  }
714  last_dequeue_time=min_time;
715 
716  // select bucket
717  nextbucket = time2bucket(min_time); // TODO: optimization
718  BucketList & bp = buckets[nextbucket];
719  // get first item
720  Entity * e = bp.remove_first();
721  // update size
722  --_size;
723  if (_size < low_bucket_mark)
724  Resize(-1);
725  if(++numop > MAX_OP)
726  Resize();
727  // update mintime
729  return e;
730 }
731 
732 ////////////////////////////////////////////////////////////////////////////
733 /// remove entity e from calendar
734 /// <br>called only if rescheduling
736 {
737 // Dprintf(("CalendarQueue::Get(e=%s)",e->Name().c_str()));
738  if(Empty())
739  SIMLIB_error(EmptyCalendar); // internal use only --> TODO:remove
740  if(e->Idle ())
742 
743  if(_size<LIST_MIN && !list_impl())
744  switchtolist();
745 
746  if(list_impl()) {
747  list.remove(e);
748  // update size
749  --_size;
750  // update mintime
751  if(Empty())
753  else
755  return e;
756  }
757 
758  // else
759 
760  // TODO: Get statistics!
761 
762  double t = e->ActivationTime();
763  unsigned b = time2bucket(t);
764  BucketList & bp = buckets[b];
765  bp.remove(e);
766  // update size
767  --_size;
768  if (_size < low_bucket_mark) // should be resized
769  Resize(-1);
770  if(++numop > MAX_OP)
771  Resize();
772  // update mintime
773  if(t==MinTime()) // maybe first item removed - update mintime
774  SearchMinTime(t);
775  return e;
776 }
777 
778 /////////////////////////////////////////////////////////////////////////////
779 /// compute new mintime
780 // TODO: compute dequeue price here
781 //
782 void CalendarQueue::SearchMinTime (double starttime)
783 {
784  if(Empty()) {
786  return;
787  }
788 
789  // search for minimum from starttime
790  double tmpmin=SIMLIB_MAXTIME;
791 // unsigned tmpnextbucket = 0;
792 
793  nextbucket = time2bucket(starttime);
794  buckettop = time2bucket_top(starttime);
795 
796  // search buckets
797  for (int n__ = nbuckets; n__ > 0; --n__) { // n__ is not used
798  BucketList & bp = buckets[nextbucket];
799  if (!bp.empty()) {
800  // check first item in bucket
801  double t = bp.first_time();
802  if (t < buckettop) { // time is in this "year"
803  // debug only -- TODO: leave out after tests
804  if (t < starttime) SIMLIB_error("CalendarQueue implementation error in SearchMinTime");
805  // first item is OK
806  SetMinTime(t);
807  return;
808  }
809  // search minimum time of all buckets for fallback
810  if (t < tmpmin) {
811  tmpmin = t;
812 // tmpnextbucket = nextbucket;
813  }
814  }
815 
816  // go to next bucket (modulo nbuckets)
817  // TODO: can be optimized if nbuckets is power of 2
818  ++nextbucket;
819  if (nextbucket == nbuckets)
820  nextbucket = 0;
822  }
823 
824  // all buckets checked and none record found in current "year"
825  // we use tmpmin
826  // (happens when the queued times are sparse)
827 
828  SetMinTime(tmpmin);
829 // nextbucket = tmpnextbucket;
830 // buckettop = time2bucket_top (mintime);
831 
832 }
833 
834 /////////////////////////////////////////////////////////////////////////////
835 /// compute new bucket width --- EXPERIMENTAL
836 //
838  Dprintf(("Calendar bucket width estimation:"));
839 #ifdef MEASURE
840  OP_MEASURE |= OP_ESTIMATE;
841 #endif
842  if(ndelta>10 && sumdelta>0) { // do not use bad statistics
843  double bu_width = MUL_PAR * sumdelta/ndelta;
844  Dprintf((" estm1: %g", bu_width));
845  if(bu_width < 1e-12*MinTime())
846  SIMLIB_error("CalendarQueue:e1 bucketwidth < 1e-12*Time -- total loss of precision");
847  return bu_width;
848  }
849 
850 // =========================== EXPERIMENTAL CODE ========================
851  // no past statistics - use future events
852  const unsigned LIMIT = nbuckets>1000?1000:nbuckets; // limit # of intervals skipped (cca 1 "year")
853  double last_time = MinTime();
854  unsigned count=0; // number of non-zero intervals
855 
856 for(int a__ = 0; a__<2; ++a__) {
857  double tmpmin = SIMLIB_MAXTIME;
858  unsigned next_bucket = time2bucket(last_time);
859  double bucket_top = time2bucket_top(last_time);
860  // search all buckets
861  for (int n__ = nbuckets; n__ > 0; --n__) { // n__ is not used
862  BucketList & bp = buckets[next_bucket];
863  // check items in bucket
864  for(BucketList::iterator i=bp.begin(); i != bp.end(); ++i) {
865  double t=(*i)->time;
866  if (t > bucket_top||t < last_time) { // time is NOT in this "year"
867  // search minimum time of next years
868  if (t < tmpmin)
869  tmpmin = t;
870  break;
871  }
872  double diff = t - last_time;
873  if(diff>0.0) {
874  ++count;
875  }
876  last_time=t;
877  if(count>LIMIT) break;
878  }
879  if(count>LIMIT) break;
880  // go to next bucket (modulo nbuckets)
881  // TODO: can be optimized if nbuckets is power of 2
882  ++next_bucket;
883  if (next_bucket == nbuckets)
884  next_bucket = 0;
885  bucket_top += bucket_width;
886  }
887 
888  if(count>10) {
889  double avg = (last_time-MinTime())/count;
890  Dprintf((" estm2: avg=%g", avg));
891  double bu_width = MUL_PAR * avg;
892  if(bu_width < 1e-12*MinTime())
893  SIMLIB_error("CalendarQueue:e2 bucketwidth < 1e-12*Time -- total loss of precision");
894  return bu_width;
895  }
896 
897  if(tmpmin < SIMLIB_MAXTIME) {
898  Dprintf((" estm3: next tmpmin=%g", tmpmin));
899  last_time = tmpmin;
900  continue; // scan next year
901  } else
902  break;
903 } // for ==================================================
904 
905  // should (almost) never be reached
906  // we have problem - bad calendar structure
907  // TODO
908  return 1.0;
909 }
910 
911 /////////////////////////////////////////////////////////////////////////////
912 /// Resize bucket array
913 // - parameter:
914 // grow > 0 grow
915 // grow == 0 update bucket_width, init
916 // grow < 0 shrink
917 // - does not change mintime !
918 //
919 // PROBLEM: TODO: too high-cost for 512-256-128 resize down !
920 void CalendarQueue::Resize(int grow) // TODO: is it better to use target size?
921 {
922 
923  // visualize("before Resize");
924 #ifdef MEASURE
925  OP_MEASURE |= OP_RESIZE;
926 #endif
927 
928  // first tune bucket_width
929  bool bucket_width_changed = false;
930  numop=0; // number of operations from last tuning/checking
931  // test/change bucket_width
932  double new_bucket_width = estimate_bucket_width();
933  // TODO: 1.3/0.7 -- this needs improvement
934  if(new_bucket_width>1.3*bucket_width || new_bucket_width<0.7*bucket_width) {
935  bucket_width = new_bucket_width;
936  bucket_width_changed = true;
937  }
938 
939  // save old contents
940  unsigned oldnbuckets = nbuckets;
941  BucketList *oldbuckets = buckets;
942 
943  // change nbuckets
944  if (grow>0)
945  nbuckets = oldnbuckets * 2;
946  if (grow<0)
947  nbuckets = oldnbuckets / 2;
948 
949  // check low limit
950  if(nbuckets < MINBUCKETS)
951  nbuckets = MINBUCKETS; // minimal number of buckets is 4
952 
953 // TODO: switch to list if <LOWLIMIT
954 // switch to calqueue if >HIGHLIMIT
955 
956  Dprintf(("Calendar resize: nbuckets=%d->%d", oldnbuckets, nbuckets));
957  // nbuckets is a power of 2
958 
959  if(oldnbuckets == nbuckets && !bucket_width_changed) // no change
960  return;
961 
962  // allocate new bucket array
963  buckets = new BucketList[nbuckets]; // initialized by default constructors
964 
965  // TODO: search optimal PARAMETERS
966  hi_bucket_mark = static_cast<unsigned>(nbuckets * COEF_PAR); // cca 1.5 TODO: benchmarking
967  low_bucket_mark = (nbuckets / 2) - 2;
968 
969  // if initialization only, we can stop here
970  if (oldbuckets == NULL)
971  return;
972 
973  // move old contents into new bucket array
974  _size = 0;
975  for (unsigned n = 0; n < oldnbuckets; ++n) {
976  BucketList &oldbp = oldbuckets[n];
977  while(!oldbp.empty()) {
978  // extract EventNotice from old bucket
979  EventNotice * en = oldbp.extract_first(); // no change of e,t,p
980  // select new bucket
981  BucketList &bp = buckets[time2bucket(en->time)];
982  // insert EventNotice at right position
983  bp.insert_extracted(en);
984  ++_size;
985  }
986  }
987  delete [] oldbuckets; // all are empty
988 
989 } // Resize
990 
991 
992 /// switch to list implementation
994 {
995  // _size, _mintime does not change
996  // assert (buckets != NULL);
997  // assert list.empty()
998 #ifdef MEASURE
999  OP_MEASURE |= OP_SWITCH2LIST;
1000 #endif
1001 
1002  // fill list from CQ
1003  for (unsigned n = 0; n < nbuckets; ++n) {
1004  BucketList &oldbp = buckets[n];
1005  while(!oldbp.empty()) {
1006  // extract EventNotice from old bucket
1007  EventNotice * en = oldbp.extract_first(); // no change of e,t,p
1008  // insert EventNotice at right position
1009  list.insert_extracted(en); // list is short
1010  }
1011  }
1012  delete [] buckets; // all are empty
1013  buckets = NULL;
1014  nbuckets = 0;
1015 
1016  // visualize("after switchtolist");
1017 } // switch2list
1018 
1019 /// switch to calendar queue implementation
1021 {
1022  // first some initialization:
1023 #ifdef MEASURE
1024  OP_MEASURE |= OP_SWITCH2CQ;
1025 #endif
1026 
1027  // _size does not change
1028  // MinTime unchanged
1029  // assert (buckets == NULL);
1030 
1031  // nit CQ statistics:
1032  last_dequeue_time = -1.0;
1033  sumdelta = 0.0;
1034  ndelta = 0;
1035 
1036  numop=0; // number of operations from last tuning/checking
1037 
1038  // compute bucket_width
1040  double t0=(*i)->time; // mintime
1041  unsigned count = 0;
1042  for(unsigned n=0; i!=list.end() && n<100; ++i, ++n) {
1043  double t1=(*i)->time;
1044  if(t1==t0) continue;
1045  t0 = t1;
1046  ++count;
1047  }
1048  if(count > 5) {
1049  double avg = (t0-MinTime())/count;
1050  bucket_width = MUL_PAR * avg;
1051  } else
1052  bucket_width = 1.0; // TODO: ?
1053 
1054  // assert
1055  if(bucket_width < 1e-12*MinTime())
1056  SIMLIB_warning("CalendarQueue:switchtocq bucketwidth<1e-12*Time = loss of precision");
1057 
1058  // search for first power of 2 greater than size
1059  for(nbuckets=4; nbuckets<_size; nbuckets<<=1) { /*empty*/ }
1060  // assert: nbuckets is power of 2
1061 
1062  // allocate new bucket array
1063  buckets = new BucketList[nbuckets]; // initialized by default constructors
1064 
1065  // TODO: search optimal PARAMETERS
1066  hi_bucket_mark = static_cast<unsigned>(nbuckets * COEF_PAR); // cca 1.5 TODO: benchmarking
1067  low_bucket_mark = (nbuckets / 2) - 2;
1068 
1069  // move list contents into new bucket array
1070  while(!list.empty()) {
1071  // extract EventNotice from list
1072  EventNotice * en = list.extract_first(); // no change of e,t,p
1073  // select new bucket
1074  BucketList &bp = buckets[time2bucket(en->time)];
1075  // insert EventNotice at right position
1076  bp.insert_extracted(en);
1077  }
1078 
1079  // visualize("after switchtocq");
1080 } // switch2cq
1081 
1082 
1083 /////////////////////////////////////////////////////////////////////////////
1084 /// clear calendar queue
1085 //
1086 // DIFFERENCE from simple list implementation:
1087 // - order of entity destruction is different
1088 //
1089 void CalendarQueue::clear(bool destroy)
1090 {
1091  Dprintf(("CalendarQueue::clear(%s)",destroy?"true":"false"));
1092  // clear non-empty calendar
1093  if(!Empty()) {
1094  if(list_impl())
1095  list.clear(destroy);
1096  else
1097  // empty all buckets
1098  for(unsigned i=0; i<nbuckets; i++)
1099  buckets[i].clear(destroy);
1100  _size = 0;
1101  }
1102  // delete bucketarray
1103  delete [] buckets;
1104  buckets = NULL;
1105  nbuckets = 0;
1106  //
1107  // re-initialize
1108  // statistics:
1109  last_dequeue_time = -1.0;
1110  sumdelta = 0.0;
1111  ndelta = 0;
1112 
1113  numop = 0; // for tuning
1114 
1115  // list implementation is active now.
1117 }
1118 
1119 /////////////////////////////////////////////////////////////////////////////
1120 /// Destroy calendar queue
1122 {
1123  Dprintf(("CalendarQueue::~CalendarQueue()"));
1124  clear(true);
1125  allocator.clear(); // clear freelist
1126 }
1127 
1128 
1129 /////////////////////////////////////////////////////////////////////////////
1130 /////////////////////////////////////////////////////////////////////////////
1131 /////////////////////////////////////////////////////////////////////////////
1132 
1133 
1134 #ifndef NDEBUG
1135 ////////////////////////////////////////////////////////////////////////////
1136 void CalendarListImplementation::debug_print() // print of list contents
1137 {
1138  int n=0;
1139  for(iterator i = begin(); i!=end(); ++i) {
1140  Print(" [%03u]:", ++n ); // order
1141  Print("\t %s", (*i)->entity->Name().c_str() ); // print entity ID
1142  Print("\t at=%g", (*i)->time ); // schedule time
1143  Print("\n");
1144  }
1145  if(n==0)
1146  Print(" <empty>\n");
1147 }
1148 ////////////////////////////////////////////////////////////////////////////
1149 void CalendarList::debug_print() // print of calendar contents
1150 {
1151  Print("CalendarList:\n");
1153  l.debug_print();
1154  Print("\n");
1155 }
1156 ////////////////////////////////////////////////////////////////////////////
1157 void CalendarQueue::debug_print() // print of calendar queue contents
1158 {
1159  Print("CalendarQueue:\n");
1161  for(unsigned i=0; i<nbuckets; i++) {
1162  Print(" bucket#%03u:\n", i);
1163  buckets[i].debug_print();
1164  Print("\n");
1165  }
1166  Print("\n");
1167 }
1168 ////////////////////////////////////////////////////////////////////////////
1169 /// CalendarQueue::visualize -- output suitable for Gnuplot
1170 void CalendarQueue::visualize(const char *msg)
1171 {
1172  Print("# CalendarQueue::visualize %s\n",msg);
1173  if(list_impl())
1174  Print("# size=%u, mintime=%g (list)\n", Size(), MinTime());
1175  else
1176  Print("# size=%u, nbuckets=%d, mintime=%g, operations=%u, bucket_width=%g\n",
1178  if(Empty()) return;
1179  for(unsigned b=0; b<nbuckets; b++) {
1180  BucketList &bl = buckets[b];
1181  unsigned cnt=0;
1182  Print("%d:", b );
1183  for(BucketList::iterator i = bl.begin(); i!=bl.end(); ++i) {
1184  //Print("%g %d\n", (*i)->time, b ); // schedule time
1185  Print(" %g", (*i)->time ); // schedule time
1186  cnt++;
1187  }
1188  Print("\n");
1189  //if(cnt>0) Print("#[%u].len = %u\n", b, cnt );
1190  }
1191  Print("\n");
1192 }
1193 ////////////////////////////////////////////////////////////////////////////
1194 #endif
1195 
1196 
1197 
1198 ////////////////////////////////////////////////////////////////////////////
1199 
1200 /// static pointer to singleton instance
1202 
1203 /// interface to singleton instance
1205  if(_instance==0) {
1206 #if 1 // choose default
1207  _instance = CalendarList::create(); // create default calendar
1208 #else
1209  _instance = CalendarQueue::create(); // create default calendar
1210 #endif
1211  }
1212  return _instance;
1213 }
1214 
1215 /// destroy single instance
1217  Dprintf(("Calendar::delete_instance()"));
1218  if(_instance) {
1219  delete _instance; // remove all, free
1220  _instance = 0;
1221  }
1222 }
1223 
1224 
1225 #if 0
1226 class Calendars {
1227  typedef Calendar * (*create_fun_ptr_t)();
1228  std::map<string, create_fun_ptr_t> record;
1229  Calendars() {}
1230  Register(create_fun_ptr_t f, const char *name) {
1231  string n(name);
1232  for(string::iterator i=n.begin(); i!=n.end(); ++i)
1233  *i = std::tolower(*i);
1234  record[n] = f;
1235  }
1236  Calendar *create(const char *name) {
1237  string n(name);
1238  for(string::iterator i=n.begin(); i!=n.end(); ++i)
1239  *i = std::tolower(*i);
1240  if(record.count(n)==0) // not present
1241  SIMLIB_error("Bad calendar type name");
1242  create_fun_ptr_t f = record[n];
1243  return f();
1244  }
1245 };
1246 #endif
1247 
1248 /// choose calendar implementation
1249 /// default is list
1250 void SetCalendar(const char *name) {
1251  if( SIMLIB_Phase == INITIALIZATION ||
1252  SIMLIB_Phase == SIMULATION ) SIMLIB_error("SetCalendar() can't be used after Init()");
1253 
1254  if(Calendar::_instance) // already initialized
1256  if(name==0 || std::strcmp(name,"")==0 || std::strcmp(name,"default")==0)
1257  Calendar::_instance = CalendarList::create();
1258  else if(std::strcmp(name,"list")==0)
1259  Calendar::_instance = CalendarList::create();
1260  else if(std::strcmp(name,"cq")==0)
1261  Calendar::_instance = CalendarQueue::create();
1262  else
1263  SIMLIB_error("SetCalendar: bad argument");
1264 }
1265 
1266 
1267 ////////////////////////////////////////////////////////////////////////////
1268 // public INTERFACE = exported functions...
1269 //
1270 
1271 #ifdef MEASURE
1272 // global measurement results (in simlib3 namespace)
1273 unsigned cal_cost_size;
1274 double cal_cost_time;
1275 int cal_cost_flag;
1276 const char * cal_cost_op;
1277 #endif
1278 
1279 /// empty calendar predicate
1280 bool SQS::Empty() { // used by Run() only
1281  return Calendar::instance()->Empty();
1282 }
1283 
1284 /// schedule entity e at given time t using scheduling priority from e
1285 /// @param e entity
1286 /// @param t time of activation
1287 void SQS::ScheduleAt(Entity *e, double t) { // used by scheduling operations
1288  if(!e->Idle())
1289  SIMLIB_error("ScheduleAt call if already scheduled");
1290 #ifdef MEASURE
1291  START_T();
1292 #endif
1294 #ifdef MEASURE
1295  double ttt=STOP_T();
1296 // Print("enqueue %d %g %d\n", Calendar::instance()->size(), ttt, OP_MEASURE);
1297 cal_cost_size = Calendar::instance()->Size();
1298 cal_cost_time = ttt;
1299 cal_cost_flag = OP_MEASURE;
1300 cal_cost_op = "enqueue";
1301 OP_MEASURE=0;
1302 // if(Calendar::instance()->size() < 300) Calendar::instance()->visualize("");
1303 #endif
1305 }
1306 
1307 /// remove selected entity activation record from calendar
1308 void SQS::Get(Entity *e) { // used by Run() only
1309 #ifdef MEASURE
1310  START_T();
1311 #endif
1312  Calendar::instance()->Get(e);
1313 #ifdef MEASURE
1314  double ttt=STOP_T();
1315 // Print("dequeue2 %d %g %d\n", Calendar::instance()->size(), ttt, OP_MEASURE);
1316 cal_cost_size = Calendar::instance()->Size();
1317 cal_cost_time = ttt;
1318 cal_cost_flag = OP_MEASURE;
1319 cal_cost_op = "delete";
1320 OP_MEASURE=0;
1321 #endif
1323 }
1324 
1325 /// remove entity with minimum activation time
1326 /// @returns pointer to entity
1327 Entity *SQS::GetFirst() { // used by Run()
1328 #ifdef MEASURE
1329  START_T();
1330 #endif
1331  Entity * ret = Calendar::instance()->GetFirst();
1332 #ifdef MEASURE
1333  double ttt=STOP_T();
1334 // Print("dequeue %d %g %d\n", Calendar::instance()->size(), ttt, OP_MEASURE);
1335 cal_cost_size = Calendar::instance()->Size();
1336 cal_cost_time = ttt;
1337 cal_cost_flag = OP_MEASURE;
1338 cal_cost_op = "dequeue";
1339 OP_MEASURE=0;
1340 #endif
1342  return ret;
1343 }
1344 
1345 /// remove all scheduled entities
1346 void SQS::Clear() { // remove all
1347  Calendar::instance()->clear(true);
1349 }
1350 
1351 int SQS::debug_print() { // for debugging only
1353  return Calendar::instance()->Size();
1354 }
1355 
1356 /// get activation time of entity - iff scheduled <br>
1357 /// it is here, because Entity has no knowledge of calendar activation record structure
1358 double Entity::ActivationTime() { // activation time
1359  //if(Idle()) SIMLIB_internal_error(); // passive entity
1360  if(Idle()) return SIMLIB_MAXTIME; // passive entity
1361  return GetEventNotice()->time;
1362 }
1363 
1364 
1365 } // end of namespace
1366 
void Resize(int grow=0)
Resize bucket array.
Definition: calendar.cc:920
bool Empty() const
Definition: calendar.cc:69
const double SIMLIB_MAXTIME
maximum time (1e30 works for float, too)
Definition: simlib.h:148
static bool instance_exists()
check if the instance exists
Definition: calendar.cc:101
void insert(Entity *e, double t)
enqueue operation
Definition: calendar.cc:311
void free(EventNotice *en)
free EventNotice, add to freelist for future allocation
Definition: calendar.cc:210
void SIMLIB_error(const enum _ErrEnum N)
print error message and abort program
Definition: error.cc:38
virtual void debug_print() override
for debugging only
Definition: calendar.cc:1149
friend void SetCalendar(const char *name)
choose calendar implementation default is list
Definition: calendar.cc:1250
virtual const char * Name()=0
const unsigned MINBUCKETS
Definition: calendar.cc:536
CQ implementation of calendar.
Definition: calendar.cc:547
double time2bucket_top(double t)
Compute bucket top limit.
Definition: calendar.cc:575
void clear(bool destroy)
remove all items
Definition: calendar.cc:333
Priority_t Priority
priority of the entity (scheduling,queues)
Definition: simlib.h:399
~CalendarQueue()
Destroy calendar queue.
Definition: calendar.cc:1121
virtual ~Calendar()
clear is called in derived class dtr
Definition: calendar.cc:106
allocate activation records fast
Definition: calendar.cc:199
EventNotice * GetEventNotice()
Definition: simlib.h:427
virtual const char * Name() override
Definition: calendar.cc:386
const unsigned LIST_MAX
Definition: calendar.cc:535
Entity * remove(Entity *e)
special dequeue operation for rescheduling
Definition: calendar.cc:318
EventNoticeLinkBase * p
< bidirectional iterator
Definition: calendar.cc:268
CalendarListImplementation BucketList
Definition: calendar.cc:548
void Get(Entity *e)
remove selected entity activation record from calendar
Definition: calendar.cc:1308
virtual void ScheduleAt(Entity *p, double t) override
enqueue
Definition: calendar.cc:646
virtual Entity * GetFirst() override
dequeue first
Definition: calendar.cc:683
void delete_reverse_link()
delete link from entity to activation record
Definition: calendar.cc:167
EventNotice * _evn
points to calendar item, iff scheduled
Definition: simlib.h:425
bool isAllocated() const
Definition: simlib.h:318
int Print(const char *fmt,...)
for Output methods, can be redirected
Definition: print.cc:92
int time2bucket(double t)
Convert time to bucket number.
Definition: calendar.cc:567
EventNotice * extract_first()
fast special operations for list swap (Dangerous!):
Definition: calendar.cc:349
common interface for all calendar (PES) implementations
Definition: calendar.cc:67
Implementation of class CalendarList interface is static - using global functions in SQS namespace...
Definition: algloop.cc:32
virtual void debug_print() override
for debugging only
Definition: calendar.cc:1157
virtual void debug_print()=0
for debugging only
static EventNotice * Create(Entity *p, double t)
creates new EventNotice,
Definition: calendar.cc:413
void SIMLIB_warning(const enum _ErrEnum N)
print warning message and continue
Definition: error.cc:74
abstract base class for active entities (Process, Event) instances of derived classes provide Behavio...
Definition: simlib.h:375
void Set(Entity *e, double t)
set new values to existing (unlinked) record
Definition: calendar.cc:179
EventNoticeLinkBase * succ
next object in list
Definition: calendar.cc:120
static void delete_instance()
destroy single instance
Definition: calendar.cc:1216
virtual Entity * GetFirst() override
dequeue first entity
Definition: calendar.cc:456
const double & Time
model time (is NOT the block)
Definition: run.cc:48
static Calendar * instance()
create/get single instance (singleton)
Definition: calendar.cc:1204
void remove()
remove from calendar list
Definition: calendar.cc:125
#define MAX_OP
Definition: calendar.cc:621
EventNotice(Entity *p, double t)
Definition: calendar.cc:153
class simlib3::EventNoticeAllocator allocator
void SearchMinTime(double starttime)
compute new mintime
Definition: calendar.cc:782
double ActivationTime()
get activation time of entity - iff scheduled it is here, because Entity has no knowledge of calend...
Definition: calendar.cc:1358
class CalendarListImplementation — sorted list
Definition: calendar.cc:264
virtual void clear(bool destroy=false) override
remove all
Definition: calendar.cc:1089
Test t(F)
unsigned Size() const
Definition: calendar.cc:70
void visualize(const char *msg)
CalendarQueue::visualize – output suitable for Gnuplot.
Definition: calendar.cc:1170
void switchtocq()
switch to calendar queue implementation
Definition: calendar.cc:1020
Entity::Priority_t priority
priority at the time of scheduling
Definition: calendar.cc:151
void ScheduleAt(Entity *e, double t)
schedule entity e at given time t using scheduling priority from e
Definition: calendar.cc:1287
const double COEF_PAR
Definition: calendar.cc:540
void clear()
clear: delete all free-list items
Definition: calendar.cc:238
EventNoticeLinkBase l
head of circular list
Definition: calendar.cc:265
double estimate_bucket_width()
compute new bucket width — EXPERIMENTAL
Definition: calendar.cc:837
bool operator==(const ParameterVector &p1, const ParameterVector &p2)
Definition: opt-param.cc:86
static void Destroy(EventNotice *en)
delete EventNotice, if inserted in calendar remove it first
Definition: calendar.cc:435
Entity * GetFirst()
remove entity with minimum activation time
Definition: calendar.cc:1327
double MinTime() const
time of activation of first item
Definition: calendar.cc:85
CalendarListImplementation l
Definition: calendar.cc:365
virtual void ScheduleAt(Entity *p, double t) override
enqueue
Definition: calendar.cc:442
Internal header file for SIMLIB/C++.
class CalendarList — list implementation of calendar
Definition: calendar.cc:364
const double & NextTime
next-event time
Definition: run.cc:49
void insert_extracted(EventNotice *evn)
fast special enqueue operation
Definition: calendar.cc:355
static CalendarQueue * create()
create calendar instance
Definition: calendar.cc:596
static Calendar * _instance
pointer to single instance
Definition: calendar.cc:109
Main SIMLIB/C++ interface.
Entity * entity
which entity is scheduled
Definition: calendar.cc:147
virtual std::string Name() const
get object name
Definition: object.cc:134
void SetMinTime(double t)
set cache for faster access
Definition: calendar.cc:88
void debug_print()
print of calendar contents - FOR DEBUGGING ONLY
Definition: calendar.cc:1136
SIMLIB_IMPLEMENTATION
Definition: algloop.cc:34
unsigned _size
number of scheduled items
Definition: calendar.cc:93
bool Empty()
empty calendar predicate
Definition: calendar.cc:1280
virtual void clear(bool destroy=false) override
remove all
Definition: calendar.cc:499
#define _SetTime(t, x)
macro for simple assignement to internal time variables
Definition: internal.h:228
bool Idle()
entity activation is not scheduled in calendar
Definition: simlib.h:412
void switchtolist()
switch to list implementation
Definition: calendar.cc:993
virtual void clear(bool destroy_entities=false)=0
remove all scheduled entities
EventNotice * alloc(Entity *p, double t)
EventNotice allocation or reuse from freelist.
Definition: calendar.cc:225
iterator search(EventNotice *en)
search — linear search for insert position
Definition: calendar.cc:292
activation record
Definition: calendar.cc:145
SIMLIB_Phase_t SIMLIB_Phase
Definition: run.cc:57
CalendarQueue()
Initialize calendar queue.
Definition: calendar.cc:625
virtual Entity * Get(Entity *p) override
dequeue
Definition: calendar.cc:735
EventNoticeLinkBase * l
Definition: calendar.cc:201
virtual void ScheduleAt(Entity *e, double t)=0
enqueue
EntityPriority_t Priority_t
Definition: simlib.h:397
calendar item - PRIVATE for any implementation we use double-linked circular list ...
Definition: calendar.cc:117
unsigned low_bucket_mark
Definition: calendar.cc:553
#define Dprintf(f)
Definition: internal.h:100
virtual const char * Name() override
Definition: calendar.cc:604
virtual Entity * GetFirst()=0
dequeue first
int debug_print()
Definition: calendar.cc:1351
static __inline__ unsigned long long rdtsc(void)
Definition: rdtsc.h:13
EventNoticeLinkBase * pred
previous object in list
Definition: calendar.cc:119
virtual Entity * Get(Entity *p) override
dequeue
Definition: calendar.cc:475
const double MUL_PAR
Definition: calendar.cc:543
virtual Entity * Get(Entity *e)=0
dequeue
void SIMLIB_atexit(SIMLIB_atexit_function_t p)
Definition: atexit.cc:26
BucketList * buckets
Definition: calendar.cc:549
void insert(EventNoticeLinkBase *p)
insert at position p
Definition: calendar.cc:132
Entity * remove_first()
dequeue operation
Definition: calendar.cc:324
double mintime
activation time of first event
Definition: calendar.cc:95
const unsigned LIST_MIN
Definition: calendar.cc:537
double time
activation time of entity
Definition: calendar.cc:149
void create_reverse_link()
create link from entity to activation record
Definition: calendar.cc:163
void Clear()
remove all scheduled entities
Definition: calendar.cc:1346
static CalendarList * create()
create calendar instance
Definition: calendar.cc:379