Main Page | Namespace List | Class Hierarchy | Alphabetical List | Compound List | File List | Compound Members | File Members

queue-monitor.cc

Go to the documentation of this file.
00001 /* -*-  Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
00002 /*
00003  * Copyright (c) 1997 Regents of the University of California.
00004  * All rights reserved.
00005  * 
00006  * Redistribution and use in source and binary forms, with or without
00007  * modification, are permitted provided that the following conditions
00008  * are met:
00009  * 1. Redistributions of source code must retain the above copyright
00010  *    notice, this list of conditions and the following disclaimer.
00011  * 2. Redistributions in binary form must reproduce the above copyright
00012  *    notice, this list of conditions and the following disclaimer in the
00013  *    documentation and/or other materials provided with the distribution.
00014  * 3. All advertising materials mentioning features or use of this software
00015  *    must display the following acknowledgement:
00016  *      This product includes software developed by the MASH Research
00017  *      Group at the University of California Berkeley.
00018  * 4. Neither the name of the University nor of the Research Group may be
00019  *    used to endorse or promote products derived from this software without
00020  *    specific prior written permission.
00021  * 
00022  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
00023  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00024  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00025  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
00026  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00027  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00028  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00029  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00030  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00031  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00032  * SUCH DAMAGE.
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                         // for printStats
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                         // for printRTTs and printSeqnos distributions
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);  // else control reaches end of
00137                                                 // non-void function, see? :-)
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 // packet arrival to a queue
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         //if enabled estimate rate now
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 // The procedure to estimate the rate of the incoming traffic
00301 void QueueMonitor::estimateRate(Packet *pkt) {
00302         
00303         hdr_cmn* hdr  = hdr_cmn::access(pkt);
00304         int pktSize   = hdr->size() << 3; /* length of the packet in bits */
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 //The procedure to keep RTT statistics.
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 //The procedure to keep Seqno (sequence number) statistics.
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  * Tcl Stuff
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 /* Added by Yun Wang, for use of In/Out tagger */
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  * a 'QueueMonitorCompat', which is used by the compat
00429  * code to produce the link statistics used available in ns-1
00430  *
00431  * in ns-1, the counters are the number of departures
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  * create an entry in the flowstats_ array.
00447  */
00448 
00449 void
00450 QueueMonitorCompat::flowstats(int flowid)
00451 {
00452         Tcl& tcl = Tcl::instance();
00453 
00454         /*
00455          * here is the deal.  we are in C code.  we'd like to do
00456          *     flowstats_[flowid] = new Samples;
00457          * but, we want to create an object that can be
00458          * referenced via tcl.  (in particular, we want ->name_
00459          * to be valid.)
00460          *
00461          * so, how do we do this?
00462          *
00463          * well, the answer is, call tcl to create it.  then,
00464          * do a lookup on the result from tcl!
00465          */
00466 
00467         tcl.evalf("new Samples");
00468         flowstats_[flowid] = (Samples*)TclObject::lookup(tcl.result());
00469         if (flowstats_[flowid] == 0) {
00470                 abort();
00471                 /*NOTREACHED*/
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                 /*NOTREACHED*/
00486         }
00487         // printf("QueueMonitorCompat::out(), fid=%d\n", fid);
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         // QueueMonitor::in() *may* do this, but we always need it...
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                 /*NOTREACHED*/
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                                 /*NOTREACHED*/
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                                 /*NOTREACHED*/
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                                 /*NOTREACHED*/
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                                 /*NOTREACHED*/
00550                         }
00551                         if (flowstats_[fid] == 0) {
00552                                 /*
00553                                  * instantiate one if user actually
00554                                  * cares enough to ask for it!
00555                                  *
00556                                  * (otherwise, need to return "",
00557                                  * and then special-case caller to
00558                                  * handle this null return.)
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;

Generated on Tue Apr 20 12:14:28 2004 for NS2.26SourcesOriginal by doxygen 1.3.3