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