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.29 2004/10/28 01:21:41 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 hdr_flags* pf = hdr_flags::access(p);
00229
00230 last_pkt_ = Scheduler::instance().clock();
00231 if (parrivals_ == 0) {
00232 first_pkt_ = last_pkt_;
00233 }
00234
00235 if (pf->qs()) {
00236 qs_pkts_++;
00237 qs_bytes_ += pktsz;
00238 }
00239
00240
00241 if (estimate_rate_) {
00242 estimateRate(p);
00243 }
00244 else {
00245 prevTime_ = now;
00246 }
00247
00248 barrivals_ += pktsz;
00249 parrivals_++;
00250 size_ += pktsz;
00251 pkts_++;
00252 if (bytesInt_)
00253 bytesInt_->newPoint(now, double(size_));
00254 if (pktsInt_)
00255 pktsInt_->newPoint(now, double(pkts_));
00256 if (delaySamp_)
00257 hdr->timestamp() = now;
00258 if (channel_)
00259 printStats();
00260
00261 }
00262
00263 void QueueMonitor::out(Packet* p)
00264 {
00265 hdr_cmn* hdr = hdr_cmn::access(p);
00266 hdr_flags* pf = hdr_flags::access(p);
00267 double now = Scheduler::instance().clock();
00268 int pktsz = hdr->size();
00269
00270 if (pf->ce() && pf->ect())
00271 pmarks_++;
00272 size_ -= pktsz;
00273 pkts_--;
00274 bdepartures_ += pktsz;
00275 pdepartures_++;
00276 if (bytesInt_)
00277 bytesInt_->newPoint(now, double(size_));
00278 if (pktsInt_)
00279 pktsInt_->newPoint(now, double(pkts_));
00280 if (delaySamp_)
00281 delaySamp_->newPoint(now - hdr->timestamp());
00282
00283 if (keepRTTstats_) {
00284 keepRTTstats(p);
00285 }
00286 if (keepSeqnoStats_) {
00287 keepSeqnoStats(p);
00288 }
00289 if (channel_)
00290 printStats();
00291 }
00292
00293 void QueueMonitor::drop(Packet* p)
00294 {
00295 hdr_cmn* hdr = hdr_cmn::access(p);
00296 double now = Scheduler::instance().clock();
00297 int pktsz = hdr->size();
00298 hdr_flags* pf = hdr_flags::access(p);
00299
00300 size_ -= pktsz;
00301 pkts_--;
00302 bdrops_ += pktsz;
00303 pdrops_++;
00304
00305 if (pf->qs())
00306 qs_drops_++;
00307
00308 if (bytesInt_)
00309 bytesInt_->newPoint(now, double(size_));
00310 if (pktsInt_)
00311 pktsInt_->newPoint(now, double(pkts_));
00312 if (channel_)
00313 printStats();
00314 }
00315
00316
00317 void QueueMonitor::estimateRate(Packet *pkt) {
00318
00319 hdr_cmn* hdr = hdr_cmn::access(pkt);
00320 int pktSize = hdr->size() << 3;
00321
00322 double now = Scheduler::instance().clock();
00323 double timeGap = ( now - prevTime_);
00324
00325 if (timeGap == 0) {
00326 temp_size_ += pktSize;
00327 return;
00328 }
00329 else {
00330 pktSize+= temp_size_;
00331 temp_size_ = 0;
00332 }
00333
00334 prevTime_ = now;
00335
00336 estRate_ = (1 - exp(-timeGap/k_))*((double)pktSize)/timeGap + exp(-timeGap/k_)*estRate_;
00337 }
00338
00339
00340 void QueueMonitor::keepRTTstats(Packet *pkt) {
00341 int i, j, topBin, rttInMs, MsPerBin;
00342 hdr_cmn* hdr = hdr_cmn::access(pkt);
00343 packet_t t = hdr->ptype();
00344 if (t == PT_TCP || t == PT_HTTP || t == PT_FTP || t == PT_TELNET) {
00345 hdr_tcp *tcph = hdr_tcp::access(pkt);
00346 rttInMs = tcph->last_rtt();
00347 if (rttInMs < 0) rttInMs = 0;
00348 topBin = maxRTT_ * binsPerSec_;
00349 if (numRTTs_ == 0) {
00350 RTTbins_ = (int *)malloc(sizeof(int)*topBin);
00351 for (i = 0; i < topBin; i++) {
00352 RTTbins_[i] = 0;
00353 }
00354 }
00355 MsPerBin = int(1000/binsPerSec_);
00356 j = (int)(rttInMs/MsPerBin);
00357 if (j < 0) j = 0;
00358 if (j >= topBin) j = topBin - 1;
00359 ++ RTTbins_[j];
00360 ++ numRTTs_;
00361 }
00362 }
00363
00364
00365 void QueueMonitor::keepSeqnoStats(Packet *pkt) {
00366 int i, j, topBin, seqno;
00367 hdr_cmn* hdr = hdr_cmn::access(pkt);
00368 packet_t t = hdr->ptype();
00369 if (t == PT_TCP || t == PT_HTTP || t == PT_FTP || t == PT_TELNET) {
00370 hdr_tcp *tcph = hdr_tcp::access(pkt);
00371 seqno = tcph->seqno();
00372 if (seqno < 0) seqno = 0;
00373 topBin = int(maxSeqno_ / SeqnoBinSize_);
00374 if (numSeqnos_ == 0) {
00375 SeqnoBins_ = (int *)malloc(sizeof(int)*topBin);
00376 for (i = 0; i < topBin; i++) {
00377 SeqnoBins_[i] = 0;
00378 }
00379 }
00380 j = (int)(seqno/SeqnoBinSize_);
00381 if (j < 0) j = 0;
00382 if (j >= topBin) j = topBin - 1;
00383 ++ SeqnoBins_[j];
00384 ++ numSeqnos_;
00385 }
00386 }
00387
00388
00389
00390
00391
00392
00393 static class SnoopQueueInClass : public TclClass {
00394 public:
00395 SnoopQueueInClass() : TclClass("SnoopQueue/In") {}
00396 TclObject* create(int, const char*const*) {
00397 return (new SnoopQueueIn());
00398 }
00399 } snoopq_in_class;
00400
00401 static class SnoopQueueOutClass : public TclClass {
00402 public:
00403 SnoopQueueOutClass() : TclClass("SnoopQueue/Out") {}
00404 TclObject* create(int, const char*const*) {
00405 return (new SnoopQueueOut());
00406 }
00407 } snoopq_out_class;
00408
00409 static class SnoopQueueDropClass : public TclClass {
00410 public:
00411 SnoopQueueDropClass() : TclClass("SnoopQueue/Drop") {}
00412 TclObject* create(int, const char*const*) {
00413 return (new SnoopQueueDrop());
00414 }
00415 } snoopq_drop_class;
00416
00417 static class SnoopQueueEDropClass : public TclClass {
00418 public:
00419 SnoopQueueEDropClass() : TclClass("SnoopQueue/EDrop") {}
00420 TclObject* create(int, const char*const*) {
00421 return (new SnoopQueueEDrop);
00422 }
00423 } snoopq_edrop_class;
00424
00425
00426 static class SnoopQueueTaggerClass : public TclClass {
00427 public:
00428 SnoopQueueTaggerClass() : TclClass("SnoopQueue/Tagger") {}
00429 TclObject* create(int, const char*const*) {
00430 return (new SnoopQueueTagger);
00431 }
00432 } snoopq_tagger_class;
00433
00434 static class QueueMonitorEDClass : public TclClass {
00435 public:
00436 QueueMonitorEDClass() : TclClass("QueueMonitor/ED") {}
00437 TclObject* create(int, const char*const*) {
00438 return (new EDQueueMonitor);
00439 }
00440 } queue_monitor_ed_class;
00441
00442
00443
00444
00445
00446
00447
00448
00449
00450
00451 #include "ip.h"
00452 QueueMonitorCompat::QueueMonitorCompat()
00453 {
00454 memset(pkts_, 0, sizeof(pkts_));
00455 memset(bytes_, 0, sizeof(bytes_));
00456 memset(drops_, 0, sizeof(drops_));
00457 memset(flowstats_, 0, sizeof(flowstats_));
00458 }
00459
00460
00461
00462
00463
00464
00465 void
00466 QueueMonitorCompat::flowstats(int flowid)
00467 {
00468 Tcl& tcl = Tcl::instance();
00469
00470
00471
00472
00473
00474
00475
00476
00477
00478
00479
00480
00481
00482
00483 tcl.evalf("new Samples");
00484 flowstats_[flowid] = (Samples*)TclObject::lookup(tcl.result());
00485 if (flowstats_[flowid] == 0) {
00486 abort();
00487
00488 }
00489 }
00490
00491
00492 void QueueMonitorCompat::out(Packet* pkt)
00493 {
00494 hdr_cmn* hdr = hdr_cmn::access(pkt);
00495 hdr_ip* iph = hdr_ip::access(pkt);
00496 double now = Scheduler::instance().clock();
00497 int fid = iph->flowid();
00498
00499 if (fid >= MAXFLOW) {
00500 abort();
00501
00502 }
00503
00504 bytes_[fid] += hdr_cmn::access(pkt)->size();
00505 pkts_[fid]++;
00506 if (flowstats_[fid] == 0) {
00507 flowstats(fid);
00508 }
00509 flowstats_[fid]->newPoint(now - hdr->timestamp());
00510 QueueMonitor::out(pkt);
00511 }
00512
00513 void QueueMonitorCompat::in(Packet* pkt)
00514 {
00515 hdr_cmn* hdr = hdr_cmn::access(pkt);
00516 double now = Scheduler::instance().clock();
00517
00518 hdr->timestamp() = now;
00519 QueueMonitor::in(pkt);
00520 }
00521
00522 void QueueMonitorCompat::drop(Packet* pkt)
00523 {
00524
00525 hdr_ip* iph = hdr_ip::access(pkt);
00526 int fid = iph->flowid();
00527 if (fid >= MAXFLOW) {
00528 abort();
00529
00530 }
00531 ++drops_[fid];
00532 QueueMonitor::drop(pkt);
00533 }
00534
00535 int QueueMonitorCompat::command(int argc, const char*const* argv)
00536 {
00537 Tcl& tcl = Tcl::instance();
00538 int fid;
00539 if (argc == 3) {
00540 fid = atoi(argv[2]);
00541 if (strcmp(argv[1], "bytes") == 0) {
00542 if (fid >= MAXFLOW) {
00543 abort();
00544
00545 }
00546 tcl.resultf("%d", bytes_[fid]);
00547 return TCL_OK;
00548 } else if (strcmp(argv[1], "pkts") == 0) {
00549 if (fid >= MAXFLOW) {
00550 abort();
00551
00552 }
00553 tcl.resultf("%d", pkts_[fid]);
00554 return TCL_OK;
00555 } else if (strcmp(argv[1], "drops") == 0) {
00556 if (fid >= MAXFLOW) {
00557 abort();
00558
00559 }
00560 tcl.resultf("%d", drops_[fid]);
00561 return TCL_OK;
00562 } else if (strcmp(argv[1], "get-class-delay-samples") == 0) {
00563 if (fid >= MAXFLOW) {
00564 abort();
00565
00566 }
00567 if (flowstats_[fid] == 0) {
00568
00569
00570
00571
00572
00573
00574
00575
00576 flowstats(fid);
00577 }
00578 tcl.resultf("%s", flowstats_[fid]->name());
00579 return TCL_OK;
00580 }
00581 }
00582 return (QueueMonitor::command(argc, argv));
00583 }
00584
00585 static class QueueMonitorCompatClass : public TclClass {
00586 public:
00587 QueueMonitorCompatClass() : TclClass("QueueMonitor/Compat") {}
00588 TclObject* create(int, const char*const*) {
00589 return (new QueueMonitorCompat);
00590 }
00591 } queue_monitor_compat_class;