00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058 #ifndef lint
00059 static const char rcsid[] =
00060 "@(#) $Header: /nfs/jade/vint/CVSROOT/ns-2/queue/red.cc,v 1.80 2004/10/28 23:35:37 haldar Exp $ (LBL)";
00061 #endif
00062
00063 #include <math.h>
00064 #include <sys/types.h>
00065 #include "config.h"
00066 #include "template.h"
00067 #include "random.h"
00068 #include "flags.h"
00069 #include "delay.h"
00070 #include "red.h"
00071
00072 static class REDClass : public TclClass {
00073 public:
00074 REDClass() : TclClass("Queue/RED") {}
00075 TclObject* create(int argc, const char*const* argv) {
00076
00077
00078
00079 if (argc==5)
00080 return (new REDQueue(argv[4]));
00081 else
00082 return (new REDQueue("Drop"));
00083 }
00084 } class_red;
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096 REDQueue::REDQueue(const char * trace) : link_(NULL), de_drop_(NULL), EDTrace(NULL), tchan_(0), idle_(1)
00097 {
00098 initParams();
00099
00100
00101 if (strlen(trace) >=20) {
00102 printf("trace type too long - allocate more space to traceType in red.h and recompile\n");
00103 exit(0);
00104 }
00105 strcpy(traceType, trace);
00106 bind_bool("bytes_", &edp_.bytes);
00107 bind_bool("queue_in_bytes_", &qib_);
00108
00109
00110 bind("thresh_", &edp_.th_min_pkts);
00111 bind("thresh_queue_", &edp_.th_min);
00112 bind("maxthresh_", &edp_.th_max_pkts);
00113 bind("minthresh_queue_", &edp_.th_max);
00114 bind("mean_pktsize_", &edp_.mean_pktsize);
00115 bind("idle_pktsize_", &edp_.idle_pktsize);
00116 bind("q_weight_", &edp_.q_w);
00117 bind("adaptive_", &edp_.adaptive);
00118 bind("cautious_", &edp_.cautious);
00119 bind("alpha_", &edp_.alpha);
00120 bind("beta_", &edp_.beta);
00121 bind("interval_", &edp_.interval);
00122 bind("feng_adaptive_",&edp_.feng_adaptive);
00123 bind("targetdelay_", &edp_.targetdelay);
00124 bind("top_", &edp_.top);
00125 bind("bottom_", &edp_.bottom);
00126 bind_bool("wait_", &edp_.wait);
00127 bind("linterm_", &edp_.max_p_inv);
00128 bind("mark_p_", &edp_.mark_p);
00129 bind_bool("setbit_", &edp_.setbit);
00130 bind_bool("gentle_", &edp_.gentle);
00131
00132
00133
00134
00135 bind_bool("summarystats_", &summarystats_);
00136 bind_bool("drop_tail_", &drop_tail_);
00137
00138
00139 bind_bool("drop_front_", &drop_front_);
00140
00141
00142 bind_bool("drop_rand_", &drop_rand_);
00143
00144
00145 bind_bool("ns1_compat_", &ns1_compat_);
00146
00147
00148 bind("ave_", &edv_.v_ave);
00149 bind("prob1_", &edv_.v_prob1);
00150 bind("curq_", &curq_);
00151 bind("cur_max_p_", &edv_.cur_max_p);
00152
00153
00154 q_ = new PacketQueue();
00155 pq_ = q_;
00156
00157 #ifdef notdef
00158 print_edp();
00159 print_edv();
00160 #endif
00161
00162 }
00163
00164
00165
00166
00167
00168
00169
00170
00171 void REDQueue::initialize_params()
00172 {
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186 if (edp_.q_w == 0.0) {
00187 edp_.q_w = 1.0 - exp(-1.0/edp_.ptc);
00188 } else if (edp_.q_w == -1.0) {
00189 double rtt = 3.0*(edp_.delay+1.0/edp_.ptc);
00190
00191 if (rtt < 0.1)
00192 rtt = 0.1;
00193 edp_.q_w = 1.0 - exp(-1.0/(10*rtt*edp_.ptc));
00194 } else if (edp_.q_w == -2.0) {
00195 edp_.q_w = 1.0 - exp(-10.0/edp_.ptc);
00196 }
00197
00198
00199
00200 if (edp_.th_min_pkts == 0) {
00201 edp_.th_min_pkts = 5.0;
00202
00203
00204 double targetqueue = edp_.targetdelay * edp_.ptc;
00205 if (edp_.th_min_pkts < targetqueue / 2.0 )
00206 edp_.th_min_pkts = targetqueue / 2.0 ;
00207 }
00208 if (edp_.th_max_pkts == 0)
00209 edp_.th_max_pkts = 3.0 * edp_.th_min_pkts;
00210
00211
00212 if (edp_.bottom == 0) {
00213 edp_.bottom = 0.01;
00214
00215
00216
00217
00218 double bottom1 = 80000.0/link_->bandwidth();
00219 if (bottom1 < edp_.bottom)
00220 edp_.bottom = bottom1;
00221
00222 }
00223 }
00224
00225 void REDQueue::initParams()
00226 {
00227 edp_.mean_pktsize = 0;
00228 edp_.idle_pktsize = 0;
00229 edp_.bytes = 0;
00230 edp_.wait = 0;
00231 edp_.setbit = 0;
00232 edp_.gentle = 0;
00233 edp_.th_min = 0.0;
00234 edp_.th_min_pkts = 0.0;
00235 edp_.th_max = 0.0;
00236 edp_.th_max_pkts = 0.0;
00237 edp_.max_p_inv = 0.0;
00238 edp_.mark_p = 0.0;
00239 edp_.q_w = 0.0;
00240 edp_.adaptive = 0;
00241 edp_.cautious = 0;
00242 edp_.alpha = 0.0;
00243 edp_.beta = 0.0;
00244 edp_.interval = 0.0;
00245 edp_.targetdelay = 0.0;
00246 edp_.top = 0.0;
00247 edp_.bottom = 0.0;
00248 edp_.feng_adaptive = 0;
00249 edp_.ptc = 0.0;
00250 edp_.delay = 0.0;
00251
00252 edv_.v_ave = 0.0;
00253 edv_.v_prob1 = 0.0;
00254 edv_.v_slope = 0.0;
00255 edv_.v_prob = 0.0;
00256 edv_.v_a = 0.0;
00257 edv_.v_b = 0.0;
00258 edv_.v_c = 0.0;
00259 edv_.v_d = 0.0;
00260 edv_.count = 0;
00261 edv_.count_bytes = 0;
00262 edv_.old = 0;
00263 edv_.cur_max_p = 1.0;
00264 edv_.lastset = 0;
00265 }
00266
00267
00268 void REDQueue::reset()
00269 {
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279 if (link_) {
00280 edp_.ptc = link_->bandwidth() / (8. * edp_.mean_pktsize);
00281 initialize_params();
00282 }
00283 if (edp_.th_max_pkts == 0)
00284 edp_.th_max_pkts = 3.0 * edp_.th_min_pkts;
00285
00286
00287
00288
00289 if (qib_) {
00290
00291 edp_.th_min = edp_.th_min_pkts * edp_.mean_pktsize;
00292 edp_.th_max = edp_.th_max_pkts * edp_.mean_pktsize;
00293
00294 } else {
00295 edp_.th_min = edp_.th_min_pkts;
00296 edp_.th_max = edp_.th_max_pkts;
00297 }
00298
00299 edv_.v_ave = 0.0;
00300 edv_.v_slope = 0.0;
00301 edv_.count = 0;
00302 edv_.count_bytes = 0;
00303 edv_.old = 0;
00304 double th_diff = (edp_.th_max - edp_.th_min);
00305 if (th_diff == 0) {
00306
00307
00308
00309
00310
00311 th_diff = 1.0;
00312 }
00313 edv_.v_a = 1.0 / th_diff;
00314 edv_.cur_max_p = 1.0 / edp_.max_p_inv;
00315 edv_.v_b = - edp_.th_min / th_diff;
00316 edv_.lastset = 0.0;
00317 if (edp_.gentle) {
00318 edv_.v_c = ( 1.0 - edv_.cur_max_p ) / edp_.th_max;
00319 edv_.v_d = 2 * edv_.cur_max_p - 1.0;
00320 }
00321
00322 idle_ = 1;
00323 if (&Scheduler::instance() != NULL)
00324 idletime_ = Scheduler::instance().clock();
00325 else
00326 idletime_ = 0.0;
00327
00328 if (debug_)
00329 printf("Doing a queue reset\n");
00330 Queue::reset();
00331 if (debug_)
00332 printf("Done queue reset\n");
00333 }
00334
00335
00336
00337
00338
00339
00340
00341 void REDQueue::updateMaxPFeng(double new_ave)
00342 {
00343 if ( edp_.th_min < new_ave && new_ave < edp_.th_max) {
00344 edv_.status = edv_.Between;
00345 }
00346 if (new_ave < edp_.th_min && edv_.status != edv_.Below) {
00347 edv_.status = edv_.Below;
00348 edv_.cur_max_p = edv_.cur_max_p / edp_.alpha;
00349
00350
00351 }
00352 if (new_ave > edp_.th_max && edv_.status != edv_.Above) {
00353 edv_.status = edv_.Above;
00354 edv_.cur_max_p = edv_.cur_max_p * edp_.beta;
00355
00356
00357 }
00358 }
00359
00360
00361
00362
00363
00364 void REDQueue::updateMaxP(double new_ave, double now)
00365 {
00366 double part = 0.4*(edp_.th_max - edp_.th_min);
00367
00368 if ( new_ave < edp_.th_min + part && edv_.cur_max_p > edp_.bottom) {
00369
00370 edv_.cur_max_p = edv_.cur_max_p * edp_.beta;
00371 edv_.lastset = now;
00372 } else if (new_ave > edp_.th_max - part && edp_.top > edv_.cur_max_p ) {
00373
00374 double alpha = edp_.alpha;
00375 if ( alpha > 0.25*edv_.cur_max_p )
00376 alpha = 0.25*edv_.cur_max_p;
00377 edv_.cur_max_p = edv_.cur_max_p + alpha;
00378 edv_.lastset = now;
00379 }
00380 }
00381
00382
00383
00384
00385
00386 double REDQueue::estimator(int nqueued, int m, double ave, double q_w)
00387 {
00388 double new_ave, old_ave;
00389
00390 new_ave = ave;
00391 while (--m >= 1) {
00392 new_ave *= 1.0 - q_w;
00393 }
00394 old_ave = new_ave;
00395 new_ave *= 1.0 - q_w;
00396 new_ave += q_w * nqueued;
00397
00398 double now = Scheduler::instance().clock();
00399 if (edp_.adaptive == 1) {
00400 if (edp_.feng_adaptive == 1)
00401 updateMaxPFeng(new_ave);
00402 else if (now > edv_.lastset + edp_.interval)
00403 updateMaxP(new_ave, now);
00404 }
00405 return new_ave;
00406 }
00407
00408
00409
00410
00411 Packet* REDQueue::deque()
00412 {
00413 Packet *p;
00414 if (summarystats_ && &Scheduler::instance() != NULL) {
00415 Queue::updateStats(qib_?q_->byteLength():q_->length());
00416 }
00417 p = q_->deque();
00418 if (p != 0) {
00419 idle_ = 0;
00420 } else {
00421 idle_ = 1;
00422
00423
00424
00425 if (&Scheduler::instance() != NULL)
00426 idletime_ = Scheduler::instance().clock();
00427 else
00428 idletime_ = 0.0;
00429 }
00430 return (p);
00431 }
00432
00433
00434
00435
00436 double
00437 REDQueue::calculate_p_new(double v_ave, double th_max, int gentle, double v_a,
00438 double v_b, double v_c, double v_d, double max_p)
00439 {
00440 double p;
00441 if (gentle && v_ave >= th_max) {
00442
00443
00444 p = v_c * v_ave + v_d;
00445 } else {
00446
00447
00448 p = v_a * v_ave + v_b;
00449 p *= max_p;
00450 }
00451 if (p > 1.0)
00452 p = 1.0;
00453 return p;
00454 }
00455
00456
00457
00458
00459
00460 double
00461 REDQueue::calculate_p(double v_ave, double th_max, int gentle, double v_a,
00462 double v_b, double v_c, double v_d, double max_p_inv)
00463 {
00464 double p = calculate_p_new(v_ave, th_max, gentle, v_a,
00465 v_b, v_c, v_d, 1.0 / max_p_inv);
00466 return p;
00467 }
00468
00469
00470
00471
00472 double
00473 REDQueue::modify_p(double p, int count, int count_bytes, int bytes,
00474 int mean_pktsize, int wait, int size)
00475 {
00476 double count1 = (double) count;
00477 if (bytes)
00478 count1 = (double) (count_bytes/mean_pktsize);
00479 if (wait) {
00480 if (count1 * p < 1.0)
00481 p = 0.0;
00482 else if (count1 * p < 2.0)
00483 p /= (2 - count1 * p);
00484 else
00485 p = 1.0;
00486 } else {
00487 if (count1 * p < 1.0)
00488 p /= (1.0 - count1 * p);
00489 else
00490 p = 1.0;
00491 }
00492 if (bytes && p < 1.0) {
00493 p = p * size / mean_pktsize;
00494 }
00495 if (p > 1.0)
00496 p = 1.0;
00497 return p;
00498 }
00499
00500
00501
00502
00503
00504
00505
00506
00507 int
00508 REDQueue::drop_early(Packet* pkt)
00509 {
00510 hdr_cmn* ch = hdr_cmn::access(pkt);
00511
00512 edv_.v_prob1 = calculate_p_new(edv_.v_ave, edp_.th_max, edp_.gentle,
00513 edv_.v_a, edv_.v_b, edv_.v_c, edv_.v_d, edv_.cur_max_p);
00514 edv_.v_prob = modify_p(edv_.v_prob1, edv_.count, edv_.count_bytes,
00515 edp_.bytes, edp_.mean_pktsize, edp_.wait, ch->size());
00516
00517
00518 if (edp_.cautious == 1) {
00519
00520
00521
00522 int qsize = qib_?q_->byteLength():q_->length();
00523
00524 double pkts = edp_.ptc * 0.05;
00525 double fraction = pow( (1-edp_.q_w), pkts);
00526
00527 if ((double) qsize < fraction * edv_.v_ave) {
00528
00529
00530 return (0);
00531 }
00532 }
00533 double u = Random::uniform();
00534 if (edp_.cautious == 2) {
00535
00536
00537
00538 int qsize = qib_?q_->byteLength():q_->length();
00539
00540 double pkts = edp_.ptc * 0.05;
00541 double fraction = pow( (1-edp_.q_w), pkts);
00542
00543 double ratio = qsize / (fraction * edv_.v_ave);
00544 if (ratio < 1.0) {
00545
00546 u *= 1.0 / ratio;
00547 }
00548 }
00549 if (u <= edv_.v_prob) {
00550
00551 edv_.count = 0;
00552 edv_.count_bytes = 0;
00553 hdr_flags* hf = hdr_flags::access(pickPacketForECN(pkt));
00554 if (edp_.setbit && hf->ect() && edv_.v_prob1 < edp_.mark_p) {
00555 hf->ce() = 1;
00556
00557 return (0);
00558 } else {
00559 return (1);
00560 }
00561 }
00562 return (0);
00563 }
00564
00565
00566
00567
00568
00569
00570
00571
00572 Packet*
00573 REDQueue::pickPacketForECN(Packet* pkt)
00574 {
00575 return pkt;
00576 }
00577
00578
00579
00580
00581
00582
00583 Packet*
00584 REDQueue::pickPacketToDrop()
00585 {
00586 int victim;
00587
00588 if (drop_front_)
00589 victim = min(1, q_->length()-1);
00590 else if (drop_rand_)
00591 victim = Random::integer(q_->length());
00592 else
00593 victim = q_->length() - 1;
00594
00595 return(q_->lookup(victim));
00596 }
00597
00598
00599
00600
00601
00602
00603
00604
00605
00606
00607
00608
00609
00610
00611
00612
00613
00614
00615 #define DTYPE_NONE 0
00616 #define DTYPE_FORCED 1
00617 #define DTYPE_UNFORCED 2
00618
00619 void REDQueue::enque(Packet* pkt)
00620 {
00621
00622
00623
00624
00625
00626
00627
00628 int m = 0;
00629 if (idle_) {
00630
00631
00632 double now = Scheduler::instance().clock();
00633
00634 idle_ = 0;
00635
00636
00637 if (edp_.cautious == 3) {
00638 double ptc = edp_.ptc *
00639 edp_.mean_pktsize / edp_.idle_pktsize;
00640 m = int(ptc * (now - idletime_));
00641 } else
00642 m = int(edp_.ptc * (now - idletime_));
00643 }
00644
00645
00646
00647
00648
00649 edv_.v_ave = estimator(qib_ ? q_->byteLength() : q_->length(), m + 1, edv_.v_ave, edp_.q_w);
00650
00651
00652 if (summarystats_) {
00653
00654 Queue::updateStats(qib_?q_->byteLength():q_->length());
00655 }
00656
00657
00658
00659
00660
00661
00662
00663 hdr_cmn* ch = hdr_cmn::access(pkt);
00664 ++edv_.count;
00665 edv_.count_bytes += ch->size();
00666
00667
00668
00669
00670
00671
00672
00673
00674
00675 register double qavg = edv_.v_ave;
00676 int droptype = DTYPE_NONE;
00677 int qlen = qib_ ? q_->byteLength() : q_->length();
00678 int qlim = qib_ ? (qlim_ * edp_.mean_pktsize) : qlim_;
00679
00680 curq_ = qlen;
00681
00682 if (qavg >= edp_.th_min && qlen > 1) {
00683 if ((!edp_.gentle && qavg >= edp_.th_max) ||
00684 (edp_.gentle && qavg >= 2 * edp_.th_max)) {
00685 droptype = DTYPE_FORCED;
00686 } else if (edv_.old == 0) {
00687
00688
00689
00690
00691
00692
00693 edv_.count = 1;
00694 edv_.count_bytes = ch->size();
00695 edv_.old = 1;
00696 } else if (drop_early(pkt)) {
00697 droptype = DTYPE_UNFORCED;
00698 }
00699 } else {
00700
00701 edv_.v_prob = 0.0;
00702 edv_.old = 0;
00703 }
00704 if (qlen >= qlim) {
00705
00706 droptype = DTYPE_FORCED;
00707 }
00708
00709 if (droptype == DTYPE_UNFORCED) {
00710
00711 Packet *pkt_to_drop = pickPacketForECN(pkt);
00712
00713
00714
00715
00716 if (pkt_to_drop != pkt) {
00717 q_->enque(pkt);
00718 q_->remove(pkt_to_drop);
00719 pkt = pkt_to_drop;
00720 }
00721
00722
00723 if (de_drop_ != NULL) {
00724
00725
00726
00727
00728 if (EDTrace != NULL)
00729 ((Trace *)EDTrace)->recvOnly(pkt);
00730
00731 reportDrop(pkt);
00732 de_drop_->recv(pkt);
00733 }
00734 else {
00735 reportDrop(pkt);
00736 drop(pkt);
00737 }
00738 } else {
00739
00740 q_->enque(pkt);
00741
00742
00743 if (droptype == DTYPE_FORCED) {
00744
00745 pkt = pickPacketToDrop();
00746 q_->remove(pkt);
00747 reportDrop(pkt);
00748 drop(pkt);
00749 if (!ns1_compat_) {
00750
00751 edv_.count = 0;
00752 edv_.count_bytes = 0;
00753 }
00754 }
00755 }
00756 return;
00757 }
00758
00759 int REDQueue::command(int argc, const char*const* argv)
00760 {
00761 Tcl& tcl = Tcl::instance();
00762 if (argc == 2) {
00763 if (strcmp(argv[1], "reset") == 0) {
00764 reset();
00765 return (TCL_OK);
00766 }
00767 if (strcmp(argv[1], "early-drop-target") == 0) {
00768 if (de_drop_ != NULL)
00769 tcl.resultf("%s", de_drop_->name());
00770 return (TCL_OK);
00771 }
00772 if (strcmp(argv[1], "edrop-trace") == 0) {
00773 if (EDTrace != NULL) {
00774 tcl.resultf("%s", EDTrace->name());
00775 if (debug_)
00776 printf("edrop trace exists according to RED\n");
00777 }
00778 else {
00779 if (debug_)
00780 printf("edrop trace doesn't exist according to RED\n");
00781 tcl.resultf("0");
00782 }
00783 return (TCL_OK);
00784 }
00785 if (strcmp(argv[1], "trace-type") == 0) {
00786 tcl.resultf("%s", traceType);
00787 return (TCL_OK);
00788 }
00789 if (strcmp(argv[1], "printstats") == 0) {
00790 print_summarystats();
00791 return (TCL_OK);
00792 }
00793 }
00794 else if (argc == 3) {
00795
00796 if (strcmp(argv[1], "attach") == 0) {
00797 int mode;
00798 const char* id = argv[2];
00799 tchan_ = Tcl_GetChannel(tcl.interp(), (char*)id, &mode);
00800 if (tchan_ == 0) {
00801 tcl.resultf("RED: trace: can't attach %s for writing", id);
00802 return (TCL_ERROR);
00803 }
00804 return (TCL_OK);
00805 }
00806
00807 if (strcmp(argv[1], "link") == 0) {
00808 LinkDelay* del = (LinkDelay*)TclObject::lookup(argv[2]);
00809 if (del == 0) {
00810 tcl.resultf("RED: no LinkDelay object %s",
00811 argv[2]);
00812 return(TCL_ERROR);
00813 }
00814
00815 link_ = del;
00816 edp_.ptc = link_->bandwidth() /
00817 (8. * edp_.mean_pktsize);
00818 edp_.delay = link_->delay();
00819 if (
00820 (edp_.q_w <= 0.0 || edp_.th_min_pkts == 0 ||
00821 edp_.th_max_pkts == 0))
00822 initialize_params();
00823 return (TCL_OK);
00824 }
00825 if (strcmp(argv[1], "early-drop-target") == 0) {
00826 NsObject* p = (NsObject*)TclObject::lookup(argv[2]);
00827 if (p == 0) {
00828 tcl.resultf("no object %s", argv[2]);
00829 return (TCL_ERROR);
00830 }
00831 de_drop_ = p;
00832 return (TCL_OK);
00833 }
00834 if (strcmp(argv[1], "edrop-trace") == 0) {
00835 if (debug_)
00836 printf("Ok, Here\n");
00837 NsObject * t = (NsObject *)TclObject::lookup(argv[2]);
00838 if (debug_)
00839 printf("Ok, Here too\n");
00840 if (t == 0) {
00841 tcl.resultf("no object %s", argv[2]);
00842 return (TCL_ERROR);
00843 }
00844 EDTrace = t;
00845 if (debug_)
00846 printf("Ok, Here too too too %d\n", ((Trace *)EDTrace)->type_);
00847 return (TCL_OK);
00848 }
00849 if (!strcmp(argv[1], "packetqueue-attach")) {
00850 delete q_;
00851 if (!(q_ = (PacketQueue*) TclObject::lookup(argv[2])))
00852 return (TCL_ERROR);
00853 else {
00854 pq_ = q_;
00855 return (TCL_OK);
00856 }
00857 }
00858 }
00859 return (Queue::command(argc, argv));
00860 }
00861
00862
00863
00864
00865
00866
00867
00868
00869 void
00870 REDQueue::trace(TracedVar* v)
00871 {
00872 char wrk[500], *p;
00873
00874 if (((p = strstr(v->name(), "ave")) == NULL) &&
00875 ((p = strstr(v->name(), "prob")) == NULL) &&
00876 ((p = strstr(v->name(), "curq")) == NULL) &&
00877 ((p = strstr(v->name(), "cur_max_p"))==NULL) ) {
00878 fprintf(stderr, "RED:unknown trace var %s\n",
00879 v->name());
00880 return;
00881 }
00882
00883 if (tchan_) {
00884 int n;
00885 double t = Scheduler::instance().clock();
00886
00887 if (strstr(v->name(), "curq") != NULL) {
00888 sprintf(wrk, "Q %g %d", t, int(*((TracedInt*) v)));
00889 } else {
00890 sprintf(wrk, "%c %g %g", *p, t,
00891 double(*((TracedDouble*) v)));
00892 }
00893 n = strlen(wrk);
00894 wrk[n] = '\n';
00895 wrk[n+1] = 0;
00896 (void)Tcl_Write(tchan_, wrk, n+1);
00897 }
00898 return;
00899 }
00900
00901
00902 void REDQueue::print_edp()
00903 {
00904 printf("mean_pktsz: %d\n", edp_.mean_pktsize);
00905 printf("bytes: %d, wait: %d, setbit: %d\n",
00906 edp_.bytes, edp_.wait, edp_.setbit);
00907 printf("minth: %f, maxth: %f\n", edp_.th_min, edp_.th_max);
00908 printf("max_p: %f, qw: %f, ptc: %f\n",
00909 (double) edv_.cur_max_p, edp_.q_w, edp_.ptc);
00910 printf("qlim: %d, idletime: %f\n", qlim_, idletime_);
00911 printf("=========\n");
00912 }
00913
00914 void REDQueue::print_edv()
00915 {
00916 printf("v_a: %f, v_b: %f\n", edv_.v_a, edv_.v_b);
00917 }
00918
00919 void REDQueue::print_summarystats()
00920 {
00921
00922 printf("True average queue: %5.3f", true_ave_);
00923 if (qib_)
00924 printf(" (in bytes)");
00925 printf(" time: %5.3f\n", total_time_);
00926 }
00927
00928
00929
00930
00931
00932
00933
00934
00935
00936
00937
00938
00939 void REDQueue::run_estimator(int nqueued, int m)
00940 {
00941 double f, f_sl, f_old;
00942
00943 f = edv_.v_ave;
00944 f_sl = edv_.v_slope;
00945 #define RED_EWMA
00946 #ifdef RED_EWMA
00947 while (--m >= 1) {
00948 f_old = f;
00949 f *= 1.0 - edp_.q_w;
00950 }
00951 f_old = f;
00952 f *= 1.0 - edp_.q_w;
00953 f += edp_.q_w * nqueued;
00954 #endif
00955 #ifdef RED_HOLT_WINTERS
00956 while (--m >= 1) {
00957 f_old = f;
00958 f += f_sl;
00959 f *= 1.0 - edp_.q_w;
00960 f_sl *= 1.0 - 0.5 * edp_.q_w;
00961 f_sl += 0.5 * edp_.q_w * (f - f_old);
00962 }
00963 f_old = f;
00964 f += f_sl;
00965 f *= 1.0 - edp_.q_w;
00966 f += edp_.q_w * nqueued;
00967 f_sl *= 1.0 - 0.5 * edp_.q_w;
00968 f_sl += 0.5 * edp_.q_w * (f - f_old);
00969 #endif
00970 edv_.v_ave = f;
00971 edv_.v_slope = f_sl;
00972 }
00973