dsr-priqueue.cc

Go to the documentation of this file.
00001 /* -*- c++ -*-
00002    priqueue.cc
00003    
00004    A simple priority queue with a remove packet function
00005    $Id: dsr-priqueue.cc,v 1.2 2002/09/11 20:11:09 buchheim Exp $
00006    */
00007 
00008 #include <object.h>
00009 #include <packet.h>
00010 #include <cmu-trace.h>
00011 #include <dsr-priqueue.h>
00012 
00013 #define PRIQUEUE_DEBUG 0
00014 
00015 static class CMUPriQueueClass : public TclClass {
00016 public:
00017   CMUPriQueueClass() : TclClass("CMUPriQueue") {}
00018   TclObject* create(int, const char*const*) {
00019     return (new CMUPriQueue);
00020   }
00021 } class_CMUPriQueue;
00022 
00023 /* ======================================================================
00024    Priority Queue Handler
00025    ====================================================================== */
00026 void CMUPriQueueHandler::handle(Event*)
00027 {
00028         qh_ifq->prq_resume();
00029 }       
00030 
00031 /* ======================================================================
00032    CMUPriQueue - public routines
00033    ====================================================================== */
00034 CMUPriQueue::CMUPriQueue() : Connector(), prq_qh_(this)
00035 {
00036     int i;
00037 
00038     for(i = 0; i < IFQ_MAX; i++) {
00039         prq_snd_[i].ifq_head = prq_snd_[i].ifq_tail = 0;
00040         prq_snd_[i].ifq_len = 0;
00041         prq_snd_[i].ifq_maxlen = IFQ_MAXLEN;
00042         prq_snd_[i].ifq_drops = 0;
00043 
00044         last_ifqlen_[i] = 0;
00045     }
00046     prq_logtarget_ = 0;     // no logging target by default
00047     prq_ipaddr_ = 0;
00048     prq_blocked_ = 0;
00049 
00050     bind("qlen_logthresh_", &qlen_logthresh_);
00051     bind("fw_logthresh_", &fw_logthresh_);
00052     assert(qlen_logthresh_ > 0 && fw_logthresh_ > 0);
00053 
00054     bzero(last_ifqlen_, sizeof(last_ifqlen_));
00055     stat_send_ = stat_recv_ = stat_blocked_ = 0;
00056 }
00057 
00058 int
00059 CMUPriQueue::command(int argc, const char*const* argv)
00060 {
00061     if (argc == 2 && strcasecmp(argv[1], "reset") == 0) {
00062         Terminate();
00063         //FALL-THROUGH to give parents a chance to reset
00064     } else if(argc == 3) {
00065         if(strcmp(argv[1], "logtarget") == 0) {
00066             prq_logtarget_ = (Trace*) TclObject::lookup(argv[2]);
00067             assert(prq_logtarget_);
00068             return (TCL_OK);
00069         }
00070         else if(strcmp(argv[1], "ipaddr") == 0) {
00071             prq_ipaddr_ = atoi(argv[2]);
00072             assert(prq_ipaddr_ > 0);
00073             return (TCL_OK);
00074         }
00075     }
00076     return Connector::command(argc, argv);
00077 }
00078 
00079 void
00080 CMUPriQueue::log_stats()
00081 {
00082     int q, s = 0, d = 0;
00083 
00084     assert(IFQ_MAX == 4);
00085 
00086     /*
00087      * avoid logging useless information
00088      */
00089     for(q = 0; q < IFQ_MAX; q++) {
00090         s += prq_snd_[q].ifq_len;
00091         d += (prq_snd_[q].ifq_len - last_ifqlen_[q]);
00092     }
00093     if(d < 0)
00094         d = -d;
00095 
00096     /*
00097      * Only write an entry to the log file is the queue length
00098      * or "delta change" over the last second meets the threshold
00099      * level OR, if this node is generally busy (forwarding more
00100      * than a certain number of packets per second).
00101      */
00102     if(s >= qlen_logthresh_ || d >= qlen_logthresh_ ||
00103        stat_recv_ > fw_logthresh_) {
00104         if (prq_logtarget_->pt_->tagged()) {
00105            // using the new tagged trace format
00106            trace("I "TIME_FORMAT" -prq:adr %d -prq:rx %d -prq:tx %d -prq:bl %d -prq:snd0 {%d %d} -prq:snd1 {%d %d} -prq:snd2 {%d %d} -prq:snd3 {%d %d}",
00107               Scheduler::instance().clock(),
00108               prq_ipaddr_,
00109               stat_recv_, stat_send_, stat_blocked_,
00110               prq_snd_[0].ifq_len, prq_snd_[0].ifq_len-last_ifqlen_[0],
00111               prq_snd_[1].ifq_len, prq_snd_[1].ifq_len-last_ifqlen_[1],
00112               prq_snd_[2].ifq_len, prq_snd_[2].ifq_len-last_ifqlen_[2],
00113               prq_snd_[3].ifq_len, prq_snd_[3].ifq_len-last_ifqlen_[3]);
00114         } else {
00115            trace("I %.9f _%d_ ifq rx %d tx %d bl %d [%d %d] [%d %d] [%d %d] [%d %d]",
00116               Scheduler::instance().clock(),
00117               prq_ipaddr_,
00118               stat_recv_, stat_send_, stat_blocked_,
00119               prq_snd_[0].ifq_len, prq_snd_[0].ifq_len-last_ifqlen_[0],
00120               prq_snd_[1].ifq_len, prq_snd_[1].ifq_len-last_ifqlen_[1],
00121               prq_snd_[2].ifq_len, prq_snd_[2].ifq_len-last_ifqlen_[2],
00122               prq_snd_[3].ifq_len, prq_snd_[3].ifq_len-last_ifqlen_[3]);
00123         }
00124     }
00125 
00126     for(q = 0; q < IFQ_MAX; q++) {
00127         last_ifqlen_[q] = prq_snd_[q].ifq_len;
00128     }
00129     stat_send_ = stat_recv_ = stat_blocked_ = 0;
00130 }
00131 
00132 void
00133 CMUPriQueue::trace(char* fmt, ...)
00134 {
00135     va_list ap;
00136   
00137     assert(prq_logtarget_);
00138 
00139     va_start(ap, fmt);
00140     vsprintf(prq_logtarget_->pt_->buffer(), fmt, ap);
00141     prq_logtarget_->pt_->dump();
00142     va_end(ap);
00143 }
00144 
00145 void
00146 CMUPriQueue::recv(Packet *p, Handler *)
00147 {
00148 #if PRIQUEUE_DEBUG > 0
00149     prq_validate();
00150 #endif
00151     stat_recv_++;
00152     if(prq_blocked_ == 1) {
00153         stat_blocked_++;
00154     } else {
00155         assert(prq_length() == 0);
00156     }
00157     prq_enqueue(p);
00158 #if PRIQUEUE_DEBUG > 0
00159     prq_validate();
00160 #endif
00161 }
00162 
00163 void
00164 CMUPriQueue::prq_resume()
00165 {
00166     Packet *p;
00167 
00168     assert(prq_blocked_);
00169 #if PRIQUEUE_DEBUG > 0
00170     prq_validate();
00171 #endif
00172     p = prq_dequeue();
00173     if (p != 0) {
00174         stat_send_++;
00175                 target_->recv(p, &prq_qh_);
00176         } else {
00177         prq_blocked_ = 0;
00178         }
00179 }
00180 
00181 
00182 /*
00183  * Called at the end of the simulation to purge the IFQ.
00184  */
00185 void
00186 CMUPriQueue::Terminate()
00187 {
00188     Packet *p;
00189     while((p = prq_dequeue())) {
00190         drop(p, DROP_END_OF_SIMULATION);
00191     }
00192 }
00193 
00194 Packet*
00195 CMUPriQueue::prq_get_nexthop(nsaddr_t id)
00196 {
00197     int q;
00198     Packet *p, *pprev = 0;
00199     struct ifqueue *ifq;
00200 
00201 #if PRIQUEUE_DEBUG > 0
00202     prq_validate();
00203 #endif
00204     for(q = 0; q < IFQ_MAX; q++) {
00205         ifq = &prq_snd_[q];
00206         pprev = 0;
00207         for(p = ifq->ifq_head; p; p = p->next_) {
00208             struct hdr_cmn *ch = HDR_CMN(p);
00209 
00210             if(ch->next_hop() == id)
00211                 break;
00212             pprev = p;
00213         }
00214 
00215     if(p) {
00216         if(p == ifq->ifq_head) {
00217             assert(pprev == 0);
00218 
00219             IF_DEQUEUE(ifq, p);
00220             /* don't increment drop counter */
00221 #if PRIQUEUE_DEBUG > 0
00222             prq_validate();
00223 #endif
00224             return p;
00225         } else {
00226             assert(pprev);
00227             pprev->next_ = p->next_;
00228     
00229             if(p == ifq->ifq_tail)
00230                 ifq->ifq_tail = pprev;
00231             ifq->ifq_len--;
00232 
00233 #if PRIQUEUE_DEBUG > 0
00234             prq_validate();
00235 #endif
00236             p->next_ = 0;
00237             return p;
00238         }
00239     }
00240      }
00241 
00242     return (Packet*) 0;
00243 }
00244 
00245 int
00246 CMUPriQueue::prq_isfull(Packet *p)
00247 {
00248     int q = prq_assign_queue(p);
00249     struct ifqueue *ifq = &prq_snd_[q];
00250 
00251     if(IF_QFULL(ifq))
00252         return 1;
00253     else
00254         return 0;
00255 }
00256 
00257 int
00258 CMUPriQueue::prq_length()
00259 {
00260     int q, tlen = 0;
00261 
00262     for(q = 0; q < IFQ_MAX; q++) {
00263         tlen += prq_snd_[q].ifq_len;
00264     }
00265 
00266     return tlen;
00267 }
00268 
00269 /* ======================================================================
00270    CMUPriQueue - private routines
00271    ====================================================================== */
00272 void
00273 CMUPriQueue::prq_enqueue(Packet *p)
00274 {
00275     int q = prq_assign_queue(p);
00276     struct ifqueue *ifq = &prq_snd_[q];
00277 
00278     if(IF_QFULL(ifq)) {
00279         IF_DROP(ifq);
00280         drop(p, DROP_IFQ_QFULL);
00281         return;
00282     }
00283     IF_ENQUEUE(ifq, p);
00284 
00285     /*
00286      * Start queue if idle...
00287      */
00288     if(prq_blocked_ == 0) {
00289         p = prq_dequeue();
00290         prq_blocked_ = 1;
00291 
00292         stat_send_++;
00293         target_->recv(p, &prq_qh_);
00294     }
00295 }
00296 
00297 Packet*
00298 CMUPriQueue::prq_dequeue(void)
00299 {
00300     Packet *p;
00301     int q;
00302 
00303     for(q = 0; q < IFQ_MAX; q++) {
00304         if(prq_snd_[q].ifq_len > 0) {
00305             IF_DEQUEUE(&prq_snd_[q], p);
00306             return p;
00307         } else {
00308             assert(prq_snd_[q].ifq_head == 0);
00309         }
00310     }
00311     return (Packet*) 0;
00312 }
00313 
00314 int
00315 CMUPriQueue::prq_assign_queue(Packet *p)
00316 {
00317         struct hdr_cmn *ch = HDR_CMN(p);
00318 
00319     switch(ch->ptype()) {
00320     case PT_AODV:
00321     case PT_DSR:
00322     case PT_IMEP:
00323     case PT_MESSAGE:    /* used by DSDV */
00324     case PT_TORA:
00325         return IFQ_RTPROTO;
00326 
00327     case PT_AUDIO:
00328     case PT_VIDEO:
00329         return IFQ_REALTIME;
00330 
00331     case PT_ACK:
00332         return IFQ_LOWDELAY;
00333 
00334     default:
00335         return IFQ_NORMAL;
00336     }
00337 }
00338 
00339 void
00340 CMUPriQueue::prq_validate()
00341 {
00342     int q, qlen;
00343     Packet *p;
00344     struct ifqueue *ifq;
00345 
00346     for(q = 0; q < IFQ_MAX; q++) {
00347         ifq = &prq_snd_[q];
00348         qlen = 0;
00349             
00350         if(ifq->ifq_head == 0) {
00351             assert(ifq->ifq_len == 0);
00352             assert(ifq->ifq_head == ifq->ifq_tail);
00353         } else {
00354 
00355             for(p = ifq->ifq_head; p; p = p->next_) {
00356                 if(p->next_ == 0)
00357                     assert(p == ifq->ifq_tail);
00358                 qlen++;
00359             }
00360 
00361             assert(qlen == ifq->ifq_len);
00362             assert(qlen <= ifq->ifq_maxlen);
00363         }
00364     }
00365 }

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