fq.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/queue/fq.cc,v 1.12 2005/08/22 05:08:34 tomh Exp $ (ANS)";
00038 #endif
00039 
00040 #include "config.h"
00041 #include <stdlib.h>
00042 #include <float.h>
00043 #include "queue.h"
00044 
00045 /*XXX*/
00046 #define MAXFLOW 32
00047 
00048 class FQ : public Queue {
00049 public: 
00050     FQ();
00051     virtual int command(int argc, const char*const* argv);
00052     Packet *deque(void);
00053     void enque(Packet *pkt);
00054     void recv(Packet* p, Handler* h);
00055 protected:
00056     int update();
00057     struct flowState {
00058         Queue* q_;
00059         Packet* hol_;   /* head-of-line packet for each flow */
00060         double finishTime_; /* FQ finish time for hol packet */
00061         double delta_;
00062         Handler* handler_;
00063     } fs_[MAXFLOW];
00064     inline double finish(const flowState& fs, int nactive)
00065     {
00066         return (fs.finishTime_ + fs.delta_ * nactive);
00067     }
00068     int maxflow_;
00069     double secsPerByte_;
00070 };
00071 
00072 static class FQClass : public TclClass {
00073 public:
00074     FQClass() : TclClass("Queue/FQ") {}
00075     TclObject* create(int, const char*const*) {
00076         return (new FQ);
00077     }
00078 } class_fq;
00079 
00080 FQ::FQ()
00081 {
00082     for (int i = 0; i < MAXFLOW; ++i) {
00083         fs_[i].q_ = 0;
00084         fs_[i].hol_ = 0;
00085         fs_[i].finishTime_ = 0.;
00086     }
00087     maxflow_ = -1;
00088     secsPerByte_ = 0.;
00089     bind("secsPerByte_", &secsPerByte_);
00090 }
00091 
00092 int FQ::command(int argc, const char*const* argv)
00093 {
00094     if (argc == 4) {
00095         if (strcmp(argv[1], "install") == 0) {
00096             int flowID = atoi(argv[2]);
00097             fs_[flowID].q_ = (Queue*)TclObject::lookup(argv[3]);
00098             if (flowID > maxflow_)
00099                 maxflow_ = flowID;
00100             /*XXX*/
00101             if (flowID >= MAXFLOW)
00102                 abort();
00103             return (TCL_OK);
00104         }
00105     }
00106     return (Queue::command(argc, argv));
00107 }
00108 
00109 /*XXX this is quite inefficient.*/
00110 int FQ::update()
00111 {
00112     int nactive = 0;
00113     for (int i = 0; i <= maxflow_; ++i) {
00114         Queue* q = fs_[i].q_;
00115         if (q != 0) {
00116             if (fs_[i].hol_ == 0) {
00117                 Packet* p = q->deque();
00118                 if (p != 0) {
00119                     fs_[i].hol_ = p;
00120                     ++nactive;
00121                 }
00122             } else
00123                 ++nactive;
00124         }
00125     }
00126     return (nactive);
00127 }
00128 
00129 Packet* FQ::deque()
00130 
00131 {
00132     int nactive = update();
00133     int target = -1;
00134     double best = DBL_MAX;
00135     for (int i = 0; i <= maxflow_; ++i) {
00136         if (fs_[i].hol_ != 0) {
00137             if (target < 0) { 
00138                 target = i;
00139                 best = finish(fs_[i], nactive);
00140             } else {
00141                 double F = finish(fs_[i], nactive);
00142                 if (F < best) {
00143                     target = i;
00144                     best = F;
00145                 }
00146             }
00147         }
00148     }
00149     if (target >= 0) {
00150         Packet* p = fs_[target].hol_;
00151         fs_[target].hol_ = 0;
00152         fs_[target].finishTime_ = best;
00153         /* let this upstream queue resume */
00154         Handler* h = fs_[target].handler_;
00155         /*XXX null event okay because queue doesn't use it*/
00156         h->handle(0);
00157         return (p);
00158     }
00159     return (0);
00160 }
00161 
00162 /*
00163  * Called when one of our queues is unblocked by us in FQ::deque
00164  * (or gets its first packet).
00165  */
00166 void FQ::recv(Packet* p, Handler* handler)
00167 {
00168     hdr_ip* h = hdr_ip::access(p);
00169     int flowid = h->flowid();
00170     /* shouldn't be called when head-of-line is pending */
00171     if (flowid >= MAXFLOW || fs_[flowid].hol_ != 0)
00172         abort();
00173 
00174     /*
00175      * Put this packet at the head-of-line for its queue
00176      * and set up scheduling state according to the
00177      * standard fair-queueing "finish time" equation.
00178      */
00179     fs_[flowid].hol_ = p;
00180     double now = Scheduler::instance().clock();
00181     if (now > fs_[flowid].finishTime_)
00182         fs_[flowid].finishTime_ = now;
00183     fs_[flowid].handler_ = handler;
00184     int size = hdr_cmn::access(p)->size();
00185     fs_[flowid].delta_ = size * secsPerByte_;
00186 
00187     if (!blocked_) {
00188         /*
00189          * We're not blocked.  Get a packet and send it on.
00190          * We perform an extra check because the queue
00191          * might drop the packet even if it was
00192          * previously empty!  (e.g., RED can do this.)
00193          */
00194         p = deque();
00195         if (p != 0) {
00196             blocked_ = 1;
00197             target_->recv(p, &qh_);
00198         }
00199     }
00200 }
00201 
00202 void FQ::enque(Packet*)
00203 {
00204     /* should never be called because we override recv */
00205     abort();
00206 }

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