OLD | NEW |
---|---|
1 /* | 1 /* |
2 * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. | 2 * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license | 4 * Use of this source code is governed by a BSD-style license |
5 * that can be found in the LICENSE file in the root of the source | 5 * that can be found in the LICENSE file in the root of the source |
6 * tree. An additional intellectual property rights grant can be found | 6 * tree. An additional intellectual property rights grant can be found |
7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
9 * | 9 * |
10 */ | 10 */ |
11 | 11 |
12 #include "webrtc/modules/remote_bitrate_estimator/test/estimators/bbr.h" | 12 #include "webrtc/modules/remote_bitrate_estimator/test/estimators/bbr.h" |
13 | 13 |
14 #include <stdlib.h> | 14 #include <stdlib.h> |
15 #include <algorithm> | |
15 | 16 |
16 #include "webrtc/modules/remote_bitrate_estimator/test/estimators/congestion_win dow.h" | 17 #include "webrtc/modules/remote_bitrate_estimator/test/estimators/congestion_win dow.h" |
17 #include "webrtc/modules/remote_bitrate_estimator/test/estimators/max_bandwidth_ filter.h" | 18 #include "webrtc/modules/remote_bitrate_estimator/test/estimators/max_bandwidth_ filter.h" |
18 #include "webrtc/modules/remote_bitrate_estimator/test/estimators/min_rtt_filter .h" | 19 #include "webrtc/modules/remote_bitrate_estimator/test/estimators/min_rtt_filter .h" |
19 | 20 |
20 namespace webrtc { | 21 namespace webrtc { |
21 namespace testing { | 22 namespace testing { |
22 namespace bwe { | 23 namespace bwe { |
23 namespace { | 24 namespace { |
24 const int kFeedbackIntervalsMs = 3; | 25 const int kFeedbackIntervalsMs = 5; |
25 // BBR uses this value to double sending rate each round trip. Design document | 26 // BBR uses this value to double sending rate each round trip. Design document |
26 // suggests using this value. | 27 // suggests using this value. |
27 const float kHighGain = 2.885f; | 28 const float kHighGain = 2.885f; |
28 // BBR uses this value to drain queues created during STARTUP in one round trip | 29 // BBR uses this value to drain queues created during STARTUP in one round trip |
29 // time. | 30 // time. |
30 const float kDrainGain = 1 / kHighGain; | 31 const float kDrainGain = 1 / kHighGain; |
31 // kStartupGrowthTarget and kMaxRoundsWithoutGrowth are chosen from | 32 // kStartupGrowthTarget and kMaxRoundsWithoutGrowth are chosen from |
32 // experiments, according to the design document. | 33 // experiments, according to the design document. |
33 const float kStartupGrowthTarget = 1.25f; | 34 const float kStartupGrowthTarget = 1.25f; |
34 const int kMaxRoundsWithoutGrowth = 3; | 35 const int kMaxRoundsWithoutGrowth = 3; |
35 // Pacing gain values for Probe Bandwidth mode. | 36 // Pacing gain values for Probe Bandwidth mode. |
36 const float kPacingGain[] = {1.25, 0.75, 1, 1, 1, 1, 1, 1}; | 37 const float kPacingGain[] = {1.25, 0.75, 1, 1, 1, 1, 1, 1}; |
37 const size_t kGainCycleLength = sizeof(kPacingGain) / sizeof(kPacingGain[0]); | 38 const size_t kGainCycleLength = sizeof(kPacingGain) / sizeof(kPacingGain[0]); |
38 // The least amount of rounds PROBE_RTT mode should last. | 39 // Least amount number of rounds PROBE_RTT should last. |
terelius
2017/08/08 17:32:40
nit: Remove "amount"?
gnish1
2017/08/09 10:05:53
Done.
| |
39 const int kProbeRttDurationRounds = 1; | 40 const int kProbeRttDurationRounds = 1; |
40 // The least amount of milliseconds PROBE_RTT mode should last. | 41 // The least amount of milliseconds PROBE_RTT mode should last. |
41 const int kProbeRttDurationMs = 200; | 42 const int kProbeRttDurationMs = 200; |
42 // Gain value for congestion window for assuming that network has no queues. | 43 // Gain value for congestion window for assuming that network has no queues. |
43 const float kTargetCongestionWindowGain = 1; | 44 const float kTargetCongestionWindowGain = 1; |
44 // Gain value for congestion window in PROBE_BW mode. In theory it should be | 45 // Gain value for congestion window in PROBE_BW mode. In theory it should be |
45 // equal to 1, but in practice because of delayed acks and the way networks | 46 // equal to 1, but in practice because of delayed acks and the way networks |
46 // work, it is nice to have some extra room in congestion window for full link | 47 // work, it is nice to have some extra room in congestion window for full link |
47 // utilization. Value chosen by observations on different tests. | 48 // utilization. Value chosen by observations on different tests. |
48 const float kCruisingCongestionWindowGain = 1.5f; | 49 const float kCruisingCongestionWindowGain = 1.5f; |
49 // Expiration time for min_rtt sample, which is set to 10 seconds according to | 50 // Pacing gain specific for Recovery mode. Chosen by experiments in simulation |
50 // BBR design doc. | 51 // tool. |
51 const int64_t kMinRttFilterSizeMs = 10000; | 52 const float kRecoveryPacingGain = 0.5f; |
53 // Congestion window gain specific for Recovery mode. Chosen by experiments in | |
54 // simulation tool. | |
55 const float kRecoveryCongestionWindowGain = 1.5f; | |
56 // Number of rounds over which average rtt is stored for Recovery mode. | |
57 const size_t kPastRttsFilterSize = 1; | |
58 // Threshold to assume average rtt has increased for a round. Chosen by | |
terelius
2017/08/08 17:32:40
rtt -> RTT. Same below.
gnish1
2017/08/09 10:05:53
Done.
| |
59 // experiments in simulation tool. | |
60 const float kRttIncreaseThreshold = 3; | |
61 // Threshold to assume average rtt has decreased for a round. Chosen by | |
62 // experiments in simulation tool. | |
63 const float kRttDecreaseThreshold = 1.5f; | |
terelius
2017/08/08 17:32:40
I wouldn't call it a "decrease" if the RTT is 1.5
gnish1
2017/08/09 10:05:53
Yes, but I didn't want to create another mode simi
| |
52 } // namespace | 64 } // namespace |
53 | 65 |
54 BbrBweSender::BbrBweSender(Clock* clock) | 66 BbrBweSender::BbrBweSender(Clock* clock) |
55 : BweSender(0), | 67 : BweSender(0), |
56 clock_(clock), | 68 clock_(clock), |
57 mode_(STARTUP), | 69 mode_(STARTUP), |
58 max_bandwidth_filter_(new MaxBandwidthFilter()), | 70 max_bandwidth_filter_(new MaxBandwidthFilter()), |
59 min_rtt_filter_(new MinRttFilter()), | 71 min_rtt_filter_(new MinRttFilter()), |
60 congestion_window_(new CongestionWindow()), | 72 congestion_window_(new CongestionWindow()), |
61 rand_(new Random(time(NULL))), | 73 rand_(new Random(time(NULL))), |
62 round_count_(0), | 74 round_count_(0), |
63 last_packet_sent_(0), | |
64 round_trip_end_(0), | 75 round_trip_end_(0), |
65 full_bandwidth_reached_(false), | 76 full_bandwidth_reached_(false), |
66 cycle_start_time_ms_(0), | 77 cycle_start_time_ms_(0), |
67 cycle_index_(0), | 78 cycle_index_(0), |
68 prior_in_flight_(0), | 79 bytes_acked_(0), |
69 probe_rtt_start_time_ms_(0), | 80 probe_rtt_start_time_ms_(0), |
70 minimum_congestion_window_start_time_ms_(), | 81 minimum_congestion_window_start_time_ms_(0), |
71 minimum_congestion_window_start_round_(0) { | 82 minimum_congestion_window_start_round_(0), |
83 bytes_sent_(0), | |
84 last_packet_sent_sequence_number_(0), | |
85 last_packet_acked_sequence_number_(0), | |
86 last_packet_ack_time_(0), | |
87 last_packet_send_time_(0), | |
88 pacing_rate_bps_(0), | |
89 last_packet_send_time_during_high_gain_ms_(-1), | |
90 data_sent_before_high_gain_started_bytes_(-1), | |
91 data_sent_before_high_gain_ended_bytes_(-1), | |
92 first_packet_ack_time_during_high_gain_ms_(-1), | |
93 last_packet_ack_time_during_high_gain_ms_(-1), | |
94 data_acked_before_high_gain_started_bytes_(-1), | |
95 data_acked_before_high_gain_ended_bytes_(-1), | |
96 first_packet_seq_num_during_high_gain_(-1), | |
97 last_packet_seq_num_during_high_gain_(-1), | |
98 high_gain_over_(false), | |
99 packet_stats_(), | |
100 past_rtts_() { | |
72 // Initially enter Startup mode. | 101 // Initially enter Startup mode. |
73 EnterStartup(); | 102 EnterStartup(); |
74 } | 103 } |
75 | 104 |
76 BbrBweSender::~BbrBweSender() {} | 105 BbrBweSender::~BbrBweSender() {} |
77 | 106 |
78 int BbrBweSender::GetFeedbackIntervalMs() const { | 107 int BbrBweSender::GetFeedbackIntervalMs() const { |
79 return kFeedbackIntervalsMs; | 108 return kFeedbackIntervalsMs; |
80 } | 109 } |
81 | 110 |
111 void BbrBweSender::CalculatePacingRate() { | |
112 pacing_rate_bps_ = | |
113 max_bandwidth_filter_->max_bandwidth_estimate_bps() * pacing_gain_; | |
114 } | |
115 | |
116 void BbrBweSender::HandleLoss(uint64_t last_acked_packet, | |
117 uint64_t recently_acked_packet) { | |
118 // Logic specific to wrapping sequence numbers. | |
119 if (!last_acked_packet) | |
120 return; | |
121 for (uint16_t i = last_acked_packet + 1; | |
122 AheadOrAt<uint64_t>(recently_acked_packet - 1, i); i++) | |
terelius
2017/08/08 17:32:40
I'd prefer curly braces around the loop body becau
terelius
2017/08/08 17:32:40
Is it safe to subtract one here, or could the subt
gnish1
2017/08/09 10:05:53
It will underflow, but it is safe, the loop will w
gnish1
2017/08/09 10:05:53
Done.
| |
123 congestion_window_->AckReceived(packet_stats_[i].payload_size_bytes); | |
124 } | |
125 | |
126 void BbrBweSender::AddToPastRtts(int64_t rtt_sample_ms) { | |
127 uint64_t last_round = 0; | |
128 if (!past_rtts_.empty()) | |
129 last_round = past_rtts_.back().round; | |
130 | |
131 // Try to add the sample to the last round. | |
132 if (last_round == round_count_ && !past_rtts_.empty()) { | |
133 past_rtts_.back().sum_of_rtts_ms += rtt_sample_ms; | |
134 past_rtts_.back().num_samples++; | |
135 } else { | |
136 // If the sample belongs to a new round, keep number of rounds in the window | |
137 // equal to |kPastRttsFilterSize|. | |
138 if (past_rtts_.size() == kPastRttsFilterSize) | |
139 past_rtts_.pop_front(); | |
140 past_rtts_.push_back( | |
141 BbrBweSender::AverageRtt(rtt_sample_ms, 1, round_count_)); | |
142 } | |
143 } | |
144 | |
82 void BbrBweSender::GiveFeedback(const FeedbackPacket& feedback) { | 145 void BbrBweSender::GiveFeedback(const FeedbackPacket& feedback) { |
146 int64_t now_ms = clock_->TimeInMilliseconds(); | |
147 last_packet_ack_time_ = now_ms; | |
83 const BbrBweFeedback& fb = static_cast<const BbrBweFeedback&>(feedback); | 148 const BbrBweFeedback& fb = static_cast<const BbrBweFeedback&>(feedback); |
84 // feedback_vector holds values of acknowledged packets' sequence numbers. | 149 // feedback_vector holds values of acknowledged packets' sequence numbers. |
85 const std::vector<uint64_t>& feedback_vector = fb.packet_feedback_vector(); | 150 const std::vector<uint64_t>& feedback_vector = fb.packet_feedback_vector(); |
86 // Check if new round started for the connection. Round is the period of time | 151 // Go through all the packets acked, update variables/containers accordingly. |
87 // from sending packet to its acknowledgement. | 152 for (uint64_t f : feedback_vector) { |
terelius
2017/08/08 17:32:40
Better name than f?
gnish1
2017/08/09 10:05:53
Done.
| |
153 // Completing packet information with a recently received ack. | |
154 PacketStats* packet = &packet_stats_[f]; | |
155 bytes_acked_ += packet->payload_size_bytes; | |
156 packet->data_sent_bytes = bytes_sent_; | |
157 packet->last_sent_packet_send_time_ms = last_packet_send_time_; | |
158 packet->data_acked_bytes = bytes_acked_; | |
159 packet->ack_time_ms = now_ms; | |
160 // Logic specific to applying "bucket" to high gain, in order to have | |
161 // quicker ramp-up. We check if we started receiving acks for the packets | |
162 // sent during high gain phase. | |
163 if (packet->sequence_number == first_packet_seq_num_during_high_gain_) { | |
164 first_packet_ack_time_during_high_gain_ms_ = now_ms; | |
165 data_acked_before_high_gain_started_bytes_ = bytes_acked_; | |
166 } | |
167 // If the last packet of high gain phase has been acked, high gain phase is | |
168 // over. | |
169 if (packet->sequence_number == last_packet_seq_num_during_high_gain_) { | |
170 last_packet_ack_time_during_high_gain_ms_ = now_ms; | |
171 data_acked_before_high_gain_ended_bytes_ = bytes_acked_; | |
172 high_gain_over_ = true; | |
173 } | |
174 // Notify pacer that an ack was received, to adjust data inflight. | |
175 // TODO(gnish): Add implementation for BitrateObserver class, to notify | |
176 // pacer about incoming acks. | |
177 congestion_window_->AckReceived(packet->payload_size_bytes); | |
178 HandleLoss(last_packet_acked_sequence_number_, packet->sequence_number); | |
179 last_packet_acked_sequence_number_ = packet->sequence_number; | |
180 // Logic for wrapping sequence numbers. If round started with packet number | |
181 // x, it can never end on y, if x > y. That could happen when sequence | |
182 // numbers are wrapped after some point. | |
183 if (packet->sequence_number == 0) | |
184 round_trip_end_ = 0; | |
185 } | |
186 // Check if new round started for the connection. | |
88 bool new_round_started = false; | 187 bool new_round_started = false; |
89 if (!feedback_vector.empty()) { | 188 if (!feedback_vector.empty()) { |
90 uint64_t last_acked_packet = *feedback_vector.rbegin(); | 189 if (last_packet_acked_sequence_number_ > round_trip_end_) { |
91 if (last_acked_packet > round_trip_end_) { | |
92 new_round_started = true; | 190 new_round_started = true; |
93 round_count_++; | 191 round_count_++; |
94 round_trip_end_ = last_packet_sent_; | 192 round_trip_end_ = last_packet_sent_sequence_number_; |
95 } | 193 } |
96 } | 194 } |
195 bool min_rtt_expired = false; | |
196 min_rtt_expired = | |
197 UpdateBandwidthAndMinRtt(now_ms, feedback_vector, bytes_acked_); | |
97 if (new_round_started && !full_bandwidth_reached_) { | 198 if (new_round_started && !full_bandwidth_reached_) { |
98 full_bandwidth_reached_ = max_bandwidth_filter_->FullBandwidthReached( | 199 full_bandwidth_reached_ = max_bandwidth_filter_->FullBandwidthReached( |
99 kStartupGrowthTarget, kMaxRoundsWithoutGrowth); | 200 kStartupGrowthTarget, kMaxRoundsWithoutGrowth); |
100 } | 201 } |
101 int now_ms = clock_->TimeInMilliseconds(); | |
102 switch (mode_) { | 202 switch (mode_) { |
103 break; | 203 break; |
104 case STARTUP: | 204 case STARTUP: |
105 TryExitingStartup(); | 205 TryExitingStartup(); |
106 break; | 206 break; |
107 case DRAIN: | 207 case DRAIN: |
108 TryExitingDrain(now_ms); | 208 TryExitingDrain(now_ms); |
109 break; | 209 break; |
110 case PROBE_BW: | 210 case PROBE_BW: |
111 TryUpdatingCyclePhase(now_ms); | 211 TryUpdatingCyclePhase(now_ms); |
112 break; | 212 break; |
113 case PROBE_RTT: | 213 case PROBE_RTT: |
114 TryExitingProbeRtt(now_ms, 0); | 214 TryExitingProbeRtt(now_ms, round_count_); |
215 break; | |
216 case RECOVERY: | |
217 TryExitingRecovery(new_round_started); | |
115 break; | 218 break; |
116 } | 219 } |
117 TryEnteringProbeRtt(now_ms); | 220 TryEnteringProbeRtt(now_ms); |
118 // TODO(gnish): implement functions updating congestion window and pacing rate | 221 TryEnteringRecovery(new_round_started); // Comment this line to disable |
119 // controllers. | 222 // entering Recovery mode. |
223 for (uint64_t f : feedback_vector) | |
224 AddToPastRtts(packet_stats_[f].ack_time_ms - packet_stats_[f].send_time_ms); | |
225 CalculatePacingRate(); | |
226 // Make sure we don't get stuck when pacing_rate is 0, because of simulation | |
227 // tool specifics. | |
228 if (!pacing_rate_bps_) | |
229 pacing_rate_bps_ = 100; | |
230 BWE_TEST_LOGGING_PLOT(1, "SendRate", now_ms, pacing_rate_bps_ / 1000); | |
231 // TODO(gnish): Add implementation for BitrateObserver class to update pacing | |
232 // rate for the pacer and the encoder. | |
120 } | 233 } |
121 | 234 |
122 size_t BbrBweSender::TargetCongestionWindow(float gain) { | 235 size_t BbrBweSender::TargetCongestionWindow(float gain) { |
123 size_t target_congestion_window = | 236 size_t target_congestion_window = |
124 congestion_window_->GetTargetCongestionWindow( | 237 congestion_window_->GetTargetCongestionWindow( |
125 max_bandwidth_filter_->max_bandwidth_estimate_bps(), | 238 max_bandwidth_filter_->max_bandwidth_estimate_bps(), |
126 min_rtt_filter_->min_rtt_ms(), gain); | 239 min_rtt_filter_->min_rtt_ms(), gain); |
127 return target_congestion_window; | 240 return target_congestion_window; |
128 } | 241 } |
129 | 242 |
130 bool BbrBweSender::UpdateBandwidthAndMinRtt() { | 243 rtc::Optional<int64_t> BbrBweSender::CalculateBandwidthSample( |
131 return false; | 244 size_t data_sent_bytes, |
245 int64_t send_time_delta_ms, | |
246 size_t data_acked_bytes, | |
247 int64_t ack_time_delta_ms) { | |
248 rtc::Optional<int64_t> bandwidth_sample; | |
249 if (send_time_delta_ms > 0) | |
250 *bandwidth_sample = data_sent_bytes * 8000 / send_time_delta_ms; | |
251 rtc::Optional<int64_t> ack_rate; | |
252 if (ack_time_delta_ms > 0) | |
253 *ack_rate = data_acked_bytes * 8000 / ack_time_delta_ms; | |
254 // If send rate couldn't be calculated automaticaly set |bandwidth_sample| to | |
255 // ack_rate. | |
256 if (!bandwidth_sample) | |
257 bandwidth_sample = ack_rate; | |
258 if (bandwidth_sample && ack_rate) | |
259 *bandwidth_sample = std::min(*bandwidth_sample, *ack_rate); | |
260 return bandwidth_sample; | |
261 } | |
262 | |
263 void BbrBweSender::AddSampleForHighGain() { | |
264 if (!high_gain_over_) | |
265 return; | |
266 high_gain_over_ = false; | |
267 // Calculate data sent/acked and time elapsed only for packets sent during | |
268 // high gain phase. | |
269 size_t data_sent_bytes = data_sent_before_high_gain_ended_bytes_ - | |
270 data_sent_before_high_gain_started_bytes_; | |
271 int64_t send_time_delta_ms = last_packet_send_time_during_high_gain_ms_ - | |
terelius
2017/08/08 17:32:40
Won't this overestimate the bandwidth? If we are s
gnish1
2017/08/09 10:05:53
It could overestimate bw, as normal bw calculation
terelius
2017/08/11 09:27:52
What I am saying is that the calculation seems to
gnish1
2017/08/12 11:57:31
Done.
| |
272 *first_packet_send_time_during_high_gain_ms_; | |
273 size_t data_acked_bytes = data_acked_before_high_gain_ended_bytes_ - | |
274 data_acked_before_high_gain_started_bytes_; | |
275 int64_t ack_time_delta_ms = last_packet_ack_time_during_high_gain_ms_ - | |
276 first_packet_ack_time_during_high_gain_ms_; | |
277 rtc::Optional<int64_t> bandwidth_sample = CalculateBandwidthSample( | |
278 data_sent_bytes, send_time_delta_ms, data_acked_bytes, ack_time_delta_ms); | |
279 if (bandwidth_sample) | |
280 max_bandwidth_filter_->AddBandwidthSample(*bandwidth_sample, round_count_); | |
281 first_packet_send_time_during_high_gain_ms_.reset(); | |
282 } | |
283 | |
284 bool BbrBweSender::UpdateBandwidthAndMinRtt( | |
285 int64_t now_ms, | |
286 const std::vector<uint64_t>& feedback_vector, | |
287 int64_t bytes_acked) { | |
288 rtc::Optional<int64_t> min_rtt_sample_ms; | |
289 for (uint64_t f : feedback_vector) { | |
290 PacketStats packet = packet_stats_[f]; | |
291 size_t data_sent_bytes = | |
292 packet.data_sent_bytes - packet.data_sent_before_last_sent_packet_bytes; | |
293 int64_t send_time_delta_ms = | |
294 packet.last_sent_packet_send_time_ms - packet.send_time_ms; | |
295 size_t data_acked_bytes = packet.data_acked_bytes - | |
296 packet.data_acked_before_last_acked_packet_bytes; | |
297 int64_t ack_time_delta_ms = | |
298 packet.ack_time_ms - packet.last_acked_packet_ack_time_ms; | |
299 rtc::Optional<int64_t> bandwidth_sample = | |
300 CalculateBandwidthSample(data_sent_bytes, send_time_delta_ms, | |
301 data_acked_bytes, ack_time_delta_ms); | |
302 if (bandwidth_sample) | |
303 max_bandwidth_filter_->AddBandwidthSample(*bandwidth_sample, | |
304 round_count_); | |
305 AddSampleForHighGain(); // Comment to disable bucket for high gain. | |
306 if (!min_rtt_sample_ms) | |
307 *min_rtt_sample_ms = packet.ack_time_ms - packet.send_time_ms; | |
308 else | |
309 *min_rtt_sample_ms = std::min(*min_rtt_sample_ms, | |
310 packet.ack_time_ms - packet.send_time_ms); | |
311 BWE_TEST_LOGGING_PLOT(1, "MinRtt", now_ms, | |
312 packet.ack_time_ms - packet.send_time_ms); | |
313 } | |
314 if (!min_rtt_sample_ms) | |
315 return false; | |
316 bool min_rtt_expired = min_rtt_filter_->MinRttExpired(now_ms); | |
317 min_rtt_filter_->AddRttSample(*min_rtt_sample_ms, now_ms); | |
318 return min_rtt_expired; | |
132 } | 319 } |
133 | 320 |
134 void BbrBweSender::EnterStartup() { | 321 void BbrBweSender::EnterStartup() { |
135 mode_ = STARTUP; | 322 mode_ = STARTUP; |
136 pacing_gain_ = kHighGain; | 323 pacing_gain_ = kHighGain; |
137 congestion_window_gain_ = kHighGain; | 324 congestion_window_gain_ = kHighGain; |
138 } | 325 } |
139 | 326 |
140 void BbrBweSender::TryExitingStartup() { | 327 void BbrBweSender::TryExitingStartup() { |
141 if (full_bandwidth_reached_) { | 328 if (full_bandwidth_reached_) { |
(...skipping 25 matching lines...) Expand all Loading... | |
167 | 354 |
168 void BbrBweSender::TryUpdatingCyclePhase(int64_t now_ms) { | 355 void BbrBweSender::TryUpdatingCyclePhase(int64_t now_ms) { |
169 // Each phase should last rougly min_rtt ms time. | 356 // Each phase should last rougly min_rtt ms time. |
170 bool advance_cycle_phase = false; | 357 bool advance_cycle_phase = false; |
171 if (min_rtt_filter_->min_rtt_ms()) | 358 if (min_rtt_filter_->min_rtt_ms()) |
172 advance_cycle_phase = | 359 advance_cycle_phase = |
173 now_ms - cycle_start_time_ms_ > *min_rtt_filter_->min_rtt_ms(); | 360 now_ms - cycle_start_time_ms_ > *min_rtt_filter_->min_rtt_ms(); |
174 // If BBR was probing and it couldn't increase data inflight sufficiently in | 361 // If BBR was probing and it couldn't increase data inflight sufficiently in |
175 // one min_rtt time, continue probing. BBR design doc isn't clear about this, | 362 // one min_rtt time, continue probing. BBR design doc isn't clear about this, |
176 // but condition helps in quicker ramp-up and performs better. | 363 // but condition helps in quicker ramp-up and performs better. |
177 if (pacing_gain_ > 1.0 && | 364 if (pacing_gain_ > 1.0 && congestion_window_->data_inflight() < |
178 prior_in_flight_ < TargetCongestionWindow(pacing_gain_)) | 365 TargetCongestionWindow(pacing_gain_)) |
179 advance_cycle_phase = false; | 366 advance_cycle_phase = false; |
180 // If BBR has already drained queues there is no point in continuing draining | 367 // If BBR has already drained queues there is no point in continuing draining |
181 // phase. | 368 // phase. |
182 if (pacing_gain_ < 1.0 && prior_in_flight_ <= TargetCongestionWindow(1)) | 369 if (pacing_gain_ < 1.0 && |
370 congestion_window_->data_inflight() <= TargetCongestionWindow(1)) | |
183 advance_cycle_phase = true; | 371 advance_cycle_phase = true; |
184 if (advance_cycle_phase) { | 372 if (advance_cycle_phase) { |
185 cycle_index_++; | 373 cycle_index_++; |
186 cycle_index_ %= kGainCycleLength; | 374 cycle_index_ %= kGainCycleLength; |
187 pacing_gain_ = kPacingGain[cycle_index_]; | 375 pacing_gain_ = kPacingGain[cycle_index_]; |
188 cycle_start_time_ms_ = now_ms; | 376 cycle_start_time_ms_ = now_ms; |
189 } | 377 } |
190 } | 378 } |
191 | 379 |
192 void BbrBweSender::TryEnteringProbeRtt(int64_t now_ms) { | 380 void BbrBweSender::TryEnteringProbeRtt(int64_t now_ms) { |
193 if (min_rtt_filter_->min_rtt_expired(now_ms, kMinRttFilterSizeMs) && | 381 if (min_rtt_filter_->MinRttExpired(now_ms) && mode_ != PROBE_RTT) { |
194 mode_ != PROBE_RTT) { | |
195 mode_ = PROBE_RTT; | 382 mode_ = PROBE_RTT; |
196 pacing_gain_ = 1; | 383 pacing_gain_ = 1; |
197 probe_rtt_start_time_ms_ = now_ms; | 384 probe_rtt_start_time_ms_ = now_ms; |
198 minimum_congestion_window_start_time_ms_.reset(); | 385 minimum_congestion_window_start_time_ms_.reset(); |
199 } | 386 } |
200 } | 387 } |
201 | 388 |
202 // minimum_congestion_window_start_time_'s value is set to the first moment when | 389 // |minimum_congestion_window_start_time_|'s value is set to the first moment |
203 // data inflight was less then kMinimumCongestionWindowBytes, we should make | 390 // when data inflight was less then |
204 // sure that BBR has been in PROBE_RTT mode for at least one round or 200ms. | 391 // |CongestionWindow::kMinimumCongestionWindowBytes|, we should make sure that |
392 // BBR has been in PROBE_RTT mode for at least one round or 200ms. | |
205 void BbrBweSender::TryExitingProbeRtt(int64_t now_ms, int64_t round) { | 393 void BbrBweSender::TryExitingProbeRtt(int64_t now_ms, int64_t round) { |
206 if (!minimum_congestion_window_start_time_ms_) { | 394 if (!minimum_congestion_window_start_time_ms_) { |
207 if (congestion_window_->data_inflight() <= | 395 if (congestion_window_->data_inflight() <= |
208 CongestionWindow::kMinimumCongestionWindowBytes) { | 396 CongestionWindow::kMinimumCongestionWindowBytes) { |
209 *minimum_congestion_window_start_time_ms_ = now_ms; | 397 *minimum_congestion_window_start_time_ms_ = now_ms; |
210 minimum_congestion_window_start_round_ = round; | 398 minimum_congestion_window_start_round_ = round; |
211 } | 399 } |
212 } else { | 400 } else { |
213 if (now_ms - *minimum_congestion_window_start_time_ms_ >= | 401 if (now_ms - *minimum_congestion_window_start_time_ms_ >= |
214 kProbeRttDurationMs && | 402 kProbeRttDurationMs && |
215 round - minimum_congestion_window_start_round_ >= | 403 round - minimum_congestion_window_start_round_ >= |
216 kProbeRttDurationRounds) | 404 kProbeRttDurationRounds) |
217 EnterProbeBw(now_ms); | 405 EnterProbeBw(now_ms); |
218 } | 406 } |
219 } | 407 } |
220 | 408 |
409 void BbrBweSender::TryEnteringRecovery(bool new_round_started) { | |
410 // If we are already in Recovery don't try to enter. | |
411 if (mode_ == RECOVERY || !new_round_started || !full_bandwidth_reached_) | |
412 return; | |
413 uint64_t increased_rtt_round_counter = 0; | |
414 // If average rtt for past |kPastRttsFilterSize| rounds has been more than | |
415 // some multiplier of min_rtt_ms enter Recovery. | |
416 for (BbrBweSender::AverageRtt i : past_rtts_) { | |
417 if (i.sum_of_rtts_ms / (int64_t)i.num_samples >= | |
418 *min_rtt_filter_->min_rtt_ms() * kRttIncreaseThreshold) | |
419 increased_rtt_round_counter++; | |
420 } | |
421 if (increased_rtt_round_counter < kPastRttsFilterSize) | |
422 return; | |
423 mode_ = RECOVERY; | |
424 pacing_gain_ = kRecoveryPacingGain; | |
425 congestion_window_gain_ = kRecoveryCongestionWindowGain; | |
426 } | |
427 | |
428 void BbrBweSender::TryExitingRecovery(bool new_round_started) { | |
429 if (mode_ != RECOVERY || !new_round_started || !full_bandwidth_reached_) | |
430 return; | |
431 // If average rtt for the past round has decreased sufficiently exit Recovery. | |
432 if (!past_rtts_.empty()) { | |
433 BbrBweSender::AverageRtt last_round_sample = past_rtts_.back(); | |
434 if (last_round_sample.sum_of_rtts_ms / last_round_sample.num_samples <= | |
435 *min_rtt_filter_->min_rtt_ms() * kRttDecreaseThreshold) { | |
436 EnterProbeBw(clock_->TimeInMilliseconds()); | |
437 } | |
438 } | |
439 } | |
440 | |
221 int64_t BbrBweSender::TimeUntilNextProcess() { | 441 int64_t BbrBweSender::TimeUntilNextProcess() { |
222 return 100; | 442 return 50; |
223 } | 443 } |
224 | 444 |
225 void BbrBweSender::OnPacketsSent(const Packets& packets) { | 445 void BbrBweSender::OnPacketsSent(const Packets& packets) { |
226 last_packet_sent_ = | 446 for (Packet* packet : packets) { |
227 static_cast<const MediaPacket*>(packets.back())->sequence_number(); | 447 if (packet->GetPacketType() == Packet::kMedia) { |
448 MediaPacket* media_packet = static_cast<MediaPacket*>(packet); | |
449 bytes_sent_ += media_packet->payload_size(); | |
450 PacketStats packet_stats = PacketStats( | |
451 media_packet->sequence_number(), 0, | |
452 media_packet->sender_timestamp_ms(), 0, last_packet_ack_time_, | |
453 media_packet->payload_size(), 0, bytes_sent_, 0, bytes_acked_); | |
454 packet_stats_[media_packet->sequence_number()] = packet_stats; | |
455 last_packet_send_time_ = media_packet->sender_timestamp_ms(); | |
456 last_packet_sent_sequence_number_ = media_packet->sequence_number(); | |
457 // If this is the first packet sent for high gain phase, save data for it. | |
458 if (!first_packet_send_time_during_high_gain_ms_ && pacing_gain_ > 1) { | |
459 *first_packet_send_time_during_high_gain_ms_ = last_packet_send_time_; | |
460 data_sent_before_high_gain_started_bytes_ = bytes_sent_; | |
461 first_packet_seq_num_during_high_gain_ = | |
462 media_packet->sequence_number(); | |
463 } | |
464 // This condition ensures that |last_packet_seq_num_during_high_gain_| | |
465 // will contain a sequence number of the last packet sent during high gain | |
466 // phase. | |
467 if (pacing_gain_ > 1) { | |
468 last_packet_send_time_during_high_gain_ms_ = last_packet_send_time_; | |
469 data_sent_before_high_gain_ended_bytes_ = bytes_sent_; | |
470 last_packet_seq_num_during_high_gain_ = media_packet->sequence_number(); | |
471 } | |
472 congestion_window_->PacketSent(media_packet->payload_size()); | |
473 } | |
474 } | |
228 } | 475 } |
229 | 476 |
230 void BbrBweSender::Process() {} | 477 void BbrBweSender::Process() {} |
231 | 478 |
232 BbrBweReceiver::BbrBweReceiver(int flow_id) | 479 BbrBweReceiver::BbrBweReceiver(int flow_id) |
233 : BweReceiver(flow_id, kReceivingRateTimeWindowMs), clock_(0) {} | 480 : BweReceiver(flow_id, kReceivingRateTimeWindowMs), clock_(0) {} |
234 | 481 |
235 BbrBweReceiver::~BbrBweReceiver() {} | 482 BbrBweReceiver::~BbrBweReceiver() {} |
236 | 483 |
237 void BbrBweReceiver::ReceivePacket(int64_t arrival_time_ms, | 484 void BbrBweReceiver::ReceivePacket(int64_t arrival_time_ms, |
238 const MediaPacket& media_packet) {} | 485 const MediaPacket& media_packet) {} |
239 | 486 |
240 FeedbackPacket* BbrBweReceiver::GetFeedback(int64_t now_ms) { | 487 FeedbackPacket* BbrBweReceiver::GetFeedback(int64_t now_ms) { |
241 return nullptr; | 488 return nullptr; |
242 } | 489 } |
243 } // namespace bwe | 490 } // namespace bwe |
244 } // namespace testing | 491 } // namespace testing |
245 } // namespace webrtc | 492 } // namespace webrtc |
OLD | NEW |