pi.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) 1990-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 Computer Systems
00017  *  Engineering Group at Lawrence Berkeley Laboratory.
00018  * 4. Neither the name of the University nor of the Laboratory may be used
00019  *    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  */
00036 
00037 /*
00038  * Based on PI controller described in:
00039  * C. Hollot, V. Misra, D. Towsley and W. Gong. 
00040  * On Designing Improved Controllers for AQM Routers
00041  * Supporting TCP Flows, 
00042  * INFOCOMM 2001. 
00043  */
00044 
00045 #include <math.h>
00046 #include <sys/types.h>
00047 #include "config.h"
00048 #include "template.h"
00049 #include "random.h"
00050 #include "flags.h"
00051 #include "delay.h"
00052 #include "pi.h"
00053 
00054 static class PIClass : public TclClass {
00055 public:
00056     PIClass() : TclClass("Queue/PI") {}
00057     TclObject* create(int argc, const char*const* argv) {
00058         if (argc==5) 
00059             return (new PIQueue(argv[4]));
00060         else
00061             return (new PIQueue("Drop"));
00062     }
00063 } class_pi;
00064 
00065 
00066 PIQueue::PIQueue(const char * trace) : CalcTimer(this), link_(NULL), q_(NULL),
00067     qib_(0), de_drop_(NULL), EDTrace(NULL), tchan_(0), curq_(0),
00068     edp_(), edv_(), first_reset_(1)
00069 {
00070     if (strlen(trace) >=20) {
00071         printf("trace type too long - allocate more space to traceType in pi.h and recompile\n");
00072         exit(0);
00073     }
00074     strcpy(traceType, trace);
00075 
00076     bind_bool("bytes_", &edp_.bytes);       // boolean: use bytes?
00077     bind_bool("queue_in_bytes_", &qib_);        // boolean: q in bytes?
00078     bind("a_", &edp_.a);        
00079     bind("b_", &edp_.b);       
00080     bind("w_", &edp_.w);          
00081     bind("qref_", &edp_.qref);        
00082     bind("mean_pktsize_", &edp_.mean_pktsize);  // avg pkt size
00083     bind_bool("setbit_", &edp_.setbit);     // mark instead of drop
00084     bind("prob_", &edv_.v_prob);            // dropping probability
00085     bind("curq_", &curq_);              // current queue size
00086     q_ = new PacketQueue();             // underlying queue
00087     pq_ = q_;
00088     reset();
00089 }
00090 
00091 void PIQueue::reset()
00092 {
00093     //double now = Scheduler::instance().clock();
00094     /*
00095     if (qib_ && first_reset_ == 1) {
00096         edp_.qref = edp_.qref*edp_.mean_pktsize;
00097     }
00098     */
00099     edv_.count = 0;
00100     edv_.count_bytes = 0;
00101     edv_.v_prob = 0;
00102     edv_.qold = 0;
00103     curq_ = 0;
00104     calculate_p();
00105     Queue::reset();
00106 }
00107 
00108 
00109 void PIQueue::enque(Packet* pkt)
00110 {
00111     //double now = Scheduler::instance().clock();
00112     hdr_cmn* ch = hdr_cmn::access(pkt);
00113     ++edv_.count;
00114     edv_.count_bytes += ch->size();
00115 
00116     int droptype = DTYPE_NONE;
00117 
00118     int qlen = qib_ ? q_->byteLength() : q_->length();
00119     curq_ = qlen;   // helps to trace queue during arrival, if enabled
00120 
00121     int qlim = qib_ ? (qlim_ * edp_.mean_pktsize) : qlim_;
00122 
00123     if (qlen >= qlim) {
00124         droptype = DTYPE_FORCED;
00125     }
00126     else {
00127         if (drop_early(pkt, qlen)) {
00128             droptype = DTYPE_UNFORCED;
00129         }
00130     }
00131 
00132     if (droptype == DTYPE_UNFORCED) {
00133         Packet *pkt_to_drop = pickPacketForECN(pkt);
00134         if (pkt_to_drop != pkt) {
00135             q_->enque(pkt);
00136             q_->remove(pkt_to_drop);
00137             pkt = pkt_to_drop; /* XXX okay because pkt is not needed anymore */
00138         }
00139 
00140         if (de_drop_ != NULL) {
00141             if (EDTrace != NULL) 
00142                 ((Trace *)EDTrace)->recvOnly(pkt);
00143             de_drop_->recv(pkt);
00144         }
00145         else {
00146             drop(pkt);
00147         }
00148     } else {
00149         q_->enque(pkt);
00150         if (droptype == DTYPE_FORCED) {
00151             pkt = pickPacketToDrop();
00152             q_->remove(pkt);
00153             drop(pkt);
00154             edv_.count = 0;
00155             edv_.count_bytes = 0;
00156         }
00157     }
00158     return;
00159 }
00160 
00161 double PIQueue::calculate_p()
00162 {
00163     //double now = Scheduler::instance().clock();
00164     double p;
00165     int qlen = qib_ ? q_->byteLength() : q_->length();
00166     
00167     if (qib_) {
00168         p=edp_.a*(qlen*1.0/edp_.mean_pktsize-edp_.qref)-
00169             edp_.b*(edv_.qold*1.0/edp_.mean_pktsize-edp_.qref)+
00170             edv_.v_prob;
00171     }
00172     else {
00173         p=edp_.a*(qlen-edp_.qref)-edp_.b*(edv_.qold-edp_.qref)+edv_.v_prob;
00174     }
00175         
00176     if (p < 0) p = 0;
00177     if (p > 1) p = 1;
00178     
00179     edv_.v_prob = p;
00180     edv_.qold = qlen;
00181 
00182     CalcTimer.resched(1.0/edp_.w);
00183     return p;
00184 }
00185 
00186 int PIQueue::drop_early(Packet* pkt, int qlen)
00187 {
00188     //double now = Scheduler::instance().clock();
00189     hdr_cmn* ch = hdr_cmn::access(pkt);
00190     double p = edv_.v_prob; 
00191 
00192     if (edp_.bytes) {
00193         p = p*ch->size()/edp_.mean_pktsize;
00194         if (p > 1) p = 1; 
00195     }
00196 
00197     double u = Random::uniform();
00198     if (u <= p) {
00199         edv_.count = 0;
00200         edv_.count_bytes = 0;
00201         hdr_flags* hf = hdr_flags::access(pickPacketForECN(pkt));
00202         if (edp_.setbit && hf->ect()) {
00203             hf->ce() = 1;   // mark Congestion Experienced bit
00204             return (0); // no drop
00205         } else {
00206             return (1); // drop
00207         }
00208     }
00209     return (0);         // no DROP/mark
00210 }
00211 
00212 Packet* PIQueue::pickPacketForECN(Packet* pkt)
00213 {
00214     return pkt; /* pick the packet that just arrived */
00215 }
00216 
00217 Packet* PIQueue::pickPacketToDrop() 
00218 {
00219     int victim;
00220     victim = q_->length() - 1;
00221     return(q_->lookup(victim)); 
00222 }
00223 
00224 Packet* PIQueue::deque()
00225 {
00226     Packet *p;
00227     p = q_->deque();
00228     curq_ = qib_ ? q_->byteLength() : q_->length(); // helps to trace queue during arrival, if enabled
00229     return (p);
00230 }
00231 
00232 int PIQueue::command(int argc, const char*const* argv)
00233 {
00234     Tcl& tcl = Tcl::instance();
00235     if (argc == 2) {
00236         if (strcmp(argv[1], "reset") == 0) {
00237             reset();
00238             return (TCL_OK);
00239         }
00240         if (strcmp(argv[1], "early-drop-target") == 0) {
00241             if (de_drop_ != NULL)
00242                 tcl.resultf("%s", de_drop_->name());
00243             return (TCL_OK);
00244         }
00245         if (strcmp(argv[1], "edrop-trace") == 0) {
00246             if (EDTrace != NULL) {
00247                 tcl.resultf("%s", EDTrace->name());
00248             }
00249             else {
00250                 tcl.resultf("0");
00251             }
00252             return (TCL_OK);
00253         }
00254         if (strcmp(argv[1], "trace-type") == 0) {
00255             tcl.resultf("%s", traceType);
00256             return (TCL_OK);
00257         }
00258     } 
00259     else if (argc == 3) {
00260         // attach a file for variable tracing
00261         if (strcmp(argv[1], "attach") == 0) {
00262             int mode;
00263             const char* id = argv[2];
00264             tchan_ = Tcl_GetChannel(tcl.interp(), (char*)id, &mode);
00265             if (tchan_ == 0) {
00266                 tcl.resultf("PI: trace: can't attach %s for writing", id);
00267                 return (TCL_ERROR);
00268             }
00269             return (TCL_OK);
00270         }
00271         // tell PI about link stats
00272         if (strcmp(argv[1], "link") == 0) {
00273             LinkDelay* del = (LinkDelay*)TclObject::lookup(argv[2]);
00274             if (del == 0) {
00275                 tcl.resultf("PI: no LinkDelay object %s", argv[2]);
00276                 return(TCL_ERROR);
00277             }
00278             link_ = del;
00279             return (TCL_OK);
00280         }
00281         if (strcmp(argv[1], "early-drop-target") == 0) {
00282             NsObject* p = (NsObject*)TclObject::lookup(argv[2]);
00283             if (p == 0) {
00284                 tcl.resultf("no object %s", argv[2]);
00285                 return (TCL_ERROR);
00286             }
00287             de_drop_ = p;
00288             return (TCL_OK);
00289         }
00290         if (strcmp(argv[1], "edrop-trace") == 0) {
00291             NsObject * t  = (NsObject *)TclObject::lookup(argv[2]);
00292             if (t == 0) {
00293                 tcl.resultf("no object %s", argv[2]);
00294                 return (TCL_ERROR);
00295             }
00296             EDTrace = t;
00297             return (TCL_OK);
00298         }
00299         if (!strcmp(argv[1], "packetqueue-attach")) {
00300             delete q_;
00301             if (!(q_ = (PacketQueue*) TclObject::lookup(argv[2])))
00302                 return (TCL_ERROR);
00303             else {
00304                 pq_ = q_;
00305                 return (TCL_OK);
00306             }
00307         }
00308     }
00309     return (Queue::command(argc, argv));
00310 }
00311 
00312 void PIQueue::trace(TracedVar* v)
00313 {
00314     char wrk[500], *p;
00315 
00316     if (((p = strstr(v->name(), "prob")) == NULL) &&
00317         ((p = strstr(v->name(), "curq")) == NULL)) {
00318         fprintf(stderr, "PI:unknown trace var %s\n", v->name());
00319         return;
00320     }
00321     if (tchan_) {
00322         int n;
00323         double t = Scheduler::instance().clock();
00324         // XXX: be compatible with nsv1 PI trace entries
00325         if (*p == 'c') {
00326             sprintf(wrk, "Q %g %d", t, int(*((TracedInt*) v)));
00327         } else {
00328             sprintf(wrk, "%c %g %g", *p, t, double(*((TracedDouble*) v)));
00329         }
00330         n = strlen(wrk);
00331         wrk[n] = '\n'; 
00332         wrk[n+1] = 0;
00333         (void)Tcl_Write(tchan_, wrk, n+1);
00334     }
00335     return; 
00336 }
00337 
00338 void PICalcTimer::expire(Event *)
00339 {
00340     a_->calculate_p();
00341 }

Generated on Tue Mar 6 16:47:49 2007 for ns2 Network Simulator 2.29 by  doxygen 1.4.6