summaryrefslogtreecommitdiff
path: root/chromium/net/third_party/quiche/src/quiche/quic/core/congestion_control/bandwidth_sampler.h
blob: 3ca09d1c57875edd0aa51298edcd67fe2e617f7b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef QUICHE_QUIC_CORE_CONGESTION_CONTROL_BANDWIDTH_SAMPLER_H_
#define QUICHE_QUIC_CORE_CONGESTION_CONTROL_BANDWIDTH_SAMPLER_H_

#include "quiche/quic/core/congestion_control/send_algorithm_interface.h"
#include "quiche/quic/core/congestion_control/windowed_filter.h"
#include "quiche/quic/core/packet_number_indexed_queue.h"
#include "quiche/quic/core/quic_bandwidth.h"
#include "quiche/quic/core/quic_packet_number.h"
#include "quiche/quic/core/quic_packets.h"
#include "quiche/quic/core/quic_time.h"
#include "quiche/quic/core/quic_types.h"
#include "quiche/quic/core/quic_unacked_packet_map.h"
#include "quiche/quic/platform/api/quic_export.h"
#include "quiche/quic/platform/api/quic_flags.h"
#include "quiche/common/quiche_circular_deque.h"

namespace quic {

namespace test {
class BandwidthSamplerPeer;
}  // namespace test

// A subset of BandwidthSampler::ConnectionStateOnSentPacket which is returned
// to the caller when the packet is acked or lost.
struct QUIC_EXPORT_PRIVATE SendTimeState {
  SendTimeState()
      : is_valid(false),
        is_app_limited(false),
        total_bytes_sent(0),
        total_bytes_acked(0),
        total_bytes_lost(0),
        bytes_in_flight(0) {}

  SendTimeState(bool is_app_limited, QuicByteCount total_bytes_sent,
                QuicByteCount total_bytes_acked, QuicByteCount total_bytes_lost,
                QuicByteCount bytes_in_flight)
      : is_valid(true),
        is_app_limited(is_app_limited),
        total_bytes_sent(total_bytes_sent),
        total_bytes_acked(total_bytes_acked),
        total_bytes_lost(total_bytes_lost),
        bytes_in_flight(bytes_in_flight) {}

  SendTimeState(const SendTimeState& other) = default;
  SendTimeState& operator=(const SendTimeState& other) = default;

  friend QUIC_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os,
                                                      const SendTimeState& s);

  // Whether other states in this object is valid.
  bool is_valid;

  // Whether the sender is app limited at the time the packet was sent.
  // App limited bandwidth sample might be artificially low because the sender
  // did not have enough data to send in order to saturate the link.
  bool is_app_limited;

  // Total number of sent bytes at the time the packet was sent.
  // Includes the packet itself.
  QuicByteCount total_bytes_sent;

  // Total number of acked bytes at the time the packet was sent.
  QuicByteCount total_bytes_acked;

  // Total number of lost bytes at the time the packet was sent.
  QuicByteCount total_bytes_lost;

  // Total number of inflight bytes at the time the packet was sent.
  // Includes the packet itself.
  // It should be equal to |total_bytes_sent| minus the sum of
  // |total_bytes_acked|, |total_bytes_lost| and total neutered bytes.
  QuicByteCount bytes_in_flight;
};

struct QUIC_NO_EXPORT ExtraAckedEvent {
  // The excess bytes acknowlwedged in the time delta for this event.
  QuicByteCount extra_acked = 0;

  // The bytes acknowledged and time delta from the event.
  QuicByteCount bytes_acked = 0;
  QuicTime::Delta time_delta = QuicTime::Delta::Zero();
  // The round trip of the event.
  QuicRoundTripCount round = 0;

  bool operator>=(const ExtraAckedEvent& other) const {
    return extra_acked >= other.extra_acked;
  }
  bool operator==(const ExtraAckedEvent& other) const {
    return extra_acked == other.extra_acked;
  }
};

struct QUIC_EXPORT_PRIVATE BandwidthSample {
  // The bandwidth at that particular sample. Zero if no valid bandwidth sample
  // is available.
  QuicBandwidth bandwidth = QuicBandwidth::Zero();

  // The RTT measurement at this particular sample.  Zero if no RTT sample is
  // available.  Does not correct for delayed ack time.
  QuicTime::Delta rtt = QuicTime::Delta::Zero();

  // |send_rate| is computed from the current packet being acked('P') and an
  // earlier packet that is acked before P was sent.
  QuicBandwidth send_rate = QuicBandwidth::Infinite();

