Delay the start of loss detection tuner to the time when the first reordering happens. protected by existing --gfe2_reloadable_flag_quic_enable_loss_detection_tuner.
PiperOrigin-RevId: 320984808
Change-Id: Ife4abd76b8d66f1a2af3302cbac5d961fad08dcc
diff --git a/quic/core/congestion_control/general_loss_algorithm.cc b/quic/core/congestion_control/general_loss_algorithm.cc
index 666e7ea..504a163 100644
--- a/quic/core/congestion_control/general_loss_algorithm.cc
+++ b/quic/core/congestion_control/general_loss_algorithm.cc
@@ -24,17 +24,13 @@
float send_to_detection_us = (detection_time - send_time).ToMicroseconds();
return send_to_detection_us / rtt.ToMicroseconds();
}
-} // namespace
-GeneralLossAlgorithm::GeneralLossAlgorithm()
- : loss_detection_timeout_(QuicTime::Zero()),
- reordering_shift_(kDefaultLossDelayShift),
- reordering_threshold_(kDefaultPacketReorderingThreshold),
- use_adaptive_reordering_threshold_(true),
- use_adaptive_time_threshold_(false),
- use_packet_threshold_for_runt_packets_(true),
- least_in_flight_(1),
- packet_number_space_(NUM_PACKET_NUMBER_SPACES) {}
+QuicTime::Delta GetMaxRtt(const RttStats& rtt_stats) {
+ return std::max(kAlarmGranularity,
+ std::max(rtt_stats.previous_srtt(), rtt_stats.latest_rtt()));
+}
+
+} // namespace
// Uses nack counts to decide when packets are lost.
LossDetectionInterface::DetectionStats GeneralLossAlgorithm::DetectLosses(
@@ -67,10 +63,8 @@
}
}
- QuicTime::Delta max_rtt =
- std::max(rtt_stats.previous_srtt(), rtt_stats.latest_rtt());
- max_rtt = std::max(kAlarmGranularity, max_rtt);
- const QuicTime::Delta loss_delay = max_rtt + (max_rtt >> reordering_shift_);
+ const QuicTime::Delta max_rtt = GetMaxRtt(rtt_stats);
+
QuicPacketNumber packet_number = unacked_packets.GetLeastUnacked();
auto it = unacked_packets.begin();
if (least_in_flight_.IsInitialized() && least_in_flight_ >= packet_number) {
@@ -99,6 +93,10 @@
continue;
}
+ if (parent_ != nullptr && largest_newly_acked != packet_number) {
+ parent_->OnReorderingDetected();
+ }
+
if (largest_newly_acked - packet_number >
detection_stats.sent_packets_max_sequence_reordering) {
detection_stats.sent_packets_max_sequence_reordering =
@@ -120,6 +118,7 @@
}
// Time threshold loss detection.
+ const QuicTime::Delta loss_delay = max_rtt + (max_rtt >> reordering_shift_);
QuicTime when_lost = it->sent_time + loss_delay;
if (time < when_lost) {
if (time >=
@@ -178,8 +177,9 @@
}
}
-void GeneralLossAlgorithm::SetPacketNumberSpace(
- PacketNumberSpace packet_number_space) {
+void GeneralLossAlgorithm::Initialize(PacketNumberSpace packet_number_space,
+ LossDetectionInterface* parent) {
+ parent_ = parent;
if (packet_number_space_ < NUM_PACKET_NUMBER_SPACES) {
QUIC_BUG << "Cannot switch packet_number_space";
return;
diff --git a/quic/core/congestion_control/general_loss_algorithm.h b/quic/core/congestion_control/general_loss_algorithm.h
index 950831e..b2ec008 100644
--- a/quic/core/congestion_control/general_loss_algorithm.h
+++ b/quic/core/congestion_control/general_loss_algorithm.h
@@ -22,7 +22,7 @@
// Also implements TCP's early retransmit(RFC5827).
class QUIC_EXPORT_PRIVATE GeneralLossAlgorithm : public LossDetectionInterface {
public:
- GeneralLossAlgorithm();
+ GeneralLossAlgorithm() = default;
GeneralLossAlgorithm(const GeneralLossAlgorithm&) = delete;
GeneralLossAlgorithm& operator=(const GeneralLossAlgorithm&) = delete;
~GeneralLossAlgorithm() override {}
@@ -68,7 +68,13 @@
<< "Unexpected call to GeneralLossAlgorithm::OnConnectionClosed";
}
- void SetPacketNumberSpace(PacketNumberSpace packet_number_space);
+ void OnReorderingDetected() override {
+ DCHECK(false)
+ << "Unexpected call to GeneralLossAlgorithm::OnReorderingDetected";
+ }
+
+ void Initialize(PacketNumberSpace packet_number_space,
+ LossDetectionInterface* parent);
void Reset();
@@ -107,23 +113,24 @@
}
private:
- QuicTime loss_detection_timeout_;
+ LossDetectionInterface* parent_ = nullptr;
+ QuicTime loss_detection_timeout_ = QuicTime::Zero();
// Fraction of a max(SRTT, latest_rtt) to permit reordering before declaring
// loss. Fraction calculated by shifting max(SRTT, latest_rtt) to the right
// by reordering_shift.
- int reordering_shift_;
+ int reordering_shift_ = kDefaultLossDelayShift;
// Reordering threshold for loss detection.
- QuicPacketCount reordering_threshold_;
+ QuicPacketCount reordering_threshold_ = kDefaultPacketReorderingThreshold;
// If true, uses adaptive reordering threshold for loss detection.
- bool use_adaptive_reordering_threshold_;
+ bool use_adaptive_reordering_threshold_ = true;
// If true, uses adaptive time threshold for time based loss detection.
- bool use_adaptive_time_threshold_;
+ bool use_adaptive_time_threshold_ = false;
// If true, uses packet threshold when largest acked is a runt packet.
- bool use_packet_threshold_for_runt_packets_;
+ bool use_packet_threshold_for_runt_packets_ = true;
// The least in flight packet. Loss detection should start from this. Please
// note, least_in_flight_ could be largest packet ever sent + 1.
- QuicPacketNumber least_in_flight_;
- PacketNumberSpace packet_number_space_;
+ QuicPacketNumber least_in_flight_{1};
+ PacketNumberSpace packet_number_space_ = NUM_PACKET_NUMBER_SPACES;
};
} // namespace quic
diff --git a/quic/core/congestion_control/general_loss_algorithm_test.cc b/quic/core/congestion_control/general_loss_algorithm_test.cc
index be33c25..9124e49 100644
--- a/quic/core/congestion_control/general_loss_algorithm_test.cc
+++ b/quic/core/congestion_control/general_loss_algorithm_test.cc
@@ -27,7 +27,7 @@
rtt_stats_.UpdateRtt(QuicTime::Delta::FromMilliseconds(100),
QuicTime::Delta::Zero(), clock_.Now());
EXPECT_LT(0, rtt_stats_.smoothed_rtt().ToMicroseconds());
- loss_algorithm_.SetPacketNumberSpace(HANDSHAKE_DATA);
+ loss_algorithm_.Initialize(HANDSHAKE_DATA, nullptr);
}
~GeneralLossAlgorithmTest() override {}
diff --git a/quic/core/congestion_control/loss_detection_interface.h b/quic/core/congestion_control/loss_detection_interface.h
index 6799de9..8e7bbc3 100644
--- a/quic/core/congestion_control/loss_detection_interface.h
+++ b/quic/core/congestion_control/loss_detection_interface.h
@@ -63,6 +63,11 @@
virtual void OnUserAgentIdKnown() = 0;
virtual void OnConnectionClosed() = 0;
+
+ // Called when a reordering is detected by the loss algorithm, but _before_
+ // the reordering_shift and reordering_threshold are consulted to see whether
+ // it is a loss.
+ virtual void OnReorderingDetected() = 0;
};
} // namespace quic
diff --git a/quic/core/congestion_control/uber_loss_algorithm.cc b/quic/core/congestion_control/uber_loss_algorithm.cc
index 5debad6..986478b 100644
--- a/quic/core/congestion_control/uber_loss_algorithm.cc
+++ b/quic/core/congestion_control/uber_loss_algorithm.cc
@@ -13,8 +13,8 @@
UberLossAlgorithm::UberLossAlgorithm() {
for (int8_t i = INITIAL_DATA; i < NUM_PACKET_NUMBER_SPACES; ++i) {
- general_loss_algorithms_[i].SetPacketNumberSpace(
- static_cast<PacketNumberSpace>(i));
+ general_loss_algorithms_[i].Initialize(static_cast<PacketNumberSpace>(i),
+ this);
}
}
@@ -101,7 +101,7 @@
void UberLossAlgorithm::MaybeStartTuning() {
if (tuner_started_ || !tuning_enabled_ || !min_rtt_available_ ||
- !user_agent_known_) {
+ !user_agent_known_ || !reorder_happened_) {
return;
}
@@ -141,6 +141,22 @@
}
}
+void UberLossAlgorithm::OnReorderingDetected() {
+ const bool tuner_started_before = tuner_started_;
+ const bool reorder_happened_before = reorder_happened_;
+
+ reorder_happened_ = true;
+ MaybeStartTuning();
+
+ if (!tuner_started_before && tuner_started_) {
+ if (reorder_happened_before) {
+ QUIC_CODE_COUNT(quic_loss_tuner_started_after_first_reorder);
+ } else {
+ QUIC_CODE_COUNT(quic_loss_tuner_started_on_first_reorder);
+ }
+ }
+}
+
void UberLossAlgorithm::SetReorderingShift(int reordering_shift) {
for (int8_t i = INITIAL_DATA; i < NUM_PACKET_NUMBER_SPACES; ++i) {
general_loss_algorithms_[i].set_reordering_shift(reordering_shift);
diff --git a/quic/core/congestion_control/uber_loss_algorithm.h b/quic/core/congestion_control/uber_loss_algorithm.h
index 0d1453c..a2c8887 100644
--- a/quic/core/congestion_control/uber_loss_algorithm.h
+++ b/quic/core/congestion_control/uber_loss_algorithm.h
@@ -75,6 +75,7 @@
void OnMinRttAvailable() override;
void OnUserAgentIdKnown() override;
void OnConnectionClosed() override;
+ void OnReorderingDetected() override;
// Sets reordering_shift for all packet number spaces.
void SetReorderingShift(int reordering_shift);
@@ -132,6 +133,7 @@
bool user_agent_known_ =
!GetQuicReloadableFlag(quic_save_user_agent_in_quic_session);
bool tuning_enabled_ = false; // Whether tuning is enabled by config.
+ bool reorder_happened_ = false; // Whether any reordered packet is observed.
};
} // namespace quic
diff --git a/quic/core/congestion_control/uber_loss_algorithm_test.cc b/quic/core/congestion_control/uber_loss_algorithm_test.cc
index e663540..458152f 100644
--- a/quic/core/congestion_control/uber_loss_algorithm_test.cc
+++ b/quic/core/congestion_control/uber_loss_algorithm_test.cc
@@ -262,8 +262,12 @@
EXPECT_EQ(old_reordering_threshold,
loss_algorithm_.GetPacketReorderingThreshold());
- // Tuning should start when MinRtt becomes available.
+ // MinRtt available. Tuner should not start yet because no reordering yet.
loss_algorithm_.OnMinRttAvailable();
+ EXPECT_FALSE(test_tuner->start_called());
+
+ // Reordering happened. Tuner should start now.
+ loss_algorithm_.OnReorderingDetected();
EXPECT_TRUE(test_tuner->start_called());
EXPECT_NE(old_reordering_shift, loss_algorithm_.GetPacketReorderingShift());
EXPECT_NE(old_reordering_threshold,
@@ -294,6 +298,10 @@
EXPECT_EQ(old_reordering_threshold,
loss_algorithm_.GetPacketReorderingThreshold());
+ // Pretend a reodering has happened.
+ loss_algorithm_.OnReorderingDetected();
+ EXPECT_FALSE(test_tuner->start_called());
+
QuicConfig config;
QuicTagVector connection_options;
connection_options.push_back(kELDT);
@@ -336,6 +344,10 @@
EXPECT_EQ(old_reordering_threshold,
loss_algorithm_.GetPacketReorderingThreshold());
+ // Pretend a reodering has happened.
+ loss_algorithm_.OnReorderingDetected();
+ EXPECT_FALSE(test_tuner->start_called());
+
// Parameters should not change since test_tuner->Start() returns false.
loss_algorithm_.OnMinRttAvailable();
EXPECT_TRUE(test_tuner->start_called());
diff --git a/quic/test_tools/quic_test_utils.h b/quic/test_tools/quic_test_utils.h
index 870f99d..2b483b5 100644
--- a/quic/test_tools/quic_test_utils.h
+++ b/quic/test_tools/quic_test_utils.h
@@ -1317,6 +1317,7 @@
MOCK_METHOD(void, OnMinRttAvailable, (), (override));
MOCK_METHOD(void, OnUserAgentIdKnown, (), (override));
MOCK_METHOD(void, OnConnectionClosed, (), (override));
+ MOCK_METHOD(void, OnReorderingDetected, (), (override));
};
class MockAckListener : public QuicAckListenerInterface {