#include //#include //#include #include #include "rcp-tap.h" #include "flags.h" //sale >>> #include "formula.h" #ifndef __my_formula_with_inverse_h__ #include "my-formula-with-inverse.h" #endif /*__my_formula_with_inverse_h__*/ //sale <<< /* * TclObject & Initialization */ static class RcpTapClass : public TclClass { public: RcpTapClass() : TclClass("Agent/RCPTap") {} TclObject* create(int , const char*const*) { return (new RcpTap()); } } class_rcptap; RcpTap::RcpTap() : Agent(PT_TCP), curseq_(0), maxseq_(-1), r_seqno_(-1), o_seqno_(-1), nreqpack_(0), closed_(0), ts_peer_(0), timer_(this), Maxseq_sale_ (-1) { type_ = PT_TCP; peer_ = NULL; repnxt_ = 0; for (int i=0;i>> sum_bytes = 0; time_last = 0; rate_last = 0; bind("ndatapack_", &ndatapack_); bind("ndatabytes_", &ndatabytes_); bind("nrexmitpack_", &nrexmitpack_); bind("nrexmitbytes_", &nrexmitbytes_); //sale <<< //sale >>> bind("loss_int_used_", &loss_int_used); bind("rtt_", &rtt_); bind("rtt_sum_", &rtt_sum_); bind("rtt_num_", &rtt_num_); //from TFRC bind("InitHistorySize_", &hsz); bind("NumFeedback_", &NumFeedback_); bind ("AdjustHistoryAfterSS_", &adjust_history_after_ss); bind ("printLoss_", &printLoss_); bind ("algo_", &algo); // algo for loss estimation // for WALI ONLY bind ("NumSamples_", &numsamples); bind ("discount_", &discount); bind ("smooth_", &smooth_); // EWMA use only bind ("history_", &history); // EWMA history // for RBPH use only bind("minlc_", &minlc); //sale!!! original: rtt_ = 0; rtt_ = 0.11; rtt_sum_ = 0.11; rtt_num_ = 1; tzero_ = 1.0; //1 second RFC 1323 // last_timestamp_ = 0; // last_arrival_ = 0; last_report_sent=0; //maxseq = -1; We now use maxseq_ rcvd_since_last_report = 0; // losses_since_last_report = 0; loss_seen_yet = 0; lastloss = 0; // lastloss_round_id = -1 ; // UrgentFlag = 0 ; rtvec_ = NULL; tsvec_ = NULL; lossvec_ = NULL; // used by WALI and EWMA last_sample = 0; // used only for WALI false_sample = 0; sample = NULL ; weights = NULL ; mult = NULL ; sample_count = 1 ; mult_factor_ = 1.0; init_WALI_flag = 0; // used only for EWMA avg_loss_int = -1 ; loss_int = 0 ; // used only bu RBPH sendrate = 0 ; // current send rate //sale <<< } void RcpTap::delay_bind_init_all() { delay_bind_init_one("seqno_"); delay_bind_init_one("maxseq_"); delay_bind_init_one("o_seqno_"); delay_bind_init_one("r_seqno_"); delay_bind_init_one("nreqpack_"); delay_bind_init_one("ndatapack_"); delay_bind_init_one("ndatabytes_"); delay_bind_init_one("nrexmitpack_"); delay_bind_init_one("nrexmitbytes_"); //sale >>> delay_bind_init_one("TCP_rate_"); delay_bind_init_one("est_loss_"); delay_bind_init_one("TFRC_rate_"); delay_bind_init_one("ploss_"); delay_bind_init_one("EQ_rate_"); delay_bind_init_one("ratio_TCP_TFRC_"); delay_bind_init_one("ratio_TCP_EQ_"); //sale <<< Agent::delay_bind_init_all(); reset(); } int RcpTap::delay_bind_dispatch( const char *varName, const char *localName, TclObject *tracer) { if (delay_bind(varName,localName,"curseq_",&curseq_,tracer)) return TCL_OK; if (delay_bind(varName,localName,"maxseq_",&maxseq_ ,tracer)) return TCL_OK; if (delay_bind(varName,localName,"o_seqno_",&o_seqno_ ,tracer)) return TCL_OK; if (delay_bind(varName,localName,"r_seqno_",&r_seqno_ ,tracer)) return TCL_OK; if (delay_bind(varName,localName,"nreqpack_",&nreqpack_,tracer)) return TCL_OK; if (delay_bind(varName,localName,"ndatapack_",&ndatapack_,tracer)) return TCL_OK; if (delay_bind(varName,localName,"ndatabytes_",&ndatabytes_,tracer)) return TCL_OK; if (delay_bind(varName,localName,"nrexmitpack_",&nrexmitpack_,tracer)) return TCL_OK; if (delay_bind(varName,localName,"nrexmitbytes_",&nrexmitbytes_,tracer)) return TCL_OK; //sale >>> if (delay_bind(varName,localName,"TCP_rate_",&TCP_rate_,tracer)) return TCL_OK; if (delay_bind(varName,localName,"est_loss_",&est_loss_,tracer)) return TCL_OK; if (delay_bind(varName,localName,"TFRC_rate_",&TFRC_rate_,tracer)) return TCL_OK; if (delay_bind(varName,localName,"ploss_",&ploss_,tracer)) return TCL_OK; if (delay_bind(varName,localName,"EQ_rate_",&EQ_rate_,tracer)) return TCL_OK; if (delay_bind(varName,localName,"ratio_TCP_TFRC_",&ratio_TCP_TFRC_,tracer)) return TCL_OK; if (delay_bind(varName,localName,"ratio_TCP_EQ_",&ratio_TCP_EQ_,tracer)) return TCL_OK; //sale <<< return Agent::delay_bind_dispatch(varName, localName, tracer); } void RcpTap::reset() { curseq_ = 0; maxseq_ = r_seqno_ = o_seqno_ = -1; //sale >>> Maxseq_sale_ = -1; //sale <<< nreqpack_ = 0; ndatapack_ = 0; ndatabytes_ = 0; nrexmitpack_ = 0; nrexmitbytes_ = 0; //sale >>> TCP_rate_ = 0; est_loss_ = 0; TFRC_rate_ = 0; ploss_ = 0; EQ_rate_ = 0; ratio_TCP_TFRC_ = 0; ratio_TCP_EQ_ = 0; //sale <<< closed_ = 0; ts_peer_ = 0; repnxt_ = 0; for (int i=0;i maxseq_) advanceby(newseq - curseq_); else advanceby(maxseq_ - curseq_); return TCL_OK; } if (strcmp(argv[1], "advanceby") == 0) { advanceby(atoi(argv[2])); return TCL_OK; } if (strcmp(argv[1], "attach-peer") == 0) { peer_ = (Agent*)TclObject::lookup(argv[2]); return (peer_ ? TCL_OK : TCL_ERROR); } } return (Agent::command(argc, argv)); } /* * one-way TCP uses packets instead of bytes */ void RcpTap::sendmsg(int nbytes, const char* /*flags*/) { if (nbytes == -1 && curseq_ <= TCP_MAXSEQ) curseq_ = TCP_MAXSEQ; else curseq_ += (nbytes/size_ + (nbytes%size_ ? 1 : 0)); //send_much(0, 0, maxburst_); /* XXX: inform the receiver to start pulling to facilitate the same * usage in the TCL scripts for TCP and RCP */ assert(peer_); peer_->sendmsg(curseq_,NULL,0); /* note the sematics is different */ } void RcpTap::advanceby(int delta) { curseq_ += delta; if (delta > 0) closed_ = 0; //send_much(0, 0, maxburst_); assert(peer_); peer_->sendmsg(curseq_,NULL,0); /* note the semantics is different */ } /* * recv */ void RcpTap::recv(Packet *pkt, Handler *) { hdr_tcp *tcph = hdr_tcp::access(pkt); assert(HDR_CMN(pkt)->ptype() == PT_REQUEST); //sale >>> double now = Scheduler::instance().clock(); //I wanted to initiate lossvec_ and others here, but did it when the packet //is actually sent //if (nreqpack_ == 0) { //} //sale <<< ++nreqpack_; ts_peer_ = tcph->ts(); int p=0, j=0; for (int i=0;isa_length();i++) { int u = tcph->sack_area_[i/2][i%2]; assert(u>=0); int m = rep_(repnxt_-1-j>0 ? repnxt_-1-j : 0); if (u!=m) { // fprintf(stderr,"\nt=%f i=%d u=%d j=%d m=%d",NOW,i,u,j,m); // printf("SALE1 send req %d now: %f\n", u, now); output(u, TCP_REASON_REQOVER); p ++; } else j++; } repnxt_ += (tcph->sa_length()-j); for (int i=0;isa_length();i++) rep_(repnxt_-1-i)=tcph->sack_area_[i/2][i%2]; int seqno = r_seqno_ = tcph->seqno(); if (hdr_flags::access(pkt)->pull()==1) { // printf("SALE2 send req %d now: %f\n", seqno, now); output(seqno, 0); p ++; rep_(repnxt_++) = seqno; } else { // assert(seqno==maxseq_+1); // is pull necessary? /* * pull: accumulated request * * XXX: what if t_seqno_ is reset? */ assert(seqno>maxseq_); for (int i=maxseq_+1;i<=seqno;i++) { // printf("SALE3 send req %d now: %f\n", i, now); output(i, (i==seqno?0:TCP_REASON_REQOVER)); p ++; if (i==seqno) rep_(repnxt_++) = i; // sync the state } } Packet::free(pkt); } /* * output packets */ int RcpTap::headersize() { int total = tcpip_base_hdr_size_; assert (total>0); if (ts_option_) total += ts_option_size_; return (total); } void RcpTap::output(int seqno, int reason) { Packet *p = allocpkt(); hdr_tcp *tcph = hdr_tcp::access(p); int databytes = hdr_cmn::access(p)->size(); tcph->seqno() = o_seqno_ = seqno; tcph->ts() = Scheduler::instance().clock(); //sale >>> double now = Scheduler::instance().clock(); //printf("req_to_send packet number %d\n", seqno); //sale <<< tcph->ts_echo()= ts_peer_; tcph->reason() = reason; //sale>>> if(ndatapack_==0) { last_report_sent = now; //printf("Last report sent = %f\n",last_report_sent); } //exit(1); //sale<<< if (reason==TCP_REASON_REQOVER) hdr_flags::access(p)->no_ts_ = 1; // don't use for rtt if (seqno == 0) { if (syn_) { // send out initial SYN packet databytes = 0; curseq_ += 1; // XXX: inform the receiver hdr_cmn::access(p)->size() = tcpip_base_hdr_size_; } else if (useHeaders_ == true) { hdr_cmn::access(p)->size() += headersize(); } } else if (useHeaders_ == true) { hdr_cmn::access(p)->size() += headersize(); } ++ndatapack_; ndatabytes_ += databytes; send(p, 0); //sale >>> if (maxseq_ < 0) { rtvec_=(double *)malloc(sizeof(double)*hsz); tsvec_=(double *)malloc(sizeof(double)*hsz); lossvec_=(char *)malloc(sizeof(double)*hsz); if (rtvec_ && lossvec_) { int i; for (i = 0; i < hsz ; i ++) { lossvec_[i] = UNKNOWN; rtvec_[i] = -1; tsvec_[i] = -1; } for (i = 0; i <= (maxseq_+1) ; i++) { lossvec_[i] = NOLOSS ; rtvec_[i] = now ; //we dont' use this tsvec_[i] = now ; } } else { printf ("error allocating memory for packet buffers\n"); abort (); } } //sale <<< if (seqno == curseq_ && seqno > maxseq_) idle(); //sale >>> //original // if (seqno > maxseq_) maxseq_ = seqno; // else { // ++nrexmitpack_; // nrexmitbytes_ += databytes; // } //we: if (seqno > maxseq_) { maxseq_ = seqno; //sale!!! //Maxseq_sale_ = seqno; //end sale!!! lossvec_[seqno%hsz] = RCVD; //actually SEND rtvec_[seqno%hsz]=now; //we don't use this tsvec_[seqno%hsz]=now; //printf("SENT PACKET NO %d, MAXSEQ = %d, time= %f\n", seqno, (maxseq_+1-1), tsvec_[seqno%hsz]); } else { //they have a bug(?) here because the packets are not sent in order if (tsvec_[seqno%hsz] < 0.0){ lossvec_[seqno%hsz] = RCVD; //actually SEND rtvec_[seqno%hsz]=now; //we don't use this tsvec_[seqno%hsz]=now; //printf("SENT PACKET NO %d, MAXSEQ = %d, time= %f\n", seqno, (maxseq_+1-1), tsvec_[seqno%hsz]); } else { ++nrexmitpack_; nrexmitbytes_ += databytes; //printf("RXMIT PACKET NO %d, MAXSEQ = %d, time= %f\n", seqno, (maxseq_+1-1), tsvec_[seqno%hsz]); lossvec_[seqno%hsz] = LOST; //only this should compute less throughput //but we want to compute the upper bound, and remove losses within //the same rtt //printf("loss_int_used = %d\n", loss_int_used); if (loss_int_used == 1) { double time = tsvec_[seqno%hsz] - rtt_; //printf ("START: rtt_: %3.3f bound_time:%3.3f\n", rtt_, time); if (seqno>=1){ int ind=0; for (int i=seqno-1;(i>=0)&&(tsvec_[i%hsz]>=time);i--) { if (lossvec_[i%hsz] == LOST) { lossvec_[seqno%hsz]=NOLOSS; ind=1; //printf ("START1: loss %d found at %3.3f time\n", i, tsvec_[i%hsz]); } } if (ind == 0) { //you didn't find a loss in the range -> this is really loss Maxseq_sale_ = seqno; } } } else { Maxseq_sale_ = seqno; } //end else } //end else //and we do not set time here, because the time is //already set when it was sent if (nrexmitpack_ == 1) { //first loss indication //we should have inferred the rtt_ by now //do the comparioson here or //call the function to update the history? //start computing the throughput compute_thr(0); } else { //We immediately compute the throughput compute_thr(1); } } //end else //sale <<< } //end output() //sale >>> /* * Schedule this report, and set timer for the next one. */ void RcpTap::compute_thr(int ind) { double now = Scheduler::instance().clock(); //double pe; if (ind == 0) { //first time //this is just for now - have to change later rate_last = ndatabytes_/now; est_loss_=est_loss(); //printf("Before History adjusted, p = %f\n",pe); est_loss_=adjust_history(now); //printf("After History adjusted, p = %f\n",pe); } else { //not the first time est_loss_=est_loss(); } //update rtt //double pe = est_loss(); double nnrexmitbytes_ = nrexmitbytes_; double nndatabytes_ = ndatabytes_; ploss_ = nnrexmitbytes_/(nndatabytes_+nnrexmitbytes_); if (est_loss_ > 0.0) { //estimate throughput bval_ = 1; double TFRC_local_rate_ = p_to_b(est_loss_, rtt_, tzero_, size_, bval_); double rtt_ave_ = rtt_sum_/rtt_num_; //printf("rtt_sum_: %f, rtt_num_: %f rtt_ave_: %f\n",rtt_sum_, rtt_num_, rtt_ave_); double comp_rate_1_ = p_to_b(ploss_, rtt_ave_, tzero_, size_, bval_); //print both throughputs double last_round_bytes = rate_last*(now-time_last); sum_bytes += last_round_bytes; TCP_rate_ = (ndatabytes_ + nrexmitbytes_)/now; est_loss_ = est_loss_; TFRC_rate_ = sum_bytes/now; // ploss_ = ploss_; EQ_rate_ = comp_rate_1_; ratio_TCP_TFRC_ = TCP_rate_/TFRC_rate_; ratio_TCP_EQ_ = TCP_rate_/EQ_rate_; double TCP_rate__ = (ndatabytes_ + nrexmitbytes_)/now; double est_loss__ = est_loss_; double TFRC_rate__ = TFRC_rate_; //this is average TFRC rate computed by now double ploss__ = ploss_; double EQ_rate__ = EQ_rate_; double ratio_TCP_TFRC__ = TCP_rate__/TFRC_rate__; double ratio_TCP_EQ__ = TCP_rate__/EQ_rate__; //PRINTING //printf("time: %7.5f TCP_rate: %5.3f, est_loss: %1.7f, TFRC_rate: %5.3f, ploss: %1.7f, EQ_rate: %5.3f, ratio_TCP_TFRC: %2.2f, ratio_TCP_EQ: %2.2f\n", now, TCP_rate__, est_loss__, TFRC_rate__, ploss__, EQ_rate__, ratio_TCP_TFRC__, ratio_TCP_EQ__); // printf ("time: %7.5f rtt: %4.4f est_loss: %1.7f comp_rate: %5.3f comp_Bytes: %7.1f sent_Bytes: %d\n", now, rtt_, pe, comp_rate_, sum_bytes, (ndatabytes_ + nrexmitbytes_)); //printf ("time: %7.5f rtt: %4.4f est_loss: %1.7f comp_rate: %5.3f comp_Bytes: %7.1f sent_Bytes: %d ratioTCP/TFRC: %2.2f tot_loss_by_now: %2.4f comp_tot_Bytes %2.2f ratioTCP/EQ: %f\n", now, rtt_, pe, comp_rate_, sum_bytes, (ndatabytes_ + nrexmitbytes_), ((ndatabytes_+nrexmitbytes_)/sum_bytes), ploss_, comp_rate_1_*now, ((ndatabytes_+nrexmitbytes_)/(comp_rate_1_*now))); rate_last = TFRC_local_rate_; time_last = now; } /* schedule next report rtt/NumFeedback_ later */ if (rtt_ > 0.0 && NumFeedback_ > 0) timer_.resched(1.5*rtt_/NumFeedback_); } //sale <<< //sale >>> void RcpTapTimer::expire(Event *) { a_->compute_thr(1); } //sale <<< //sale >>> //from TFRC double RcpTap::est_loss () { double p = 0 ; switch (algo) { case WALI: p = est_loss_WALI () ; break; case EWMA: p = est_loss_EWMA () ; break; case RBPH: p = est_loss_RBPH () ; break; case EBPH: p = est_loss_EBPH () ; break; default: printf ("invalid algo specified\n"); abort(); break ; } return p; } void RcpTap::print_loss(int sample, double ave_interval) { double now = Scheduler::instance().clock(); double drops = 1/ave_interval; // This is ugly to include this twice, but the first one is // for backward compatibility with earlier scripts. printf ("time: %7.5f loss_rate: %7.5f \n", now, drops); printf ("time: %7.5f sample 0: %5d loss_rate: %7.5f \n", now, sample, drops); //printf ("time: %7.5f send_rate: %7.5f\n", now, sendrate); //printf ("time: %7.5f maxseq: %d\n", now, maxseq); } void RcpTap::print_loss_all(int *sample) { double now = Scheduler::instance().clock(); printf ("%f: sample 0: %5d 1: %5d 2: %5d 3: %5d 4: %5d\n", now, sample[0], sample[1], sample[2], sample[3], sample[4]); } //////////////////////////////////////// // algo specific code ///////////////// /////////////////////////////////////// //// /// WALI Code //// double RcpTap::est_loss_WALI () { int i; double ave_interval1, ave_interval2; int ds ; if (!init_WALI_flag) { init_WALI () ; } // sample[i] counts the number of packets since the i-th loss event // sample[0] contains the most recent sample. //sale!!!for (i = last_sample; i <= maxseq_ ; i ++) { for (i = last_sample; i <= Maxseq_sale_ ; i ++) { sample[0]++; if (lossvec_[i%hsz] == LOST || lossvec_[i%hsz] == ECNLOST) { // new loss event // double now = Scheduler::instance().clock(); sample_count ++; shift_array (sample, numsamples+1, 0); multiply_array(mult, numsamples+1, mult_factor_); shift_array (mult, numsamples+1, 1.0); mult_factor_ = 1.0; } } //sale!!! last_sample = maxseq_+1 ; last_sample = Maxseq_sale_+1 ; if (sample_count>numsamples+1) // The array of loss intervals is full. ds=numsamples+1; else ds=sample_count; if (sample_count == 1 && false_sample == 0) // no losses yet return 0; /* do we need to discount weights? */ if (sample_count > 1 && discount && sample[0] > 0) { double ave = weighted_average(1, ds, 1.0, mult, weights, sample); int factor = 2; double ratio = (factor*ave)/sample[0]; double min_ratio = 0.5; if ( ratio < 1.0) { // the most recent loss interval is very large mult_factor_ = ratio; if (mult_factor_ < min_ratio) mult_factor_ = min_ratio; } } // Calculations including the most recent loss interval. ave_interval1 = weighted_average(0, ds, mult_factor_, mult, weights, sample); // The most recent loss interval does not end in a loss // event. Include the most recent interval in the // calculations only if this increases the estimated loss // interval. ave_interval2 = weighted_average(1, ds, mult_factor_, mult, weights, sample); if (ave_interval2 > ave_interval1) ave_interval1 = ave_interval2; if (ave_interval1 > 0) { if (printLoss_ > 0) { print_loss(sample[0], ave_interval1); print_loss_all(sample); } return 1/ave_interval1; } else return 999; } // Calculate the weighted average. double RcpTap::weighted_average(int start, int end, double factor, double *m, double *w, int *sample) { int i; double wsum = 0; double answer = 0; if (smooth_ == 1 && start == 0) { if (end == numsamples+1) { // the array is full, but we don't want to uses // the last loss interval in the array end = end-1; } // effectively shift the weight arrays for (i = start ; i < end; i++) if (i==0) wsum += m[i]*w[i+1]; else wsum += factor*m[i]*w[i+1]; for (i = start ; i < end; i++) if (i==0) answer += m[i]*w[i+1]*sample[i]/wsum; else answer += factor*m[i]*w[i+1]*sample[i]/wsum; return answer; } else { for (i = start ; i < end; i++) if (i==0) wsum += m[i]*w[i]; else wsum += factor*m[i]*w[i]; for (i = start ; i < end; i++) if (i==0) answer += m[i]*w[i]*sample[i]/wsum; else answer += factor*m[i]*w[i]*sample[i]/wsum; return answer; } } // Shift array a[] up, starting with a[sz-2] -> a[sz-1]. void RcpTap::shift_array(int *a, int sz, int defval) { int i ; for (i = sz-2 ; i >= 0 ; i--) { a[i+1] = a[i] ; } a[0] = defval; } void RcpTap::shift_array(double *a, int sz, double defval) { int i ; for (i = sz-2 ; i >= 0 ; i--) { a[i+1] = a[i] ; } a[0] = defval; } // Multiply array by value, starting with array index 1. // Array index 0 of the unshifted array contains the most recent interval. void RcpTap::multiply_array(double *a, int sz, double multiplier) { int i ; for (i = 1; i <= sz-1; i++) { double old = a[i]; a[i] = old * multiplier ; } } double RcpTap::adjust_history (double ts) { int i; double p; for (i = maxseq_; i >= 0 ; i --) { //for (i = Maxseq_sale_; i >= 0 ; i --) { if (lossvec_[i%hsz] == LOST || lossvec_[i%hsz] == ECNLOST ) { lossvec_[i%hsz] = NOLOSS; } } lastloss = ts; //sale!!! lastloss_round_id = round_id ; p=my_b_to_p(est_thput()*size_, rtt_, tzero_, size_, 1); //printf("p=%f\n",p); false_sample = (int)(1.0/p); sample[1] = false_sample; sample[0] = 0; sample_count++; if (printLoss_) { print_loss_all (sample); } false_sample = -1 ; return p; } /* * compute estimated throughput for report. */ double RcpTap::est_thput () { double time_for_rcv_rate; double now = Scheduler::instance().clock(); double thput = 1 ; if ((rtt_ > 0) && ((now - last_report_sent) >= rtt_)) { // more than an RTT since the last report time_for_rcv_rate = (now - last_report_sent); //sale!!! if (time_for_rcv_rate > 0 && rcvd_since_last_report > 0) { if (time_for_rcv_rate > 0 && ndatapack_ > 0) { //sale!!!thput = rcvd_since_last_report/time_for_rcv_rate; thput = ndatapack_/time_for_rcv_rate; } } else { // count number of packets received in the last RTT if (rtt_ > 0){ double last = rtvec_[maxseq_%hsz]; int rcvd = 0; int i = maxseq_; while (i > 0) { if (lossvec_[i%hsz] == RCVD) { if ((rtvec_[i%hsz] + rtt_) > last) rcvd++; else break ; } i--; } if (rcvd > 0) thput = rcvd/rtt_; //sale!!! printf("Rcvd=%f,rtt=%f,Thput=%f\n",rcvd, rtt_, thput); } } //printf("Thput=%f\n",thput); return thput ; } void RcpTap::init_WALI () { int i; if (numsamples < 0) numsamples = DEFAULT_NUMSAMPLES ; if (smooth_ == 1) { numsamples = numsamples + 1; } sample = (int *)malloc((numsamples+1)*sizeof(int)); weights = (double *)malloc((numsamples+1)*sizeof(double)); mult = (double *)malloc((numsamples+1)*sizeof(double)); for (i = 0 ; i < numsamples+1 ; i ++) { sample[i] = 0 ; } if (smooth_ == 1) { int mid = int(numsamples/2); for (i = 0; i < mid; i ++) { weights[i] = 1.0; } for (i = mid; i <= numsamples; i ++){ weights[i] = 1.0 - (i-mid)/(mid + 1.0); } } else { int mid = int(numsamples/2); for (i = 0; i < mid; i ++) { weights[i] = 1.0; } for (i = mid; i <= numsamples; i ++){ weights[i] = 1.0 - (i+1-mid)/(mid + 1.0); } } for (i = 0; i < numsamples+1; i ++) { mult[i] = 1.0 ; } init_WALI_flag = 1; /* initialization done */ } /////////////////////////// // EWMA ////////////////// ////////////////////////// double RcpTap::est_loss_EWMA () { double p1, p2 ; for (int i = last_sample; i <= maxseq_ ; i ++) { loss_int++; if (lossvec_[i%hsz] == LOST || lossvec_[i%hsz] == ECNLOST ) { if (avg_loss_int < 0) { avg_loss_int = loss_int ; } else { avg_loss_int = history*avg_loss_int + (1-history)*loss_int ; } loss_int = 0 ; } } last_sample = maxseq_+1 ; if (avg_loss_int < 0) { p1 = 0; } else { p1 = 1.0/avg_loss_int ; } if (loss_int == 0) { p2 = p1 ; } else { p2 = 1.0/(history*avg_loss_int + (1-history)*loss_int) ; } if (p2 < p1) { p1 = p2 ; } if (printLoss_ > 0) { if (p1 > 0) print_loss(loss_int, 1.0/p1); else print_loss(loss_int, 0.00001); print_loss_all(sample); } return p1 ; } /////////////////////////// // RBPH ////////////////// ////////////////////////// double RcpTap::est_loss_RBPH () { double numpkts = hsz ; double p ; // how many pkts we should go back? if (sendrate > 0 && rtt_ > 0) { //sale!!! double x = my_b_to_p(sendrate, rtt_, tzero_, size_, 1); double x = 1; if (x > 0) numpkts = minlc/x ; else numpkts = hsz ; } // that number must be below maxseq_ and hsz if (numpkts > maxseq_) numpkts = maxseq_ ; if (numpkts > hsz) numpkts = hsz ; int lc = 0; int pc = 0; int i = maxseq_ ; // first see if how many lc's we find in numpkts while (pc < numpkts) { pc ++ ; if (lossvec_[i%hsz] == LOST || lossvec_[i%hsz] == ECNLOST ) lc ++ ; i -- ; } // if not enough lsos events, keep going back ... if (lc < minlc) { // but only as far as the history allows ... numpkts = maxseq_ ; if (numpkts > hsz) numpkts = hsz ; while ((lc < minlc) && (pc < numpkts)) { pc ++ ; if (lossvec_[i%hsz] == LOST || lossvec_[i%hsz] == ECNLOST ) lc ++ ; i -- ; } } if (pc == 0) p = 0; else p = (double)lc/(double)pc ; if (printLoss_ > 0) { if (p > 0) print_loss(0, 1.0/p); else print_loss(0, 0.00001); print_loss_all(sample); } return p ; } /////////////////////////// // EBPH ////////////////// ////////////////////////// double RcpTap::est_loss_EBPH () { double numpkts = hsz ; double p ; int lc = 0; int pc = 0; int i = maxseq_ ; numpkts = maxseq_ ; if (numpkts > hsz) numpkts = hsz ; while ((lc < minlc) && (pc < numpkts)) { pc ++ ; if (lossvec_[i%hsz] == LOST || lossvec_[i%hsz] == ECNLOST) lc ++ ; i -- ; } if (pc == 0) p = 0; else p = (double)lc/(double)pc ; if (printLoss_ > 0) { if (p > 0) print_loss(0, 1.0/p); else print_loss(0, 0.00001); print_loss_all(sample); } return p ; } //sale <<<