  // States captured when the packet was sent.
  SendTimeState state_at_send;
};

// MaxAckHeightTracker is part of the BandwidthSampler. It is called after every
// ack event to keep track the degree of ack aggregation(a.k.a "ack height").
class QUIC_EXPORT_PRIVATE MaxAckHeightTracker {
 public:
  explicit MaxAckHeightTracker(QuicRoundTripCount initial_filter_window)
      : max_ack_height_filter_(initial_filter_window, ExtraAckedEvent(), 0) {}

  QuicByteCount Get() const {
    return max_ack_height_filter_.GetBest().extra_acked;
  }

  QuicByteCount Update(QuicBandwidth bandwidth_estimate,
                       bool is_new_max_bandwidth,
                       QuicRoundTripCount round_trip_count,
                       QuicPacketNumber last_sent_packet_number,
                       QuicPacketNumber last_acked_packet_number,
                       QuicTime ack_time, QuicByteCount bytes_acked);

  void SetFilterWindowLength(QuicRoundTripCount length) {
    max_ack_height_filter_.SetWindowLength(length);
  }

  void Reset(QuicByteCount new_height, QuicRoundTripCount new_time) {
    ExtraAckedEvent new_event;
    new_event.extra_acked = new_height;
    new_event.round = new_time;
    max_ack_height_filter_.Reset(new_event, new_time);
  }

  void SetAckAggregationBandwidthThreshold(double threshold) {
    ack_aggregation_bandwidth_threshold_ = threshold;
  }

  void SetStartNewAggregationEpochAfterFullRound(bool value) {
    start_new_aggregation_epoch_after_full_round_ = value;
  }

  void SetReduceExtraAckedOnBandwidthIncrease(bool value) {
    reduce_extra_acked_on_bandwidth_increase_ = value;
  }

  double ack_aggregation_bandwidth_threshold() const {
    return ack_aggregation_bandwidth_threshold_;
  }

  uint64_t num_ack_aggregation_epochs() const {
    return num_ack_aggregation_epochs_;
  }

 private:
  // Tracks the maximum number of bytes acked faster than the estimated
  // bandwidth.
  using MaxAckHeightFilter =
      WindowedFilter<ExtraAckedEvent, MaxFilter<ExtraAckedEvent>,
                     QuicRoundTripCount, QuicRoundTripCount>;
  MaxAckHeightFilter max_ack_height_filter_;

  // The time this aggregation started and the number of bytes acked during it.
  QuicTime aggregation_epoch_start_time_ = QuicTime::Zero();
  QuicByteCount aggregation_epoch_bytes_ = 0;
  // The last sent packet number before the current aggregation epoch started.
  QuicPacketNumber last_sent_packet_number_before_epoch_;
  // The number of ack aggregation epochs ever started, including the ongoing
  // one. Stats only.
  uint64_t num_ack_aggregation_epochs_ = 0;
  double ack_aggregation_bandwidth_threshold_ =
      GetQuicFlag(quic_ack_aggregation_bandwidth_threshold);
  bool start_new_aggregation_epoch_after_full_round_ = false;
  bool reduce_extra_acked_on_bandwidth_increase_ = false;
};

// An interface common to any class that can provide bandwidth samples from the
// information per individual acknowledged packet.
class QUIC_EXPORT_PRIVATE BandwidthSamplerInterface {
 public:
  virtual ~BandwidthSamplerInterface() {}

  // Inputs the sent packet information into the sampler. Assumes that all
  // packets are sent in order. The information about the packet will not be
  // released from the sampler until it the packet is either acknowledged or
  // declared lost.
  virtual void OnPacketSent(
      QuicTime sent_time, QuicPacketNumber packet_number, QuicByteCount bytes,
      QuicByteCount bytes_in_flight,
      HasRetransmittableData has_retransmittable_data) = 0;

  virtual void OnPacketNeutered(QuicPacketNumber packet_number) = 0;

