3 * congestion control logic for the swift protocol
5 * Created by Victor Grishchenko on 12/10/09.
6 * Copyright 2009 Delft University of Technology. All rights reserved.
12 using namespace swift;
15 tint Channel::MIN_DEV = 50*TINT_MSEC;
16 tint Channel::MAX_SEND_INTERVAL = TINT_SEC*58;
17 tint Channel::LEDBAT_TARGET = TINT_MSEC*25;
18 float Channel::LEDBAT_GAIN = 1.0/LEDBAT_TARGET;
19 tint Channel::LEDBAT_DELAY_BIN = TINT_SEC*30;
20 tint Channel::MAX_POSSIBLE_RTT = TINT_SEC*10;
21 const char* Channel::SEND_CONTROL_MODES[] = {"keepalive", "pingpong",
22 "slowstart", "standard_aimd", "ledbat", "closing"};
25 tint Channel::NextSendTime () {
26 TimeoutDataOut(); // precaution to know free cwnd
27 switch (send_control_) {
28 case KEEP_ALIVE_CONTROL: return KeepAliveNextSendTime();
29 case PING_PONG_CONTROL: return PingPongNextSendTime();
30 case SLOW_START_CONTROL: return SlowStartNextSendTime();
31 case AIMD_CONTROL: return AimdNextSendTime();
32 case LEDBAT_CONTROL: return LedbatNextSendTime();
33 case CLOSE_CONTROL: return TINT_NEVER;
34 default: assert(false);
38 tint Channel::SwitchSendControl (int control_mode) {
39 dprintf("%s #%u sendctrl switch %s->%s\n",tintstr(),id(),
40 SEND_CONTROL_MODES[send_control_],SEND_CONTROL_MODES[control_mode]);
41 switch (control_mode) {
42 case KEEP_ALIVE_CONTROL:
43 send_interval_ = rtt_avg_; //max(TINT_SEC/10,rtt_avg_);
44 dev_avg_ = max(TINT_SEC,rtt_avg_);
45 data_out_cap_ = bin64_t::ALL;
48 case PING_PONG_CONTROL:
49 dev_avg_ = max(TINT_SEC,rtt_avg_);
50 data_out_cap_ = bin64_t::ALL;
53 case SLOW_START_CONTROL:
65 send_control_ = control_mode;
66 return NextSendTime();
69 tint Channel::KeepAliveNextSendTime () {
70 if (sent_since_recv_>=3 && last_recv_time_<NOW-TINT_MIN)
71 return SwitchSendControl(CLOSE_CONTROL);
73 return SwitchSendControl(SLOW_START_CONTROL);
74 if (data_in_.time!=TINT_NEVER)
76 if (last_send_time_==NOW)
78 if (send_interval_>MAX_SEND_INTERVAL)
79 send_interval_ = MAX_SEND_INTERVAL;
80 return last_send_time_ + send_interval_;
83 tint Channel::PingPongNextSendTime () { // FIXME INFINITE LOOP
85 return SwitchSendControl(KEEP_ALIVE_CONTROL);
87 return SwitchSendControl(SLOW_START_CONTROL);
88 if (data_in_.time!=TINT_NEVER)
90 if (last_recv_time_>last_send_time_)
94 return last_send_time_ + ack_timeout(); // timeout
97 tint Channel::CwndRateNextSendTime () {
98 if (data_in_.time!=TINT_NEVER)
99 return NOW; // TODO: delayed ACKs
100 //if (last_recv_time_<NOW-rtt_avg_*4)
101 // return SwitchSendControl(KEEP_ALIVE_CONTROL);
102 send_interval_ = rtt_avg_/cwnd_;
103 if (send_interval_>max(rtt_avg_,TINT_SEC)*4)
104 return SwitchSendControl(KEEP_ALIVE_CONTROL);
105 if (data_out_.size()<cwnd_) {
106 dprintf("%s #%u sendctrl next in %llius (cwnd %.2f, data_out %i)\n",
107 tintstr(),id_,send_interval_,cwnd_,(int)data_out_.size());
108 return last_data_out_time_ + send_interval_;
110 assert(data_out_.front().time!=TINT_NEVER);
111 return data_out_.front().time + ack_timeout();
115 void Channel::BackOffOnLosses (float ratio) {
116 ack_rcvd_recent_ = 0;
117 ack_not_rcvd_recent_ = 0;
118 if (last_loss_time_<NOW-rtt_avg_) {
120 last_loss_time_ = NOW;
121 dprintf("%s #%u sendctrl backoff %3.2f\n",tintstr(),id_,cwnd_);
125 tint Channel::SlowStartNextSendTime () {
126 if (ack_not_rcvd_recent_) {
128 return SwitchSendControl(LEDBAT_CONTROL);//AIMD_CONTROL);
130 if (rtt_avg_/cwnd_<TINT_SEC/10)
131 return SwitchSendControl(LEDBAT_CONTROL);//AIMD_CONTROL);
132 cwnd_+=ack_rcvd_recent_;
134 return CwndRateNextSendTime();
137 tint Channel::AimdNextSendTime () {
138 if (ack_not_rcvd_recent_)
140 if (ack_rcvd_recent_) {
142 cwnd_ += ack_rcvd_recent_/cwnd_;
147 return CwndRateNextSendTime();
150 tint Channel::LedbatNextSendTime () {
151 tint owd_cur(TINT_NEVER), owd_min(TINT_NEVER);
152 for(int i=0; i<4; i++) {
153 if (owd_min>owd_min_bins_[i])
154 owd_min = owd_min_bins_[i];
155 if (owd_cur>owd_current_[i])
156 owd_cur = owd_current_[i];
158 if (ack_not_rcvd_recent_)
159 BackOffOnLosses(0.8);
160 ack_rcvd_recent_ = 0;
161 tint queueing_delay = owd_cur - owd_min;
162 tint off_target = LEDBAT_TARGET - queueing_delay;
163 cwnd_ += LEDBAT_GAIN * off_target / cwnd_;
166 if (owd_cur==TINT_NEVER || owd_min==TINT_NEVER)
168 dprintf("%s #%u sendctrl ledbat %lli-%lli => %3.2f\n",
169 tintstr(),id_,owd_cur,owd_min,cwnd_);
170 return CwndRateNextSendTime();