blob: 7e0a44e61d910a7da0ca76c26696de3c6828bf6f [file] [log] [blame]
Sebastian Janssona8bf1692018-05-16 14:16:12 +02001/*
2 * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
3 *
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
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10// Based on the Quic implementation in Chromium.
11
12#ifndef MODULES_CONGESTION_CONTROLLER_BBR_BANDWIDTH_SAMPLER_H_
13#define MODULES_CONGESTION_CONTROLLER_BBR_BANDWIDTH_SAMPLER_H_
14
Danil Chapovalov0040b662018-06-18 10:48:16 +020015#include "absl/types/optional.h"
Sebastian Janssona8bf1692018-05-16 14:16:12 +020016#include "api/units/data_rate.h"
17#include "api/units/data_size.h"
18#include "api/units/time_delta.h"
19#include "api/units/timestamp.h"
20#include "modules/congestion_controller/bbr/packet_number_indexed_queue.h"
21
22namespace webrtc {
23namespace bbr {
24
25namespace test {
26class BandwidthSamplerPeer;
27} // namespace test
28
29struct BandwidthSample {
30 // The bandwidth at that particular sample. Zero if no valid bandwidth sample
31 // is available.
32 DataRate bandwidth;
33
34 // The RTT measurement at this particular sample. Zero if no RTT sample is
35 // available. Does not correct for delayed ack time.
36 TimeDelta rtt;
37
38 // Indicates whether the sample might be artificially low because the sender
39 // did not have enough data to send in order to saturate the link.
40 bool is_app_limited;
41
42 BandwidthSample()
43 : bandwidth(DataRate::Zero()),
44 rtt(TimeDelta::Zero()),
45 is_app_limited(false) {}
46};
47
48// BandwidthSampler keeps track of sent and acknowledged packets and outputs a
49// bandwidth sample for every packet acknowledged. The samples are taken for
50// individual packets, and are not filtered; the consumer has to filter the
51// bandwidth samples itself. In certain cases, the sampler will locally severely
52// underestimate the bandwidth, hence a maximum filter with a size of at least
53// one RTT is recommended.
54//
55// This class bases its samples on the slope of two curves: the number of
56// data_size sent over time, and the number of data_size acknowledged as
57// received over time. It produces a sample of both slopes for every packet that
58// gets acknowledged, based on a slope between two points on each of the
59// corresponding curves. Note that due to the packet loss, the number of
60// data_size on each curve might get further and further away from each other,
61// meaning that it is not feasible to compare byte values coming from different
62// curves with each other.
63//
64// The obvious points for measuring slope sample are the ones corresponding to
65// the packet that was just acknowledged. Let us denote them as S_1 (point at
66// which the current packet was sent) and A_1 (point at which the current packet
67// was acknowledged). However, taking a slope requires two points on each line,
68// so estimating bandwidth requires picking a packet in the past with respect to
69// which the slope is measured.
70//
71// For that purpose, BandwidthSampler always keeps track of the most recently
72// acknowledged packet, and records it together with every outgoing packet.
73// When a packet gets acknowledged (A_1), it has not only information about when
74// it itself was sent (S_1), but also the information about the latest
75// acknowledged packet right before it was sent (S_0 and A_0).
76//
77// Based on that data, send and ack rate are estimated as:
78// send_rate = (data_size(S_1) - data_size(S_0)) / (time(S_1) - time(S_0))
79// ack_rate = (data_size(A_1) - data_size(A_0)) / (time(A_1) - time(A_0))
80//
81// Here, the ack rate is intuitively the rate we want to treat as bandwidth.
82// However, in certain cases (e.g. ack compression) the ack rate at a point may
83// end up higher than the rate at which the data was originally sent, which is
84// not indicative of the real bandwidth. Hence, we use the send rate as an upper
85// bound, and the sample value is
86// rate_sample = min(send_rate, ack_rate)
87//
88// An important edge case handled by the sampler is tracking the app-limited
89// samples. There are multiple meaning of "app-limited" used interchangeably,
90// hence it is important to understand and to be able to distinguish between
91// them.
92//
93// Meaning 1: connection state. The connection is said to be app-limited when
94// there is no outstanding data to send. This means that certain bandwidth
95// samples in the future would not be an accurate indication of the link
96// capacity, and it is important to inform consumer about that. Whenever
97// connection becomes app-limited, the sampler is notified via OnAppLimited()
98// method.
99//
100// Meaning 2: a phase in the bandwidth sampler. As soon as the bandwidth
101// sampler becomes notified about the connection being app-limited, it enters
102// app-limited phase. In that phase, all *sent* packets are marked as
103// app-limited. Note that the connection itself does not have to be
104// app-limited during the app-limited phase, and in fact it will not be
105// (otherwise how would it send packets?). The boolean flag below indicates
106// whether the sampler is in that phase.
107//
108// Meaning 3: a flag on the sent packet and on the sample. If a sent packet is
109// sent during the app-limited phase, the resulting sample related to the
110// packet will be marked as app-limited.
111//
112// With the terminology issue out of the way, let us consider the question of
113// what kind of situation it addresses.
114//
115// Consider a scenario where we first send packets 1 to 20 at a regular
116// bandwidth, and then immediately run out of data. After a few seconds, we send
117// packets 21 to 60, and only receive ack for 21 between sending packets 40 and
118// 41. In this case, when we sample bandwidth for packets 21 to 40, the S_0/A_0
119// we use to compute the slope is going to be packet 20, a few seconds apart
120// from the current packet, hence the resulting estimate would be extremely low
121// and not indicative of anything. Only at packet 41 the S_0/A_0 will become 21,
122// meaning that the bandwidth sample would exclude the quiescence.
123//
124// Based on the analysis of that scenario, we implement the following rule: once
125// OnAppLimited() is called, all sent packets will produce app-limited samples
126// up until an ack for a packet that was sent after OnAppLimited() was called.
127// Note that while the scenario above is not the only scenario when the
128// connection is app-limited, the approach works in other cases too.
129class BandwidthSampler {
130 public:
131 BandwidthSampler();
132 ~BandwidthSampler();
133 // Inputs the sent packet information into the sampler. Assumes that all
134 // packets are sent in order. The information about the packet will not be
135 // released from the sampler until the packet is either acknowledged or
136 // declared lost.
137 void OnPacketSent(Timestamp sent_time,
138 int64_t packet_number,
139 DataSize data_size,
140 DataSize data_in_flight);
141
142 // Notifies the sampler that the |packet_number| is acknowledged. Returns a
143 // bandwidth sample. If no bandwidth sample is available, bandwidth is set to
144 // DataRate::Zero().
145 BandwidthSample OnPacketAcknowledged(Timestamp ack_time,
146 int64_t packet_number);
147
148 // Informs the sampler that a packet is considered lost and it should no
149 // longer keep track of it.
150 void OnPacketLost(int64_t packet_number);
151
152 // Informs the sampler that the connection is currently app-limited, causing
153 // the sampler to enter the app-limited phase. The phase will expire by
154 // itself.
155 void OnAppLimited();
156
157 // Remove all the packets lower than the specified packet number.
158 void RemoveObsoletePackets(int64_t least_unacked);
159
160 // Total number of data_size currently acknowledged by the receiver.
161 DataSize total_data_acked() const;
162
163 // Application-limited information exported for debugging.
164 bool is_app_limited() const;
165 int64_t end_of_app_limited_phase() const;
166
167 private:
168 friend class test::BandwidthSamplerPeer;
169 // ConnectionStateOnSentPacket represents the information about a sent packet
170 // and the state of the connection at the moment the packet was sent,
171 // specifically the information about the most recently acknowledged packet at
172 // that moment.
173 struct ConnectionStateOnSentPacket {
174 // Time at which the packet is sent.
175 Timestamp sent_time;
176
177 // Size of the packet.
178 DataSize size;
179
180 // The value of |total_data_sent_| at the time the packet was sent.
181 // Includes the packet itself.
182 DataSize total_data_sent;
183
184 // The value of |total_data_sent_at_last_acked_packet_| at the time the
185 // packet was sent.
186 DataSize total_data_sent_at_last_acked_packet;
187
188 // The value of |last_acked_packet_sent_time_| at the time the packet was
189 // sent.
Danil Chapovalov0040b662018-06-18 10:48:16 +0200190 absl::optional<Timestamp> last_acked_packet_sent_time;
Sebastian Janssona8bf1692018-05-16 14:16:12 +0200191
192 // The value of |last_acked_packet_ack_time_| at the time the packet was
193 // sent.
Danil Chapovalov0040b662018-06-18 10:48:16 +0200194 absl::optional<Timestamp> last_acked_packet_ack_time;
Sebastian Janssona8bf1692018-05-16 14:16:12 +0200195
196 // The value of |total_data_acked_| at the time the packet was
197 // sent.
198 DataSize total_data_acked_at_the_last_acked_packet;
199
200 // The value of |is_app_limited_| at the time the packet was
201 // sent.
202 bool is_app_limited;
203
204 // Snapshot constructor. Records the current state of the bandwidth
205 // sampler.
206 ConnectionStateOnSentPacket(Timestamp sent_time,
207 DataSize size,
208 const BandwidthSampler& sampler);
209
210 // Default constructor. Required to put this structure into
211 // PacketNumberIndexedQueue.
212 ConnectionStateOnSentPacket();
213 ~ConnectionStateOnSentPacket();
214 };
215
216 // The total number of congestion controlled data_size sent during the
217 // connection.
218 DataSize total_data_sent_;
219
220 // The total number of congestion controlled data_size which were
221 // acknowledged.
222 DataSize total_data_acked_;
223
224 // The value of |total_data_sent_| at the time the last acknowledged packet
225 // was sent. Valid only when |last_acked_packet_sent_time_| is valid.
226 DataSize total_data_sent_at_last_acked_packet_;
227
228 // The time at which the last acknowledged packet was sent. Set to
229 // Timestamp::Zero() if no valid timestamp is available.
Danil Chapovalov0040b662018-06-18 10:48:16 +0200230 absl::optional<Timestamp> last_acked_packet_sent_time_;
Sebastian Janssona8bf1692018-05-16 14:16:12 +0200231
232 // The time at which the most recent packet was acknowledged.
Danil Chapovalov0040b662018-06-18 10:48:16 +0200233 absl::optional<Timestamp> last_acked_packet_ack_time_;
Sebastian Janssona8bf1692018-05-16 14:16:12 +0200234
235 // The most recently sent packet.
236 int64_t last_sent_packet_;
237
238 // Indicates whether the bandwidth sampler is currently in an app-limited
239 // phase.
240 bool is_app_limited_;
241
242 // The packet that will be acknowledged after this one will cause the sampler
243 // to exit the app-limited phase.
244 int64_t end_of_app_limited_phase_;
245
246 // Record of the connection state at the point where each packet in flight was
247 // sent, indexed by the packet number.
248 PacketNumberIndexedQueue<ConnectionStateOnSentPacket> connection_state_map_;
249
250 // Handles the actual bandwidth calculations, whereas the outer method handles
251 // retrieving and removing |sent_packet|.
252 BandwidthSample OnPacketAcknowledgedInner(
253 Timestamp ack_time,
254 int64_t packet_number,
255 const ConnectionStateOnSentPacket& sent_packet);
256};
257
258} // namespace bbr
259} // namespace webrtc
260
261#endif // MODULES_CONGESTION_CONTROLLER_BBR_BANDWIDTH_SAMPLER_H_