  struct QUIC_NO_EXPORT CongestionEventSample {
    // The maximum bandwidth sample from all acked packets.
    // QuicBandwidth::Zero() if no samples are available.
    QuicBandwidth sample_max_bandwidth = QuicBandwidth::Zero();
    // Whether |sample_max_bandwidth| is from a app-limited sample.
    bool sample_is_app_limited = false;
    // The minimum rtt sample from all acked packets.
    // QuicTime::Delta::Infinite() if no samples are available.
    QuicTime::Delta sample_rtt = QuicTime::Delta::Infinite();
    // For each packet p in acked packets, this is the max value of INFLIGHT(p),
    // where INFLIGHT(p) is the number of bytes acked while p is inflight.
    QuicByteCount sample_max_inflight = 0;
    // The send state of the largest packet in acked_packets, unless it is
    // empty. If acked_packets is empty, it's the send state of the largest
    // packet in lost_packets.
    SendTimeState last_packet_send_state;
    // The number of extra bytes acked from this ack event, compared to what is
    // expected from the flow's bandwidth. Larger value means more ack
    // aggregation.
    QuicByteCount extra_acked = 0;
  };
  // Notifies the sampler that at |ack_time|, all packets in |acked_packets|
  // have been acked, and all packets in |lost_packets| have been lost.
  // See the comments in CongestionEventSample for the return value.
  // |max_bandwidth| is the windowed maximum observed bandwidth.
  // |est_bandwidth_upper_bound| is an upper bound of estimated bandwidth used
  // to calculate extra_acked.
  virtual CongestionEventSample OnCongestionEvent(
      QuicTime ack_time, const AckedPacketVector& acked_packets,
      const LostPacketVector& lost_packets, QuicBandwidth max_bandwidth,
      QuicBandwidth est_bandwidth_upper_bound,
      QuicRoundTripCount round_trip_count) = 0;

  // Informs the sampler that the connection is currently app-limited, causing
  // the sampler to enter the app-limited phase.  The phase will expire by
  // itself.
  virtual void OnAppLimited() = 0;

  // Remove all the packets lower than the specified packet number.
  virtual void RemoveObsoletePackets(QuicPacketNumber least_unacked) = 0;

  // Total number of bytes sent/acked/lost/neutered in the connection.
  virtual QuicByteCount total_bytes_sent() const = 0;
  virtual QuicByteCount total_bytes_acked() const = 0;
  virtual QuicByteCount total_bytes_lost() const = 0;
  virtual QuicByteCount total_bytes_neutered() const = 0;

  // Application-limited information exported for debugging.
  virtual bool is_app_limited() const = 0;

  virtual QuicPacketNumber end_of_app_limited_phase() const = 0;
};

// BandwidthSampler keeps track of sent and acknowledged packets and outputs a
// bandwidth sample for every packet acknowledged. The samples are taken for
// individual packets, and are not filtered; the consumer has to filter the
// bandwidth samples itself. In certain cases, the sampler will locally severely
// underestimate the bandwidth, hence a maximum filter with a size of at least
// one RTT is recommended.
//
// This class bases its samples on the slope of two curves: the number of bytes
// sent over time, and the number of bytes acknowledged as received over time.
// It produces a sample of both slopes for every packet that gets acknowledged,
// based on a slope between two points on each of the corresponding curves. Note
// that due to the packet loss, the number of bytes on each curve might get
// further and further away from each other, meaning that it is not feasible to
// compare byte values coming from different curves with each other.
//
// The obvious points for measuring slope sample are the ones corresponding to
// the packet that was just acknowledged. Let us denote them as S_1 (point at
// which the current packet was sent) and A_1 (point at which the current packet
// was acknowledged). However, taking a slope requires two points on each line,
// so estimating bandwidth requires picking a packet in the past with respect to
// which the slope is measured.
//
// For that purpose, BandwidthSampler always keeps track of the most recently
// acknowledged packet, and records it together with every outgoing packet.
// When a packet gets acknowledged (A_1), it has not only information about when
// it itself was sent (S_1), but also the information about a previously
// acknowledged packet before it was sent (S_0 and A_0).
//
// Based on that data, send and ack rate are estimated as:
//   send_rate = (bytes(S_1) - bytes(S_0)) / (time(S_1) - time(S_0))
//   ack_rate = (bytes(A_1) - bytes(A_0)) / (time(A_1) - time(A_0))
//
// Here, the ack rate is intuitively the rate we want to treat as bandwidth.
// However, in certain cases (e.g. ack compression) the ack rate at a point may
// end up higher than the rate at which the data was originally sent, which is
// not indicative of the real bandwidth. Hence, we use the send rate as an upper
// bound, and the sample value is
//   rate_sample = min(send_rate, ack_rate)
//
// An important edge case handled by the sampler is tracking the app-limited
// samples. There are multiple meaning of "app-limited" used interchangeably,
// hence it is important to understand and to be able to distinguish between
// them.
//
// Meaning 1: connection state. The connection is said to be app-limited when
// there is no outstanding data to send. This means that certain bandwidth
// samples in the future would not be an accurate indication of the link
// capacity, and it is important to inform consumer about that. Whenever
// connection becomes app-limited, the sampler is notified via OnAppLimited()
// method.
//
// Meaning 2: a phase in the bandwidth sampler. As soon as the bandwidth
// sampler becomes notified about the connection being app-limited, it enters
// app-limited phase. In that phase, all *sent* packets are marked as
// app-limited. Note that the connection itself does not have to be
// app-limited during the app-limited phase, and in fact it will not be
// (otherwise how would it send packets?). The boolean flag below indicates
// whether the sampler is in that phase.
//
// Meaning 3: a flag on the sent packet and on the sample. If a sent packet is
// sent during the app-limited phase, the resulting sample related to the
// packet will be marked as app-limited.
//
// With the terminology issue out of the way, let us consider the question of
// what kind of situation it addresses.
//
// Consider a scenario where we first send packets 1 to 20 at a regular
// bandwidth, and then immediately run out of data. After a few seconds, we send
// packets 21 to 60, and only receive ack for 21 between sending packets 40 and
// 41. In this case, when we sample bandwidth for packets 21 to 40, the S_0/A_0
// we use to compute the slope is going to be packet 20, a few seconds apart
// from the current packet, hence the resulting estimate would be extremely low
// and not indicative of anything. Only at packet 41 the S_0/A_0 will become 21,
// meaning that the bandwidth sample would exclude the quiescence.
//
// Based on the analysis of that scenario, we implement the following rule: once
// OnAppLimited() is called, all sent packets will produce app-limited samples
// up until an ack for a packet that was sent after OnAppLimited() was called.
// Note that while the scenario above is not the only scenario when the
// connection is app-limited, the approach works in other cases too.
class QUIC_EXPORT_PRIVATE BandwidthSampler : public BandwidthSamplerInterface {
 public:
  BandwidthSampler(const QuicUnackedPacketMap* unacked_packet_map,
                   QuicRoundTripCount max_height_tracker_window_length);

