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