1 /*
2  * Copyright (c) Facebook, Inc. and its affiliates.
3  *
4  * This source code is licensed under the MIT license found in the
5  * LICENSE file in the root directory of this source tree.
6  *
7  */
8 
9 #include <quic/congestion_control/Pacer.h>
10 
11 #include <folly/portability/GTest.h>
12 #include <quic/congestion_control/TokenlessPacer.h>
13 
14 using namespace testing;
15 
16 namespace quic {
17 namespace test {
18 
19 class TokenlessPacerTest : public Test {
20  public:
SetUp()21   void SetUp() override {
22     conn.transportSettings.pacingTimerTickInterval = 1us;
23   }
24 
25  protected:
26   QuicConnectionStateBase conn{QuicNodeType::Client};
27   TokenlessPacer pacer{conn, conn.transportSettings.minCwndInMss};
28 };
29 
TEST_F(TokenlessPacerTest,RateCalculator)30 TEST_F(TokenlessPacerTest, RateCalculator) {
31   pacer.setPacingRateCalculator([](const QuicConnectionStateBase&,
32                                    uint64_t,
33                                    uint64_t,
34                                    std::chrono::microseconds) {
35     return PacingRate::Builder().setInterval(1234us).setBurstSize(4321).build();
36   });
37   pacer.refreshPacingRate(200000, 200us);
38   EXPECT_EQ(0us, pacer.getTimeUntilNextWrite());
39   EXPECT_EQ(4321, pacer.updateAndGetWriteBatchSize(Clock::now()));
40   EXPECT_NEAR(1234, pacer.getTimeUntilNextWrite().count(), 100);
41 }
42 
TEST_F(TokenlessPacerTest,NoCompensateTimerDrift)43 TEST_F(TokenlessPacerTest, NoCompensateTimerDrift) {
44   pacer.setPacingRateCalculator([](const QuicConnectionStateBase&,
45                                    uint64_t,
46                                    uint64_t,
47                                    std::chrono::microseconds) {
48     return PacingRate::Builder().setInterval(1000us).setBurstSize(10).build();
49   });
50   auto currentTime = Clock::now();
51   pacer.refreshPacingRate(20, 100us); // These two values do not matter here
52   EXPECT_EQ(10, pacer.updateAndGetWriteBatchSize(currentTime + 1000us));
53   EXPECT_EQ(10, pacer.updateAndGetWriteBatchSize(currentTime + 2000us));
54 }
55 
TEST_F(TokenlessPacerTest,NextWriteTime)56 TEST_F(TokenlessPacerTest, NextWriteTime) {
57   EXPECT_EQ(0us, pacer.getTimeUntilNextWrite());
58 
59   pacer.setPacingRateCalculator([](const QuicConnectionStateBase&,
60                                    uint64_t,
61                                    uint64_t,
62                                    std::chrono::microseconds rtt) {
63     return PacingRate::Builder().setInterval(rtt).setBurstSize(10).build();
64   });
65   pacer.refreshPacingRate(20, 1000us);
66   // Right after refresh, it's always 0us. You can always send right after an
67   // ack.
68   EXPECT_EQ(0us, pacer.getTimeUntilNextWrite());
69   EXPECT_EQ(10, pacer.updateAndGetWriteBatchSize(Clock::now()));
70 
71   // Then we use real delay:
72   EXPECT_NEAR(1000, pacer.getTimeUntilNextWrite().count(), 100);
73 }
74 
TEST_F(TokenlessPacerTest,RttFactor)75 TEST_F(TokenlessPacerTest, RttFactor) {
76   auto realRtt = 100ms;
77   bool calculatorCalled = false;
78   pacer.setRttFactor(1, 2);
79   pacer.setPacingRateCalculator([&](const QuicConnectionStateBase&,
80                                     uint64_t,
81                                     uint64_t,
82                                     std::chrono::microseconds rtt) {
83     EXPECT_EQ(rtt, realRtt / 2);
84     calculatorCalled = true;
85     return PacingRate::Builder().setInterval(rtt).setBurstSize(10).build();
86   });
87   pacer.refreshPacingRate(20, realRtt);
88   EXPECT_TRUE(calculatorCalled);
89 }
90 
TEST_F(TokenlessPacerTest,ImpossibleToPace)91 TEST_F(TokenlessPacerTest, ImpossibleToPace) {
92   conn.transportSettings.pacingTimerTickInterval = 1ms;
93   pacer.setPacingRateCalculator([](const QuicConnectionStateBase& conn,
94                                    uint64_t cwndBytes,
95                                    uint64_t,
96                                    std::chrono::microseconds rtt) {
97     return PacingRate::Builder()
98         .setInterval(rtt)
99         .setBurstSize(cwndBytes / conn.udpSendPacketLen)
100         .build();
101   });
102   pacer.refreshPacingRate(200 * conn.udpSendPacketLen, 100us);
103   EXPECT_EQ(0us, pacer.getTimeUntilNextWrite());
104   EXPECT_EQ(
105       conn.transportSettings.writeConnectionDataPacketsLimit,
106       pacer.updateAndGetWriteBatchSize(Clock::now()));
107 }
108 
TEST_F(TokenlessPacerTest,ChangeMaxPacingRate)109 TEST_F(TokenlessPacerTest, ChangeMaxPacingRate) {
110   int calculatorCallCount = 0;
111   pacer.setPacingRateCalculator([&calculatorCallCount](
112                                     const QuicConnectionStateBase& conn,
113                                     uint64_t cwndBytes,
114                                     uint64_t,
115                                     std::chrono::microseconds rtt) {
116     calculatorCallCount++;
117     return PacingRate::Builder()
118         .setInterval(rtt)
119         .setBurstSize(cwndBytes / conn.udpSendPacketLen)
120         .build();
121   });
122   auto rtt = 500 * 1000us;
123   auto timestamp = Clock::now();
124   // Request pacing at 50 Mbps
125   pacer.refreshPacingRate(3125000, rtt);
126   EXPECT_EQ(1, calculatorCallCount);
127   EXPECT_EQ(
128       3125000 / kDefaultUDPSendPacketLen,
129       pacer.updateAndGetWriteBatchSize(timestamp));
130   EXPECT_EQ(rtt.count(), pacer.getTimeUntilNextWrite(timestamp).count());
131 
132   // Set max pacing rate to 40 Mbps
133   pacer.setMaxPacingRate(5 * 1000 * 1000u); // Bytes per second
134   // This should bring down the pacer rate to 40 Mbps
135   EXPECT_EQ(0us, pacer.getTimeUntilNextWrite(timestamp));
136   auto burst = pacer.updateAndGetWriteBatchSize(timestamp);
137   auto interval = pacer.getTimeUntilNextWrite(timestamp);
138   uint64_t pacerRate =
139       burst * kDefaultUDPSendPacketLen * std::chrono::seconds{1} / interval;
140   EXPECT_EQ(5 * 1000 * 1000u, pacerRate);
141   pacer.reset();
142   // Requesting a rate of 50 Mbps should not change interval or burst
143   pacer.refreshPacingRate(3125000, rtt);
144   EXPECT_EQ(1, calculatorCallCount); // Calculator not called again.
145   EXPECT_EQ(burst, pacer.updateAndGetWriteBatchSize(timestamp));
146   EXPECT_EQ(interval.count(), pacer.getTimeUntilNextWrite(timestamp).count());
147   pacer.reset();
148 
149   // The setPacingRate API shouldn't make changes either
150   pacer.setPacingRate(6250 * 1000u); // 50 Mbps
151   EXPECT_EQ(burst, pacer.updateAndGetWriteBatchSize(timestamp));
152   EXPECT_EQ(interval.count(), pacer.getTimeUntilNextWrite(timestamp).count());
153   pacer.reset();
154 
155   // Increasing max pacing rate to 75 Mbps shouldn't make changes
156   pacer.setMaxPacingRate(9375 * 1000u);
157   EXPECT_EQ(burst, pacer.updateAndGetWriteBatchSize(timestamp));
158   EXPECT_EQ(interval.count(), pacer.getTimeUntilNextWrite(timestamp).count());
159   pacer.reset();
160 
161   // Increase pacing to 50 Mbps and ensure it takes effect
162   pacer.refreshPacingRate(3125000, rtt);
163   EXPECT_EQ(2, calculatorCallCount); // Calculator called
164   EXPECT_EQ(
165       3125000 / kDefaultUDPSendPacketLen,
166       pacer.updateAndGetWriteBatchSize(timestamp));
167   EXPECT_EQ(rtt.count(), pacer.getTimeUntilNextWrite(timestamp).count());
168   pacer.reset();
169 
170   // Increase pacing to 80 Mbps using alternative API and ensure rate is limited
171   // to 75 Mbps
172   pacer.setPacingRate(10 * 1000 * 1000u);
173   burst = pacer.updateAndGetWriteBatchSize(timestamp);
174   interval = pacer.getTimeUntilNextWrite(timestamp);
175   pacerRate =
176       burst * kDefaultUDPSendPacketLen * std::chrono::seconds{1} / interval;
177   EXPECT_NEAR(9375 * 1000u, pacerRate, 1000); // To accommodate rounding
178 }
179 
TEST_F(TokenlessPacerTest,SetMaxPacingRateOnUnlimitedPacer)180 TEST_F(TokenlessPacerTest, SetMaxPacingRateOnUnlimitedPacer) {
181   auto timestamp = Clock::now();
182   // Pacing is currently not pacing
183   EXPECT_EQ(0us, pacer.getTimeUntilNextWrite(timestamp));
184   EXPECT_NE(0, pacer.updateAndGetWriteBatchSize(timestamp));
185   EXPECT_EQ(0us, pacer.getTimeUntilNextWrite(timestamp));
186 
187   // Set max pacing rate 40 Mbps and ensure it took effect
188   pacer.setMaxPacingRate(5 * 1000 * 1000u); // Bytes per second
189   EXPECT_EQ(0us, pacer.getTimeUntilNextWrite(timestamp));
190   auto burst = pacer.updateAndGetWriteBatchSize(timestamp);
191   auto interval = pacer.getTimeUntilNextWrite(timestamp);
192   uint64_t pacerRate =
193       burst * kDefaultUDPSendPacketLen * std::chrono::seconds{1} / interval;
194   EXPECT_NEAR(5 * 1000 * 1000u, pacerRate, 1000); // To accommodate rounding
195 }
196 
TEST_F(TokenlessPacerTest,SetZeroPacingRate)197 TEST_F(TokenlessPacerTest, SetZeroPacingRate) {
198   auto timestamp = Clock::now();
199   // A Zero pacing rate should not result in a divide-by-zero
200   conn.transportSettings.pacingTimerTickInterval = 1000us;
201   pacer.setPacingRate(0);
202   EXPECT_EQ(0, pacer.updateAndGetWriteBatchSize(timestamp));
203   EXPECT_EQ(1000, pacer.getTimeUntilNextWrite(timestamp).count());
204 }
205 
TEST_F(TokenlessPacerTest,RefreshPacingRateWhenRTTIsZero)206 TEST_F(TokenlessPacerTest, RefreshPacingRateWhenRTTIsZero) {
207   auto timestamp = Clock::now();
208   // rtt=0 should not result in a divide-by-zero
209   conn.transportSettings.pacingTimerTickInterval = 1000us;
210   pacer.refreshPacingRate(100, 0us);
211   // Verify burst is writeConnectionDataPacketsLimit and interval is
212   // 0us right after writing
213   EXPECT_EQ(
214       conn.transportSettings.writeConnectionDataPacketsLimit,
215       pacer.updateAndGetWriteBatchSize(timestamp));
216   EXPECT_EQ(0us, pacer.getTimeUntilNextWrite(timestamp));
217 }
218 
219 } // namespace test
220 } // namespace quic
221