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

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

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