  // Copy states from |other|. This is useful when changing send algorithms in
  // the middle of a connection.
  BandwidthSampler(const BandwidthSampler& other);
  ~BandwidthSampler() override;

  void OnPacketSent(QuicTime sent_time, QuicPacketNumber packet_number,
                    QuicByteCount bytes, QuicByteCount bytes_in_flight,
                    HasRetransmittableData has_retransmittable_data) override;
  void OnPacketNeutered(QuicPacketNumber packet_number) override;

  CongestionEventSample OnCongestionEvent(
      QuicTime ack_time, const AckedPacketVector& acked_packets,
      const LostPacketVector& lost_packets, QuicBandwidth max_bandwidth,
      QuicBandwidth est_bandwidth_upper_bound,
      QuicRoundTripCount round_trip_count) override;
  QuicByteCount OnAckEventEnd(QuicBandwidth bandwidth_estimate,
                              bool is_new_max_bandwidth,
                              QuicRoundTripCount round_trip_count);

  void OnAppLimited() override;

  void RemoveObsoletePackets(QuicPacketNumber least_unacked) override;

  QuicByteCount total_bytes_sent() const override;
  QuicByteCount total_bytes_acked() const override;
  QuicByteCount total_bytes_lost() const override;
  QuicByteCount total_bytes_neutered() const override;

  bool is_app_limited() const override;

  QuicPacketNumber end_of_app_limited_phase() const override;

  QuicByteCount max_ack_height() const { return max_ack_height_tracker_.Get(); }

  uint64_t num_ack_aggregation_epochs() const {
    return max_ack_height_tracker_.num_ack_aggregation_epochs();
  }

  void SetMaxAckHeightTrackerWindowLength(QuicRoundTripCount length) {
    max_ack_height_tracker_.SetFilterWindowLength(length);
  }

  void ResetMaxAckHeightTracker(QuicByteCount new_height,
                                QuicRoundTripCount new_time) {
    max_ack_height_tracker_.Reset(new_height, new_time);
  }

  void SetStartNewAggregationEpochAfterFullRound(bool value) {
    max_ack_height_tracker_.SetStartNewAggregationEpochAfterFullRound(value);
  }

  void SetLimitMaxAckHeightTrackerBySendRate(bool value) {
    limit_max_ack_height_tracker_by_send_rate_ = value;
  }

  void SetReduceExtraAckedOnBandwidthIncrease(bool value) {
    max_ack_height_tracker_.SetReduceExtraAckedOnBandwidthIncrease(value);
  }

