1
0
mirror of https://github.com/facebookincubator/mvfst.git synced 2025-08-06 22:22:38 +03:00

Count number of packets sent and lost by type

Summary:
We currently have a count of the number of packets retransmitted, and the number of packets marked as lost spuriously, but we do *not* have the total number of packets sent or lost, which is necessary to calculate statistics such as % of packets retransmitted % of losses that are spurious.

At the moment, we do not count loss events for D6D packets. Will likely add a separate counter for those in a subsequent diff.

Reviewed By: xttjsn

Differential Revision: D25540531

fbshipit-source-id: 80db729eb8c91f7805d342f4aab302a5b3ca4347
This commit is contained in:
Brandon Schlinker
2020-12-14 16:31:49 -08:00
committed by Facebook GitHub Bot
parent f8dde62725
commit 68d660c46d
7 changed files with 197 additions and 1 deletions

View File

@@ -132,6 +132,10 @@ class QuicSocket {
uint64_t pacingBurstSize{0}; uint64_t pacingBurstSize{0};
std::chrono::microseconds pacingInterval{0us}; std::chrono::microseconds pacingInterval{0us};
uint32_t packetsRetransmitted{0}; uint32_t packetsRetransmitted{0};
uint32_t totalPacketsSent{0};
uint32_t totalPacketsMarkedLost{0};
uint32_t totalPacketsMarkedLostByPto{0};
uint32_t totalPacketsMarkedLostByReorderingThreshold{0};
uint32_t packetsSpuriouslyLost{0}; uint32_t packetsSpuriouslyLost{0};
uint32_t timeoutBasedLoss{0}; uint32_t timeoutBasedLoss{0};
std::chrono::microseconds pto{0us}; std::chrono::microseconds pto{0us};

View File

@@ -585,6 +585,13 @@ QuicSocket::TransportInfo QuicTransportBase::getTransportInfo() const {
transportInfo.pacingBurstSize = burstSize; transportInfo.pacingBurstSize = burstSize;
transportInfo.pacingInterval = pacingInterval; transportInfo.pacingInterval = pacingInterval;
transportInfo.packetsRetransmitted = conn_->lossState.rtxCount; transportInfo.packetsRetransmitted = conn_->lossState.rtxCount;
transportInfo.totalPacketsSent = conn_->lossState.totalPacketsSent;
transportInfo.totalPacketsMarkedLost =
conn_->lossState.totalPacketsMarkedLost;
transportInfo.totalPacketsMarkedLostByPto =
conn_->lossState.totalPacketsMarkedLostByPto;
transportInfo.totalPacketsMarkedLostByReorderingThreshold =
conn_->lossState.totalPacketsMarkedLostByReorderingThreshold;
transportInfo.timeoutBasedLoss = conn_->lossState.timeoutBasedRtxCount; transportInfo.timeoutBasedLoss = conn_->lossState.timeoutBasedRtxCount;
transportInfo.totalBytesRetransmitted = transportInfo.totalBytesRetransmitted =
conn_->lossState.totalBytesRetransmitted; conn_->lossState.totalBytesRetransmitted;

View File

@@ -660,6 +660,7 @@ void updateConnection(
conn.pendingEvents.setLossDetectionAlarm = retransmittable; conn.pendingEvents.setLossDetectionAlarm = retransmittable;
} }
conn.lossState.totalBytesSent += encodedSize; conn.lossState.totalBytesSent += encodedSize;
conn.lossState.totalPacketsSent++;
if (!retransmittable && !isPing) { if (!retransmittable && !isPing) {
DCHECK(!packetEvent); DCHECK(!packetEvent);

View File

@@ -2129,6 +2129,15 @@ TEST_F(QuicTransportFunctionsTest, TotalBytesSentUpdate) {
EXPECT_EQ(5555, conn->lossState.totalBytesSent); EXPECT_EQ(5555, conn->lossState.totalBytesSent);
} }
TEST_F(QuicTransportFunctionsTest, TotalPacketsSentUpdate) {
const auto startTotalPacketsSent = 1234;
auto conn = createConn();
conn->lossState.totalPacketsSent = startTotalPacketsSent;
auto packet = buildEmptyPacket(*conn, PacketNumberSpace::Handshake);
updateConnection(*conn, folly::none, packet.packet, TimePoint{}, 4321);
EXPECT_EQ(startTotalPacketsSent + 1, conn->lossState.totalPacketsSent);
}
TEST_F(QuicTransportFunctionsTest, TimeoutBasedRetxCountUpdate) { TEST_F(QuicTransportFunctionsTest, TimeoutBasedRetxCountUpdate) {
auto conn = createConn(); auto conn = createConn();
auto stream = conn->streamManager->createNextBidirectionalStream().value(); auto stream = conn->streamManager->createNextBidirectionalStream().value();

View File

@@ -283,10 +283,17 @@ folly::Optional<CongestionController::LossEvent> detectLossPackets(
<< " handshake=" << pkt.metadata.isHandshake << " " << conn; << " handshake=" << pkt.metadata.isHandshake << " " << conn;
// Rather than erasing here, instead mark the packet as lost so we can // Rather than erasing here, instead mark the packet as lost so we can
// determine if this was spurious later. // determine if this was spurious later.
conn.lossState.totalPacketsMarkedLost++;
if (lostByTimeout) {
conn.lossState.totalPacketsMarkedLostByPto++;
}
if (lostByReorder) {
conn.lossState.totalPacketsMarkedLostByReorderingThreshold++;
}
conn.outstandings.declaredLostCount++; conn.outstandings.declaredLostCount++;
iter->declaredLost = true; iter->declaredLost = true;
iter++; iter++;
} } // while (iter != conn.outstandings.packets.end()) {
// if there are observers, enqueue a function to call it // if there are observers, enqueue a function to call it
if (observerLossEvent.hasPackets()) { if (observerLossEvent.hasPackets()) {

View File

@@ -2084,6 +2084,163 @@ TEST_F(QuicLossFunctionsTest, TestNoInstrumentationObserverCallback) {
EXPECT_EQ(0, size(conn->pendingCallbacks)); EXPECT_EQ(0, size(conn->pendingCallbacks));
} }
TEST_F(QuicLossFunctionsTest, TotalPacketsMarkedLostByReordering) {
auto conn = createConn();
auto noopLossVisitor = [](auto&, auto&, bool) {};
// send 7 packets
PacketNum largestSent = 0;
for (int i = 0; i < 7; ++i) {
largestSent =
sendPacket(*conn, TimePoint(i * 10ms), folly::none, PacketType::OneRtt);
}
// Some packets are already acked
conn->outstandings.packets.erase(
getFirstOutstandingPacket(*conn, PacketNumberSpace::AppData) + 2,
getFirstOutstandingPacket(*conn, PacketNumberSpace::AppData) + 5);
// setting a very low reordering threshold to force loss by reorder
conn->lossState.reorderingThreshold = 1;
// setting time out parameters higher than the time at which detectLossPackets
// is called to make sure there are no losses by timeout
conn->lossState.srtt = 400ms;
conn->lossState.lrtt = 350ms;
conn->transportSettings.timeReorderingThreshDividend = 1.0;
conn->transportSettings.timeReorderingThreshDivisor = 1.0;
TimePoint checkTime = TimePoint(200ms);
detectLossPackets(
*conn,
largestSent + 1,
noopLossVisitor,
checkTime,
PacketNumberSpace::AppData);
// Sent 7 packets, out of 0, 1, 2, 3, 4, 5, 6 -- we deleted (acked) 2,3,4
// 0, 1, and 5 should be marked lost due to reordering, none due to timeout
// 6 is outstanding / on the wire still (no determination made)
EXPECT_EQ(3, conn->lossState.totalPacketsMarkedLost);
EXPECT_EQ(0, conn->lossState.totalPacketsMarkedLostByPto);
EXPECT_EQ(3, conn->lossState.totalPacketsMarkedLostByReorderingThreshold);
}
TEST_F(QuicLossFunctionsTest, TotalPacketsMarkedLostByPto) {
auto conn = createConn();
auto noopLossVisitor = [](auto&, auto&, bool) {};
// send 7 packets
PacketNum largestSent = 0;
for (int i = 0; i < 7; ++i) {
largestSent =
sendPacket(*conn, TimePoint(i * 10ms), folly::none, PacketType::OneRtt);
}
// setting a very high reordering threshold to force loss by timeout only
conn->lossState.reorderingThreshold = 100;
// setting time out parameters lower than the time at which detectLossPackets
// is called to make sure all packets timeout
conn->lossState.srtt = 400ms;
conn->lossState.lrtt = 350ms;
conn->transportSettings.timeReorderingThreshDividend = 1.0;
conn->transportSettings.timeReorderingThreshDivisor = 1.0;
TimePoint checkTime = TimePoint(500ms);
detectLossPackets(
*conn,
largestSent + 1,
noopLossVisitor,
checkTime,
PacketNumberSpace::AppData);
// All 7 packets should be marked as lost by PTO
EXPECT_EQ(7, conn->lossState.totalPacketsMarkedLost);
EXPECT_EQ(7, conn->lossState.totalPacketsMarkedLostByPto);
EXPECT_EQ(0, conn->lossState.totalPacketsMarkedLostByReorderingThreshold);
}
TEST_F(QuicLossFunctionsTest, TotalPacketsMarkedLostByPtoPartial) {
auto conn = createConn();
auto noopLossVisitor = [](auto&, auto&, bool) {};
// send 7 packets
PacketNum largestSent = 0;
for (int i = 0; i < 7; ++i) {
largestSent =
sendPacket(*conn, TimePoint(i * 10ms), folly::none, PacketType::OneRtt);
}
// Some packets are already acked
conn->outstandings.packets.erase(
getFirstOutstandingPacket(*conn, PacketNumberSpace::AppData) + 2,
getFirstOutstandingPacket(*conn, PacketNumberSpace::AppData) + 5);
// setting a very high reordering threshold to force loss by timeout only
conn->lossState.reorderingThreshold = 100;
// setting time out parameters lower than the time at which detectLossPackets
// is called to make sure all packets timeout
conn->lossState.srtt = 400ms;
conn->lossState.lrtt = 350ms;
conn->transportSettings.timeReorderingThreshDividend = 1.0;
conn->transportSettings.timeReorderingThreshDivisor = 1.0;
TimePoint checkTime = TimePoint(500ms);
detectLossPackets(
*conn,
largestSent + 1,
noopLossVisitor,
checkTime,
PacketNumberSpace::AppData);
// Sent 7 packets, out of 0, 1, 2, 3, 4, 5, 6 -- we deleted (acked) 2,3,4
// 0, 1, 5, and 6 should be marked lost due to timeout, none due to reordering
EXPECT_EQ(4, conn->lossState.totalPacketsMarkedLost);
EXPECT_EQ(4, conn->lossState.totalPacketsMarkedLostByPto);
EXPECT_EQ(0, conn->lossState.totalPacketsMarkedLostByReorderingThreshold);
}
TEST_F(QuicLossFunctionsTest, TotalPacketsMarkedLostByPtoAndReordering) {
auto conn = createConn();
auto noopLossVisitor = [](auto&, auto&, bool) {};
// send 7 packets
PacketNum largestSent = 0;
for (int i = 0; i < 7; ++i) {
largestSent =
sendPacket(*conn, TimePoint(i * 10ms), folly::none, PacketType::OneRtt);
}
// Some packets are already acked
conn->outstandings.packets.erase(
getFirstOutstandingPacket(*conn, PacketNumberSpace::AppData) + 2,
getFirstOutstandingPacket(*conn, PacketNumberSpace::AppData) + 5);
// setting a low reorder threshold
conn->lossState.reorderingThreshold = 1;
// setting time out parameters lower than the time at which detectLossPackets
// is called to make sure all packets timeout
conn->lossState.srtt = 400ms;
conn->lossState.lrtt = 350ms;
conn->transportSettings.timeReorderingThreshDividend = 1.0;
conn->transportSettings.timeReorderingThreshDivisor = 1.0;
TimePoint checkTime = TimePoint(500ms);
detectLossPackets(
*conn,
largestSent + 1,
noopLossVisitor,
checkTime,
PacketNumberSpace::AppData);
// Sent 7 packets, out of 0, 1, 2, 3, 4, 5, 6 -- we deleted (acked) 2,3,4
// 0, 1, and 5 should be marked lost due to reordering AND timeout
// 6 should be marked as lost due to timeout only
EXPECT_EQ(4, conn->lossState.totalPacketsMarkedLost);
EXPECT_EQ(4, conn->lossState.totalPacketsMarkedLostByPto);
EXPECT_EQ(3, conn->lossState.totalPacketsMarkedLostByReorderingThreshold);
}
INSTANTIATE_TEST_CASE_P( INSTANTIATE_TEST_CASE_P(
QuicLossFunctionsTests, QuicLossFunctionsTests,
QuicLossFunctionsTest, QuicLossFunctionsTest,

View File

@@ -452,6 +452,17 @@ struct LossState {
// The total number of bytes acked on this connection when the last time a // The total number of bytes acked on this connection when the last time a
// packet is acked. // packet is acked.
uint64_t totalBytesAckedAtLastAck{0}; uint64_t totalBytesAckedAtLastAck{0};
// Total number of packets sent on this connection, including retransmissions.
uint32_t totalPacketsSent{0};
// Total number of packets which were declared lost, including losses that
// we later detected were spurious (see spuriousLossCount below).
uint32_t totalPacketsMarkedLost{0};
// Total number of packets which were declared lost due to PTO; a packet can
// marked as lost by multiple detection mechanisms.
uint32_t totalPacketsMarkedLostByPto{0};
// Total number of packets which were declared lost based on the reordering
// threshold; a packet can marked as lost by multiple detection mechanisms.
uint32_t totalPacketsMarkedLostByReorderingThreshold{0};
// Inflight bytes // Inflight bytes
uint64_t inflightBytes{0}; uint64_t inflightBytes{0};
// Reordering threshold used // Reordering threshold used