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 NS_OBJECT_ENSURE_REGISTERED (CalendarScheduler);
34 
35 TypeId
37 {
38  static TypeId tid = TypeId ("ns3::CalendarScheduler")
39  .SetParent<Scheduler> ()
40  .AddConstructor<CalendarScheduler> ()
41  ;
42  return tid;
43 }
44 
46 {
47  NS_LOG_FUNCTION (this);
48  Init (2, 1, 0);
49  m_qSize = 0;
50 }
52 {
53  NS_LOG_FUNCTION (this);
54  delete [] m_buckets;
55  m_buckets = 0;
56 }
57 void
58 CalendarScheduler::Init (uint32_t nBuckets,
59  uint64_t width,
60  uint64_t startPrio)
61 {
62  NS_LOG_FUNCTION (this << nBuckets << width << startPrio);
63  m_buckets = new Bucket [nBuckets];
64  m_nBuckets = nBuckets;
65  m_width = width;
66  m_lastPrio = startPrio;
67  m_lastBucket = Hash (startPrio);
68  m_bucketTop = (startPrio / width + 1) * width;
69 }
70 void
72 {
73  std::cout << "nBuckets=" << m_nBuckets << ", width=" << m_width << std::endl;
74  std::cout << "Bucket Distribution ";
75  for (uint32_t i = 0; i < m_nBuckets; i++)
76  {
77  std::cout << m_buckets[i].size () << " ";
78  }
79  std::cout << std::endl;
80 }
81 uint32_t
82 CalendarScheduler::Hash (uint64_t ts) const
83 {
84  uint32_t bucket = (ts / m_width) % m_nBuckets;
85  return bucket;
86 }
87 
88 void
90 {
91  NS_LOG_FUNCTION (this << ev.key.m_ts << ev.key.m_uid);
92  // calculate bucket index.
93  uint32_t bucket = Hash (ev.key.m_ts);
94  NS_LOG_LOGIC ("insert in bucket=" << bucket);
95 
96  // insert in bucket list.
97  Bucket::iterator end = m_buckets[bucket].end ();
98  for (Bucket::iterator i = m_buckets[bucket].begin (); i != end; ++i)
99  {
100  if (ev.key < i->key)
101  {
102  m_buckets[bucket].insert (i, ev);
103  return;
104  }
105  }
106  m_buckets[bucket].push_back (ev);
107 }
108 
109 void
111 {
112  DoInsert (ev);
113  m_qSize++;
114  ResizeUp ();
115 }
116 bool
118 {
119  return m_qSize == 0;
120 }
123 {
125  NS_ASSERT (!IsEmpty ());
126  uint32_t i = m_lastBucket;
127  uint64_t bucketTop = m_bucketTop;
128  Scheduler::Event minEvent = { static_cast<uint64_t>(0), { static_cast<uint32_t>(~0), static_cast<uint32_t>(~0)}};
129  do
130  {
131  if (!m_buckets[i].empty ())
132  {
133  Scheduler::Event next = m_buckets[i].front ();
134  if (next.key.m_ts < bucketTop)
135  {
136  return next;
137  }
138  if (next.key < minEvent.key)
139  {
140  minEvent = next;
141  }
142  }
143  i++;
144  i %= m_nBuckets;
145  bucketTop += m_width;
146  }
147  while (i != m_lastBucket);
148 
149  return minEvent;
150 }
151 
154 {
155  uint32_t i = m_lastBucket;
156  uint64_t bucketTop = m_bucketTop;
157  int32_t minBucket = -1;
158  Scheduler::EventKey minKey;
159  NS_ASSERT(!IsEmpty());
160  minKey.m_ts = uint64_t(-int64_t(1));
161  minKey.m_uid = 0;
162  minKey.m_context = 0xffffffff;
163  do
164  {
165  if (!m_buckets[i].empty ())
166  {
167  Scheduler::Event next = m_buckets[i].front ();
168  if (next.key.m_ts < bucketTop)
169  {
170  m_lastBucket = i;
171  m_lastPrio = next.key.m_ts;
172  m_bucketTop = bucketTop;
173  m_buckets[i].pop_front ();
174  return next;
175  }
176  if (next.key < minKey)
177  {
178  minKey = next.key;
179  minBucket = i;
180  }
181  }
182  i++;
183  i %= m_nBuckets;
184  bucketTop += m_width;
185  }
186  while (i != m_lastBucket);
187 
188  m_lastPrio = minKey.m_ts;
189  m_lastBucket = Hash (minKey.m_ts);
190  m_bucketTop = (minKey.m_ts / m_width + 1) * m_width;
191  Scheduler::Event next = m_buckets[minBucket].front();
192  m_buckets[minBucket].pop_front ();
193 
194  return next;
195 }
196 
199 {
201  NS_ASSERT (!IsEmpty ());
202 
204  NS_LOG_LOGIC ("remove ts=" << ev.key.m_ts <<
205  ", key=" << ev.key.m_uid <<
206  ", from bucket=" << m_lastBucket);
207  m_qSize--;
208  ResizeDown ();
209  return ev;
210 }
211 
212 void
214 {
215  NS_ASSERT (!IsEmpty ());
216  // bucket index of event
217  uint32_t bucket = Hash (ev.key.m_ts);
218 
219  Bucket::iterator end = m_buckets[bucket].end ();
220  for (Bucket::iterator i = m_buckets[bucket].begin (); i != end; ++i)
221  {
222  if (i->key.m_uid == ev.key.m_uid)
223  {
224  NS_ASSERT (ev.impl == i->impl);
225  m_buckets[bucket].erase (i);
226 
227  m_qSize--;
228  ResizeDown ();
229  return;
230  }
231  }
232  NS_ASSERT (false);
233 }
234 
235 void
237 {
238  if (m_qSize > m_nBuckets * 2
239  && m_nBuckets < 32768)
240  {
241  Resize (m_nBuckets * 2);
242  }
243 }
244 void
246 {
247  if (m_qSize < m_nBuckets / 2)
248  {
249  Resize (m_nBuckets / 2);
250  }
251 }
252 
253 uint32_t
255 {
256  if (m_qSize < 2)
257  {
258  return 1;
259  }
260  uint32_t nSamples;
261  if (m_qSize <= 5)
262  {
263  nSamples = m_qSize;
264  }
265  else
266  {
267  nSamples = 5 + m_qSize / 10;
268  }
269  if (nSamples > 25)
270  {
271  nSamples = 25;
272  }
273 
274  // we gather the first nSamples from the queue
275  std::list<Scheduler::Event> samples;
276  // save state
277  uint32_t lastBucket = m_lastBucket;
278  uint64_t bucketTop = m_bucketTop;
279  uint64_t lastPrio = m_lastPrio;
280 
281  // gather requested events
282  for (uint32_t i = 0; i < nSamples; i++)
283  {
284  samples.push_back (DoRemoveNext ());
285  }
286  // put them back
287  for (std::list<Scheduler::Event>::const_iterator i = samples.begin ();
288  i != samples.end (); ++i)
289  {
290  DoInsert (*i);
291  }
292 
293  // restore state.
294  m_lastBucket = lastBucket;
295  m_bucketTop = bucketTop;
296  m_lastPrio = lastPrio;
297 
298  // finally calculate inter-time average over samples.
299  uint64_t totalSeparation = 0;
300  std::list<Scheduler::Event>::const_iterator end = samples.end ();
301  std::list<Scheduler::Event>::const_iterator cur = samples.begin ();
302  std::list<Scheduler::Event>::const_iterator next = cur;
303  next++;
304  while (next != end)
305  {
306  totalSeparation += next->key.m_ts - cur->key.m_ts;
307  cur++;
308  next++;
309  }
310  uint64_t twiceAvg = totalSeparation / (nSamples - 1) * 2;
311  totalSeparation = 0;
312  cur = samples.begin ();
313  next = cur;
314  next++;
315  while (next != end)
316  {
317  uint64_t diff = next->key.m_ts - cur->key.m_ts;
318  if (diff <= twiceAvg)
319  {
320  totalSeparation += diff;
321  }
322  cur++;
323  next++;
324  }
325 
326  totalSeparation *= 3;
327  totalSeparation = std::max (totalSeparation, (uint64_t)1);
328  return totalSeparation;
329 }
330 void
331 CalendarScheduler::DoResize (uint32_t newSize, uint32_t newWidth)
332 {
333  Bucket *oldBuckets = m_buckets;
334  uint32_t oldNBuckets = m_nBuckets;
335  Init (newSize, newWidth, m_lastPrio);
336 
337  for (uint32_t i = 0; i < oldNBuckets; i++)
338  {
339  Bucket::iterator end = oldBuckets[i].end ();
340  for (Bucket::iterator j = oldBuckets[i].begin (); j != end; ++j)
341  {
342  DoInsert (*j);
343  }
344  }
345  delete [] oldBuckets;
346 }
347 void
348 CalendarScheduler::Resize (uint32_t newSize)
349 {
350  NS_LOG_FUNCTION (this << newSize);
351 
352  // PrintInfo ();
353  uint32_t newWidth = CalculateNewWidth ();
354  DoResize (newSize, newWidth);
355 }
356 
357 } // namespace ns3