Let lossdetectioninterface::detectlosses to return a detectionstats which includes the max sequence reordering observed from acked packets. protected by existing flag --gfe2_reloadable_flag_quic_enable_loss_detection_experiment_at_gfe.

The previous change, cl/309076773, used number of reordered _incoming_ packets to decide whether to send feedback to reordering_threshold_session. This CL changed it to use maximum reordering from _acked_ packets instead.

PiperOrigin-RevId: 311210547
Change-Id: I1e1d4d5f842ee7036f23c3832ee3ece8ab38a497
diff --git a/quic/core/congestion_control/general_loss_algorithm.cc b/quic/core/congestion_control/general_loss_algorithm.cc
index 1e67db6..f00045e 100644
--- a/quic/core/congestion_control/general_loss_algorithm.cc
+++ b/quic/core/congestion_control/general_loss_algorithm.cc
@@ -23,13 +23,15 @@
       packet_number_space_(NUM_PACKET_NUMBER_SPACES) {}
 
 // Uses nack counts to decide when packets are lost.
-void GeneralLossAlgorithm::DetectLosses(
+LossDetectionInterface::DetectionStats GeneralLossAlgorithm::DetectLosses(
     const QuicUnackedPacketMap& unacked_packets,
     QuicTime time,
     const RttStats& rtt_stats,
     QuicPacketNumber largest_newly_acked,
     const AckedPacketVector& packets_acked,
     LostPacketVector* packets_lost) {
+  DetectionStats detection_stats;
+
   loss_detection_timeout_ = QuicTime::Zero();
   if (!packets_acked.empty() && least_in_flight_.IsInitialized() &&
       packets_acked.front().packet_number == least_in_flight_) {
@@ -40,7 +42,7 @@
       // do not use this optimization if largest_newly_acked is not the largest
       // packet in packets_acked.
       least_in_flight_ = largest_newly_acked + 1;
-      return;
+      return detection_stats;
     }
     // There is hole in acked_packets, increment least_in_flight_ if possible.
     for (const auto& acked : packets_acked) {
@@ -50,6 +52,7 @@
       ++least_in_flight_;
     }
   }
+
   QuicTime::Delta max_rtt =
       std::max(rtt_stats.previous_srtt(), rtt_stats.latest_rtt());
   max_rtt = std::max(kAlarmGranularity, max_rtt);
@@ -77,9 +80,17 @@
       // Skip packets of different packet number space.
       continue;
     }
+
     if (!it->in_flight) {
       continue;
     }
+
+    if (largest_newly_acked - packet_number >
+        detection_stats.sent_packets_max_sequence_reordering) {
+      detection_stats.sent_packets_max_sequence_reordering =
+          largest_newly_acked - packet_number;
+    }
+
     // Packet threshold loss detection.
     // Skip packet threshold loss detection if largest_newly_acked is a runt.
     const bool skip_packet_threshold_detection =
@@ -108,6 +119,8 @@
     // There is no in flight packet.
     least_in_flight_ = largest_newly_acked + 1;
   }
+
+  return detection_stats;
 }
 
 QuicTime GeneralLossAlgorithm::GetLossTimeout() const {
diff --git a/quic/core/congestion_control/general_loss_algorithm.h b/quic/core/congestion_control/general_loss_algorithm.h
index b9e5d8e..ee8ba64 100644
--- a/quic/core/congestion_control/general_loss_algorithm.h
+++ b/quic/core/congestion_control/general_loss_algorithm.h
@@ -31,12 +31,12 @@
                      Perspective /*perspective*/) override {}
 
   // Uses |largest_acked| and time to decide when packets are lost.
-  void DetectLosses(const QuicUnackedPacketMap& unacked_packets,
-                    QuicTime time,
-                    const RttStats& rtt_stats,
-                    QuicPacketNumber largest_newly_acked,
-                    const AckedPacketVector& packets_acked,
-                    LostPacketVector* packets_lost) override;
+  DetectionStats DetectLosses(const QuicUnackedPacketMap& unacked_packets,
+                              QuicTime time,
+                              const RttStats& rtt_stats,
+                              QuicPacketNumber largest_newly_acked,
+                              const AckedPacketVector& packets_acked,
+                              LostPacketVector* packets_lost) override;
 
   // Returns a non-zero value when the early retransmit timer is active.
   QuicTime GetLossTimeout() const override;
