tfrc-sink.cc

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 1999  International Computer Science Institute
00003  * All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions
00007  * are met:
00008  * 1. Redistributions of source code must retain the above copyright
00009  *    notice, this list of conditions and the following disclaimer.
00010  * 2. Redistributions in binary form must reproduce the above copyright
00011  *    notice, this list of conditions and the following disclaimer in the
00012  *    documentation and/or other materials provided with the distribution.
00013  * 3. All advertising materials mentioning features or use of this software
00014  *    must display the following acknowledgement:
00015  *  This product includes software developed by ACIRI, the AT&T 
00016  *      Center for Internet Research at ICSI (the International Computer
00017  *      Science Institute).
00018  * 4. Neither the name of ACIRI nor of ICSI 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 ICSI 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 ICSI 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 #include <stdio.h>
00036 #include <stdlib.h>
00037 #include <sys/types.h>
00038 #include <math.h>
00039  
00040 #include "tfrc-sink.h"
00041 #include "formula-with-inverse.h"
00042 #include "flags.h"
00043 
00044 static class TfrcSinkClass : public TclClass {
00045 public:
00046     TfrcSinkClass() : TclClass("Agent/TFRCSink") {}
00047     TclObject* create(int, const char*const*) {
00048             return (new TfrcSinkAgent());
00049     }
00050 } class_tfrcSink; 
00051 
00052 
00053 TfrcSinkAgent::TfrcSinkAgent() : Agent(PT_TFRC_ACK), nack_timer_(this)
00054 {
00055     bind("packetSize_", &size_);    
00056     bind("InitHistorySize_", &hsz);
00057     bind("NumFeedback_", &NumFeedback_);
00058     bind ("AdjustHistoryAfterSS_", &adjust_history_after_ss);
00059     bind ("printLoss_", &printLoss_);
00060     bind ("algo_", &algo); // algo for loss estimation
00061     bind ("PreciseLoss_", &PreciseLoss_);
00062     bind ("numPkts_", &numPkts_);
00063 
00064     // for WALI ONLY
00065     bind ("NumSamples_", &numsamples);
00066     bind ("discount_", &discount);
00067     bind ("smooth_", &smooth_);
00068     bind ("ShortIntervals_", &ShortIntervals_);
00069 
00070     // EWMA use only
00071     bind ("history_", &history); // EWMA history
00072 
00073     // for RBPH use only
00074     bind("minlc_", &minlc); 
00075 
00076     bind("bytes_", &bytes_);
00077     rtt_ =  0; 
00078     tzero_ = 0;
00079     last_timestamp_ = 0;
00080     last_arrival_ = 0;
00081     last_report_sent=0;
00082     total_received_ = 0;
00083     total_losses_ = 0;
00084     total_dropped_ = 0;
00085 
00086     maxseq = -1;
00087     maxseqList = -1;
00088     rcvd_since_last_report  = 0;
00089     losses_since_last_report = 0;
00090     loss_seen_yet = 0;
00091     lastloss = 0;
00092     lastloss_round_id = -1 ;
00093     numPktsSoFar_ = 0;
00094 
00095     rtvec_ = NULL;
00096     tsvec_ = NULL;
00097     lossvec_ = NULL;
00098 
00099     // used by WALI and EWMA
00100     last_sample = 0;
00101 
00102     // used only for WALI 
00103     false_sample = 0;
00104     sample = NULL ; 
00105     weights = NULL ;
00106     mult = NULL ;
00107         losses = NULL ;
00108     count_losses = NULL ;
00109     sample_count = 1 ;
00110     mult_factor_ = 1.0;
00111     init_WALI_flag = 0;
00112 
00113     // used only for EWMA
00114     avg_loss_int = -1 ;
00115     loss_int = 0 ;
00116 
00117     // used only bu RBPH
00118     sendrate = 0 ; // current send rate
00119 }
00120 
00121 /*
00122  * This is a new loss event if it is at least an RTT after the beginning
00123  *   of the last one.
00124  * If PreciseLoss_ is set, the new_loss also checks that there is a
00125  *     new round_id.
00126  * The sender updates the round_id when it receives a new report from
00127  *   the receiver, and when it reduces its rate after no feedback.
00128  * Sometimes the rtt estimates can be less than the actual RTT, and
00129  *   the round_id will catch this.  This can be useful if the actual
00130  *   RTT increases dramatically.
00131  */
00132 int TfrcSinkAgent::new_loss(int i, double tstamp)
00133 {
00134     double time_since_last_loss_interval = tsvec_[i%hsz]-lastloss;
00135     if ((time_since_last_loss_interval > rtt_)
00136          && (PreciseLoss_ == 0 || (round_id > lastloss_round_id))) {
00137         lastloss = tstamp;
00138         lastloss_round_id = round_id ;
00139                 if (time_since_last_loss_interval < 2.0 * rtt_ &&
00140                 algo == WALI) {
00141                         count_losses[0] = 1;
00142                 }
00143         return TRUE;
00144     } else return FALSE;
00145 }
00146 
00147 double TfrcSinkAgent::estimate_tstamp(int before, int after, int i)
00148 {
00149     double delta = (tsvec_[after%hsz]-tsvec_[before%hsz])/(after-before) ; 
00150     double tstamp = tsvec_[before%hsz]+(i-before)*delta ;
00151     return tstamp;
00152 }
00153 
00154 /*
00155  * Receive new data packet.  If appropriate, generate a new report.
00156  */
00157 void TfrcSinkAgent::recv(Packet *pkt, Handler *)
00158 {
00159     hdr_tfrc *tfrch = hdr_tfrc::access(pkt); 
00160     hdr_flags* hf = hdr_flags::access(pkt);
00161     double now = Scheduler::instance().clock();
00162     double p = -1;
00163     int ecnEvent = 0;
00164     int congestionEvent = 0;
00165     int UrgentFlag = 0; // send loss report immediately
00166     int newdata = 0;    // a new data packet received
00167 
00168     if (algo == WALI && !init_WALI_flag) {
00169         init_WALI () ;
00170     }
00171     rcvd_since_last_report ++;
00172     total_received_ ++;
00173     // bytes_ was added by Tom Phelan, for reporting bytes received.
00174     bytes_ += hdr_cmn::access(pkt)->size();
00175 
00176     if (maxseq < 0) {
00177         // This is the first data packet.
00178         newdata = 1;
00179         maxseq = tfrch->seqno - 1 ;
00180         maxseqList = tfrch->seqno;
00181         rtvec_=(double *)malloc(sizeof(double)*hsz);
00182         tsvec_=(double *)malloc(sizeof(double)*hsz);
00183         lossvec_=(char *)malloc(sizeof(double)*hsz);
00184         if (rtvec_ && lossvec_) {
00185             int i;
00186             for (i = 0; i < hsz ; i ++) {
00187                 lossvec_[i] = UNKNOWN;
00188                 rtvec_[i] = -1; 
00189                 tsvec_[i] = -1; 
00190             }
00191         }
00192         else {
00193             printf ("error allocating memory for packet buffers\n");
00194             abort (); 
00195         }
00196     }
00197     /* for the time being, we will ignore out of order and duplicate 
00198        packets etc. */
00199     int seqno = tfrch->seqno ;
00200     fsize_ = tfrch->fsize;
00201     int oldmaxseq = maxseq;
00202     // if this is the highest packet yet, or an unknown packet
00203     //   between maxseqList and maxseq  
00204     if ((seqno > maxseq) || 
00205       (seqno > maxseqList && lossvec_[seqno%hsz] == UNKNOWN )) {
00206         if (seqno > maxseqList + 1)
00207             ++ numPktsSoFar_;
00208         UrgentFlag = tfrch->UrgentFlag;
00209         round_id = tfrch->round_id ;
00210         rtt_=tfrch->rtt;
00211         tzero_=tfrch->tzero;
00212         psize_=tfrch->psize;
00213         sendrate = tfrch->rate;
00214         last_arrival_=now;
00215         last_timestamp_=tfrch->timestamp;
00216         rtvec_[seqno%hsz]=now;  
00217         tsvec_[seqno%hsz]=last_timestamp_;  
00218         if (hf->ect() == 1 && hf->ce() == 1) {
00219             // ECN action
00220             lossvec_[seqno%hsz] = ECN_RCVD;
00221             ++ total_losses_;
00222             losses_since_last_report++;
00223             if (new_loss(seqno, tsvec_[seqno%hsz])) {
00224                 ecnEvent = 1;
00225                 lossvec_[seqno%hsz] = ECNLOST;
00226             } 
00227             if (algo == WALI) {
00228                             ++ losses[0];
00229             }
00230         } else lossvec_[seqno%hsz] = RCVD;
00231     }
00232     if (seqno > maxseq) {
00233         int i = maxseq + 1;
00234         while (i < seqno) {
00235             // Added 3/1/05 in case we have wrapped around
00236             //   in packet sequence space.
00237             lossvec_[i%hsz] = UNKNOWN;
00238             ++ i;
00239             ++ total_losses_;
00240             ++ total_dropped_;
00241         }
00242     }
00243     if (seqno > maxseqList && 
00244       (ecnEvent || numPktsSoFar_ >= numPkts_ ||
00245          tsvec_[seqno%hsz] - tsvec_[maxseqList%hsz] > rtt_)) {
00246         // numPktsSoFar_ >= numPkts_:
00247         // Number of pkts since we last entered this procedure
00248         //   at least equal numPkts_, the number of non-sequential 
00249         //   packets that must be seen before inferring loss.
00250         // maxseqList: max seq number checked for dropped packets
00251         // Decide which losses begin new loss events.
00252         int i = maxseqList ;
00253         while(i < seqno) {
00254             if (lossvec_[i%hsz] == UNKNOWN) {
00255                 rtvec_[i%hsz]=now;  
00256                 tsvec_[i%hsz]=estimate_tstamp(oldmaxseq, seqno, i); 
00257                 if (new_loss(i, tsvec_[i%hsz])) {
00258                     congestionEvent = 1;
00259                     lossvec_[i%hsz] = LOST;
00260                 } else {
00261                     // This lost packet is marked "NOT_RCVD"
00262                     // as it does not begin a loss event.
00263                     lossvec_[i%hsz] = NOT_RCVD; 
00264                 }
00265                 if (algo == WALI) {
00266                         ++ losses[0];
00267                 }
00268                 losses_since_last_report++;
00269             }
00270             i++;
00271         }
00272         maxseqList = seqno;
00273         numPktsSoFar_ = 0;
00274     } else if (seqno == maxseqList + 1) {
00275         maxseqList = seqno;
00276         numPktsSoFar_ = 0;
00277     } 
00278     if (seqno > maxseq) {
00279         maxseq = tfrch->seqno ;
00280         // if we are in slow start (i.e. (loss_seen_yet ==0)), 
00281         // and if we saw a loss, report it immediately
00282         if ((algo == WALI) && (loss_seen_yet ==0) && 
00283           (tfrch->seqno - oldmaxseq > 1 || ecnEvent )) {
00284             UrgentFlag = 1 ; 
00285             loss_seen_yet = 1;
00286             if (adjust_history_after_ss) {
00287                 p = adjust_history(tfrch->timestamp);
00288             }
00289 
00290         }
00291         if ((rtt_ > SMALLFLOAT) && 
00292             (now - last_report_sent >= rtt_/NumFeedback_)) {
00293             UrgentFlag = 1 ;
00294         }
00295     }
00296     if (UrgentFlag || ecnEvent || congestionEvent) {
00297         nextpkt(p);
00298     }
00299     Packet::free(pkt);
00300 }
00301 
00302 double TfrcSinkAgent::est_loss () 
00303 {   
00304     double p = 0 ;
00305     switch (algo) {
00306         case WALI:
00307             p = est_loss_WALI () ;
00308             break;
00309         case EWMA:
00310             p = est_loss_EWMA () ;
00311             break;
00312         case RBPH:
00313             p = est_loss_RBPH () ;
00314             break;
00315         case EBPH:
00316             p = est_loss_EBPH () ;
00317             break;
00318         default:
00319             printf ("invalid algo specified\n");
00320             abort();
00321             break ; 
00322     }
00323     return p;
00324 }
00325 
00326 /*
00327  * compute estimated throughput in packets per RTT for report.
00328  */
00329 double TfrcSinkAgent::est_thput () 
00330 {
00331     double time_for_rcv_rate;
00332     double now = Scheduler::instance().clock();
00333     double thput = 1 ;
00334 
00335     if ((rtt_ > 0) && ((now - last_report_sent) >= rtt_)) {
00336         // more than an RTT since the last report
00337         time_for_rcv_rate = (now - last_report_sent);
00338         if (rcvd_since_last_report > 0) {
00339             thput = rcvd_since_last_report/time_for_rcv_rate;
00340         }
00341     }
00342     else {
00343         // count number of packets received in the last RTT
00344         if (rtt_ > 0){
00345             double last = rtvec_[maxseq%hsz]; 
00346             int rcvd = 0;
00347             int i = maxseq;
00348             while (i > 0) {
00349                 if (lossvec_[i%hsz] == RCVD) {
00350                     if ((rtvec_[i%hsz] + rtt_) > last) 
00351                         rcvd++; 
00352                     else
00353                         break ;
00354                 }
00355                 i--; 
00356             }
00357             if (rcvd > 0)
00358                 thput = rcvd/rtt_; 
00359         }
00360     }
00361     return thput ;
00362 }
00363 
00364 /*
00365  * Schedule sending this report, and set timer for the next one.
00366  */
00367 void TfrcSinkAgent::nextpkt(double p) {
00368 
00369     sendpkt(p);
00370 
00371     /* schedule next report rtt/NumFeedback_ later */
00372     if (rtt_ > 0.0 && NumFeedback_ > 0) 
00373         nack_timer_.resched(1.5*rtt_/NumFeedback_);
00374 }
00375 
00376 /*
00377  * Create report message, and send it.
00378  */
00379 void TfrcSinkAgent::sendpkt(double p)
00380 {
00381     double now = Scheduler::instance().clock();
00382 
00383     /*don't send an ACK unless we've received new data*/
00384     /*if we're sending slower than one packet per RTT, don't need*/
00385     /*multiple responses per data packet.*/
00386         /*
00387      * Do we want to send a report even if we have not received
00388      * any new data?
00389          */ 
00390 
00391     if (last_arrival_ >= last_report_sent) {
00392 
00393         Packet* pkt = allocpkt();
00394         if (pkt == NULL) {
00395             printf ("error allocating packet\n");
00396             abort(); 
00397         }
00398     
00399         hdr_tfrc_ack *tfrc_ackh = hdr_tfrc_ack::access(pkt);
00400     
00401         tfrc_ackh->seqno=maxseq;
00402         tfrc_ackh->timestamp_echo=last_timestamp_;
00403         tfrc_ackh->timestamp_offset=now-last_arrival_;
00404         tfrc_ackh->timestamp=now;
00405         tfrc_ackh->NumFeedback_ = NumFeedback_;
00406         if (p < 0) 
00407             tfrc_ackh->flost = est_loss (); 
00408         else
00409             tfrc_ackh->flost = p;
00410         tfrc_ackh->rate_since_last_report = est_thput ();
00411         tfrc_ackh->losses = losses_since_last_report;
00412         if (total_received_ <= 0) 
00413             tfrc_ackh->true_loss = 0.0;
00414         else 
00415             tfrc_ackh->true_loss = 1.0 * 
00416                 total_losses_/(total_received_+total_dropped_);
00417         last_report_sent = now; 
00418         rcvd_since_last_report = 0;
00419         losses_since_last_report = 0;
00420         send(pkt, 0);
00421     }
00422 }
00423 
00424 int TfrcSinkAgent::command(int argc, const char*const* argv) 
00425 {
00426     if (argc == 3) {
00427         if (strcmp(argv[1], "weights") == 0) {
00428             /* 
00429              * weights is a string of numbers, seperated by + signs
00430              * the firs number is the total number of weights.
00431              * the rest of them are the actual weights
00432              * this overrides the defaults
00433              */
00434             char *w ;
00435             w = (char *)calloc(strlen(argv[2])+1, sizeof(char)) ;
00436             if (w == NULL) {
00437                 printf ("error allocating w\n");
00438                 abort();
00439             }
00440             strcpy(w, (char *)argv[2]);
00441             numsamples = atoi(strtok(w,"+"));
00442             sample = (int *)malloc((numsamples+1)*sizeof(int));
00443             losses = (int *)malloc((numsamples+1)*sizeof(int));
00444                         count_losses = (int *)malloc((numsamples+1)*sizeof(int));
00445             weights = (double *)malloc((numsamples+1)*sizeof(double));
00446             mult = (double *)malloc((numsamples+1)*sizeof(double));
00447             fflush(stdout);
00448             if (sample && weights) {
00449                 int count = 0 ;
00450                 while (count < numsamples) {
00451                     sample[count] = 0;
00452                     losses[count] = 1;
00453                     count_losses[count] = 0;
00454                     mult[count] = 1;
00455                     char *w;
00456                     w = strtok(NULL, "+");
00457                     if (w == NULL)
00458                         break ; 
00459                     else {
00460                         weights[count++] = atof(w);
00461                     }   
00462                 }
00463                 if (count < numsamples) {
00464                     printf ("error in weights string %s\n", argv[2]);
00465                     abort();
00466                 }
00467                 sample[count] = 0;
00468                 losses[count] = 1;
00469                 count_losses[count] = 0;
00470                 weights[count] = 0;
00471                 mult[count] = 1;
00472                 free(w);
00473                 return (TCL_OK);
00474             }
00475             else {
00476                 printf ("error allocating memory for smaple and weights:2\n");
00477                 abort();
00478             }
00479         }
00480     }
00481     return (Agent::command(argc, argv));
00482 }
00483 
00484 void TfrcNackTimer::expire(Event *) {
00485     a_->nextpkt(-1);
00486 }
00487 
00488 void TfrcSinkAgent::print_loss(int sample, double ave_interval)
00489 {
00490     double now = Scheduler::instance().clock();
00491     double drops = 1/ave_interval;
00492     // This is ugly to include this twice, but the first one is
00493     //   for backward compatibility with earlier scripts. 
00494     printf ("time: %7.5f loss_rate: %7.5f \n", now, drops);
00495     printf ("time: %7.5f sample 0: %5d loss_rate: %7.5f \n", 
00496         now, sample, drops);
00497     //printf ("time: %7.5f send_rate: %7.5f\n", now, sendrate);
00498     //printf ("time: %7.5f maxseq: %d\n", now, maxseq);
00499 }
00500 
00501 void TfrcSinkAgent::print_loss_all(int *sample) 
00502 {
00503     double now = Scheduler::instance().clock();
00504     printf ("%f: sample 0: %5d 1: %5d 2: %5d 3: %5d 4: %5d\n", 
00505         now, sample[0], sample[1], sample[2], sample[3], sample[4]); 
00506 }
00507 
00508 void TfrcSinkAgent::print_losses_all(int *losses) 
00509 {
00510     double now = Scheduler::instance().clock();
00511     printf ("%f: losses 0: %5d 1: %5d 2: %5d 3: %5d 4: %5d\n", 
00512         now, losses[0], losses[1], losses[2], losses[3], losses[4]); 
00513 }
00514 
00515 void TfrcSinkAgent::print_count_losses_all(int *count_losses) 
00516 {
00517     double now = Scheduler::instance().clock();
00518     printf ("%f: count? 0: %5d 1: %5d 2: %5d 3: %5d 4: %5d\n", 
00519         now, count_losses[0], count_losses[1], count_losses[2], count_losses[3], count_losses[4]); 
00520 }
00521 
00523 // algo specific code /////////////////
00525 
00526 
00530 double TfrcSinkAgent::est_loss_WALI () 
00531 {
00532     int i;
00533     double ave_interval1, ave_interval2; 
00534     int ds ; 
00535         
00536     if (!init_WALI_flag) {
00537         init_WALI () ;
00538     }
00539     // sample[i] counts the number of packets since the i-th loss event
00540     // sample[0] contains the most recent sample.
00541     for (i = last_sample; i <= maxseq ; i ++) {
00542         sample[0]++;
00543         if (lossvec_[i%hsz] == LOST || lossvec_[i%hsz] == ECNLOST) {
00544                 //  new loss event
00545             // double now = Scheduler::instance().clock();
00546             sample_count ++;
00547             shift_array (sample, numsamples+1, 0); 
00548             shift_array (losses, numsamples+1, 1); 
00549             shift_array (count_losses, numsamples+1, 0); 
00550             multiply_array(mult, numsamples+1, mult_factor_);
00551             shift_array (mult, numsamples+1, 1.0); 
00552             mult_factor_ = 1.0;
00553         }
00554     }
00555     last_sample = maxseq+1 ; 
00556 
00557     if (sample_count>numsamples+1)
00558         // The array of loss intervals is full.
00559         ds=numsamples+1;
00560         else
00561         ds=sample_count;
00562 
00563     if (sample_count == 1 && false_sample == 0) 
00564         // no losses yet
00565         return 0; 
00566     /* do we need to discount weights? */
00567     if (sample_count > 1 && discount && sample[0] > 0) {
00568                 double ave = weighted_average1(1, ds, 1.0, mult, weights, sample, ShortIntervals_, losses, count_losses);
00569                 //double ave = weighted_average(1, ds, 1.0, mult, weights, sample);
00570         int factor = 2;
00571         double ratio = (factor*ave)/sample[0];
00572         double min_ratio = 0.5;
00573         if ( ratio < 1.0) {
00574             // the most recent loss interval is very large
00575             mult_factor_ = ratio;
00576             if (mult_factor_ < min_ratio) 
00577                 mult_factor_ = min_ratio;
00578         }
00579     }
00580     // Calculations including the most recent loss interval.
00581         ave_interval1 = weighted_average1(0, ds, mult_factor_, mult, weights, sample, ShortIntervals_, losses, count_losses);
00582         //ave_interval1 = weighted_average(0, ds, mult_factor_, mult, weights, sample);
00583     // The most recent loss interval does not end in a loss
00584     // event.  Include the most recent interval in the 
00585     // calculations only if this increases the estimated loss
00586     // interval.
00587         ave_interval2 = weighted_average1(1, ds, mult_factor_, mult, weights, sample, ShortIntervals_, losses, count_losses);
00588         //ave_interval2 = weighted_average(1, ds, mult_factor_, mult, weights, sample);
00589     if (ave_interval2 > ave_interval1)
00590         ave_interval1 = ave_interval2;
00591     if (ave_interval1 > 0) { 
00592         if (printLoss_ > 0) {
00593             print_loss(sample[0], ave_interval1);
00594             print_loss_all(sample);
00595             if (ShortIntervals_ > 0) {
00596                 print_losses_all(losses);
00597                 print_count_losses_all(count_losses);
00598             }
00599         }
00600         return 1/ave_interval1; 
00601     } else return 999;     
00602 }
00603 
00604 // Calculate the weighted average.
00605 double TfrcSinkAgent::weighted_average(int start, int end, double factor, double *m, double *w, int *sample)
00606 {
00607     int i; 
00608     double wsum = 0;
00609     double answer = 0;
00610     if (smooth_ == 1 && start == 0) {
00611         if (end == numsamples+1) {
00612             // the array is full, but we don't want to uses
00613             //  the last loss interval in the array
00614             end = end-1;
00615         } 
00616         // effectively shift the weight arrays 
00617         for (i = start ; i < end; i++) 
00618             if (i==0)
00619                 wsum += m[i]*w[i+1];
00620             else 
00621                 wsum += factor*m[i]*w[i+1];
00622         for (i = start ; i < end; i++)  
00623             if (i==0)
00624                 answer += m[i]*w[i+1]*sample[i]/wsum;
00625             else 
00626                 answer += factor*m[i]*w[i+1]*sample[i]/wsum;
00627             return answer;
00628 
00629     } else {
00630         for (i = start ; i < end; i++) 
00631             if (i==0)
00632                 wsum += m[i]*w[i];
00633             else 
00634                 wsum += factor*m[i]*w[i];
00635         for (i = start ; i < end; i++)  
00636             if (i==0)
00637                 answer += m[i]*w[i]*sample[i]/wsum;
00638             else 
00639                 answer += factor*m[i]*w[i]*sample[i]/wsum;
00640             return answer;
00641     }
00642 }
00643 
00644 int TfrcSinkAgent::get_sample(int oldSample, int numLosses) 
00645 {
00646     int newSample;
00647     if (numLosses == 0) {
00648         newSample = oldSample;
00649     } else {
00650         newSample = (int) floor(oldSample / numLosses);
00651     }
00652     return newSample;
00653 }
00654 
00655 // Calculate the weighted average, factor*m[i]*w[i]*sample[i]/wsum.
00656 // "factor" is "mult_factor_", for weighting the most recent interval
00657 //    when it is very large
00658 // "m[i]" is "mult[]", for old values of "mult_factor_".
00659 //
00660 // When ShortIntervals_ is 1, the length of a loss interval is
00661 //   "sample[i]/losses[i]" for short intervals, not just "sample[i]".
00662 //   This is equivalent to a loss event rate of "losses[i]/sample[i]",
00663 //   instead of "1/sample[i]".
00664 //
00665 // When ShortIntervals_ is 2, it is like ShortIntervals_ of 1,
00666 //   except that the number of losses per loss interval is at
00667 //   most 1460/byte-size-of-small-packets.
00668 //
00669 double TfrcSinkAgent::weighted_average1(int start, int end, double factor, double *m, double *w, int *sample, int ShortIntervals, int *losses, int *count_losses)
00670 {
00671         int i;
00672         int ThisSample;
00673         double wsum = 0;
00674         double answer = 0;
00675         if (smooth_ == 1 && start == 0) {
00676                 if (end == numsamples+1) {
00677                         // the array is full, but we don't want to uses
00678                         //  the last loss interval in the array
00679                         end = end-1;
00680                 }
00681                 // effectively shift the weight arrays
00682                 for (i = start ; i < end; i++)
00683                         if (i==0)
00684                                 wsum += m[i]*w[i+1];
00685                         else
00686                                 wsum += factor*m[i]*w[i+1];
00687                 for (i = start ; i < end; i++) {
00688                         ThisSample = sample[i];
00689                         if (ShortIntervals == 1 && count_losses[i] == 1) {
00690                    ThisSample = get_sample(sample[i], losses[i]);
00691                         }
00692                         if (ShortIntervals == 2 && count_losses[i] == 1) {
00693                    int adjusted_losses = int(fsize_/size_);
00694                    if (losses[i] < adjusted_losses) {
00695                     adjusted_losses = losses[i];
00696                    }
00697                    ThisSample = get_sample(sample[i], adjusted_losses);
00698                         }
00699                         if (i==0)
00700                                 answer += m[i]*w[i+1]*ThisSample/wsum;
00701                                 //answer += m[i]*w[i+1]*sample[i]/wsum;
00702                         else
00703                                 answer += factor*m[i]*w[i+1]*ThisSample/wsum;
00704                                 //answer += factor*m[i]*w[i+1]*sample[i]/wsum;
00705         }
00706                 return answer;
00707 
00708         } else {
00709                 for (i = start ; i < end; i++)
00710                         if (i==0)
00711                                 wsum += m[i]*w[i];
00712                         else
00713                                 wsum += factor*m[i]*w[i];
00714                 for (i = start ; i < end; i++) {
00715                        ThisSample = sample[i];
00716                        if (ShortIntervals == 1 && count_losses[i] == 1) {
00717                    ThisSample = get_sample(sample[i], losses[i]);
00718                        }
00719                        if (ShortIntervals == 2 && count_losses[i] == 1) {
00720                    ThisSample = get_sample(sample[i], 7);
00721                    // Replace 7 by 1460/packet size.
00722                        }
00723                        if (i==0)
00724                                 answer += m[i]*w[i]*ThisSample/wsum;
00725                                 //answer += m[i]*w[i]*sample[i]/wsum;
00726                         else
00727                                 answer += factor*m[i]*w[i]*ThisSample/wsum;
00728                                 //answer += factor*m[i]*w[i]*sample[i]/wsum;
00729         }
00730                 return answer;
00731         }
00732 }
00733 
00734 // Shift array a[] up, starting with a[sz-2] -> a[sz-1].
00735 void TfrcSinkAgent::shift_array(int *a, int sz, int defval) 
00736 {
00737     int i ;
00738     for (i = sz-2 ; i >= 0 ; i--) {
00739         a[i+1] = a[i] ;
00740     }
00741     a[0] = defval;
00742 }
00743 void TfrcSinkAgent::shift_array(double *a, int sz, double defval) {
00744     int i ;
00745     for (i = sz-2 ; i >= 0 ; i--) {
00746         a[i+1] = a[i] ;
00747     }
00748     a[0] = defval;
00749 }
00750 
00751 // Multiply array by value, starting with array index 1.
00752 // Array index 0 of the unshifted array contains the most recent interval.
00753 void TfrcSinkAgent::multiply_array(double *a, int sz, double multiplier) {
00754     int i ;
00755     for (i = 1; i <= sz-1; i++) {
00756         double old = a[i];
00757         a[i] = old * multiplier ;
00758     }
00759 }
00760 
00761 /*
00762  * We just received our first loss, and need to adjust our history.
00763  */
00764 double TfrcSinkAgent::adjust_history (double ts)
00765 {
00766     int i;
00767     double p;
00768     for (i = maxseq; i >= 0 ; i --) {
00769         if (lossvec_[i%hsz] == LOST || lossvec_[i%hsz] == ECNLOST ) {
00770             lossvec_[i%hsz] = NOT_RCVD; 
00771         }
00772     }
00773     lastloss = ts; 
00774     lastloss_round_id = round_id ;
00775     p=b_to_p(est_thput()*psize_, rtt_, tzero_, fsize_, 1);
00776     false_sample = (int)(1.0/p);
00777     sample[1] = false_sample;
00778     sample[0] = 0;
00779     losses[1] = 0;
00780     losses[0] = 1;
00781     count_losses[1] = 0;
00782     count_losses[0] = 0;
00783     sample_count++; 
00784     if (printLoss_) {
00785         print_loss_all (sample);
00786         if (ShortIntervals_ == 1) {
00787             print_losses_all(losses);
00788             print_count_losses_all(count_losses);
00789         }
00790     }
00791     false_sample = -1 ; 
00792     return p;
00793 }
00794 
00795 
00796 /*
00797  * Initialize data structures for weights.
00798  */
00799 void TfrcSinkAgent::init_WALI () {
00800     int i;
00801     if (numsamples < 0)
00802         numsamples = DEFAULT_NUMSAMPLES ;   
00803     if (smooth_ == 1) {
00804         numsamples = numsamples + 1;
00805     }
00806     sample = (int *)malloc((numsamples+1)*sizeof(int));
00807         losses = (int *)malloc((numsamples+1)*sizeof(int));
00808         count_losses = (int *)malloc((numsamples+1)*sizeof(int));
00809     weights = (double *)malloc((numsamples+1)*sizeof(double));
00810     mult = (double *)malloc((numsamples+1)*sizeof(double));
00811     for (i = 0 ; i < numsamples+1 ; i ++) {
00812         sample[i] = 0 ; 
00813     }
00814     if (smooth_ == 1) {
00815         int mid = int(numsamples/2);
00816         for (i = 0; i < mid; i ++) {
00817             weights[i] = 1.0;
00818         }
00819         for (i = mid; i <= numsamples; i ++){
00820             weights[i] = 1.0 - (i-mid)/(mid + 1.0);
00821         }
00822     } else {
00823         int mid = int(numsamples/2);
00824         for (i = 0; i < mid; i ++) {
00825             weights[i] = 1.0;
00826         }
00827         for (i = mid; i <= numsamples; i ++){
00828             weights[i] = 1.0 - (i+1-mid)/(mid + 1.0);
00829         }
00830     }
00831     for (i = 0; i < numsamples+1; i ++) {
00832         mult[i] = 1.0 ; 
00833     }
00834     init_WALI_flag = 1;  /* initialization done */
00835 }
00836 
00838 // EWMA //////////////////
00840 
00841 double TfrcSinkAgent::est_loss_EWMA () {
00842     double p1, p2 ;
00843     for (int i = last_sample; i <= maxseq ; i ++) {
00844         loss_int++; 
00845         if (lossvec_[i%hsz] == LOST || lossvec_[i%hsz] == ECNLOST ) {
00846             if (avg_loss_int < 0) {
00847                 avg_loss_int = loss_int ; 
00848             } else {
00849                 avg_loss_int = history*avg_loss_int + (1-history)*loss_int ;
00850             }
00851             loss_int = 0 ;
00852         }
00853     }
00854     last_sample = maxseq+1 ; 
00855 
00856     if (avg_loss_int < 0) { 
00857         p1 = 0;
00858     } else {
00859         p1 = 1.0/avg_loss_int ; 
00860     }
00861     if (loss_int == 0 
00862         || avg_loss_int < 0){ //XXX this last check was added by a
00863                   //person who knows nothing of this
00864                   //code just to stop FP div by zero.
00865                   //Values were history=.75,
00866                   //avg_loss_int=-1, loss_int=3.  If
00867                   //you know what should be here,
00868                   //please cleanup and remove this
00869                   //comment.
00870 
00871         p2 = p1 ; 
00872     } else {
00873         p2 = 1.0/(history*avg_loss_int + (1-history)*loss_int) ;
00874     }
00875     if (p2 < p1) {
00876         p1 = p2 ; 
00877     }
00878     if (printLoss_ > 0) {
00879         if (p1 > 0) 
00880             print_loss(loss_int, 1.0/p1);
00881         else
00882             print_loss(loss_int, 0.00001);
00883         print_loss_all(sample);
00884     }
00885     return p1 ;
00886 }
00887 
00889 // RBPH //////////////////
00891 double TfrcSinkAgent::est_loss_RBPH () {
00892 
00893     double numpkts = hsz ;
00894     double p ; 
00895 
00896     // how many pkts we should go back?
00897     if (sendrate > 0 && rtt_ > 0) {
00898         double x = b_to_p(sendrate, rtt_, tzero_, psize_, 1);
00899         if (x > 0) 
00900             numpkts = minlc/x ; 
00901         else
00902             numpkts = hsz ;
00903     }
00904 
00905     // that number must be below maxseq and hsz 
00906     if (numpkts > maxseq)
00907         numpkts = maxseq ;
00908     if (numpkts > hsz)
00909         numpkts = hsz ;
00910 
00911     int lc = 0;
00912     int pc = 0;
00913     int i = maxseq ;
00914 
00915     // first see if how many lc's we find in numpkts 
00916     while (pc < numpkts) {
00917         pc ++ ;
00918         if (lossvec_[i%hsz] == LOST || lossvec_[i%hsz] == ECNLOST )
00919             lc ++ ; 
00920         i -- ;
00921     }
00922 
00923     // if not enough lsos events, keep going back ...
00924     if (lc < minlc) {
00925 
00926         // but only as far as the history allows ...
00927         numpkts = maxseq ;
00928         if (numpkts > hsz)
00929             numpkts = hsz ;
00930 
00931         while ((lc < minlc) && (pc < numpkts)) {
00932             pc ++ ;
00933             if (lossvec_[i%hsz] == LOST || lossvec_[i%hsz] == ECNLOST )
00934                 lc ++ ;
00935             i -- ;
00936         
00937         }
00938     }
00939 
00940     if (pc == 0) 
00941         p = 0; 
00942     else
00943         p = (double)lc/(double)pc ; 
00944     if (printLoss_ > 0) {
00945         if (p > 0) 
00946             print_loss(0, 1.0/p);
00947         else
00948             print_loss(0, 0.00001);
00949         print_loss_all(sample);
00950     }
00951     return p ;
00952 }
00953 
00955 // EBPH //////////////////
00957 double TfrcSinkAgent::est_loss_EBPH () {
00958 
00959     double numpkts = hsz ;
00960     double p ; 
00961 
00962     int lc = 0;
00963     int pc = 0;
00964     int i = maxseq ;
00965 
00966     numpkts = maxseq ;
00967     if (numpkts > hsz)
00968         numpkts = hsz ;
00969 
00970     while ((lc < minlc) && (pc < numpkts)) {
00971         pc ++ ;
00972         if (lossvec_[i%hsz] == LOST || lossvec_[i%hsz] == ECNLOST)
00973             lc ++ ;
00974         i -- ;
00975     }
00976 
00977     if (pc == 0) 
00978         p = 0; 
00979     else
00980         p = (double)lc/(double)pc ; 
00981     if (printLoss_ > 0) {
00982         if (p > 0) 
00983             print_loss(0, 1.0/p);
00984         else
00985             print_loss(0, 0.00001);
00986         print_loss_all(sample);
00987     }
00988     return p ;
00989 }

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