RINASim  October 2016
Documentation of framework for OMNeT++
DQMonitor.cc
Go to the documentation of this file.
1 //
2 // Copyright © 2014 - 2015 PRISTINE Consortium (http://ict-pristine.eu)
3 //
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU Lesser General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
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 Lesser General Public License for more details.
13 //
14 // You should have received a copy of the GNU Lesser General Public License
15 // along with this program. If not, see http://www.gnu.org/licenses/.
16 //
17 
18 #include <DQMonitor.h>
19 
20 namespace DQMonitor {
21 
23 
24 void DQMonitor::onPolicyInit() {
25 
26  //Parsing L data
27  if (par("lData").xmlValue() != NULL
28  && par("lData").xmlValue()->hasChildren()) {
29  parseL(par("lData").xmlValue());
30  } else {
31  error("lData parameter not initialized!");
32  }
33 
34 
35  //Parsing C data
36  if (par("cData").xmlValue() != NULL
37  && par("cData").xmlValue()->hasChildren()) {
38  parseC(par("cData").xmlValue());
39  } else {
40  error("cData parameter not initialized!");
41  }
42 
43 
44  //Parsing U data
45  if (par("uData").xmlValue() != NULL
46  && par("uData").xmlValue()->hasChildren()) {
47  parseU(par("uData").xmlValue());
48  } else {
49  error("uData parameter not initialized!");
50  }
51 
52 
53  //Parsing cuData
54  cXMLElement* xml = NULL;
55  if (par("cuData").xmlValue() != NULL
56  && par("cuData").xmlValue()->hasChildren()) {
57  xml = par("cuData").xmlValue();
58  } else {
59  error("cuData parameter not initialized!");
60  }
61  cXMLElementList cus = xml->getChildrenByTagName("CUItem");
62  for(cXMLElement * m : cus){
63  if (!m->getAttribute("id")) {
64  error("Error parsing CU. Its ID is missing!");
65  }
66 
67  std::string id = m->getAttribute("id");
68  if (id == "") {
69  error("Error parsing CU. Its ID is missing!");
70  }
71 
72  string qn = "";
73  L * l = NULL;
74  U * u = NULL;
75  C * c = NULL;
76 
77  cXMLElementList attrs = m->getChildren();
78  for(cXMLElement * n : attrs ){
79  string val = n->getNodeValue();
80  if (!strcmp(n->getTagName(), "limit")) {
81  if (Ls.find(val) != Ls.end()) {
82  l = &Ls[val];
83  } else {
84  std::cout << "Limit " << val << "not found" <<endl;
85  }
86  } else if (!strcmp(n->getTagName(), "cherish")) {
87  if (Cs.find(val) != Cs.end()) {
88  c = &Cs[val];
89  } else {
90  std::cout << "Cherish " << val << "not found" <<endl;
91  }
92  } else if (!strcmp(n->getTagName(), "urgency")) {
93  if (Us.find(val) != Us.end()) {
94  u = &Us[val];
95  } else {
96  std::cout << "Urgency " << val << "not found" <<endl;
97  }
98  } else if (!strcmp(n->getTagName(), "queue")) {
99  qn = val;
100  }
101  }
102  if(l == NULL || u == NULL || c == NULL) {
103  std::cout << l << " " << c << " " << u <<endl;
104  error("L/C/U missing");
105  }
106 
107  CUs[id] = dlCUInfo(qn, l, c, u);
108  }
109 
110 }
111 void DQMonitor::parseL(cXMLElement* xml) {
112  cXMLElementList ls = xml->getChildrenByTagName("L");
113  for(cXMLElement* m : ls){
114  if (!m->getAttribute("id")) {
115  error("Error parsing L. Its ID is missing!");
116  }
117 
118  std::string id = m->getAttribute("id");
119  if (id == "") {
120  error("Error parsing L. Its ID is missing!");
121  }
122 
123  bool limit = (m->getChildrenByTagName("limit").size() > 0);
124  bool space = (m->getChildrenByTagName("space").size() > 0);
125 
126  ILimValsList v;
127  IDropProbList p;
128 
129  if (limit || space) {
130  cXMLElementList limVals = m->getChildrenByTagName("limVals");
131  for(cXMLElement* n : limVals) {
132  double index;
133  long long rate; // bps
134  long long spaceRate; //bps
135  double spaceVar; //[0..1]
136  double dropProb = 0; //[0..1]
137 
138  if (!n->getAttribute("wt")) {
139  error("Error parsing limVals. Its wt is missing!");
140  }
141  index = atof(n->getAttribute("wt"));
142  if (index < 0.0 ) {
143  error("Error parsing limVals. wt cannot be negative");
144  }
145 
146  //Rate
147  if (n->getChildrenByTagName("rate").size() != 1) {
148  error( "Error parsing limVals. There must be one an only one rate per limVals");
149  }
150  rate = atoll((*n->getChildrenByTagName("rate").begin())->getNodeValue());
151  if (rate <= 0) {
152  error( "Error parsing limVals. rate cannot be 0 or negative");
153  }
154 
155  //Space Rate
156  if (n->getChildrenByTagName("spaceRate").size() != 1) {
157  error("Error parsing limVals. There must be one an only one spaceRate per limVals");
158  }
159  spaceRate = atoll((*n->getChildrenByTagName("spaceRate").begin())->getNodeValue());
160  if (spaceRate <= 0) {
161  error( "Error parsing limVals. spaceRate cannot be 0 or negative");
162  }
163 
164  //Space Rate Variation
165  if (n->getChildrenByTagName("spaceVar").size() != 1) {
166  error( "Error parsing limVals. There must be one an only one spaceVar per limVals");
167  }
168  spaceVar = atof((*n->getChildrenByTagName("spaceVar").begin())->getNodeValue());
169  if (spaceVar < 0 || spaceVar > 1) {
170  error( "Error parsing limVals. spaceVar must be between 0 and 1");
171  }
172 
173  if (limit) {
174  //Drop Probability
175  if (n->getChildrenByTagName("dropProb").size() != 1) {
176  error( "Error parsing limVals. There must be one an only one dropProb per limVals");
177  }
178  dropProb = atof((*n->getChildrenByTagName("dropProb").begin())->getNodeValue());
179  if (dropProb < 0 || dropProb > 1) {
180  error( "Error parsing limVals. dropProb must be between 0 and 1");
181  }
182  }
183 
184  v.push_back(ILimVals(index, rate, spaceRate, spaceVar, dropProb));
185  }
186  }
187 
188  if (limit) {
189  cXMLElementList dropVals = m->getChildrenByTagName("dropProb");
190  for(cXMLElement* n : dropVals) {
191  double index;
192  double dropProb; //[0..1]
193 
194  if (!n->getAttribute("ws")) {
195  error("Error parsing dropProb. Its ws is missing!");
196  }
197  index = atof(n->getAttribute("ws"));
198  if (index < 0 ) {
199  error("Error parsing dropProb. ws cannot be negative");
200  }
201 
202 
203  //Drop Probability
204  if (!n->getAttribute("prob")) {
205  error("Error parsing dropProb. Its prob is missing!");
206  }
207  dropProb = atof(n->getAttribute("prob"));
208  if (dropProb < 0 || dropProb > 1 ) {
209  error("Error parsing dropProb. prob must be between 0 and 1");
210  }
211 
212  p.push_back(IDropProb(index, dropProb));
213  }
214  }
215  Ls[id] = L(limit, space, v, p);
216  std::cout << "L :: "<< id << " => "<< &Ls[id] << endl;
217  }
218 
219 }
220 void DQMonitor::parseC(cXMLElement* xml){
221  cXMLElementList ls = xml->getChildrenByTagName("C");
222  for(cXMLElement* m : ls) {
223  if (!m->getAttribute("id")) {
224  error("Error parsing C. Its ID is missing!");
225  }
226 
227  std::string id = m->getAttribute("id");
228  if (id == "") {
229  error("Error parsing C. Its ID is missing!");
230  }
231 
232  double def = 0.0; //[0..1]
233  IDropProbList p;
234 
235  if (m->getAttribute("defaultDropProb")) {
236  def = atof(m->getAttribute("defaultDropProb"));
237  if(def < 0 || def > 1) {
238  error("Error parsing C. defaultDropProb must be between 0 and 1");
239  }
240  }
241 
242  cXMLElementList dropPVals = m->getChildrenByTagName("dropProb");
243  for (cXMLElement* n : dropPVals) {
244  double index;
245  double dropProb; //[0..1]
246 
247  if (!n->getAttribute("ws")) {
248  error("Error parsing dropProb. Its ws is missing!");
249  }
250  index = atof(n->getAttribute("ws"));
251  if (index < 0 ) {
252  error("Error parsing dropProb. ws cannot be negative");
253  }
254 
255  //Drop Probability
256  if (!n->getAttribute("prob")) {
257  error("Error parsing dropProb. Its prob is missing!");
258  }
259  dropProb = atof(n->getAttribute("prob"));
260  if (dropProb < 0 || dropProb > 1 ) {
261  error("Error parsing dropProb. prob must be between 0 and 1");
262  }
263 
264  p.push_back(IDropProb(index, dropProb));
265  }
266  Cs[id] = C(def, p);
267  }
268 }
269 void DQMonitor::parseU(cXMLElement* xml) {
270 
271  cXMLElementList ls = xml->getChildrenByTagName("U");
272  for(cXMLElement* m : ls){
273  if (!m->getAttribute("id")) {
274  error("Error parsing U. Its ID is missing!");
275  }
276 
277  std::string id = m->getAttribute("id");
278  if (id == "") {
279  error("Error parsing U. Its ID is missing!");
280  }
281 
282  int defPrio = 0;
283  if (m->getAttribute("defaultPriority")) {
284  defPrio = atoi(m->getAttribute("defaultPriority"));
285  }
286 
287  bool degraded = (m->getChildrenByTagName("degraded").size() > 0);
288 
289  long long rate = 0;
290  IDegradList dl;
291 
292  if (degraded) {
293  //Rate
294  if (m->getChildrenByTagName("rate").size() != 1) {
295  error( "Error parsing U. There must be one an only one rate per limVals");
296  }
297  rate = atoll((*m->getChildrenByTagName("rate").begin())->getNodeValue());
298  if (rate <= 0) {
299  error( "Error parsing U. rate cannot be 0 or negative");
300  }
301 
302  cXMLElementList degVals = m->getChildrenByTagName("degradList");
303  for(cXMLElement* n : degVals) {
304  double index;
305  if (!n->getAttribute("wt")) {
306  error("Error parsing degradList. Its wt is missing!");
307  }
308  index = atof(n->getAttribute("wt"));
309  if (index < 0.0 ) {
310  error("Error parsing degradList. rate wt be negative");
311  }
312 
313  IDegrad dd(index);
314 
315  cXMLElementList ppl = n->getChildrenByTagName("PP");
316  for(cXMLElement* w : ppl) {
317  int prior;
318  double prob;
319 
320  //Priority
321  if (!w->getAttribute("priority")) {
322  error( "Error parsing PP. There must be one an only one priority per PP");
323  }
324 
325  prior = atoi(w->getAttribute("priority"));
326 
327  //Probability
328  if (!w->getAttribute("probability")) {
329  error( "Error parsing PP. There must be one an only one probability per PP");
330  }
331  prob = atof(w->getAttribute("probability"));
332  if (prob <= 0) {
333  error( "Error parsing PP. probability must be between 0 and 1");
334  }
335 
336  dd.PPs.push_back(PP(prior, prob));
337  }
338  dl.push_back(dd);
339  }
340  }
341 
342  Us[id] = U(defPrio, degraded, rate, dl);
343  }
344 }
345 
346 void DQMonitor::postPDUInsertion(RMTQueue* queue) {
347  //Get port and dlCUInfo for the queue
348  RMTPort* port = rmtAllocator->getQueueToPortMapping(queue);
349  dlCUInfo * cu = Q2CU[queue];
350 
351  if (port != NULL && cu != NULL ) {
352  switch(queue->getType()){
353 
354  //At input::
355  case RMTQueue::INPUT : {
356 
357  //Get queue times list
358  list<simtime_t> * times = &LTimes[port][cu->limit];
359 
360  //Clear serving times of past times
361  for(list<simtime_t>::iterator it = times->begin(); it != times->end();){
362  list<simtime_t>::iterator tmpIt = it++;
363  if(*tmpIt <= simTime()) { times->erase(tmpIt); }
364  }
365 
366  // Get serve and space times
367  Times t;
368  if(times->empty()){
369  std::cout << cu->limit << endl;
370  t = Times( cu->limit->getTimes(0.0, queue->getLastPDU()->getBitLength()) );
371  } else {
372  t = Times( cu->limit->getTimes( (times->back() - simTime()).dbl(), queue->getLastPDU()->getBitLength()) );
373  }
374 
375  //Insert new serve and space times
376  LTimes[port][cu->limit].push_back( t.serveT+simTime() );
377  SpaceTimes[port][cu->limit].push_back( t.spaceT+simTime() );
378 
379  //Push "queue serve" into waiting queue
380  LQueues[port][cu->limit].push_back(queue);
381 
382  } break;
383 
384  //At output::
385  case RMTQueue::OUTPUT : {
386 
387  //Count number of PDUs waiting on port
388  outC[port]++;
389 
390  //Get queue times list
391  list<simtime_t> * times = &UTimes[queue];
392 
393  //Clear serving times of past times
394  for(list<simtime_t>::iterator it = times->begin(); it != times->end();){
395  list<simtime_t>::iterator tmpIt = it++;
396  if(*tmpIt <= simTime()) { times->erase(tmpIt); }
397  }
398 
399  //Get last serving time, if none, current
400  simtime_t lt = simTime();
401  if(!times->empty()) { lt = times->back();}
402 
403  //Get next urgency given last serving time
405  int u = -cu->urgency->getPriority( (lt-simTime()).dbl() );
406  lastUrgency[queue] = u;
407 
408  //Compute next servint time and add to the queue times list
409  lt += cu->urgency->getTime(queue->getLastPDU()->getBitLength());
410  times->push_back(lt);
411 
412  //Push "queue serve" into waiting queue for given priority
413  UQueues[port][u].push_back(queue);
414 
415  } break;
416  }
417  } else {
418  error ("Unkown queue");
419  }
420 }
421 
422 void DQMonitor::onMessageDrop(RMTQueue* queue, const cPacket* pdu) {
423  //Get port and dlCUInfo for the queue
424  RMTPort* port = rmtAllocator->getQueueToPortMapping(queue);
425  dlCUInfo * cu = Q2CU[queue];
426 
427  if (port != NULL && cu != NULL ) {
428  switch(queue->getType()){
429 
430  //At input::
431  case RMTQueue::INPUT : {
432 
433  //Remove last serve and space times
434  LTimes[port][cu->limit].pop_back();
435  SpaceTimes[port][cu->limit].pop_back();
436 
437  //Remove last "queue serve"
438  LQueues[port][cu->limit].pop_back();
439 
440  } break;
441 
442  //At output::
443  case RMTQueue::OUTPUT : {
444  //Decrement number of PDUs waiting on port
445  outC[port]--;
446 
447  //Check for weird errors
448  if(lastUrgency.find(queue) == lastUrgency.end()) { error("PDUs removed without going through monitor?"); }
449 
450  //Get and clear lastUrgency
451  int lastU = lastUrgency[queue];
452  lastUrgency.erase(queue);
453 
454  //Pop last "queue serve" from waiting queue for given priority.
455  //Erase urgency queue if empty
456  UQueues[port][lastU].pop_back();
457  if(UQueues[port][lastU].empty()){ UQueues[port].erase(lastU); }
458 
459 
460  //Get queue times list and try to remove last insertion
461  list<simtime_t> * times = &UTimes[queue];
462  if(!times->empty()) {
463  times->pop_back();
464  } else {
465  error("PDUs removed without going through monitor?");
466  }
467  } break;
468  }
469  }
470 }
471 
472 void DQMonitor::postQueueCreation(RMTQueue* queue) {
473  std::string cu = "BE";
474 
475  for(auto cl : CUs){
476  if(cl.second.queueName == queue->getName()){
477  cu = cl.first;
478  }
479  }
480 
481  Q2CU[queue] = &CUs[cu];
482 
483  std::cout << queue->getName() << " => "<< cu<<endl;
484 }
485 
486 double DQMonitor::getInDropProb(RMTQueue * queue) {
487  //Get port and dlCUInfo for the queue
488  RMTPort* port = rmtAllocator->getQueueToPortMapping(queue);
489  dlCUInfo * cu = Q2CU[queue];
490 
491  if (port != NULL && cu != NULL ) {
492  //Return state : drop with prob X, given by last serving time + waiting pdus
493  list<simtime_t> * times = &LTimes[port][cu->limit];
494  cu->limit->getDropProb((times->back()-simTime()).dbl(), times->size());
495  }
496 
497  return 1;
498 }
499 
500 RMTQueue* DQMonitor::getNextInput(RMTPort* port) {
501  //Initialice vars
502  RMTQueue* q = NULL;
503  L * minL = NULL;
504  simtime_t minT = DBL_MAX;
505 
506  //Iterate through all L and get that with lower space time
507  for(auto l : SpaceTimes[port]) {
508  if(l.second.empty()){
509  simtime_t tmp = l.second.front();
510  if(tmp < minT) {
511  minT = tmp;
512  minL = l.first;
513  }
514  }
515  }
516 
517  if(minL != NULL) {
518  //save nextServe time for the port
519  nextServe[port] = minT;
520 
521  //If next serve is not in the future, get the next queue and pop extra data
522  if(minT <= simTime()) {
523  q = LQueues [port][minL].front();
524  LQueues [port][minL].pop_front();
525  LTimes [port][minL].pop_front();
526  SpaceTimes [port][minL].pop_front();
527  }
528  }
529  return q;
530 }
531 
532 simtime_t DQMonitor::getNextInputTime(RMTPort* port) {
533  //return last computed nextServe time for that port
534  return nextServe[port];
535 }
536 
537 
538 
539 double DQMonitor::getOutDropProb(RMTQueue * queue) {
540  //Get port and dlCUInfo for the queue
541  RMTPort* port = rmtAllocator->getQueueToPortMapping(queue);
542  dlCUInfo * cu = Q2CU[queue];
543 
544  if (port == NULL || cu == NULL) { error ("Unkown queue"); }
545 
546  //Compute the drop probability
547  return cu->cherish->getDropProb(outC[port]);
548 }
549 
550 RMTQueue* DQMonitor::getNextOutput(RMTPort* port) {
551 
552  //Iterate through all priorities and return the first queue found
554  for(auto uQ : UQueues[port]){
555  if(!uQ.second.empty()) {
556  RMTQueue* q = uQ.second.front();
557  uQ.second.pop_front();
558  outC[port]--;
559  return q;
560  }
561  }
562 
563  return NULL;
564 }
565 
566 }
queueType getType() const
Definition: RMTQueue.cc:241
int getPriority(double wt)
Definition: dlCUInfo.cc:155
vector< IDropProb > IDropProbList
Definition: dlCUInfo.h:72
double getDropProb(int s)
Definition: dlCUInfo.cc:130
Define_Module(DQMonitor)
const cPacket * getLastPDU() const
Definition: RMTQueue.cc:276
double getTime(int size)
Definition: dlCUInfo.cc:150
Times getTimes(double wt, int size)
Definition: dlCUInfo.cc:79
double serveT
Definition: dlCUInfo.h:80
double spaceT
Definition: dlCUInfo.h:81
double getDropProb(double wt, int ws)
Definition: dlCUInfo.cc:107
vector< ILimVals > ILimValsList
Definition: dlCUInfo.h:71
vector< IDegrad > IDegradList
Definition: dlCUInfo.h:73