  // AckPoint represents a point on the ack line.
  struct QUIC_NO_EXPORT AckPoint {
    QuicTime ack_time = QuicTime::Zero();
    QuicByteCount total_bytes_acked = 0;

    friend QUIC_NO_EXPORT std::ostream& operator<<(std::ostream& os,
                                                   const AckPoint& ack_point) {
      return os << ack_point.ack_time << ":" << ack_point.total_bytes_acked;
    }
  };

  // RecentAckPoints maintains the most recent 2 ack points at distinct times.
  class QUIC_NO_EXPORT RecentAckPoints {
   public:
    void Update(QuicTime ack_time, QuicByteCount total_bytes_acked) {
      QUICHE_DCHECK_GE(total_bytes_acked, ack_points_[1].total_bytes_acked);

      if (ack_time < ack_points_[1].ack_time) {
        // This can only happen when time goes backwards, we use the smaller
        // timestamp for the most recent ack point in that case.
        // TODO(wub): Add a QUIC_BUG if ack time stops going backwards.
        ack_points_[1].ack_time = ack_time;
      } else if (ack_time > ack_points_[1].ack_time) {
        ack_points_[0] = ack_points_[1];
        ack_points_[1].ack_time = ack_time;
      }

      ack_points_[1].total_bytes_acked = total_bytes_acked;
    }

    void Clear() { ack_points_[0] = ack_points_[1] = AckPoint(); }

    const AckPoint& MostRecentPoint() const { return ack_points_[1]; }

    const AckPoint& LessRecentPoint() const {
      if (ack_points_[0].total_bytes_acked != 0) {
        return ack_points_[0];
      }

      return ack_points_[1];
    }

   private:
    AckPoint ack_points_[2];
  };

  void EnableOverestimateAvoidance();
  bool IsOverestimateAvoidanceEnabled() const {
    return overestimate_avoidance_;
  }

 private:
  friend class test::BandwidthSamplerPeer;

  // ConnectionStateOnSentPacket represents the information about a sent packet
  // and the state of the connection at the moment the packet was sent,
  // specifically the information about the most recently acknowledged packet at
  // that moment.
  struct QUIC_EXPORT_PRIVATE ConnectionStateOnSentPacket {
    // Time at which the packet is sent.
    QuicTime sent_time;

    // Size of the packet.
    QuicByteCount size;

    // The value of |total_bytes_sent_at_last_acked_packet_| at the time the
    // packet was sent.
    QuicByteCount total_bytes_sent_at_last_acked_packet;

    // The value of |last_acked_packet_sent_time_| at the time the packet was
    // sent.
    QuicTime last_acked_packet_sent_time;

    // The value of |last_acked_packet_ack_time_| at the time the packet was
    // sent.
    QuicTime last_acked_packet_ack_time;

    // Send time states that are returned to the congestion controller when the
    // packet is acked or lost.
    SendTimeState send_time_state;

    // Snapshot constructor. Records the current state of the bandwidth
    // sampler.
    // |bytes_in_flight| is the bytes in flight right after the packet is sent.
    ConnectionStateOnSentPacket(QuicTime sent_time, QuicByteCount size,
                                QuicByteCount bytes_in_flight,
                                const BandwidthSampler& sampler)
        : sent_time(sent_time),
          size(size),
          total_bytes_sent_at_last_acked_packet(
              sampler.total_bytes_sent_at_last_acked_packet_),
          last_acked_packet_sent_time(sampler.last_acked_packet_sent_time_),
          last_acked_packet_ack_time(sampler.last_acked_packet_ack_time_),
          send_time_state(sampler.is_app_limited_, sampler.total_bytes_sent_,
                          sampler.total_bytes_acked_, sampler.total_bytes_lost_,
                          bytes_in_flight) {}

    // Default constructor.  Required to put this structure into
    // PacketNumberIndexedQueue.
    ConnectionStateOnSentPacket()
        : sent_time(QuicTime::Zero()),
          size(0),
          total_bytes_sent_at_last_acked_packet(0),
          last_acked_packet_sent_time(QuicTime::Zero()),
          last_acked_packet_ack_time(QuicTime::Zero()) {}

