netem settings
[swift-upb.git] / send_control.cpp
1 /*
2  *  send_control.cpp
3  *  congestion control logic for the swift protocol
4  *
5  *  Created by Victor Grishchenko on 12/10/09.
6  *  Copyright 2009 Delft University of Technology. All rights reserved.
7  *
8  */
9
10 #include "swift.h"
11
12 using namespace swift;
13 using namespace std;
14
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"};
23
24
25 tint    Channel::NextSendTime () {
26     switch (send_control_) {
27         case KEEP_ALIVE_CONTROL: return KeepAliveNextSendTime();
28         case PING_PONG_CONTROL:  return PingPongNextSendTime();
29         case SLOW_START_CONTROL: return SlowStartNextSendTime();
30         case AIMD_CONTROL:       return AimdNextSendTime();
31         case LEDBAT_CONTROL:     return LedbatNextSendTime();
32         case CLOSE_CONTROL:      return TINT_NEVER;
33         default:                 assert(false);
34     }
35 }
36
37 tint    Channel::SwitchSendControl (int control_mode) {
38     dprintf("%s #%u sendctrl switch %s->%s\n",tintstr(),id(),
39             SEND_CONTROL_MODES[send_control_],SEND_CONTROL_MODES[control_mode]);
40     switch (control_mode) {
41         case KEEP_ALIVE_CONTROL:
42             send_interval_ = max(TINT_SEC/10,rtt_avg_);
43             dev_avg_ = max(TINT_SEC,rtt_avg_);
44             data_out_cap_ = bin64_t::ALL;
45             cwnd_ = 1;
46             break;
47         case PING_PONG_CONTROL:
48             dev_avg_ = max(TINT_SEC,rtt_avg_);
49             data_out_cap_ = bin64_t::ALL;
50             cwnd_ = 1;
51             break;
52         case SLOW_START_CONTROL:
53             cwnd_ = 1;
54             break;
55         case AIMD_CONTROL:
56             break;
57         case LEDBAT_CONTROL:
58             break;
59         case CLOSE_CONTROL:
60             break;
61         default: 
62             assert(false);
63     }
64     send_control_ = control_mode;
65     return NextSendTime();
66 }
67
68 tint    Channel::KeepAliveNextSendTime () {
69     if (sent_since_recv_>=3 && last_recv_time_<NOW-TINT_MIN)
70         return SwitchSendControl(CLOSE_CONTROL);
71     if (ack_rcvd_recent_)
72         return SwitchSendControl(SLOW_START_CONTROL);
73     if (data_in_.time!=TINT_NEVER)
74         return NOW;
75     send_interval_ <<= 1;
76     if (send_interval_>MAX_SEND_INTERVAL)
77         send_interval_ = MAX_SEND_INTERVAL;
78     return last_send_time_ + send_interval_;
79 }
80
81 tint    Channel::PingPongNextSendTime () { // FIXME INFINITE LOOP
82     if (dgrams_sent_>=10)
83         return SwitchSendControl(KEEP_ALIVE_CONTROL);
84     if (ack_rcvd_recent_)
85         return SwitchSendControl(SLOW_START_CONTROL);
86     if (data_in_.time!=TINT_NEVER)
87         return NOW;
88     if (last_recv_time_>last_send_time_)
89         return NOW;
90     if (!last_send_time_)
91         return NOW;
92     return last_send_time_ + ack_timeout(); // timeout
93 }
94
95 tint    Channel::CwndRateNextSendTime () {
96     if (data_in_.time!=TINT_NEVER)
97         return NOW; // TODO: delayed ACKs
98     //if (last_recv_time_<NOW-rtt_avg_*4)
99     //    return SwitchSendControl(KEEP_ALIVE_CONTROL);
100     send_interval_ = rtt_avg_/cwnd_;
101     if (send_interval_>std::max(rtt_avg_,TINT_SEC)*4)
102         return SwitchSendControl(KEEP_ALIVE_CONTROL);
103     if (data_out_.size()<cwnd_) {
104         dprintf("%s #%u sendctrl next in %llius (cwnd %f.2, data_out %i)\n",
105                 tintstr(),id_,send_interval_,cwnd_,(int)data_out_.size());
106         return last_data_out_time_ + send_interval_;
107     } else {
108         assert(data_out_.front().time!=TINT_NEVER);
109         return data_out_.front().time + ack_timeout();
110     }
111 }
112
113 void    Channel::BackOffOnLosses (float ratio) {
114     ack_rcvd_recent_ = 0;
115     ack_not_rcvd_recent_ =  0;
116     if (last_loss_time_<NOW-rtt_avg_) {
117         cwnd_ *= ratio;
118         last_loss_time_ = NOW;
119         dprintf("%s #%u sendctrl backoff %3.2f\n",tintstr(),id_,cwnd_);
120     }
121 }
122
123 tint    Channel::SlowStartNextSendTime () {
124     if (ack_not_rcvd_recent_) {
125         BackOffOnLosses();
126         return SwitchSendControl(LEDBAT_CONTROL);//AIMD_CONTROL);
127     } 
128     if (rtt_avg_/cwnd_<TINT_SEC/10) 
129         return SwitchSendControl(LEDBAT_CONTROL);//AIMD_CONTROL);
130     cwnd_+=ack_rcvd_recent_;
131     ack_rcvd_recent_=0;
132     return CwndRateNextSendTime();
133 }
134
135 tint    Channel::AimdNextSendTime () {
136     if (ack_not_rcvd_recent_)
137         BackOffOnLosses();
138     if (ack_rcvd_recent_) {
139         if (cwnd_>1)
140             cwnd_ += ack_rcvd_recent_/cwnd_;
141         else
142             cwnd_ *= 2;
143     }
144     ack_rcvd_recent_=0;
145     return CwndRateNextSendTime();
146 }
147
148 tint Channel::LedbatNextSendTime () {
149     tint owd_cur(TINT_NEVER), owd_min(TINT_NEVER);
150     for(int i=0; i<4; i++) {
151         if (owd_min>owd_min_bins_[i])
152             owd_min = owd_min_bins_[i];
153         if (owd_cur>owd_current_[i])
154             owd_cur = owd_current_[i];
155     }
156     if (ack_not_rcvd_recent_)
157         BackOffOnLosses(0.8);
158     ack_rcvd_recent_ = 0;
159     tint queueing_delay = owd_cur - owd_min;
160     tint off_target = LEDBAT_TARGET - queueing_delay;
161     cwnd_ += LEDBAT_GAIN * off_target / cwnd_;
162     if (cwnd_<1)
163         cwnd_ = 1;
164     dprintf("%s #%u sendctrl ledbat %lli-%lli => %3.2f\n",
165             tintstr(),id_,owd_cur,owd_min,cwnd_);
166     return CwndRateNextSendTime();
167 }
168
169
170