00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035 #ifndef lint
00036 static const char rcsid[] =
00037 "@(#) $Header: /nfs/jade/vint/CVSROOT/ns-2/tools/queue-monitor.cc,v 1.28 2002/10/23 23:20:40 sfloyd Exp $";
00038 #endif
00039
00040 #include "queue-monitor.h"
00041 #include "trace.h"
00042 #include <math.h>
00043
00044 int QueueMonitor::command(int argc, const char*const* argv)
00045 {
00046 Tcl& tcl = Tcl::instance();
00047
00048 if (argc == 2) {
00049 if (strcmp(argv[1], "get-bytes-integrator") == 0) {
00050 if (bytesInt_)
00051 tcl.resultf("%s", bytesInt_->name());
00052 else
00053 tcl.resultf("");
00054 return (TCL_OK);
00055 }
00056 if (strcmp(argv[1], "get-pkts-integrator") == 0) {
00057 if (pktsInt_)
00058 tcl.resultf("%s", pktsInt_->name());
00059 else
00060 tcl.resultf("");
00061 return (TCL_OK);
00062 }
00063 if (strcmp(argv[1], "get-delay-samples") == 0) {
00064 if (delaySamp_)
00065 tcl.resultf("%s", delaySamp_->name());
00066 else
00067 tcl.resultf("");
00068 return (TCL_OK);
00069 }
00070 if (strcmp(argv[1], "printRTTs") == 0) {
00071 if (keepRTTstats_ && channel1_) {
00072 printRTTs();
00073 }
00074 return (TCL_OK);
00075 }
00076 if (strcmp(argv[1], "printSeqnos") == 0) {
00077 if (keepSeqnoStats_ && channel1_) {
00078 printSeqnos();
00079 }
00080 return (TCL_OK);
00081 }
00082 }
00083
00084 if (argc == 3) {
00085 if (strcmp(argv[1], "set-bytes-integrator") == 0) {
00086 bytesInt_ = (Integrator *)
00087 TclObject::lookup(argv[2]);
00088 if (bytesInt_ == NULL)
00089 return (TCL_ERROR);
00090 return (TCL_OK);
00091 }
00092 if (strcmp(argv[1], "set-pkts-integrator") == 0) {
00093 pktsInt_ = (Integrator *)
00094 TclObject::lookup(argv[2]);
00095 if (pktsInt_ == NULL)
00096 return (TCL_ERROR);
00097 return (TCL_OK);
00098 }
00099 if (strcmp(argv[1], "set-delay-samples") == 0) {
00100 delaySamp_ = (Samples*)
00101 TclObject::lookup(argv[2]);
00102 if (delaySamp_ == NULL)
00103 return (TCL_ERROR);
00104 return (TCL_OK);
00105 }
00106 if (strcmp(argv[1], "trace") == 0) {
00107
00108 int mode;
00109 const char* id = argv[2];
00110 channel_ = Tcl_GetChannel(tcl.interp(), (char*)id, &mode);
00111 if (channel_ == 0) {
00112 tcl.resultf("trace: can't attach %s for writing", id);
00113 return (TCL_ERROR);
00114 }
00115 return (TCL_OK);
00116 }
00117 if (strcmp(argv[1], "traceDist") == 0) {
00118
00119 int mode;
00120 const char* id = argv[2];
00121 channel1_ = Tcl_GetChannel(tcl.interp(), (char*)id, &mode);
00122 if (channel1_ == 0) {
00123 tcl.resultf("trace: can't attach %s for writing", id);
00124 return (TCL_ERROR);
00125 }
00126 return (TCL_OK);
00127 }
00128 }
00129 if (argc == 4) {
00130 if (strcmp(argv[1], "set-src-dst") == 0) {
00131 srcId_ = atoi(argv[2]);
00132 dstId_ = atoi(argv[3]);
00133 return (TCL_OK);
00134 }
00135 }
00136 return TclObject::command(argc, argv);
00137
00138 }
00139
00140 static class QueueMonitorClass : public TclClass {
00141 public:
00142 QueueMonitorClass() : TclClass("QueueMonitor") {}
00143 TclObject* create(int, const char*const*) {
00144 return (new QueueMonitor());
00145 }
00146 } queue_monitor_class;
00147
00148
00149 void
00150 QueueMonitor::printRTTs() {
00151 int i, n, topBin, MsPerBin;
00152 char wrk[500];
00153
00154 topBin = maxRTT_ * binsPerSec_;
00155 MsPerBin = int(1000/binsPerSec_);
00156 double now = Scheduler::instance().clock();
00157 sprintf(wrk, "Distribution of RTTs, %d ms bins, time %4.2f\n", MsPerBin, now);
00158 n = strlen(wrk); wrk[n] = 0;
00159 (void)Tcl_Write(channel1_, wrk, n);
00160 for (i = 0; i < topBin; i++) {
00161 if (RTTbins_[i] > 0) {
00162 sprintf(wrk, "%d to %d ms: frac %5.3f num %d time %4.2f\n",
00163 i*MsPerBin, (i+1)*MsPerBin,
00164 (double)RTTbins_[i]/numRTTs_,
00165 RTTbins_[i], now);
00166 n = strlen(wrk); wrk[n] = 0;
00167 (void)Tcl_Write(channel1_, wrk, n);
00168 }
00169 }
00170 i = topBin - 1;
00171 if (RTTbins_[i] > 0) {
00172 sprintf(wrk, "The last bin might also contain RTTs >= %d ms.\n",
00173 (i+1)*MsPerBin);
00174 n = strlen(wrk); wrk[n] = 0;
00175 (void)Tcl_Write(channel1_, wrk, n);
00176 }
00177 }
00178
00179 void
00180 QueueMonitor::printSeqnos() {
00181 int i, n, topBin;
00182 char wrk[500];
00183
00184 topBin = int(maxSeqno_ / SeqnoBinSize_);
00185 double now = Scheduler::instance().clock();
00186 sprintf(wrk, "Distribution of Seqnos, %d seqnos per bin, time %4.2f\n",
00187 SeqnoBinSize_, now);
00188 n = strlen(wrk); wrk[n] = 0;
00189 (void)Tcl_Write(channel1_, wrk, n);
00190 for (i = 0; i < topBin; i++) {
00191 if (SeqnoBins_[i] > 0) {
00192 sprintf(wrk, "%d to %d seqnos: frac %5.3f num %d time %4.2f\n",
00193 i*SeqnoBinSize_, (i+1)*SeqnoBinSize_ - 1,
00194 (double)SeqnoBins_[i]/numSeqnos_,
00195 SeqnoBins_[i], now);
00196 n = strlen(wrk); wrk[n] = 0;
00197 (void)Tcl_Write(channel1_, wrk, n);
00198 }
00199 }
00200 i = topBin - 1;
00201 if (SeqnoBins_[i] > 0) {
00202 sprintf(wrk, "The last bin might also contain Seqnos >= %d. \n",
00203 (i+1)*SeqnoBinSize_);
00204 n = strlen(wrk); wrk[n] = 0;
00205 (void)Tcl_Write(channel1_, wrk, n);
00206 }
00207 }
00208
00209 void
00210 QueueMonitor::printStats() {
00211 char wrk[500];
00212 int n;
00213 double now = Scheduler::instance().clock();
00214 sprintf(wrk, "q -t "TIME_FORMAT" -s %d -d %d -l %d -p %d", now, srcId_, dstId_, size_, pkts_);
00215 n = strlen(wrk);
00216 wrk[n] = '\n';
00217 wrk[n+1] = 0;
00218 (void)Tcl_Write(channel_, wrk, n+1);
00219 wrk[n] = 0;
00220 }
00221
00222
00223 void QueueMonitor::in(Packet* p)
00224 {
00225 hdr_cmn* hdr = hdr_cmn::access(p);
00226 double now = Scheduler::instance().clock();
00227 int pktsz = hdr->size();
00228
00229
00230 if (estimate_rate_) {
00231 estimateRate(p);
00232 }
00233 else {
00234 prevTime_ = now;
00235 }
00236
00237 barrivals_ += pktsz;
00238 parrivals_++;
00239 size_ += pktsz;
00240 pkts_++;
00241 if (bytesInt_)
00242 bytesInt_->newPoint(now, double(size_));
00243 if (pktsInt_)
00244 pktsInt_->newPoint(now, double(pkts_));
00245 if (delaySamp_)
00246 hdr->timestamp() = now;
00247 if (channel_)
00248 printStats();
00249
00250 }
00251
00252 void QueueMonitor::out(Packet* p)
00253 {
00254 hdr_cmn* hdr = hdr_cmn::access(p);
00255 hdr_flags* pf = hdr_flags::access(p);
00256 double now = Scheduler::instance().clock();
00257 int pktsz = hdr->size();
00258
00259 if (pf->ce() && pf->ect())
00260 pmarks_++;
00261 size_ -= pktsz;
00262 pkts_--;
00263 bdepartures_ += pktsz;
00264 pdepartures_++;
00265 if (bytesInt_)
00266 bytesInt_->newPoint(now, double(size_));
00267 if (pktsInt_)
00268 pktsInt_->newPoint(now, double(pkts_));
00269 if (delaySamp_)
00270 delaySamp_->newPoint(now - hdr->timestamp());
00271
00272 if (keepRTTstats_) {
00273 keepRTTstats(p);
00274 }
00275 if (keepSeqnoStats_) {
00276 keepSeqnoStats(p);
00277 }
00278 if (channel_)
00279 printStats();
00280 }
00281
00282 void QueueMonitor::drop(Packet* p)
00283 {
00284 hdr_cmn* hdr = hdr_cmn::access(p);
00285 double now = Scheduler::instance().clock();
00286 int pktsz = hdr->size();
00287
00288 size_ -= pktsz;
00289 pkts_--;
00290 bdrops_ += pktsz;
00291 pdrops_++;
00292 if (bytesInt_)
00293 bytesInt_->newPoint(now, double(size_));
00294 if (pktsInt_)
00295 pktsInt_->newPoint(now, double(pkts_));
00296 if (channel_)
00297 printStats();
00298 }
00299
00300
00301 void QueueMonitor::estimateRate(Packet *pkt) {
00302
00303 hdr_cmn* hdr = hdr_cmn::access(pkt);
00304 int pktSize = hdr->size() << 3;
00305
00306 double now = Scheduler::instance().clock();
00307 double timeGap = ( now - prevTime_);
00308
00309 if (timeGap == 0) {
00310 temp_size_ += pktSize;
00311 return;
00312 }
00313 else {
00314 pktSize+= temp_size_;
00315 temp_size_ = 0;
00316 }
00317
00318 prevTime_ = now;
00319
00320 estRate_ = (1 - exp(-timeGap/k_))*((double)pktSize)/timeGap + exp(-timeGap/k_)*estRate_;
00321 }
00322
00323
00324 void QueueMonitor::keepRTTstats(Packet *pkt) {
00325 int i, j, topBin, rttInMs, MsPerBin;
00326 hdr_cmn* hdr = hdr_cmn::access(pkt);
00327 packet_t t = hdr->ptype();
00328 if (t == PT_TCP || t == PT_HTTP || t == PT_FTP || t == PT_TELNET) {
00329 hdr_tcp *tcph = hdr_tcp::access(pkt);
00330 rttInMs = tcph->last_rtt();
00331 if (rttInMs < 0) rttInMs = 0;
00332 topBin = maxRTT_ * binsPerSec_;
00333 if (numRTTs_ == 0) {
00334 RTTbins_ = (int *)malloc(sizeof(int)*topBin);
00335 for (i = 0; i < topBin; i++) {
00336 RTTbins_[i] = 0;
00337 }
00338 }
00339 MsPerBin = int(1000/binsPerSec_);
00340 j = (int)(rttInMs/MsPerBin);
00341 if (j < 0) j = 0;
00342 if (j >= topBin) j = topBin - 1;
00343 ++ RTTbins_[j];
00344 ++ numRTTs_;
00345 }
00346 }
00347
00348
00349 void QueueMonitor::keepSeqnoStats(Packet *pkt) {
00350 int i, j, topBin, seqno;
00351 hdr_cmn* hdr = hdr_cmn::access(pkt);
00352 packet_t t = hdr->ptype();
00353 if (t == PT_TCP || t == PT_HTTP || t == PT_FTP || t == PT_TELNET) {
00354 hdr_tcp *tcph = hdr_tcp::access(pkt);
00355 seqno = tcph->seqno();
00356 if (seqno < 0) seqno = 0;
00357 topBin = int(maxSeqno_ / SeqnoBinSize_);
00358 if (numSeqnos_ == 0) {
00359 SeqnoBins_ = (int *)malloc(sizeof(int)*topBin);
00360 for (i = 0; i < topBin; i++) {
00361 SeqnoBins_[i] = 0;
00362 }
00363 }
00364 j = (int)(seqno/SeqnoBinSize_);
00365 if (j < 0) j = 0;
00366 if (j >= topBin) j = topBin - 1;
00367 ++ SeqnoBins_[j];
00368 ++ numSeqnos_;
00369 }
00370 }
00371
00372
00373
00374
00375
00376
00377 static class SnoopQueueInClass : public TclClass {
00378 public:
00379 SnoopQueueInClass() : TclClass("SnoopQueue/In") {}
00380 TclObject* create(int, const char*const*) {
00381 return (new SnoopQueueIn());
00382 }
00383 } snoopq_in_class;
00384
00385 static class SnoopQueueOutClass : public TclClass {
00386 public:
00387 SnoopQueueOutClass() : TclClass("SnoopQueue/Out") {}
00388 TclObject* create(int, const char*const*) {
00389 return (new SnoopQueueOut());
00390 }
00391 } snoopq_out_class;
00392
00393 static class SnoopQueueDropClass : public TclClass {
00394 public:
00395 SnoopQueueDropClass() : TclClass("SnoopQueue/Drop") {}
00396 TclObject* create(int, const char*const*) {
00397 return (new SnoopQueueDrop());
00398 }
00399 } snoopq_drop_class;
00400
00401 static class SnoopQueueEDropClass : public TclClass {
00402 public:
00403 SnoopQueueEDropClass() : TclClass("SnoopQueue/EDrop") {}
00404 TclObject* create(int, const char*const*) {
00405 return (new SnoopQueueEDrop);
00406 }
00407 } snoopq_edrop_class;
00408
00409
00410 static class SnoopQueueTaggerClass : public TclClass {
00411 public:
00412 SnoopQueueTaggerClass() : TclClass("SnoopQueue/Tagger") {}
00413 TclObject* create(int, const char*const*) {
00414 return (new SnoopQueueTagger);
00415 }
00416 } snoopq_tagger_class;
00417
00418 static class QueueMonitorEDClass : public TclClass {
00419 public:
00420 QueueMonitorEDClass() : TclClass("QueueMonitor/ED") {}
00421 TclObject* create(int, const char*const*) {
00422 return (new EDQueueMonitor);
00423 }
00424 } queue_monitor_ed_class;
00425
00426
00427
00428
00429
00430
00431
00432
00433
00434
00435 #include "ip.h"
00436 QueueMonitorCompat::QueueMonitorCompat()
00437 {
00438 memset(pkts_, 0, sizeof(pkts_));
00439 memset(bytes_, 0, sizeof(bytes_));
00440 memset(drops_, 0, sizeof(drops_));
00441 memset(flowstats_, 0, sizeof(flowstats_));
00442 }
00443
00444
00445
00446
00447
00448
00449 void
00450 QueueMonitorCompat::flowstats(int flowid)
00451 {
00452 Tcl& tcl = Tcl::instance();
00453
00454
00455
00456
00457
00458
00459
00460
00461
00462
00463
00464
00465
00466
00467 tcl.evalf("new Samples");
00468 flowstats_[flowid] = (Samples*)TclObject::lookup(tcl.result());
00469 if (flowstats_[flowid] == 0) {
00470 abort();
00471
00472 }
00473 }
00474
00475
00476 void QueueMonitorCompat::out(Packet* pkt)
00477 {
00478 hdr_cmn* hdr = hdr_cmn::access(pkt);
00479 hdr_ip* iph = hdr_ip::access(pkt);
00480 double now = Scheduler::instance().clock();
00481 int fid = iph->flowid();
00482
00483 if (fid >= MAXFLOW) {
00484 abort();
00485
00486 }
00487
00488 bytes_[fid] += hdr_cmn::access(pkt)->size();
00489 pkts_[fid]++;
00490 if (flowstats_[fid] == 0) {
00491 flowstats(fid);
00492 }
00493 flowstats_[fid]->newPoint(now - hdr->timestamp());
00494 QueueMonitor::out(pkt);
00495 }
00496
00497 void QueueMonitorCompat::in(Packet* pkt)
00498 {
00499 hdr_cmn* hdr = hdr_cmn::access(pkt);
00500 double now = Scheduler::instance().clock();
00501
00502 hdr->timestamp() = now;
00503 QueueMonitor::in(pkt);
00504 }
00505
00506 void QueueMonitorCompat::drop(Packet* pkt)
00507 {
00508
00509 hdr_ip* iph = hdr_ip::access(pkt);
00510 int fid = iph->flowid();
00511 if (fid >= MAXFLOW) {
00512 abort();
00513
00514 }
00515 ++drops_[fid];
00516 QueueMonitor::drop(pkt);
00517 }
00518
00519 int QueueMonitorCompat::command(int argc, const char*const* argv)
00520 {
00521 Tcl& tcl = Tcl::instance();
00522 int fid;
00523 if (argc == 3) {
00524 fid = atoi(argv[2]);
00525 if (strcmp(argv[1], "bytes") == 0) {
00526 if (fid >= MAXFLOW) {
00527 abort();
00528
00529 }
00530 tcl.resultf("%d", bytes_[fid]);
00531 return TCL_OK;
00532 } else if (strcmp(argv[1], "pkts") == 0) {
00533 if (fid >= MAXFLOW) {
00534 abort();
00535
00536 }
00537 tcl.resultf("%d", pkts_[fid]);
00538 return TCL_OK;
00539 } else if (strcmp(argv[1], "drops") == 0) {
00540 if (fid >= MAXFLOW) {
00541 abort();
00542
00543 }
00544 tcl.resultf("%d", drops_[fid]);
00545 return TCL_OK;
00546 } else if (strcmp(argv[1], "get-class-delay-samples") == 0) {
00547 if (fid >= MAXFLOW) {
00548 abort();
00549
00550 }
00551 if (flowstats_[fid] == 0) {
00552
00553
00554
00555
00556
00557
00558
00559
00560 flowstats(fid);
00561 }
00562 tcl.resultf("%s", flowstats_[fid]->name());
00563 return TCL_OK;
00564 }
00565 }
00566 return (QueueMonitor::command(argc, argv));
00567 }
00568
00569 static class QueueMonitorCompatClass : public TclClass {
00570 public:
00571 QueueMonitorCompatClass() : TclClass("QueueMonitor/Compat") {}
00572 TclObject* create(int, const char*const*) {
00573 return (new QueueMonitorCompat);
00574 }
00575 } queue_monitor_compat_class;