    friend QUIC_EXPORT_PRIVATE std::ostream& operator<<(
        std::ostream& os, const ConnectionStateOnSentPacket& p) {
      os << "{sent_time:" << p.sent_time << ", size:" << p.size
         << ", total_bytes_sent_at_last_acked_packet:"
         << p.total_bytes_sent_at_last_acked_packet
         << ", last_acked_packet_sent_time:" << p.last_acked_packet_sent_time
         << ", last_acked_packet_ack_time:" << p.last_acked_packet_ack_time
         << ", send_time_state:" << p.send_time_state << "}";
      return os;
    }
  };

  BandwidthSample OnPacketAcknowledged(QuicTime ack_time,
                                       QuicPacketNumber packet_number);

  SendTimeState OnPacketLost(QuicPacketNumber packet_number,
                             QuicPacketLength bytes_lost);

  // Copy a subset of the (private) ConnectionStateOnSentPacket to the (public)
  // SendTimeState. Always set send_time_state->is_valid to true.
  void SentPacketToSendTimeState(const ConnectionStateOnSentPacket& sent_packet,
                                 SendTimeState* send_time_state) const;

  // Choose the best a0 from |a0_candidates_| to calculate the ack rate.
  // |total_bytes_acked| is the total bytes acked when the packet being acked is
  // sent. The best a0 is chosen as follows:
  // - If there's only one candidate, use it.
  // - If there are multiple candidates, let a[n] be the nth candidate, and
  //   a[n-1].total_bytes_acked <= |total_bytes_acked| < a[n].total_bytes_acked,
  //   use a[n-1].
  // - If all candidates's total_bytes_acked is > |total_bytes_acked|, use a[0].
  //   This may happen when acks are received out of order, and ack[n] caused
  //   some candidates of ack[n-x] to be removed.
  // - If all candidates's total_bytes_acked is <= |total_bytes_acked|, use
  //   a[a.size()-1].
  bool ChooseA0Point(QuicByteCount total_bytes_acked, AckPoint* a0);

  // The total number of congestion controlled bytes sent during the connection.
  QuicByteCount total_bytes_sent_;

  // The total number of congestion controlled bytes which were acknowledged.
  QuicByteCount total_bytes_acked_;

  // The total number of congestion controlled bytes which were lost.
  QuicByteCount total_bytes_lost_;

  // The total number of congestion controlled bytes which have been neutered.
  QuicByteCount total_bytes_neutered_;

  // The value of |total_bytes_sent_| at the time the last acknowledged packet
  // was sent. Valid only when |last_acked_packet_sent_time_| is valid.
  QuicByteCount total_bytes_sent_at_last_acked_packet_;

  // The time at which the last acknowledged packet was sent. Set to
  // QuicTime::Zero() if no valid timestamp is available.
  QuicTime last_acked_packet_sent_time_;

  // The time at which the most recent packet was acknowledged.
  QuicTime last_acked_packet_ack_time_;

  // The most recently sent packet.
  QuicPacketNumber last_sent_packet_;

  // The most recently acked packet.
  QuicPacketNumber last_acked_packet_;

  // Indicates whether the bandwidth sampler is currently in an app-limited
  // phase.
  bool is_app_limited_;

  // The packet that will be acknowledged after this one will cause the sampler
  // to exit the app-limited phase.
  QuicPacketNumber end_of_app_limited_phase_;

  // Record of the connection state at the point where each packet in flight was
  // sent, indexed by the packet number.
  PacketNumberIndexedQueue<ConnectionStateOnSentPacket> connection_state_map_;

  RecentAckPoints recent_ack_points_;
  quiche::QuicheCircularDeque<AckPoint> a0_candidates_;

  // Maximum number of tracked packets.
  const QuicPacketCount max_tracked_packets_;

  // The main unacked packet map.  Used for outputting extra debugging details.
  // May be null.
  // TODO(vasilvv): remove this once it's no longer useful for debugging.
  const QuicUnackedPacketMap* unacked_packet_map_;

  // Handles the actual bandwidth calculations, whereas the outer method handles
  // retrieving and removing |sent_packet|.
  BandwidthSample OnPacketAcknowledgedInner(
      QuicTime ack_time, QuicPacketNumber packet_number,
      const ConnectionStateOnSentPacket& sent_packet);

  MaxAckHeightTracker max_ack_height_tracker_;
  QuicByteCount total_bytes_acked_after_last_ack_event_;

  // True if connection option 'BSAO' is set.
  bool overestimate_avoidance_;

  // True if connection option 'BBRB' is set.
  bool limit_max_ack_height_tracker_by_send_rate_;
};

}  // namespace quic

#endif  // QUICHE_QUIC_CORE_CONGESTION_CONTROL_BANDWIDTH_SAMPLER_H_