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

tfrc.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) 1999  International Computer Science Institute
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 ACIRI, the AT&T 
00017  *      Center for Internet Research at ICSI (the International Computer
00018  *      Science Institute).
00019  * 4. Neither the name of ACIRI nor of ICSI may be used
00020  *    to endorse or promote products derived from this software without
00021  *    specific prior written permission.
00022  *
00023  * THIS SOFTWARE IS PROVIDED BY ICSI AND CONTRIBUTORS ``AS IS'' AND
00024  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00025  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00026  * ARE DISCLAIMED.  IN NO EVENT SHALL ICSI OR CONTRIBUTORS BE LIABLE
00027  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00028  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00029  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00030  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00031  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00032  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00033  * SUCH DAMAGE.
00034  */
00035 
00036 #include <stdlib.h>
00037 #include <sys/types.h>
00038 #include <math.h>
00039  
00040 #include "tfrc.h"
00041 #include "formula.h"
00042 #include "flags.h"
00043 
00044 int hdr_tfrc::offset_;
00045 int hdr_tfrc_ack::offset_;
00046 
00047 static class TFRCHeaderClass : public PacketHeaderClass {
00048 public:
00049         TFRCHeaderClass() : PacketHeaderClass("PacketHeader/TFRC",
00050                                               sizeof(hdr_tfrc)) {
00051                 bind_offset(&hdr_tfrc::offset_);
00052         }
00053 } class_tfrchdr;
00054 
00055 static class TFRC_ACKHeaderClass : public PacketHeaderClass {
00056 public:
00057         TFRC_ACKHeaderClass() : PacketHeaderClass("PacketHeader/TFRC_ACK",
00058                                                   sizeof(hdr_tfrc_ack)) {
00059                 bind_offset(&hdr_tfrc_ack::offset_);
00060         }
00061 } class_tfrc_ackhdr;
00062 
00063 static class TfrcClass : public TclClass {
00064 public:
00065         TfrcClass() : TclClass("Agent/TFRC") {}
00066         TclObject* create(int, const char*const*) {
00067                 return (new TfrcAgent());
00068         }
00069 } class_tfrc;
00070 
00071 
00072 TfrcAgent::TfrcAgent() : Agent(PT_TFRC), send_timer_(this), 
00073          NoFeedbacktimer_(this), rate_(0), oldrate_(0), maxrate_(0)
00074 {
00075         bind("packetSize_", &size_);
00076         bind("rate_", &rate_);
00077         bind("df_", &df_);
00078         bind("tcp_tick_", &tcp_tick_);
00079         bind("ndatapack_", &ndatapack_);
00080         bind("srtt_init_", &srtt_init_);
00081         bind("rttvar_init_", &rttvar_init_);
00082         bind("rtxcur_init_", &rtxcur_init_);
00083         bind("rttvar_exp_", &rttvar_exp_);
00084         bind("T_SRTT_BITS", &T_SRTT_BITS);
00085         bind("T_RTTVAR_BITS", &T_RTTVAR_BITS);
00086         bind("InitRate_", &InitRate_);
00087         bind("overhead_", &overhead_);
00088         bind("ssmult_", &ssmult_);
00089         bind("bval_", &bval_);
00090         bind("ca_", &ca_);
00091         bind_bool("printStatus_", &printStatus_);
00092         bind_bool("conservative_", &conservative_);
00093         bind_bool("ecn_", &ecn_);
00094         bind("maxHeavyRounds_", &maxHeavyRounds_);
00095         bind("SndrType_", &SndrType_); 
00096         bind("scmult_", &scmult_);
00097         bind_bool("oldCode_", &oldCode_);
00098         seqno_ = -1;
00099         maxseq_ = 0;
00100         datalimited_ = 0;
00101         last_pkt_time_ = 0.0;
00102 }
00103 
00104 /*
00105  * Must convert bytes into packets. 
00106  * If nbytes == -1, this corresponds to infinite send.  We approximate
00107  * infinite by a very large number (MAXSEQ).
00108  * For simplicity, when bytes are converted to packets, fractional packets 
00109  * are always rounded up.  
00110  */
00111 void TfrcAgent::sendmsg(int nbytes, const char* /*flags*/)
00112 {
00113         if (nbytes == -1 && maxseq_ < MAXSEQ)
00114                 advanceby(MAXSEQ - maxseq_);
00115         else if (size_ > 0) {
00116                 int npkts = int(nbytes/size_);
00117                 npkts += (nbytes%size_ ? 1 : 0);
00118                 //if (debug_) printf("nbytes: %d size: %d npkts: %d\n",
00119                 //    nbytes, size_, npkts);
00120                 advanceby(npkts);
00121         }
00122 }
00123 
00124 
00125 void TfrcAgent::advanceby(int delta)
00126 {
00127         maxseq_ += delta;
00128         
00129         if (seqno_ == -1) {
00130                 // if no packets hve been sent so far, call start. 
00131                 start(); 
00132         } else if (datalimited_ && maxseq_ > seqno_) {
00133                 // We were data-limited - send a packet now!
00134                 // The old code always waited for a timer to expire!!
00135                 datalimited_ = 0;
00136                 if (!oldCode_) {
00137                         sendpkt();
00138                 }
00139         }
00140 } 
00141 
00142 int TfrcAgent::command(int argc, const char*const* argv)
00143 {
00144         if (argc==2) {
00145                 // are we an infinite sender?
00146                 if ( (strcmp(argv[1],"start")==0) && (SndrType_ == 0)) {
00147                         start();
00148                         return TCL_OK;
00149                 }
00150                 if (strcmp(argv[1],"stop")==0) {
00151                         stop();
00152                         return TCL_OK;
00153                 }
00154         }
00155         if ((argc == 3) && (SndrType_ == 1)) {
00156                 // or do we need an FTP type app? 
00157         if (strcmp(argv[1], "advance") == 0) {
00158                 int newseq = atoi(argv[2]);
00159                 // THIS ISN"T USED.
00160                 // newseq: new sequence
00161                 // seqno_: next sequence to be sent
00162                 // maxseq_: max seq_  produced by app so far.
00163                 if (newseq > maxseq_)
00164                         advanceby(newseq - maxseq_);
00165                 return (TCL_OK);
00166         }
00167         if (strcmp(argv[1], "advanceby") == 0) {
00168                 advanceby(atoi(argv[2]));
00169                 return (TCL_OK);
00170                 }
00171         }
00172         return (Agent::command(argc, argv));
00173 }
00174 
00175 void TfrcAgent::start()
00176 {
00177         seqno_=0;                               
00178         rate_ = InitRate_;
00179         delta_ = 0;
00180         oldrate_ = rate_;  
00181         rate_change_ = SLOW_START;
00182         UrgentFlag = 1;
00183         rtt_=0;  
00184         sqrtrtt_=1;
00185         rttcur_=1;
00186         tzero_ = 0;
00187         last_change_=0;
00188         maxrate_ = 0; 
00189         ss_maxrate_ = 0;
00190         ndatapack_=0;
00191         active_ = 1; 
00192         round_id = 0;
00193         heavyrounds_ = 0;
00194         t_srtt_ = int(srtt_init_/tcp_tick_) << T_SRTT_BITS;
00195         t_rttvar_ = int(rttvar_init_/tcp_tick_) << T_RTTVAR_BITS;
00196         t_rtxcur_ = rtxcur_init_;
00197         rcvrate = 0 ;
00198 
00199         first_pkt_rcvd = 0 ;
00200         // send the first packet
00201         sendpkt();
00202         // ... at initial rate
00203         send_timer_.resched(size_/rate_);
00204         // ... and start timer so we can cut rate 
00205         // in half if we do not get feedback
00206         NoFeedbacktimer_.resched(2*size_/rate_); 
00207 }
00208 
00209 void TfrcAgent::stop()
00210 {
00211         active_ = 0;
00212         send_timer_.force_cancel();
00213 }
00214 
00215 void TfrcAgent::nextpkt()
00216 {
00217         double next = -1;
00218         double xrate = -1; 
00219 
00220         if (SndrType_ == 0) {
00221                 sendpkt();
00222         }
00223         else {
00224                 if (maxseq_ > seqno_) {
00225                         sendpkt();
00226                 } else
00227                         datalimited_ = 1;
00228         }
00229         
00230         // during slow start and congestion avoidance, we increase rate
00231         // slowly - by amount delta per packet 
00232         if ((rate_change_ == SLOW_START) && (oldrate_+SMALLFLOAT< rate_)) {
00233                 oldrate_ = oldrate_ + delta_;
00234                 xrate = oldrate_;
00235         }
00236         else {
00237                 if (ca_) 
00238                         xrate = rate_ * sqrtrtt_/sqrt(rttcur_);
00239                 else
00240                         xrate = rate_;
00241         }
00242         if (xrate > SMALLFLOAT) {
00243                 next = size_/xrate;
00244                 //
00245                 // randomize between next*(1 +/- woverhead_) 
00246                 //
00247                 next = next*(2*overhead_*Random::uniform()-overhead_+1);
00248                 if (next > SMALLFLOAT)
00249                         send_timer_.resched(next);
00250         }
00251 }
00252 
00253 void TfrcAgent::update_rtt (double tao, double now) 
00254 {
00255         /* the TCP update */
00256         t_rtt_ = int((now-tao) /tcp_tick_ + 0.5);
00257         if (t_rtt_==0) t_rtt_=1;
00258         if (t_srtt_ != 0) {
00259                 register short delta;
00260                 delta = t_rtt_ - (t_srtt_ >> T_SRTT_BITS);    
00261                 if ((t_srtt_ += delta) <= 0)    
00262                         t_srtt_ = 1;
00263                 if (delta < 0)
00264                         delta = -delta;
00265                 delta -= (t_rttvar_ >> T_RTTVAR_BITS);
00266                 if ((t_rttvar_ += delta) <= 0)  
00267                         t_rttvar_ = 1;
00268         } else {
00269                 t_srtt_ = t_rtt_ << T_SRTT_BITS;                
00270                 t_rttvar_ = t_rtt_ << (T_RTTVAR_BITS-1);        
00271         }
00272         t_rtxcur_ = (((t_rttvar_ << (rttvar_exp_ + (T_SRTT_BITS - T_RTTVAR_BITS))) + t_srtt_)  >> T_SRTT_BITS ) * tcp_tick_;
00273         tzero_=t_rtxcur_;
00274 
00275         /* fine grained RTT estimate for use in the equation */
00276         if (rtt_ > 0) {
00277                 rtt_ = df_*rtt_ + ((1-df_)*(now - tao));
00278                 sqrtrtt_ = df_*sqrtrtt_ + ((1-df_)*sqrt(now - tao));
00279         } else {
00280                 rtt_ = now - tao;
00281                 sqrtrtt_ = sqrt(now - tao);
00282         }
00283         rttcur_ = now - tao;
00284 }
00285 
00286 /*
00287  * Receive a status report from the receiver.
00288  */
00289 void TfrcAgent::recv(Packet *pkt, Handler *)
00290 {
00291         double now = Scheduler::instance().clock();
00292         hdr_tfrc_ack *nck = hdr_tfrc_ack::access(pkt);
00293         double ts = nck->timestamp_echo;
00294         double rate_since_last_report = nck->rate_since_last_report;
00295         // double NumFeedback_ = nck->NumFeedback_;
00296         double flost = nck->flost; 
00297         int losses = nck->losses;
00298 
00299         round_id ++ ;
00300         UrgentFlag = 0;
00301 
00302         if (rate_since_last_report > 0) {
00303                 /* compute the max rate for slow-start as two times rcv rate */ 
00304                 ss_maxrate_ = 2*rate_since_last_report*size_;
00305                 if (conservative_) { 
00306                         if (losses >= 1) {
00307                                 /* there was a loss in the most recent RTT */
00308                                 if (debug_) printf("time: %5.2f losses: %d rate %5.2f\n", 
00309                                   now, losses, rate_since_last_report);
00310                                 maxrate_ = rate_since_last_report*size_;
00311                         } else { 
00312                                 /* there was no loss in the most recent RTT */
00313                                 maxrate_ = scmult_*rate_since_last_report*size_;
00314                         }
00315                         if (debug_) printf("time: %5.2f losses: %d rate %5.2f maxrate: %5.2f\n", now, losses, rate_since_last_report, maxrate_);
00316                 } else 
00317                         maxrate_ = 2*rate_since_last_report*size_;
00318         } else {
00319                 ss_maxrate_ = 0;
00320                 maxrate_ = 0; 
00321         }
00322 
00323                 
00324         /* update the round trip time */
00325         update_rtt (ts, now);
00326 
00327         /* .. and estimate of fair rate */
00328         rcvrate = p_to_b(flost, rtt_, tzero_, size_, bval_);
00329 
00330         /* if we get no more feedback for some time, cut rate in half */
00331         double t = 2*rtt_ ; 
00332         if (t < 2*size_/rate_) 
00333                 t = 2*size_/rate_ ; 
00334         NoFeedbacktimer_.resched(t);
00335         
00336         /* if we are in slow start and we just saw a loss */
00337         /* then come out of slow start */
00338 
00339         if (first_pkt_rcvd == 0) {
00340                 first_pkt_rcvd = 1 ; 
00341                 slowstart ();
00342                 nextpkt();
00343         }
00344         else {
00345                 if (rate_change_ == SLOW_START) {
00346                         if (flost > 0) {
00347                                 rate_change_ = OUT_OF_SLOW_START;
00348                                 oldrate_ = rate_ = rcvrate;
00349                         }
00350                         else {
00351                                 slowstart ();
00352                                 nextpkt();
00353                         }
00354                 }
00355                 else {
00356                         if (rcvrate>rate_) 
00357                                 increase_rate(flost);
00358                         else 
00359                                 decrease_rate ();               
00360                 }
00361         }
00362         if (printStatus_) {
00363                 printf("time: %5.2f rate: %5.2f\n", now, rate_);
00364                 double packetrate = rate_ * rtt_ / size_;
00365                 printf("time: %5.2f packetrate: %5.2f\n", now, packetrate);
00366         }
00367         Packet::free(pkt);
00368 }
00369 
00370 void TfrcAgent::slowstart () 
00371 {
00372         double now = Scheduler::instance().clock(); 
00373 
00374         if (rate_+SMALLFLOAT< size_/rtt_ ) {
00375                 /* if this is the first report, change rate to 1 per rtt */
00376                 /* compute delta so rate increases slowly to new value   */
00377                 oldrate_ = rate_;
00378                 rate_ = size_/rtt_;
00379                 delta_ = (rate_ - oldrate_)/(rate_*rtt_/size_);
00380                 last_change_ = now;
00381         } else {
00382                 /* else multiply the rate by ssmult_, and compute delta, */
00383                 /*  so that the rate increases slowly to new value       */
00384                 if (ss_maxrate_ > 0) {
00385                         if (ssmult_*rate_ < ss_maxrate_ && now - last_change_ > rtt_) {
00386                                 rate_ = ssmult_*rate_; 
00387                                 delta_ = (rate_ - oldrate_)/(rate_*rtt_/size_);
00388                                 last_change_=now;
00389                         } else {
00390                                 if ( (oldrate_ > ss_maxrate_) || (rate_ > ss_maxrate_)) {
00391                                         if (oldrate_ > ss_maxrate_) {
00392                                                 delta_ = 0; 
00393                                                 rate_ = oldrate_ = 0.5*ss_maxrate_;
00394                                                 last_change_ = now;
00395                                         } else {
00396                                                 rate_ = ss_maxrate_; 
00397                                                 delta_ = (rate_ - oldrate_)/(rate_*rtt_/size_);
00398                                                 last_change_ = now; 
00399                                         }
00400                                 } else {
00401                                         if (now - last_change_ > rtt_) {
00402                                                 rate_ = ss_maxrate_;
00403                                                 delta_ = (rate_ - oldrate_)/(rate_*rtt_/size_);
00404                                                 last_change_=now;
00405                                         }
00406                                 }
00407                         }
00408                 } else {
00409                         rate_ = ssmult_*rate_; 
00410                         delta_ = (rate_ - oldrate_)/(rate_*rtt_/size_);
00411                         last_change_=now;
00412                 }
00413         }
00414 }
00415 
00416 void TfrcAgent::increase_rate (double p)
00417 {               
00418         double now = Scheduler::instance().clock();
00419 
00420         double mult = (now-last_change_)/rtt_ ;
00421         if (mult > 2) mult = 2 ;
00422 
00423         rate_ = rate_ + (size_/rtt_)*mult ;
00424         double maximumrate = (maxrate_>size_/rtt_)?maxrate_:size_/rtt_ ;
00425         maximumrate = (maximumrate>rcvrate)?rcvrate:maximumrate;
00426         rate_ = (rate_ > maximumrate)?maximumrate:rate_ ;
00427         
00428         rate_change_ = CONG_AVOID;  
00429         last_change_ = now;
00430         heavyrounds_ = 0;
00431 }       
00432 
00433 void TfrcAgent::decrease_rate () 
00434 {
00435         double now = Scheduler::instance().clock(); 
00436         rate_ = rcvrate;
00437         double maximumrate = (maxrate_>size_/rtt_)?maxrate_:size_/rtt_ ;
00438 
00439         // Allow sending rate to be greater than maximumrate
00440         //   (which is by default twice the receiving rate)
00441         //   for at most maxHeavyRounds_ rounds.
00442         if (rate_ > maximumrate)
00443                 heavyrounds_++;
00444         else
00445                 heavyrounds_ = 0;
00446         if (heavyrounds_ > maxHeavyRounds_) {
00447                 rate_ = (rate_ > maximumrate)?maximumrate:rate_ ;
00448         }
00449 
00450         rate_change_ = RATE_DECREASE;
00451         last_change_ = now;
00452 }
00453 
00454 void TfrcAgent::sendpkt()
00455 {
00456         if (active_) {
00457                 Packet* p = allocpkt();
00458                 hdr_tfrc *tfrch = hdr_tfrc::access(p);
00459                 hdr_flags* hf = hdr_flags::access(p);
00460                 if (ecn_) {
00461                         hf->ect() = 1;  // ECN-capable transport
00462                 }
00463                 tfrch->seqno=seqno_++;
00464                 tfrch->timestamp=Scheduler::instance().clock();
00465                 tfrch->rtt=rtt_;
00466                 tfrch->tzero=tzero_;
00467                 tfrch->rate=rate_;
00468                 tfrch->psize=size_;
00469                 tfrch->UrgentFlag=UrgentFlag;
00470                 tfrch->round_id=round_id;
00471                 ndatapack_++;
00472                 double now = Scheduler::instance().clock(); 
00473                 last_pkt_time_ = now;
00474                 send(p, 0);
00475         }
00476 }
00477 
00478 void TfrcAgent::reduce_rate_on_no_feedback()
00479 {
00480         rate_change_ = RATE_DECREASE; 
00481         if (oldCode_ || !datalimited_ || rate_ > 4.0 * size_/rtt_ ) {
00482                 // if we are not datalimited,
00483                 //   or the current rate is greater than four pkts per RTT
00484                 rate_*=0.5;
00485         }
00486         UrgentFlag = 1;
00487         round_id ++ ;
00488         double t = 2*rtt_ ; 
00489         if (t < 2*size_/rate_) 
00490                 t = 2*size_/rate_ ; 
00491         NoFeedbacktimer_.resched(t);
00492         nextpkt();
00493 }
00494 
00495 void TfrcSendTimer::expire(Event *) {
00496         a_->nextpkt();
00497 }
00498 
00499 void TfrcNoFeedbackTimer::expire(Event *) {
00500         a_->reduce_rate_on_no_feedback ();
00501 }

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