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

Control write loop time limit from knob.

Summary:
This has been hardcoded to SRTT/25 for a long time. However, especially when using DSR this might not be the most appropriate since it can start to get close to real world SRTTs.

Control it via a knob, and also add the behavior such that setting it to 0 effectively disables the time limit.

Reviewed By: jbeshay

Differential Revision: D46084438

fbshipit-source-id: 7dc619fdff1bd5c3f8654c4936200e0340ef94f2
This commit is contained in:
Matt Joras
2023-05-22 16:15:24 -07:00
committed by Facebook GitHub Bot
parent 5edf91ff75
commit 96b2c1b37d
6 changed files with 96 additions and 1 deletions

View File

@@ -168,7 +168,10 @@ BETTER_ENUM(
FIRE_LOOP_EARLY = 0x10001, FIRE_LOOP_EARLY = 0x10001,
// Controls the timer tick used for pacing // Controls the timer tick used for pacing
PACING_TIMER_TICK = 0x10002, PACING_TIMER_TICK = 0x10002,
DEFAULT_STREAM_PRIORITY = 0x10003) // Controls default stream priority
DEFAULT_STREAM_PRIORITY = 0x10003,
// Controls write loop time fraction in terms of srtt
WRITE_LOOP_TIME_FRACTION = 0x10004)
enum class FrameType : uint64_t { enum class FrameType : uint64_t {
PADDING = 0x00, PADDING = 0x00,

View File

@@ -403,6 +403,7 @@ bool writeLoopTimeLimit(
TimePoint loopBeginTime, TimePoint loopBeginTime,
const QuicConnectionStateBase& connection) { const QuicConnectionStateBase& connection) {
return connection.lossState.srtt == 0us || return connection.lossState.srtt == 0us ||
connection.transportSettings.writeLimitRttFraction == 0 ||
Clock::now() - loopBeginTime < connection.lossState.srtt / Clock::now() - loopBeginTime < connection.lossState.srtt /
connection.transportSettings.writeLimitRttFraction; connection.transportSettings.writeLimitRttFraction;
} }

View File

@@ -4077,6 +4077,56 @@ TEST_F(QuicTransportFunctionsTest, WriteLimitBytRttFraction) {
res.packetsWritten); res.packetsWritten);
} }
TEST_F(QuicTransportFunctionsTest, WriteLimitBytRttFractionNoLimit) {
auto conn = createConn();
conn->lossState.srtt = 50ms;
auto mockCongestionController =
std::make_unique<NiceMock<MockCongestionController>>();
auto rawCongestionController = mockCongestionController.get();
conn->congestionController = std::move(mockCongestionController);
conn->transportSettings.batchingMode = QuicBatchingMode::BATCHING_MODE_NONE;
conn->transportSettings.writeLimitRttFraction = 0;
EventBase evb;
auto socket =
std::make_unique<NiceMock<folly::test::MockAsyncUDPSocket>>(&evb);
auto rawSocket = socket.get();
auto stream1 = conn->streamManager->createNextBidirectionalStream().value();
auto buf = buildRandomInputData(2048 * 2048);
writeDataToQuicStream(*stream1, buf->clone(), true);
EXPECT_CALL(*rawSocket, write(_, _)).WillRepeatedly(Return(1));
EXPECT_CALL(*rawCongestionController, getWritableBytes())
.WillRepeatedly(Return(50));
auto writeLoopBeginTime = Clock::now();
auto res = writeQuicDataToSocket(
*rawSocket,
*conn,
*conn->clientConnectionId,
*conn->serverConnectionId,
*aead,
*headerCipher,
getVersion(*conn),
1000 /* packetLimit */,
writeLoopBeginTime);
EXPECT_GT(1000, res.packetsWritten);
EXPECT_EQ(res.probesWritten, 0);
res = writeQuicDataToSocket(
*rawSocket,
*conn,
*conn->clientConnectionId,
*conn->serverConnectionId,
*aead,
*headerCipher,
getVersion(*conn),
1000 /* packetLimit */,
writeLoopBeginTime);
EXPECT_EQ(1000, res.packetsWritten);
}
TEST_F(QuicTransportFunctionsTest, CongestionControlWritableBytesRoundUp) { TEST_F(QuicTransportFunctionsTest, CongestionControlWritableBytesRoundUp) {
auto conn = createConn(); auto conn = createConn();
conn->udpSendPacketLen = 2000; conn->udpSendPacketLen = 2000;

View File

@@ -91,6 +91,34 @@ TEST_F(WriteFunctionsTest, WriteLoopTimeLimit) {
EXPECT_TRUE(verifyAllOutstandingsAreDSR()); EXPECT_TRUE(verifyAllOutstandingsAreDSR());
} }
TEST_F(WriteFunctionsTest, WriteLoopTimeLimitNoLimit) {
prepareFlowControlAndStreamLimit();
auto streamId = prepareOneStream(3000);
auto cid = getTestConnectionId();
auto stream = conn_.streamManager->findStream(streamId);
auto currentBufMetaOffset = stream->writeBufMeta.offset;
size_t packetLimit = 2;
conn_.lossState.srtt = 100ms;
conn_.transportSettings.writeLimitRttFraction = 0;
EXPECT_EQ(2, writePacketizationRequest(conn_, cid, packetLimit, *aead_));
EXPECT_GT(stream->writeBufMeta.offset, currentBufMetaOffset);
EXPECT_EQ(2, stream->retransmissionBufMetas.size());
EXPECT_EQ(2, countInstructions(streamId));
EXPECT_EQ(2, conn_.outstandings.packets.size());
EXPECT_TRUE(verifyAllOutstandingsAreDSR());
// Fake the time so it's in the past.
auto writeLoopBeginTime = Clock::now() - 200ms;
EXPECT_EQ(
1,
writePacketizationRequest(
conn_, cid, packetLimit, *aead_, writeLoopBeginTime));
EXPECT_EQ(3, stream->retransmissionBufMetas.size());
EXPECT_EQ(3, countInstructions(streamId));
EXPECT_EQ(3, conn_.outstandings.packets.size());
EXPECT_TRUE(verifyAllOutstandingsAreDSR());
}
TEST_F(WriteFunctionsTest, WriteTwoInstructions) { TEST_F(WriteFunctionsTest, WriteTwoInstructions) {
prepareFlowControlAndStreamLimit(); prepareFlowControlAndStreamLimit();
auto streamId = prepareOneStream(2000); auto streamId = prepareOneStream(2000);

View File

@@ -1071,6 +1071,15 @@ void QuicServerTransport::registerAllTransportKnobParamHandlers() {
Priority(level, incremental); Priority(level, incremental);
VLOG(3) << "DEFAULT_STREAM_PRIORITY KnobParam received: " << val; VLOG(3) << "DEFAULT_STREAM_PRIORITY KnobParam received: " << val;
}); });
registerTransportKnobParamHandler(
static_cast<uint64_t>(TransportKnobParamId::WRITE_LOOP_TIME_FRACTION),
[](QuicServerTransport* serverTransport, TransportKnobParam::Val value) {
CHECK(serverTransport);
auto val = std::get<uint64_t>(value);
auto serverConn = serverTransport->serverConn_;
serverConn->transportSettings.writeLimitRttFraction = val;
VLOG(3) << "WRITE_LOOP_TIME_FRACTION KnobParam received: " << val;
});
} }
QuicConnectionStats QuicServerTransport::getConnectionsStats() const { QuicConnectionStats QuicServerTransport::getConnectionsStats() const {

View File

@@ -4837,6 +4837,10 @@ TEST_F(QuicServerTransportTest, TestAckFrequencyPolicyKnobHandler) {
{{static_cast<uint64_t>(TransportKnobParamId::DEFAULT_STREAM_PRIORITY), {{static_cast<uint64_t>(TransportKnobParamId::DEFAULT_STREAM_PRIORITY),
"4,0,10"}}); "4,0,10"}});
EXPECT_EQ(server->getTransportSettings().defaultPriority, Priority(4, false)); EXPECT_EQ(server->getTransportSettings().defaultPriority, Priority(4, false));
server->handleKnobParams(
{{static_cast<uint64_t>(TransportKnobParamId::WRITE_LOOP_TIME_FRACTION),
uint64_t(2)}});
EXPECT_EQ(server->getTransportSettings().writeLimitRttFraction, 2);
} }
TEST_F(QuicServerTransportTest, TestSetMaxPacingRateLifecycle) { TEST_F(QuicServerTransportTest, TestSetMaxPacingRateLifecycle) {