00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "calendar-scheduler.h"
00022 #include "event-impl.h"
00023 #include <utility>
00024 #include <string>
00025 #include <list>
00026 #include "ns3/assert.h"
00027 #include "ns3/log.h"
00028
00029 namespace ns3 {
00030
00031 NS_LOG_COMPONENT_DEFINE ("CalendarScheduler");
00032
00033 NS_OBJECT_ENSURE_REGISTERED (CalendarScheduler);
00034
00035 TypeId
00036 CalendarScheduler::GetTypeId (void)
00037 {
00038 static TypeId tid = TypeId ("ns3::CalendarScheduler")
00039 .SetParent<Scheduler> ()
00040 .AddConstructor<CalendarScheduler> ()
00041 ;
00042 return tid;
00043 }
00044
00045 CalendarScheduler::CalendarScheduler ()
00046 {
00047 NS_LOG_FUNCTION (this);
00048 Init (2, 1, 0);
00049 m_qSize = 0;
00050 }
00051 CalendarScheduler::~CalendarScheduler ()
00052 {
00053 NS_LOG_FUNCTION (this);
00054 delete [] m_buckets;
00055 m_buckets = 0;
00056 }
00057 void
00058 CalendarScheduler::Init (uint32_t nBuckets,
00059 uint64_t width,
00060 uint64_t startPrio)
00061 {
00062 NS_LOG_FUNCTION (this << nBuckets << width << startPrio);
00063 m_buckets = new Bucket [nBuckets];
00064 m_nBuckets = nBuckets;
00065 m_width = width;
00066 m_lastPrio = startPrio;
00067 m_lastBucket = Hash (startPrio);
00068 m_bucketTop = (startPrio / width + 1) * width;
00069 }
00070 void
00071 CalendarScheduler::PrintInfo (void)
00072 {
00073 std::cout << "nBuckets=" << m_nBuckets << ", width=" << m_width<< std::endl;
00074 std::cout << "Bucket Distribution ";
00075 for (uint32_t i = 0; i < m_nBuckets; i++)
00076 {
00077 std::cout << m_buckets[i].size () << " ";
00078 }
00079 std::cout << std::endl;
00080 }
00081 uint32_t
00082 CalendarScheduler::Hash (uint64_t ts) const
00083 {
00084 uint32_t bucket = (ts / m_width) % m_nBuckets;
00085 return bucket;
00086 }
00087
00088 void
00089 CalendarScheduler::DoInsert (const Event &ev)
00090 {
00091 NS_LOG_FUNCTION (this << ev.key.m_ts << ev.key.m_uid);
00092
00093 uint32_t bucket = Hash (ev.key.m_ts);
00094 NS_LOG_LOGIC ("insert in bucket=" << bucket);
00095
00096
00097 Bucket::iterator end = m_buckets[bucket].end ();
00098 for (Bucket::iterator i = m_buckets[bucket].begin (); i != end; ++i)
00099 {
00100 if (ev.key < i->key)
00101 {
00102 m_buckets[bucket].insert (i, ev);
00103 return;
00104 }
00105 }
00106 m_buckets[bucket].push_back (ev);
00107 }
00108
00109 void
00110 CalendarScheduler::Insert (const Event &ev)
00111 {
00112 DoInsert (ev);
00113 m_qSize++;
00114 ResizeUp ();
00115 }
00116 bool
00117 CalendarScheduler::IsEmpty (void) const
00118 {
00119 return m_qSize == 0;
00120 }
00121 Scheduler::Event
00122 CalendarScheduler::PeekNext (void) const
00123 {
00124 NS_LOG_FUNCTION (this << m_lastBucket << m_bucketTop);
00125 NS_ASSERT (!IsEmpty ());
00126 uint32_t i = m_lastBucket;
00127 uint64_t bucketTop = m_bucketTop;
00128 Scheduler::Event minEvent = {0, {~0, ~0}};
00129 do {
00130 if (!m_buckets[i].empty ())
00131 {
00132 Scheduler::Event next = m_buckets[i].front ();
00133 if (next.key.m_ts < bucketTop)
00134 {
00135 return next;
00136 }
00137 if (next.key < minEvent.key)
00138 {
00139 minEvent = next;
00140 }
00141 }
00142 i++;
00143 i %= m_nBuckets;
00144 bucketTop += m_width;
00145 } while (i != m_lastBucket);
00146
00147 return minEvent;
00148 }
00149
00150 Scheduler::Event
00151 CalendarScheduler::DoRemoveNext (void)
00152 {
00153 uint32_t i = m_lastBucket;
00154 uint64_t bucketTop = m_bucketTop;
00155 Scheduler::Event minEvent = {0, {~0, ~0}};
00156 do {
00157 if (!m_buckets[i].empty ())
00158 {
00159 Scheduler::Event next = m_buckets[i].front ();
00160 if (next.key.m_ts < bucketTop)
00161 {
00162 m_lastBucket = i;
00163 m_lastPrio = next.key.m_ts;
00164 m_bucketTop = bucketTop;
00165 m_buckets[i].pop_front ();
00166 return next;
00167 }
00168 if (next.key < minEvent.key)
00169 {
00170 minEvent = next;
00171 }
00172 }
00173 i++;
00174 i %= m_nBuckets;
00175 bucketTop += m_width;
00176 } while (i != m_lastBucket);
00177
00178 m_lastPrio = minEvent.key.m_ts;
00179 m_lastBucket = Hash (minEvent.key.m_ts);
00180 m_bucketTop = (minEvent.key.m_ts / m_width + 1) * m_width;
00181 m_buckets[m_lastBucket].pop_front ();
00182
00183 return minEvent;
00184 }
00185
00186 Scheduler::Event
00187 CalendarScheduler::RemoveNext (void)
00188 {
00189 NS_LOG_FUNCTION (this << m_lastBucket << m_bucketTop);
00190 NS_ASSERT (!IsEmpty ());
00191
00192 Scheduler::Event ev = DoRemoveNext ();
00193 NS_LOG_LOGIC ("remove ts=" << ev.key.m_ts <<
00194 ", key=" << ev.key.m_uid <<
00195 ", from bucket=" << m_lastBucket);
00196 m_qSize--;
00197 ResizeDown ();
00198 return ev;
00199 }
00200
00201 void
00202 CalendarScheduler::Remove (const Event &ev)
00203 {
00204 NS_ASSERT (!IsEmpty ());
00205
00206 uint32_t bucket = Hash (ev.key.m_ts);
00207
00208 Bucket::iterator end = m_buckets[bucket].end ();
00209 for (Bucket::iterator i = m_buckets[bucket].begin (); i != end; ++i)
00210 {
00211 if (i->key.m_uid == ev.key.m_uid)
00212 {
00213 NS_ASSERT (ev.impl == i->impl);
00214 m_buckets[bucket].erase (i);
00215
00216 m_qSize--;
00217 ResizeDown ();
00218 return;
00219 }
00220 }
00221 NS_ASSERT (false);
00222 }
00223
00224 void
00225 CalendarScheduler::ResizeUp (void)
00226 {
00227 if (m_qSize > m_nBuckets * 2 &&
00228 m_nBuckets < 32768)
00229 {
00230 Resize (m_nBuckets * 2);
00231 }
00232 }
00233 void
00234 CalendarScheduler::ResizeDown (void)
00235 {
00236 if (m_qSize < m_nBuckets / 2)
00237 {
00238 Resize (m_nBuckets / 2);
00239 }
00240 }
00241
00242 uint32_t
00243 CalendarScheduler::CalculateNewWidth (void)
00244 {
00245 if (m_qSize < 2)
00246 {
00247 return 1;
00248 }
00249 uint32_t nSamples;
00250 if (m_qSize <= 5)
00251 {
00252 nSamples = m_qSize;
00253 }
00254 else
00255 {
00256 nSamples = 5 + m_qSize / 10;
00257 }
00258 if (nSamples > 25)
00259 {
00260 nSamples = 25;
00261 }
00262
00263
00264 std::list<Scheduler::Event> samples;
00265
00266 uint32_t lastBucket = m_lastBucket;
00267 uint64_t bucketTop = m_bucketTop;
00268 uint64_t lastPrio = m_lastPrio;
00269
00270
00271 for (uint32_t i = 0; i < nSamples; i++)
00272 {
00273 samples.push_back (DoRemoveNext ());
00274 }
00275
00276 for (std::list<Scheduler::Event>::const_iterator i = samples.begin ();
00277 i != samples.end (); ++i)
00278 {
00279 DoInsert (*i);
00280 }
00281
00282
00283 m_lastBucket = lastBucket;
00284 m_bucketTop = bucketTop;
00285 m_lastPrio = lastPrio;
00286
00287
00288 uint64_t totalSeparation = 0;
00289 std::list<Scheduler::Event>::const_iterator end = samples.end ();
00290 std::list<Scheduler::Event>::const_iterator cur = samples.begin ();
00291 std::list<Scheduler::Event>::const_iterator next = cur;
00292 next++;
00293 while (next != end)
00294 {
00295 totalSeparation += next->key.m_ts - cur->key.m_ts;
00296 cur++;
00297 next++;
00298 }
00299 uint64_t twiceAvg = totalSeparation / (nSamples - 1) * 2;
00300 totalSeparation = 0;
00301 cur = samples.begin ();
00302 next = cur;
00303 next++;
00304 while (next != end)
00305 {
00306 uint64_t diff = next->key.m_ts - cur->key.m_ts;
00307 if (diff <= twiceAvg)
00308 {
00309 totalSeparation += diff;
00310 }
00311 cur++;
00312 next++;
00313 }
00314
00315 totalSeparation *= 3;
00316 totalSeparation = std::max (totalSeparation, (uint64_t)1);
00317 return totalSeparation;
00318 }
00319 void
00320 CalendarScheduler::DoResize (uint32_t newSize, uint32_t newWidth)
00321 {
00322 Bucket *oldBuckets = m_buckets;
00323 uint32_t oldNBuckets = m_nBuckets;
00324 Init (newSize, newWidth, m_lastPrio);
00325
00326 for (uint32_t i = 0; i < oldNBuckets; i++)
00327 {
00328 Bucket::iterator end = oldBuckets[i].end ();
00329 for (Bucket::iterator j = oldBuckets[i].begin (); j != end; ++j)
00330 {
00331 DoInsert (*j);
00332 }
00333 }
00334 }
00335 void
00336 CalendarScheduler::Resize (uint32_t newSize)
00337 {
00338 NS_LOG_FUNCTION (this << newSize);
00339
00340
00341 uint32_t newWidth = CalculateNewWidth ();
00342 DoResize (newSize, newWidth);
00343 }
00344
00345 }