forest-net
an overlay networks for large-scale virtual worlds
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator
QuManager.cpp
1 
9 /*
10 Implementation Notes
11 We maintain two heaps defined on the links. The active heap
12 contains links for which packets are currently queued. The
13 vactive heap contains links that are "virtually active", meaning
14 that they recently sent their last packet, but they are not
15 yet allowed to send their next, given the limit on their bit
16 rate and packet rate. If a packet arrives for a virtually active
17 link, it is moved to the active heap with a deadline inherited
18 from the vactive heap.
19 
20 It's important that links be moved off the vactive heap when
21 they become eligible to send new packets. This is done in the
22 nextReady routine, which is expected to be called frequently
23 (e.g. once on each iteration of the router's main loop).
24 
25 In addition to the active and vactive heaps, there is a HeapSet
26 data structure that contains a heap for each link. These heaps
27 contain queues and the key of a queue in its heap, is the
28 virtual finish time of the queue in a Self-Clocked Fair Queueing
29 packet scheduler.
30 */
31 
32 #include "QuManager.h"
33 
34 namespace forest {
35 
36 
37 // Constructor for QuManager, allocates space and initializes everything.
38 QuManager::QuManager(int nL1, int nP1, int nQ1, int maxppl1,
39  PacketStore *ps1, StatsModule *sm1)
40  : nL(nL1), nP(nP1), nQ(nQ1),
41  maxppl(maxppl1), ps(ps1), sm(sm1) {
42  queues = new UiListSet(nP,nQ);
43  active = new Heap(nL);
44  vactive = new Heap(nL);
45  quInfo = new QuInfo[nQ+1];
46  lnkInfo = new LinkInfo[nL+1];
47  hset = new HeapSet(nQ,nL);
48 
51  for (int lnk = 1; lnk <= nL; lnk++) {
52  lnkInfo[lnk].vt = 0; setLinkRates(lnk, rs);
53  }
54 
55  // build free list of queues using lnk field
56  for (int qid = 1; qid < nQ; qid++) {
57  quInfo[qid].lnk = qid+1;
58  quInfo[qid].pktLim = -1; // used to identify unassigned queues
59  quInfo[qid].vft = 0;
60  }
61  quInfo[nQ].lnk = 0; free = 1;
62  qCnt = 0;
63  // MAH
64  #ifdef PROFILING
65  enq_timer = new Timer("QuManager::enq(int, int, uint64_t)");
66  deq_timer = new Timer("QuManager::deq(int&, uint64_t)");
67  #endif
68 }
69 
70 QuManager::~QuManager() {
71  delete queues; delete active; delete vactive;
72  delete [] quInfo; delete [] lnkInfo; delete hset;
73  // MAH: profiling
74  #ifdef PROFILING
75  cout << *enq_timer << endl;
76  cout << *deq_timer << endl;
77  delete enq_timer; delete deq_timer;
78  #endif
79 }
80 
85 int QuManager::allocQ(int lnk) {
86  if (free == 0) return 0;
87  int qid = free; free = quInfo[qid].lnk;
88  quInfo[qid].lnk = lnk;
89  quInfo[qid].pktLim = 0; // non-negative value for assigned queues
90  qCnt++;
91  return qid;
92 }
93 
100 void QuManager::freeQ(int qid) {
101  if (qid == 0) return;
102  if (queues->empty(qid)) {
103  quInfo[qid].lnk = free; free = qid; qCnt--;
104  }
105  quInfo[qid].pktLim = -1; // negative value for free queues
106 }
107 
116 bool QuManager::enq(int px, int qid, uint64_t now) {
117  int pleng = Forest::truPktLeng((ps->getPacket(px)).length);
118  QuInfo& q = quInfo[qid]; int lnk = q.lnk;
119 
120  // don't queue it if too many packets for link
121  // or if queue is past its limits
122  if (sm->getLinkQlen(lnk) >= maxppl ||
123  sm->getQlen(qid) >= q.pktLim ||
124  sm->getQbytes(qid) + pleng > q.byteLim) {
125  return false;
126  }
127 
128  if (queues->empty(qid)) {
129  // make link active if need be
130  if (!active->member(lnk)) {
131  uint64_t d;
132  if (vactive->member(lnk)) {
133  d = vactive->key(lnk);
134  if (now >= d) d = now;
135  vactive->remove(lnk);
136  } else {
137  d = now;
138  lnkInfo[lnk].avgPktTime = lnkInfo[lnk].minDelta;
139  }
140  active->insert(lnk,d);
141  }
142  // set virtual finish time of queue
143  uint64_t d = q.nsPerByte; d *= pleng;
144  if (q.minDelta > d) d = q.minDelta;
145  q.vft = max(q.vft, lnkInfo[lnk].vt) + d;
146 
147  // add queue to scheduling heap for link
148  if (!hset->insert(qid,q.vft,lnk)) {
149  string s;
150  cerr << "enq attempt to insert in hset failed qid="
151  << qid << " lnk=" << lnk << " hset="
152  << hset->toString(lnk,s);
153  }
154  }
155 
156  // add packet to queue
157  queues->addLast(px,qid);
158  sm->incQlen(qid,lnk,pleng);
159  return true;
160 }
161 
169 int QuManager::deq(int& lnk, uint64_t now) {
170  // first process virtually active links that should now be idle
171  //
172  int vl = vactive->findmin(); uint64_t d = vactive->key(vl);
173  while (vl != 0 && now >= d) {
174  vactive->remove(vl);
175  vl = vactive->findmin(); d = vactive->key(vl);
176  }
177  // determine next active link that is ready to send
178  if (active->empty()) return 0;
179  lnk = active->findmin(); d = active->key(lnk);
180  if (now < d) return 0;
181 
182  // dequeue packet and update statistics
183  int qid = hset->findMin(lnk);
184  pktx px = queues->removeFirst(qid);
185  int pleng = Forest::truPktLeng(ps->getPacket(px).length);
186  sm->decQlen(qid,lnk,pleng);
187 
188  // and update scheduling heap and virtual time of lnk
189  QuInfo& q = quInfo[qid];
190  lnkInfo[lnk].vt = q.vft;
191  if (queues->empty(qid)) {
192  hset->deleteMin(lnk);
193  if (q.pktLim < 0) {
194  // move queue to the free list
195  q.lnk = free; free = qid; qCnt--;
196  }
197  } else {
198  int npx = queues->first(qid);
199  Packet& np = ps->getPacket(npx);
200  int npleng = Forest::truPktLeng(np.length);
201  uint64_t d = q.nsPerByte; d *= npleng;
202  if (q.minDelta > d) d = q.minDelta;
203  q.vft += d;
204  hset->changeKeyMin(q.vft, lnk);
205  }
206 
207  // update the time when lnk can send its next packet
208  uint64_t t = lnkInfo[lnk].nsPerByte; t *= pleng;
209  lnkInfo[lnk].avgPktTime = (t/16) + (15*(lnkInfo[lnk].avgPktTime/16));
210  if (lnkInfo[lnk].avgPktTime < lnkInfo[lnk].minDelta &&
211  t < lnkInfo[lnk].minDelta)
212  t = lnkInfo[lnk].minDelta;
213  t += active->key(lnk);
214 
215  if (hset->empty(lnk)) {
216  active->remove(lnk);
217  vactive->insert(lnk,t);
218  } else {
219  active->changekey(lnk,t);
220  }
221 
222  return px;
223 }
224 
225 } // ends namespace
226