A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
calendar-scheduler.h
Go to the documentation of this file.
1/*
2 * Copyright (c) 2009 INRIA
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation;
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 *
17 * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
18 * Author: Alexander Krotov <krotov@iitp.ru>
19 */
20
21#ifndef CALENDAR_SCHEDULER_H
22#define CALENDAR_SCHEDULER_H
23
24#include "scheduler.h"
25
26#include <list>
27#include <stdint.h>
28
29/**
30 * \file
31 * \ingroup scheduler
32 * ns3::CalendarScheduler class declaration.
33 */
34
35namespace ns3
36{
37
38class EventImpl;
39
40/**
41 * \ingroup scheduler
42 * \brief a calendar queue event scheduler
43 *
44 * This event scheduler is a direct implementation of the algorithm
45 * known as a calendar queue, first published in 1988 in
46 * ["Calendar Queues: A Fast O(1) Priority Queue Implementation for
47 * the Simulation Event Set Problem" by Randy Brown][Brown]. There are many
48 * refinements published later but this class implements
49 * the original algorithm (to the best of my knowledge).
50 *
51 * [Brown]: https://doi.org/10.1145/63039.63045 "Brown"
52 *
53 * This class uses a vector of buckets; each bucket covers a uniform
54 * time span. The bucket index for an event with timestamp `ts` is
55 * `(ts / m_width) % m_nBuckets`. This class automatically adjusts
56 * the number of buckets to keep the average occupancy around 2.
57 * Buckets themselves are implemented as a `std::list<>`, and events are
58 * kept sorted within the buckets.
59 *
60 * \par Time Complexity
61 *
62 * Operation | Amortized %Time | Reason
63 * :----------- | :-------------- | :-----
64 * Insert() | ~Constant | Ordering within bucket; possible resize
65 * IsEmpty() | Constant | Explicit queue size
66 * PeekNext() | ~Constant | Search buckets
67 * Remove() | ~Constant | Search within bucket; possible resize
68 * RemoveNext() | ~Constant | Search buckets; possible resize
69 *
70 * \par Memory Complexity
71 *
72 * Category | Memory | Reason
73 * :-------- | :------------------------------- | :-----
74 * Overhead | 2 x `sizeof (*)` + `size_t`<br/>(24 bytes) | `std::list`
75 * Per Event | 2 x `sizeof (*)` | `std::list`
76 *
77 * \note
78 * This queue is much slower than I expected (much slower than the
79 * std::map queue) and this seems to be because the original resizing policy
80 * is horribly bad. This is most likely the reason why there have been
81 * so many variations published which all slightly tweak the resizing
82 * heuristics to obtain a better distribution of events across buckets.
83 *
84 * \note While inserion sort is not discussed in the original article, its
85 * implementation appears to dramatically affect performance.
86 * The default implementation sorts buckets in increasing (chronological)
87 * order. The alternative, sorting buckets in decreasing order,
88 * was adopted in NS-2 because they observed that new events were
89 * more likely to be later than already scheduled events.
90 * In this case sorting buckets in reverse chronological order
91 * reduces enqueue time.
92 */
94{
95 public:
96 /**
97 * Register this type.
98 * \return The object TypeId.
99 */
100 static TypeId GetTypeId();
101
102 /** Constructor. */
104 /** Destructor. */
105 ~CalendarScheduler() override;
106
107 // Inherited
108 void Insert(const Scheduler::Event& ev) override;
109 bool IsEmpty() const override;
110 Scheduler::Event PeekNext() const override;
111 Scheduler::Event RemoveNext() override;
112 void Remove(const Scheduler::Event& ev) override;
113
114 private:
115 /** Double the number of buckets if necessary. */
116 void ResizeUp();
117 /** Halve the number of buckets if necessary. */
118 void ResizeDown();
119 /**
120 * Resize to a new number of buckets, with automatically computed width.
121 *
122 * \param [in] newSize The new number of buckets.
123 */
124 void Resize(uint32_t newSize);
125 /**
126 * Compute the new bucket size, based on up to the first 25 entries.
127 *
128 * \returns The new width.
129 */
130 uint64_t CalculateNewWidth();
131 /**
132 * Initialize the calendar queue.
133 *
134 * \param [in] nBuckets The number of buckets.
135 * \param [in] width The bucket size, in dimensionless time units.
136 * \param [in] startPrio The starting time.
137 */
138 void Init(uint32_t nBuckets, uint64_t width, uint64_t startPrio);
139 /**
140 * Hash the dimensionless time to a bucket.
141 *
142 * \param [in] key The dimensionless time.
143 * \returns The bucket index.
144 */
145 inline uint32_t Hash(uint64_t key) const;
146 /** Print the configuration and bucket size distribution. */
147 void PrintInfo();
148 /**
149 * Resize the number of buckets and width.
150 *
151 * \param [in] newSize The number of buckets.
152 * \param [in] newWidth The size of the new buckets.
153 */
154 void DoResize(uint32_t newSize, uint64_t newWidth);
155 /**
156 * Remove the earliest event.
157 *
158 * \returns The earliest event.
159 */
161 /**
162 * Insert a new event in to the correct bucket.
163 *
164 * \param [in] ev The new Event.
165 */
166 void DoInsert(const Scheduler::Event& ev);
167
168 /** Calendar bucket type: a list of Events. */
169 typedef std::list<Scheduler::Event> Bucket;
170
171 /** Array of buckets. */
173 /** Number of buckets in the array. */
175 /** Duration of a bucket, in dimensionless time units. */
176 uint64_t m_width;
177 /** Bucket index from which the last event was dequeued. */
179 /** Priority at the top of the bucket from which last event was dequeued. */
180 uint64_t m_bucketTop;
181 /** The priority of the last event removed. */
182 uint64_t m_lastPrio;
183 /** Number of events in queue. */
185
186 /**
187 * Set the insertion order.
188 *
189 * This can only be used at construction, as invoked by the
190 * Attribute Reverse.
191 *
192 * \param [in] reverse If \c true, store events in *decreasing*
193 * time stamp order.
194 */
195 void SetReverse(bool reverse);
196 /**
197 * Get the next event from the bucket, according to \c m_reverse.
198 * \param [in] bucket The bucket to draw from.
199 * \return The next event from the \c bucket.
200 */
201 Scheduler::Event& (*NextEvent)(Bucket& bucket);
202 /**
203 * Ordering function to identify the insertion point, according to \c m_reverse.
204 * \param [in] newEvent The new event being inserted.
205 * \param [in] it The current position in the bucket being examined.
206 * \return \c true if the \c newEvent belongs before \c it.
207 */
208 bool (*Order)(const EventKey& newEvent, const EventKey& it);
209 /**
210 * Pop the next event from the bucket, according to \c m_reverse.
211 * \param [in] bucket The bucket to pop from.
212 */
213 void (*Pop)(Bucket&);
214 /**
215 * Bucket ordering.
216 * If \c false (default), store events in increasing time stamp order.
217 * If \c true, store events in *decreasing* time stamp order.
218 */
219 bool m_reverse = false;
220};
221
222} // namespace ns3
223
224#endif /* CALENDAR_SCHEDULER_H */
a calendar queue event scheduler
bool m_reverse
Bucket ordering.
uint64_t CalculateNewWidth()
Compute the new bucket size, based on up to the first 25 entries.
uint32_t m_nBuckets
Number of buckets in the array.
bool(* Order)(const EventKey &newEvent, const EventKey &it)
Ordering function to identify the insertion point, according to m_reverse.
void PrintInfo()
Print the configuration and bucket size distribution.
uint32_t m_qSize
Number of events in queue.
void Remove(const Scheduler::Event &ev) override
Remove a specific event from the event list.
void Init(uint32_t nBuckets, uint64_t width, uint64_t startPrio)
Initialize the calendar queue.
void ResizeDown()
Halve the number of buckets if necessary.
uint32_t Hash(uint64_t key) const
Hash the dimensionless time to a bucket.
void Insert(const Scheduler::Event &ev) override
Insert a new Event in the schedule.
void DoInsert(const Scheduler::Event &ev)
Insert a new event in to the correct bucket.
uint64_t m_bucketTop
Priority at the top of the bucket from which last event was dequeued.
std::list< Scheduler::Event > Bucket
Calendar bucket type: a list of Events.
~CalendarScheduler() override
Destructor.
void DoResize(uint32_t newSize, uint64_t newWidth)
Resize the number of buckets and width.
Scheduler::Event PeekNext() const override
Get a pointer to the next event.
Scheduler::Event RemoveNext() override
Remove the earliest event from the event list.
Scheduler::Event DoRemoveNext()
Remove the earliest event.
uint32_t m_lastBucket
Bucket index from which the last event was dequeued.
void SetReverse(bool reverse)
Set the insertion order.
void Resize(uint32_t newSize)
Resize to a new number of buckets, with automatically computed width.
bool IsEmpty() const override
Test if the schedule is empty.
uint64_t m_lastPrio
The priority of the last event removed.
uint64_t m_width
Duration of a bucket, in dimensionless time units.
void ResizeUp()
Double the number of buckets if necessary.
Bucket * m_buckets
Array of buckets.
void(* Pop)(Bucket &)
Pop the next event from the bucket, according to m_reverse.
static TypeId GetTypeId()
Register this type.
Maintain the event list.
Definition: scheduler.h:157
a unique identifier for an interface.
Definition: type-id.h:59
Every class exported by the ns3 library is enclosed in the ns3 namespace.
ns3::Scheduler abstract base class, ns3::Scheduler::Event and ns3::Scheduler::EventKey declarations.
Scheduler event.
Definition: scheduler.h:184
Structure for sorting and comparing Events.
Definition: scheduler.h:170