diff --git a/quic/core/congestion_control/general_loss_algorithm_test.cc b/quic/core/congestion_control/general_loss_algorithm_test.cc
index 7bef933..1a58ade 100644
--- a/quic/core/congestion_control/general_loss_algorithm_test.cc
+++ b/quic/core/congestion_control/general_loss_algorithm_test.cc
@@ -61,12 +61,25 @@
   void VerifyLosses(uint64_t largest_newly_acked,
                     const AckedPacketVector& packets_acked,
                     const std::vector<uint64_t>& losses_expected) {
+    return VerifyLosses(largest_newly_acked, packets_acked, losses_expected,
+                        quiche::QuicheOptional<QuicPacketCount>());
+  }
+
+  void VerifyLosses(uint64_t largest_newly_acked,
+                    const AckedPacketVector& packets_acked,
+                    const std::vector<uint64_t>& losses_expected,
+                    quiche::QuicheOptional<QuicPacketCount>
+                        max_sequence_reordering_expected) {
     unacked_packets_.MaybeUpdateLargestAckedOfPacketNumberSpace(
         APPLICATION_DATA, QuicPacketNumber(largest_newly_acked));
     LostPacketVector lost_packets;
-    loss_algorithm_.DetectLosses(unacked_packets_, clock_.Now(), rtt_stats_,
-                                 QuicPacketNumber(largest_newly_acked),
-                                 packets_acked, &lost_packets);
+    LossDetectionInterface::DetectionStats stats = loss_algorithm_.DetectLosses(
+        unacked_packets_, clock_.Now(), rtt_stats_,
+        QuicPacketNumber(largest_newly_acked), packets_acked, &lost_packets);
+    if (max_sequence_reordering_expected.has_value()) {
+      EXPECT_EQ(stats.sent_packets_max_sequence_reordering,
+                max_sequence_reordering_expected.value());
+    }
     ASSERT_EQ(losses_expected.size(), lost_packets.size());
     for (size_t i = 0; i < losses_expected.size(); ++i) {
       EXPECT_EQ(lost_packets[i].packet_number,
@@ -91,19 +104,19 @@
   unacked_packets_.RemoveFromInFlight(QuicPacketNumber(2));
   packets_acked.push_back(AckedPacket(
       QuicPacketNumber(2), kMaxOutgoingPacketSize, QuicTime::Zero()));
-  VerifyLosses(2, packets_acked, std::vector<uint64_t>{});
+  VerifyLosses(2, packets_acked, std::vector<uint64_t>{}, 1);
   packets_acked.clear();
   // No loss on two acks.
   unacked_packets_.RemoveFromInFlight(QuicPacketNumber(3));
   packets_acked.push_back(AckedPacket(
       QuicPacketNumber(3), kMaxOutgoingPacketSize, QuicTime::Zero()));
-  VerifyLosses(3, packets_acked, std::vector<uint64_t>{});
+  VerifyLosses(3, packets_acked, std::vector<uint64_t>{}, 2);
   packets_acked.clear();
   // Loss on three acks.
   unacked_packets_.RemoveFromInFlight(QuicPacketNumber(4));
   packets_acked.push_back(AckedPacket(
       QuicPacketNumber(4), kMaxOutgoingPacketSize, QuicTime::Zero()));
-  VerifyLosses(4, packets_acked, {1});
+  VerifyLosses(4, packets_acked, {1}, 3);
   EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
 }
 
diff --git a/quic/core/congestion_control/loss_detection_interface.h b/quic/core/congestion_control/loss_detection_interface.h
index 2ed7952..8d91976 100644
--- a/quic/core/congestion_control/loss_detection_interface.h
+++ b/quic/core/congestion_control/loss_detection_interface.h
@@ -26,13 +26,19 @@
   virtual void SetFromConfig(const QuicConfig& config,
                              Perspective perspective) = 0;
 
+  struct QUIC_NO_EXPORT DetectionStats {
+    // Maximum sequence reordering observed in newly acked packets.
+    QuicPacketCount sent_packets_max_sequence_reordering = 0;
+  };
+
   // Called when a new ack arrives or the loss alarm fires.
-  virtual void DetectLosses(const QuicUnackedPacketMap& unacked_packets,
-                            QuicTime time,
-                            const RttStats& rtt_stats,
-                            QuicPacketNumber largest_newly_acked,
-                            const AckedPacketVector& packets_acked,
-                            LostPacketVector* packets_lost) = 0;
+  virtual DetectionStats DetectLosses(
+      const QuicUnackedPacketMap& unacked_packets,
+      QuicTime time,
+      const RttStats& rtt_stats,
+      QuicPacketNumber largest_newly_acked,
+      const AckedPacketVector& packets_acked,
+      LostPacketVector* packets_lost) = 0;
 
   // Get the time the LossDetectionAlgorithm wants to re-evaluate losses.
   // Returns QuicTime::Zero if no alarm needs to be set.
diff --git a/quic/core/congestion_control/uber_loss_algorithm.cc b/quic/core/congestion_control/uber_loss_algorithm.cc
index 5059a81..0f294d6 100644
--- a/quic/core/congestion_control/uber_loss_algorithm.cc
+++ b/quic/core/congestion_control/uber_loss_algorithm.cc
@@ -27,13 +27,15 @@
   }
 }
 
