A Discrete-Event Network Simulator
API
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
calendar-scheduler.cc
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2009 INRIA
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation;
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17  *
18  * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
19  */
20 
21 #include "calendar-scheduler.h"
22 #include "event-impl.h"
23 #include <utility>
24 #include <string>
25 #include <list>
26 #include "assert.h"
27 #include "log.h"
28 
29 namespace ns3 {
30 
31 NS_LOG_COMPONENT_DEFINE ("CalendarScheduler")
32  ;
33 
34 NS_OBJECT_ENSURE_REGISTERED (CalendarScheduler)
35  ;
36 
37 TypeId
39 {
40  static TypeId tid = TypeId ("ns3::CalendarScheduler")
41  .SetParent<Scheduler> ()
42  .AddConstructor<CalendarScheduler> ()
43  ;
44  return tid;
45 }
46 
48 {
49  NS_LOG_FUNCTION (this);
50  Init (2, 1, 0);
51  m_qSize = 0;
52 }
54 {
55  NS_LOG_FUNCTION (this);
56  delete [] m_buckets;
57  m_buckets = 0;
58 }
59 void
60 CalendarScheduler::Init (uint32_t nBuckets,
61  uint64_t width,
62  uint64_t startPrio)
63 {
64  NS_LOG_FUNCTION (this << nBuckets << width << startPrio);
65  m_buckets = new Bucket [nBuckets];
66  m_nBuckets = nBuckets;
67  m_width = width;
68  m_lastPrio = startPrio;
69  m_lastBucket = Hash (startPrio);
70  m_bucketTop = (startPrio / width + 1) * width;
71 }
72 void
74 {
75  NS_LOG_FUNCTION (this);
76 
77  std::cout << "nBuckets=" << m_nBuckets << ", width=" << m_width << std::endl;
78  std::cout << "Bucket Distribution ";
79  for (uint32_t i = 0; i < m_nBuckets; i++)
80  {
81  std::cout << m_buckets[i].size () << " ";
82  }
83  std::cout << std::endl;
84 }
85 uint32_t
86 CalendarScheduler::Hash (uint64_t ts) const
87 {
88  NS_LOG_FUNCTION (this);
89 
90  uint32_t bucket = (ts / m_width) % m_nBuckets;
91  return bucket;
92 }
93 
94 void
96 {
97  NS_LOG_FUNCTION (this << ev.key.m_ts << ev.key.m_uid);
98  // calculate bucket index.
99  uint32_t bucket = Hash (ev.key.m_ts);
100  NS_LOG_LOGIC ("insert in bucket=" << bucket);
101 
102  // insert in bucket list.
103  Bucket::iterator end = m_buckets[bucket].end ();
104  for (Bucket::iterator i = m_buckets[bucket].begin (); i != end; ++i)
105  {
106  if (ev.key < i->key)
107  {
108  m_buckets[bucket].insert (i, ev);
109  return;
110  }
111  }
112  m_buckets[bucket].push_back (ev);
113 }
114 
115 void
117 {
118  NS_LOG_FUNCTION (this << &ev);
119  DoInsert (ev);
120  m_qSize++;
121  ResizeUp ();
122 }
123 bool
125 {
126  NS_LOG_FUNCTION (this);
127  return m_qSize == 0;
128 }
131 {
132  NS_LOG_FUNCTION (this);
133  NS_ASSERT (!IsEmpty ());
134  uint32_t i = m_lastBucket;
135  uint64_t bucketTop = m_bucketTop;
136  Scheduler::Event minEvent;
137  minEvent.impl = 0;
138  minEvent.key.m_ts = ~0;
139  minEvent.key.m_uid = ~0;
140  minEvent.key.m_context = 0;
141  do
142  {
143  if (!m_buckets[i].empty ())
144  {
145  Scheduler::Event next = m_buckets[i].front ();
146  if (next.key.m_ts < bucketTop)
147  {
148  return next;
149  }
150  if (next.key < minEvent.key)
151  {
152  minEvent = next;
153  }
154  }
155  i++;
156  i %= m_nBuckets;
157  bucketTop += m_width;
158  }
159  while (i != m_lastBucket);
160 
161  return minEvent;
162 }
163 
166 {
167  NS_LOG_FUNCTION (this);
168 
169  uint32_t i = m_lastBucket;
170  uint64_t bucketTop = m_bucketTop;
171  int32_t minBucket = -1;
172  Scheduler::EventKey minKey;
173  NS_ASSERT(!IsEmpty());
174  minKey.m_ts = uint64_t(-int64_t(1));
175  minKey.m_uid = 0;
176  minKey.m_context = 0xffffffff;
177  do
178  {
179  if (!m_buckets[i].empty ())
180  {
181  Scheduler::Event next = m_buckets[i].front ();
182  if (next.key.m_ts < bucketTop)
183  {
184  m_lastBucket = i;
185  m_lastPrio = next.key.m_ts;
186  m_bucketTop = bucketTop;
187  m_buckets[i].pop_front ();
188  return next;
189  }
190  if (next.key < minKey)
191  {
192  minKey = next.key;
193  minBucket = i;
194  }
195  }
196  i++;
197  i %= m_nBuckets;
198  bucketTop += m_width;
199  }
200  while (i != m_lastBucket);
201 
202  m_lastPrio = minKey.m_ts;
203  m_lastBucket = Hash (minKey.m_ts);
204  m_bucketTop = (minKey.m_ts / m_width + 1) * m_width;
205  Scheduler::Event next = m_buckets[minBucket].front();
206  m_buckets[minBucket].pop_front ();
207 
208  return next;
209 }
210 
213 {
215  NS_ASSERT (!IsEmpty ());
216 
218  NS_LOG_LOGIC ("remove ts=" << ev.key.m_ts <<
219  ", key=" << ev.key.m_uid <<
220  ", from bucket=" << m_lastBucket);
221  m_qSize--;
222  ResizeDown ();
223  return ev;
224 }
225 
226 void
228 {
229  NS_LOG_FUNCTION (this << &ev);
230  NS_ASSERT (!IsEmpty ());
231  // bucket index of event
232  uint32_t bucket = Hash (ev.key.m_ts);
233 
234  Bucket::iterator end = m_buckets[bucket].end ();
235  for (Bucket::iterator i = m_buckets[bucket].begin (); i != end; ++i)
236  {
237  if (i->key.m_uid == ev.key.m_uid)
238  {
239  NS_ASSERT (ev.impl == i->impl);
240  m_buckets[bucket].erase (i);
241 
242  m_qSize--;
243  ResizeDown ();
244  return;
245  }
246  }
247  NS_ASSERT (false);
248 }
249 
250 void
252 {
253  NS_LOG_FUNCTION (this);
254 
255  if (m_qSize > m_nBuckets * 2
256  && m_nBuckets < 32768)
257  {
258  Resize (m_nBuckets * 2);
259  }
260 }
261 void
263 {
264  NS_LOG_FUNCTION (this);
265 
266  if (m_qSize < m_nBuckets / 2)
267  {
268  Resize (m_nBuckets / 2);
269  }
270 }
271 
272 uint32_t
274 {
275  NS_LOG_FUNCTION (this);
276 
277  if (m_qSize < 2)
278  {
279  return 1;
280  }
281  uint32_t nSamples;
282  if (m_qSize <= 5)
283  {
284  nSamples = m_qSize;
285  }
286  else
287  {
288  nSamples = 5 + m_qSize / 10;
289  }
290  if (nSamples > 25)
291  {
292  nSamples = 25;
293  }
294 
295  // we gather the first nSamples from the queue
296  std::list<Scheduler::Event> samples;
297  // save state
298  uint32_t lastBucket = m_lastBucket;
299  uint64_t bucketTop = m_bucketTop;
300  uint64_t lastPrio = m_lastPrio;
301 
302  // gather requested events
303  for (uint32_t i = 0; i < nSamples; i++)
304  {
305  samples.push_back (DoRemoveNext ());
306  }
307  // put them back
308  for (std::list<Scheduler::Event>::const_iterator i = samples.begin ();
309  i != samples.end (); ++i)
310  {
311  DoInsert (*i);
312  }
313 
314  // restore state.
315  m_lastBucket = lastBucket;
316  m_bucketTop = bucketTop;
317  m_lastPrio = lastPrio;
318 
319  // finally calculate inter-time average over samples.
320  uint64_t totalSeparation = 0;
321  std::list<Scheduler::Event>::const_iterator end = samples.end ();
322  std::list<Scheduler::Event>::const_iterator cur = samples.begin ();
323  std::list<Scheduler::Event>::const_iterator next = cur;
324  next++;
325  while (next != end)
326  {
327  totalSeparation += next->key.m_ts - cur->key.m_ts;
328  cur++;
329  next++;
330  }
331  uint64_t twiceAvg = totalSeparation / (nSamples - 1) * 2;
332  totalSeparation = 0;
333  cur = samples.begin ();
334  next = cur;
335  next++;
336  while (next != end)
337  {
338  uint64_t diff = next->key.m_ts - cur->key.m_ts;
339  if (diff <= twiceAvg)
340  {
341  totalSeparation += diff;
342  }
343  cur++;
344  next++;
345  }
346 
347  totalSeparation *= 3;
348  totalSeparation = std::max (totalSeparation, (uint64_t)1);
349  return totalSeparation;
350 }
351 void
352 CalendarScheduler::DoResize (uint32_t newSize, uint32_t newWidth)
353 {
354  NS_LOG_FUNCTION (this << newSize << newWidth);
355 
356  Bucket *oldBuckets = m_buckets;
357  uint32_t oldNBuckets = m_nBuckets;
358  Init (newSize, newWidth, m_lastPrio);
359 
360  for (uint32_t i = 0; i < oldNBuckets; i++)
361  {
362  Bucket::iterator end = oldBuckets[i].end ();
363  for (Bucket::iterator j = oldBuckets[i].begin (); j != end; ++j)
364  {
365  DoInsert (*j);
366  }
367  }
368  delete [] oldBuckets;
369 }
370 void
371 CalendarScheduler::Resize (uint32_t newSize)
372 {
373  NS_LOG_FUNCTION (this << newSize);
374 
375  // PrintInfo ();
376  uint32_t newWidth = CalculateNewWidth ();
377  DoResize (newSize, newWidth);
378 }
379 
380 } // namespace ns3
#define NS_LOG_FUNCTION(parameters)
Definition: log.h:345
NS_LOG_COMPONENT_DEFINE("GrantedTimeWindowMpiInterface")
uint32_t CalculateNewWidth(void)
void DoInsert(const Event &ev)
EventImpl * impl
Definition: scheduler.h:72
#define NS_ASSERT(condition)
Definition: assert.h:64
NS_OBJECT_ENSURE_REGISTERED(NullMessageSimulatorImpl)
virtual Event PeekNext(void) const
virtual bool IsEmpty(void) const
make Callback use a separate empty type
Definition: empty.h:8
virtual void Remove(const Event &ev)
void Init(uint32_t nBuckets, uint64_t width, uint64_t startPrio)
Maintain the event list.
Definition: scheduler.h:57
#define NS_LOG_LOGIC(msg)
Definition: log.h:368
void Resize(uint32_t newSize)
virtual Event RemoveNext(void)
This method cannot be invoked if the list is empty.
Scheduler::Event DoRemoveNext(void)
void DoResize(uint32_t newSize, uint32_t newWidth)
std::list< Scheduler::Event > Bucket
static TypeId GetTypeId(void)
uint32_t Hash(uint64_t key) const
virtual void Insert(const Event &ev)
a unique identifier for an interface.
Definition: type-id.h:49
TypeId SetParent(TypeId tid)
Definition: type-id.cc:611