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