-void UberLossAlgorithm::DetectLosses(
+LossDetectionInterface::DetectionStats UberLossAlgorithm::DetectLosses(
     const QuicUnackedPacketMap& unacked_packets,
     QuicTime time,
     const RttStats& rtt_stats,
     QuicPacketNumber /*largest_newly_acked*/,
     const AckedPacketVector& packets_acked,
     LostPacketVector* packets_lost) {
+  DetectionStats overall_stats;
+
   for (int8_t i = INITIAL_DATA; i < NUM_PACKET_NUMBER_SPACES; ++i) {
     const QuicPacketNumber largest_acked =
         unacked_packets.GetLargestAckedOfPacketNumberSpace(
@@ -45,10 +47,16 @@
       continue;
     }
 
-    general_loss_algorithms_[i].DetectLosses(unacked_packets, time, rtt_stats,
-                                             largest_acked, packets_acked,
-                                             packets_lost);
+    DetectionStats stats = general_loss_algorithms_[i].DetectLosses(
+        unacked_packets, time, rtt_stats, largest_acked, packets_acked,
+        packets_lost);
+
+    overall_stats.sent_packets_max_sequence_reordering =
+        std::max(overall_stats.sent_packets_max_sequence_reordering,
+                 stats.sent_packets_max_sequence_reordering);
   }
+
+  return overall_stats;
 }
 
 QuicTime UberLossAlgorithm::GetLossTimeout() const {
diff --git a/quic/core/congestion_control/uber_loss_algorithm.h b/quic/core/congestion_control/uber_loss_algorithm.h
index 1b1c1e8..86b6525 100644
--- a/quic/core/congestion_control/uber_loss_algorithm.h
+++ b/quic/core/congestion_control/uber_loss_algorithm.h
@@ -51,12 +51,12 @@
                      Perspective perspective) override;
 
   // Detects lost packets.
-  void DetectLosses(const QuicUnackedPacketMap& unacked_packets,
-                    QuicTime time,
-                    const RttStats& rtt_stats,
-                    QuicPacketNumber largest_newly_acked,
-                    const AckedPacketVector& packets_acked,
-                    LostPacketVector* packets_lost) override;
+  DetectionStats DetectLosses(const QuicUnackedPacketMap& unacked_packets,
+                              QuicTime time,
+                              const RttStats& rtt_stats,
+                              QuicPacketNumber largest_newly_acked,
+                              const AckedPacketVector& packets_acked,
+                              LostPacketVector* packets_lost) override;
 
   // Returns the earliest time the early retransmit timer should be active.
   QuicTime GetLossTimeout() const override;
diff --git a/quic/core/congestion_control/uber_loss_algorithm_test.cc b/quic/core/congestion_control/uber_loss_algorithm_test.cc
index a3daf09..6fd949f 100644
--- a/quic/core/congestion_control/uber_loss_algorithm_test.cc
+++ b/quic/core/congestion_control/uber_loss_algorithm_test.cc
@@ -11,6 +11,7 @@
 #include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
 #include "net/third_party/quiche/src/quic/test_tools/mock_clock.h"
 #include "net/third_party/quiche/src/quic/test_tools/quic_unacked_packet_map_peer.h"
+#include "net/third_party/quiche/src/common/platform/api/quiche_optional.h"
 
 namespace quic {
 namespace test {
@@ -64,10 +65,23 @@
   void VerifyLosses(uint64_t largest_newly_acked,
                     const AckedPacketVector& packets_acked,
                     const std::vector<uint64_t>& losses_expected) {
+    return VerifyLosses(largest_newly_acked, packets_acked, losses_expected,
+                        quiche::QuicheOptional<QuicPacketCount>());
+  }
+
+  void VerifyLosses(uint64_t largest_newly_acked,
+                    const AckedPacketVector& packets_acked,
+                    const std::vector<uint64_t>& losses_expected,
+                    quiche::QuicheOptional<QuicPacketCount>
+                        max_sequence_reordering_expected) {
     LostPacketVector lost_packets;
-    loss_algorithm_.DetectLosses(*unacked_packets_, clock_.Now(), rtt_stats_,
-                                 QuicPacketNumber(largest_newly_acked),
-                                 packets_acked, &lost_packets);
+    LossDetectionInterface::DetectionStats stats = loss_algorithm_.DetectLosses(
+        *unacked_packets_, clock_.Now(), rtt_stats_,
+        QuicPacketNumber(largest_newly_acked), packets_acked, &lost_packets);
+    if (max_sequence_reordering_expected.has_value()) {
+      EXPECT_EQ(stats.sent_packets_max_sequence_reordering,
+                max_sequence_reordering_expected.value());
+    }
     ASSERT_EQ(losses_expected.size(), lost_packets.size());
     for (size_t i = 0; i < losses_expected.size(); ++i) {
       EXPECT_EQ(lost_packets[i].packet_number,
@@ -98,7 +112,7 @@
   unacked_packets_->MaybeUpdateLargestAckedOfPacketNumberSpace(
       HANDSHAKE_DATA, QuicPacketNumber(4));
   // Verify no packet is detected lost.
-  VerifyLosses(4, packets_acked_, std::vector<uint64_t>{});
+  VerifyLosses(4, packets_acked_, std::vector<uint64_t>{}, 0);
   EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
 }
 
@@ -114,7 +128,7 @@
   unacked_packets_->MaybeUpdateLargestAckedOfPacketNumberSpace(
       APPLICATION_DATA, QuicPacketNumber(4));
   // No packet loss by acking 4.
-  VerifyLosses(4, packets_acked_, std::vector<uint64_t>{});
+  VerifyLosses(4, packets_acked_, std::vector<uint64_t>{}, 1);
   EXPECT_EQ(clock_.Now() + 1.25 * rtt_stats_.smoothed_rtt(),
             loss_algorithm_.GetLossTimeout());
 
@@ -122,14 +136,14 @@
   AckPackets({6});
   unacked_packets_->MaybeUpdateLargestAckedOfPacketNumberSpace(
       APPLICATION_DATA, QuicPacketNumber(6));
-  VerifyLosses(6, packets_acked_, std::vector<uint64_t>{3});
+  VerifyLosses(6, packets_acked_, std::vector<uint64_t>{3}, 3);
   EXPECT_EQ(clock_.Now() + 1.25 * rtt_stats_.smoothed_rtt(),
             loss_algorithm_.GetLossTimeout());
   packets_acked_.clear();
 
   clock_.AdvanceTime(1.25 * rtt_stats_.latest_rtt());
   // Verify 5 will be early retransmitted.
-  VerifyLosses(6, packets_acked_, {5});
+  VerifyLosses(6, packets_acked_, {5}, 1);
 }
 
 TEST_F(UberLossAlgorithmTest, ScenarioC) {
@@ -151,14 +165,14 @@
   unacked_packets_->MaybeUpdateLargestAckedOfPacketNumberSpace(
       HANDSHAKE_DATA, QuicPacketNumber(5));
   // No packet loss by acking 5.
-  VerifyLosses(5, packets_acked_, std::vector<uint64_t>{});
+  VerifyLosses(5, packets_acked_, std::vector<uint64_t>{}, 2);
   EXPECT_EQ(clock_.Now() + 1.25 * rtt_stats_.smoothed_rtt(),
             loss_algorithm_.GetLossTimeout());
   packets_acked_.clear();
 
   clock_.AdvanceTime(1.25 * rtt_stats_.latest_rtt());
   // Verify 2 and 3 will be early retransmitted.
-  VerifyLosses(5, packets_acked_, std::vector<uint64_t>{2, 3});
+  VerifyLosses(5, packets_acked_, std::vector<uint64_t>{2, 3}, 2);
 }
 
 // Regression test for b/133771183.
diff --git a/quic/core/quic_connection_stats.h b/quic/core/quic_connection_stats.h
index 911ea6d..3b0c85d 100644
--- a/quic/core/quic_connection_stats.h
+++ b/quic/core/quic_connection_stats.h
@@ -102,6 +102,9 @@
   // Maximum reordering observed in microseconds
   int64_t max_time_reordering_us = 0;
 
+  // Maximum sequence reordering observed from acked packets.
+  QuicPacketCount sent_packets_max_sequence_reordering = 0;
+
   // The following stats are used only in TcpCubicSender.
   // The number of loss events from TCP's perspective.  Each loss event includes
   // one or more lost packets.
diff --git a/quic/core/quic_connection_test.cc b/quic/core/quic_connection_test.cc
index e9165b2..ffe43c6 100644
--- a/quic/core/quic_connection_test.cc
+++ b/quic/core/quic_connection_test.cc
@@ -2853,7 +2853,8 @@
   LostPacketVector lost_packets;
   lost_packets.push_back(LostPacket(original, kMaxOutgoingPacketSize));
   EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _, _))
-      .WillOnce(SetArgPointee<5>(lost_packets));
+      .WillOnce(DoAll(SetArgPointee<5>(lost_packets),
+                      Return(LossDetectionInterface::DetectionStats())));
   EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _));
   QuicPacketNumber retransmission;
   // Packet 1 is short header for IETF QUIC because the encryption level
@@ -3573,7 +3574,8 @@
   lost_packets.push_back(
       LostPacket(QuicPacketNumber(2), kMaxOutgoingPacketSize));
   EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _, _))
-      .WillOnce(SetArgPointee<5>(lost_packets));
+      .WillOnce(DoAll(SetArgPointee<5>(lost_packets),
+                      Return(LossDetectionInterface::DetectionStats())));
   EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _));
   EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
   EXPECT_FALSE(QuicPacketCreatorPeer::SendVersionInPacket(creator_));
@@ -3655,7 +3657,8 @@
   LostPacketVector lost_packets;
   lost_packets.push_back(LostPacket(last_packet - 1, kMaxOutgoingPacketSize));
   EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _, _))
-      .WillOnce(SetArgPointee<5>(lost_packets));
+      .WillOnce(DoAll(SetArgPointee<5>(lost_packets),
+                      Return(LossDetectionInterface::DetectionStats())));
   EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _));
   EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(AtLeast(1));
   ProcessAckPacket(&nack_two);
@@ -3775,7 +3778,8 @@
   LostPacketVector lost_packets;
   lost_packets.push_back(LostPacket(last_packet - 1, kMaxOutgoingPacketSize));
   EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _, _))
-      .WillOnce(SetArgPointee<5>(lost_packets));
+      .WillOnce(DoAll(SetArgPointee<5>(lost_packets),
+                      Return(LossDetectionInterface::DetectionStats())));
   EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _));
   EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0);
   ProcessAckPacket(&ack);
@@ -3814,7 +3818,8 @@
   lost_packets.push_back(
       LostPacket(QuicPacketNumber(2), kMaxOutgoingPacketSize));
   EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _, _))
-      .WillOnce(SetArgPointee<5>(lost_packets));
+      .WillOnce(DoAll(SetArgPointee<5>(lost_packets),
+                      Return(LossDetectionInterface::DetectionStats())));
   EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _));
   EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, QuicPacketNumber(4), _, _))
       .Times(1);
@@ -3851,7 +3856,8 @@
   LostPacketVector lost_packets;
   lost_packets.push_back(LostPacket(original, kMaxOutgoingPacketSize));
   EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _, _))
-      .WillOnce(SetArgPointee<5>(lost_packets));
+      .WillOnce(DoAll(SetArgPointee<5>(lost_packets),
+                      Return(LossDetectionInterface::DetectionStats())));
   EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _));
   // Packet 1 is short header for IETF QUIC because the encryption level
   // switched to ENCRYPTION_FORWARD_SECURE in SendStreamDataToPeer.
@@ -4068,7 +4074,8 @@
         LostPacket(QuicPacketNumber(i), kMaxOutgoingPacketSize));
   }
   EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _, _))
-      .WillOnce(SetArgPointee<5>(lost_packets));
+      .WillOnce(DoAll(SetArgPointee<5>(lost_packets),
+                      Return(LossDetectionInterface::DetectionStats())));
   EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _));
   EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
   ProcessAckPacket(&nack);
@@ -7156,7 +7163,8 @@
   lost_packets.push_back(
       LostPacket(QuicPacketNumber(1), kMaxOutgoingPacketSize));
   EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _, _))
-      .WillOnce(SetArgPointee<5>(lost_packets));
+      .WillOnce(DoAll(SetArgPointee<5>(lost_packets),
+                      Return(LossDetectionInterface::DetectionStats())));
   EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _));
   ProcessAckPacket(&ack);
   size_t padding_frame_count = writer_->padding_frames().size();
@@ -7501,7 +7509,8 @@
   lost_packets.push_back(
       LostPacket(QuicPacketNumber(3), kMaxOutgoingPacketSize));
   EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _, _))
-      .WillOnce(SetArgPointee<5>(lost_packets));
+      .WillOnce(DoAll(SetArgPointee<5>(lost_packets),
+                      Return(LossDetectionInterface::DetectionStats())));
   EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _));
   EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
   ProcessAckPacket(&nack_three);
diff --git a/quic/core/quic_sent_packet_manager.cc b/quic/core/quic_sent_packet_manager.cc
index 0523b3c..5c99279 100644
--- a/quic/core/quic_sent_packet_manager.cc
+++ b/quic/core/quic_sent_packet_manager.cc
@@ -934,9 +934,17 @@
               packets_acked_.back().packet_number);
     largest_newly_acked_ = packets_acked_.back().packet_number;
   }
-  loss_algorithm_->DetectLosses(unacked_packets_, time, rtt_stats_,
-                                largest_newly_acked_, packets_acked_,
-                                &packets_lost_);
+  LossDetectionInterface::DetectionStats detection_stats =
+      loss_algorithm_->DetectLosses(unacked_packets_, time, rtt_stats_,
+                                    largest_newly_acked_, packets_acked_,
+                                    &packets_lost_);
+
+  if (detection_stats.sent_packets_max_sequence_reordering >
+      stats_->sent_packets_max_sequence_reordering) {
+    stats_->sent_packets_max_sequence_reordering =
+        detection_stats.sent_packets_max_sequence_reordering;
+  }
+
   for (const LostPacket& packet : packets_lost_) {
     QuicTransmissionInfo* info =
         unacked_packets_.GetMutableTransmissionInfo(packet.packet_number);
diff --git a/quic/core/quic_sent_packet_manager_test.cc b/quic/core/quic_sent_packet_manager_test.cc
index 9d62bb6..e11f16e 100644
--- a/quic/core/quic_sent_packet_manager_test.cc
+++ b/quic/core/quic_sent_packet_manager_test.cc
@@ -622,6 +622,7 @@
   EXPECT_EQ(1u, stats_.packets_spuriously_retransmitted);
   EXPECT_EQ(1u, stats_.packets_lost);
   EXPECT_LT(QuicTime::Delta::Zero(), stats_.total_loss_detection_time);
+  EXPECT_LE(1u, stats_.sent_packets_max_sequence_reordering);
 }
 
 TEST_F(QuicSentPacketManagerTest, AckOriginalTransmission) {