📄 zhinengpid.cc
字号:
/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- *//* * Copyright (c) 1990-1997 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the Computer Systems * Engineering Group at Lawrence Berkeley Laboratory. * 4. Neither the name of the University nor of the Laboratory may be used * to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * *//* * Based on PI controller described in: * C. Hollot, V. Misra, D. Towsley and W. Gong. * On Designing Improved Controllers for AQM Routers * Supporting TCP Flows, * INFOCOMM 2001. */#include <math.h>#include <sys/types.h>#include "config.h"#include "template.h"#include "random.h"#include "flags.h"#include "delay.h"#include "pi.h"static class PIClass : public TclClass {public: PIClass() : TclClass("Queue/PI") {} TclObject* create(int argc, const char*const* argv) { if (argc==5) return (new PIQueue(argv[4])); else return (new PIQueue("Drop")); }} class_pi;PIQueue::PIQueue(const char * trace) : CalcTimer(this), link_(NULL), q_(NULL), qib_(0), de_drop_(NULL), EDTrace(NULL), tchan_(0), curq_(0), edp_(), edv_(), first_reset_(1){ if (strlen(trace) >=20) { printf("trace type too long - allocate more space to traceType in pi.h and recompile\n"); exit(0); } strcpy(traceType, trace); bind_bool("bytes_", &edp_.bytes); // boolean: use bytes? bind_bool("queue_in_bytes_", &qib_); // boolean: q in bytes? bind("a_", &edp_.a); bind("b_", &edp_.b); bind("c_", &edp_.c); bind("m1_", &edp_.m1); bind("m2_", &edp_.m2); bind("m_", &edp_.m); bind("k1_", &edp_.k1); bind("k2_", &edp_.k2); bind("k3_", &edp_.k3); bind("w_", &edp_.w); bind("qref_", &edp_.qref); bind("mean_pktsize_", &edp_.mean_pktsize); // avg pkt size bind_bool("setbit_", &edp_.setbit); // mark instead of drop bind("prob_", &edv_.v_prob); // dropping probability bind("curq_", &curq_); // current queue size q_ = new PacketQueue(); // underlying queue pq_ = q_; reset();}void PIQueue::reset(){ //double now = Scheduler::instance().clock(); /* if (qib_ && first_reset_ == 1) { edp_.qref = edp_.qref*edp_.mean_pktsize; } */ edv_.count = 0; edv_.count_bytes = 0; edv_.v_prob = 0; edv_.qold = 0; edv_.qoldold = 0; edv_.e = 0; edv_.eold = 0; curq_ = 0; calculate_p(); Queue::reset();}void PIQueue::enque(Packet* pkt){ //double now = Scheduler::instance().clock(); hdr_cmn* ch = hdr_cmn::access(pkt); ++edv_.count; edv_.count_bytes += ch->size(); int droptype = DTYPE_NONE; int qlen = qib_ ? q_->byteLength() : q_->length(); curq_ = qlen; // helps to trace queue during arrival, if enabled int qlim = qib_ ? (qlim_ * edp_.mean_pktsize) : qlim_; if (qlen >= qlim) { droptype = DTYPE_FORCED; } else { if (drop_early(pkt, qlen)) { droptype = DTYPE_UNFORCED; } } if (droptype == DTYPE_UNFORCED) { Packet *pkt_to_drop = pickPacketForECN(pkt); if (pkt_to_drop != pkt) { q_->enque(pkt); q_->remove(pkt_to_drop); pkt = pkt_to_drop; /* XXX okay because pkt is not needed anymore */ } if (de_drop_ != NULL) { if (EDTrace != NULL) ((Trace *)EDTrace)->recvOnly(pkt); de_drop_->recv(pkt); } else { drop(pkt); } } else { q_->enque(pkt); if (droptype == DTYPE_FORCED) { pkt = pickPacketToDrop(); q_->remove(pkt); drop(pkt); edv_.count = 0; edv_.count_bytes = 0; } } return;}double PIQueue::calculate_p(){ //double now = Scheduler::instance().clock(); double p; int qlen = qib_ ? q_->byteLength() : q_->length(); if (qib_) { edv_.e = qlen*1.0/edp_.mean_pktsize-edp_.qref; if (edv_.e > 0) edv_.e=edv_.e; else edv_.e=-edv_.e; if (edv_.e > edp_.m1) { p=edp_.k3*(edp_.a*(qlen*1.0/edp_.mean_pktsize-edp_.qref)- edp_.b*(edv_.qold*1.0/edp_.mean_pktsize-edp_.qref)+ edp_.c*(edv_.qoldold*1.0/edp_.mean_pktsize-edp_.qref))+ edv_.v_prob; } else if (edv_.e < edp_.m) { p=(edp_.a+edp_.c-edp_.b)*(qlen*1.0/edp_.mean_pktsize-edp_.qref)+ edv_.v_prob; } else if (edv_.e > edp_.m2) { if (edv_.e > edv_.eold) { p=edp_.k1*(edp_.a*(qlen*1.0/edp_.mean_pktsize-edp_.qref)- edp_.b*(edv_.qold*1.0/edp_.mean_pktsize-edp_.qref)+ edp_.c*(edv_.qoldold*1.0/edp_.mean_pktsize-edp_.qref))+ edv_.v_prob; } else p=edp_.k2*(edp_.a*(qlen*1.0/edp_.mean_pktsize-edp_.qref)- edp_.b*(edv_.qold*1.0/edp_.mean_pktsize-edp_.qref)+ edp_.c*(edv_.qoldold*1.0/edp_.mean_pktsize-edp_.qref))+ edv_.v_prob; } else p=(edp_.a+edp_.c-edp_.b)*(qlen*1.0/edp_.mean_pktsize-edp_.qref)+ edv_.v_prob; } else { edv_.e = qlen-edp_.qref; if (edv_.e > 0) edv_.e=edv_.e; else edv_.e=-edv_.e; if (edv_.e > edp_.m1) { p=edp_.k3*(edp_.a*(qlen-edp_.qref)-edp_.b*(edv_.qold-edp_.qref)+ edp_.c*(edv_.qoldold-edp_.qref))+edv_.v_prob; } else if (edv_.e < edp_.m) { p=(edp_.a+edp_.c-edp_.b)*(qlen-edp_.qref)+edv_.v_prob; } else if (edv_.e > edp_.m2) { if (edv_.e > edv_.eold) { p=edp_.k1*(edp_.a*(qlen-edp_.qref)-edp_.b*(edv_.qold-edp_.qref)+ edp_.c*(edv_.qoldold-edp_.qref))+edv_.v_prob; } else p=edp_.k2*(edp_.a*(qlen-edp_.qref)-edp_.b*(edv_.qold-edp_.qref)+ edp_.c*(edv_.qoldold-edp_.qref))+edv_.v_prob; } else p=(edp_.a+edp_.c-edp_.b)*(qlen-edp_.qref)+edv_.v_prob; } if (p < 0) p = 0; if (p > 1) p = 1; edv_.v_prob = p; edv_.qold = qlen; edv_.qoldold = edv_.qold; edv_.eold = edv_.e; CalcTimer.resched(1.0/edp_.w); return p;}int PIQueue::drop_early(Packet* pkt, int qlen){ //double now = Scheduler::instance().clock(); hdr_cmn* ch = hdr_cmn::access(pkt); double p = edv_.v_prob; if (edp_.bytes) { p = p*ch->size()/edp_.mean_pktsize; if (p > 1) p = 1; } double u = Random::uniform(); if (u <= p) { edv_.count = 0; edv_.count_bytes = 0; hdr_flags* hf = hdr_flags::access(pickPacketForECN(pkt)); if (edp_.setbit && hf->ect()) { hf->ce() = 1; // mark Congestion Experienced bit return (0); // no drop } else { return (1); // drop } } return (0); // no DROP/mark}Packet* PIQueue::pickPacketForECN(Packet* pkt){ return pkt; /* pick the packet that just arrived */}Packet* PIQueue::pickPacketToDrop() { int victim; victim = q_->length() - 1; return(q_->lookup(victim)); }Packet* PIQueue::deque(){ Packet *p; p = q_->deque(); curq_ = qib_ ? q_->byteLength() : q_->length(); // helps to trace queue during arrival, if enabled return (p);}int PIQueue::command(int argc, const char*const* argv){ Tcl& tcl = Tcl::instance(); if (argc == 2) { if (strcmp(argv[1], "reset") == 0) { reset(); return (TCL_OK); } if (strcmp(argv[1], "early-drop-target") == 0) { if (de_drop_ != NULL) tcl.resultf("%s", de_drop_->name()); return (TCL_OK); } if (strcmp(argv[1], "edrop-trace") == 0) { if (EDTrace != NULL) { tcl.resultf("%s", EDTrace->name()); } else { tcl.resultf("0"); } return (TCL_OK); } if (strcmp(argv[1], "trace-type") == 0) { tcl.resultf("%s", traceType); return (TCL_OK); } } else if (argc == 3) { // attach a file for variable tracing if (strcmp(argv[1], "attach") == 0) { int mode; const char* id = argv[2]; tchan_ = Tcl_GetChannel(tcl.interp(), (char*)id, &mode); if (tchan_ == 0) { tcl.resultf("PI: trace: can't attach %s for writing", id); return (TCL_ERROR); } return (TCL_OK); } // tell PI about link stats if (strcmp(argv[1], "link") == 0) { LinkDelay* del = (LinkDelay*)TclObject::lookup(argv[2]); if (del == 0) { tcl.resultf("PI: no LinkDelay object %s", argv[2]); return(TCL_ERROR); } link_ = del; return (TCL_OK); } if (strcmp(argv[1], "early-drop-target") == 0) { NsObject* p = (NsObject*)TclObject::lookup(argv[2]); if (p == 0) { tcl.resultf("no object %s", argv[2]); return (TCL_ERROR); } de_drop_ = p; return (TCL_OK); } if (strcmp(argv[1], "edrop-trace") == 0) { NsObject * t = (NsObject *)TclObject::lookup(argv[2]); if (t == 0) { tcl.resultf("no object %s", argv[2]); return (TCL_ERROR); } EDTrace = t; return (TCL_OK); } if (!strcmp(argv[1], "packetqueue-attach")) { delete q_; if (!(q_ = (PacketQueue*) TclObject::lookup(argv[2]))) return (TCL_ERROR); else { pq_ = q_; return (TCL_OK); } } } return (Queue::command(argc, argv));}void PIQueue::trace(TracedVar* v){ char wrk[500], *p; if (((p = strstr(v->name(), "prob")) == NULL) && ((p = strstr(v->name(), "curq")) == NULL)) { fprintf(stderr, "PI:unknown trace var %s\n", v->name()); return; } if (tchan_) { int n; double t = Scheduler::instance().clock(); // XXX: be compatible with nsv1 PI trace entries if (*p == 'c') { sprintf(wrk, "Q %g %d", t, int(*((TracedInt*) v))); } else { sprintf(wrk, "%c %g %g", *p, t, double(*((TracedDouble*) v))); } n = strlen(wrk); wrk[n] = '\n'; wrk[n+1] = 0; (void)Tcl_Write(tchan_, wrk, n+1); } return; }void PICalcTimer::expire(Event *){ a_->calculate_p();}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -