| Index: net/quic/core/congestion_control/cubic_test.cc
|
| diff --git a/net/quic/core/congestion_control/cubic_test.cc b/net/quic/core/congestion_control/cubic_test.cc
|
| index c9342c0af6fd4adba003e3a784ecac2674c12411..7020b4803d1c208debfa37ad236fa2374c5142b9 100644
|
| --- a/net/quic/core/congestion_control/cubic_test.cc
|
| +++ b/net/quic/core/congestion_control/cubic_test.cc
|
| @@ -7,15 +7,19 @@
|
| #include <cstdint>
|
|
|
| #include "base/logging.h"
|
| +#include "net/quic/core/quic_flags.h"
|
| #include "net/quic/test_tools/mock_clock.h"
|
| #include "testing/gtest/include/gtest/gtest.h"
|
|
|
| namespace net {
|
| namespace test {
|
|
|
| -const float kBeta = 0.7f; // Default Cubic backoff factor.
|
| +const float kBeta = 0.7f; // Default Cubic backoff factor.
|
| +const float kBetaLastMax = 0.85f; // Default Cubic backoff factor.
|
| const uint32_t kNumConnections = 2;
|
| const float kNConnectionBeta = (kNumConnections - 1 + kBeta) / kNumConnections;
|
| +const float kNConnectionBetaLastMax =
|
| + (kNumConnections - 1 + kBetaLastMax) / kNumConnections;
|
| const float kNConnectionAlpha = 3 * kNumConnections * kNumConnections *
|
| (1 - kNConnectionBeta) / (1 + kNConnectionBeta);
|
|
|
| @@ -29,7 +33,13 @@ class CubicTest : public ::testing::TestWithParam<bool> {
|
| cubic_(&clock_) {
|
| fix_convex_mode_ = GetParam();
|
| cubic_.SetFixConvexMode(fix_convex_mode_);
|
| + cubic_.SetFixBetaLastMax(FLAGS_quic_fix_beta_last_max);
|
| }
|
| +
|
| + QuicByteCount LastMaxCongestionWindow() {
|
| + return cubic_.last_max_congestion_window();
|
| + }
|
| +
|
| const QuicTime::Delta one_ms_;
|
| const QuicTime::Delta hundred_ms_;
|
| MockClock clock_;
|
| @@ -51,7 +61,8 @@ TEST_P(CubicTest, AboveOrigin) {
|
| // Initialize the state.
|
| clock_.AdvanceTime(one_ms_);
|
| const QuicTime initial_time = clock_.ApproximateNow();
|
| - current_cwnd = cubic_.CongestionWindowAfterAck(current_cwnd, rtt_min);
|
| + current_cwnd =
|
| + cubic_.CongestionWindowAfterAck(current_cwnd, rtt_min, initial_time);
|
| ASSERT_EQ(expected_cwnd, current_cwnd);
|
| const QuicPacketCount initial_cwnd = current_cwnd;
|
| // Normal TCP phase.
|
| @@ -64,12 +75,13 @@ TEST_P(CubicTest, AboveOrigin) {
|
| const QuicByteCount max_per_ack_cwnd = current_cwnd;
|
| for (QuicPacketCount n = 1; n < max_per_ack_cwnd / kNConnectionAlpha; ++n) {
|
| // Call once per ACK.
|
| - const QuicByteCount next_cwnd =
|
| - cubic_.CongestionWindowAfterAck(current_cwnd, rtt_min);
|
| + const QuicByteCount next_cwnd = cubic_.CongestionWindowAfterAck(
|
| + current_cwnd, rtt_min, clock_.ApproximateNow());
|
| ASSERT_EQ(current_cwnd, next_cwnd);
|
| }
|
| clock_.AdvanceTime(hundred_ms_);
|
| - current_cwnd = cubic_.CongestionWindowAfterAck(current_cwnd, rtt_min);
|
| + current_cwnd = cubic_.CongestionWindowAfterAck(current_cwnd, rtt_min,
|
| + clock_.ApproximateNow());
|
| if (fix_convex_mode_) {
|
| // When we fix convex mode and the uint64 arithmetic, we
|
| // increase the expected_cwnd only after after the first 100ms,
|
| @@ -86,10 +98,12 @@ TEST_P(CubicTest, AboveOrigin) {
|
| for (QuicPacketCount n = 1; n < current_cwnd; ++n) {
|
| // Call once per ACK.
|
| ASSERT_EQ(current_cwnd,
|
| - cubic_.CongestionWindowAfterAck(current_cwnd, rtt_min));
|
| + cubic_.CongestionWindowAfterAck(current_cwnd, rtt_min,
|
| + clock_.ApproximateNow()));
|
| }
|
| clock_.AdvanceTime(hundred_ms_);
|
| - current_cwnd = cubic_.CongestionWindowAfterAck(current_cwnd, rtt_min);
|
| + current_cwnd = cubic_.CongestionWindowAfterAck(current_cwnd, rtt_min,
|
| + clock_.ApproximateNow());
|
| }
|
| // Total time elapsed so far; add min_rtt (0.1s) here as well.
|
| const float elapsed_time_ms =
|
| @@ -112,14 +126,61 @@ TEST_P(CubicTest, LossEvents) {
|
| fix_convex_mode_ ? current_cwnd : current_cwnd + 1;
|
| // Initialize the state.
|
| clock_.AdvanceTime(one_ms_);
|
| - EXPECT_EQ(expected_cwnd,
|
| - cubic_.CongestionWindowAfterAck(current_cwnd, rtt_min));
|
| + EXPECT_EQ(expected_cwnd, cubic_.CongestionWindowAfterAck(
|
| + current_cwnd, rtt_min, clock_.ApproximateNow()));
|
| +
|
| + // On the first loss, the last max congestion window is set to the
|
| + // congestion window before the loss.
|
| + QuicByteCount pre_loss_cwnd = current_cwnd;
|
| expected_cwnd = static_cast<QuicPacketCount>(current_cwnd * kNConnectionBeta);
|
| + ASSERT_EQ(0u, LastMaxCongestionWindow());
|
| EXPECT_EQ(expected_cwnd,
|
| cubic_.CongestionWindowAfterPacketLoss(current_cwnd));
|
| + ASSERT_EQ(pre_loss_cwnd, LastMaxCongestionWindow());
|
| + current_cwnd = expected_cwnd;
|
| +
|
| + // On the second loss, the current congestion window is
|
| + // significantly lower than the last max congestion window. The
|
| + // last max congestion window will be reduced by an additional
|
| + // backoff factor to allow for competition.
|
| + pre_loss_cwnd = current_cwnd;
|
| + expected_cwnd = static_cast<QuicPacketCount>(current_cwnd * kNConnectionBeta);
|
| + ASSERT_EQ(expected_cwnd,
|
| + cubic_.CongestionWindowAfterPacketLoss(current_cwnd));
|
| + current_cwnd = expected_cwnd;
|
| + EXPECT_GT(pre_loss_cwnd, LastMaxCongestionWindow());
|
| + QuicByteCount expected_last_max =
|
| + FLAGS_quic_fix_beta_last_max
|
| + ? static_cast<QuicPacketCount>(pre_loss_cwnd *
|
| + kNConnectionBetaLastMax)
|
| + : static_cast<QuicPacketCount>(pre_loss_cwnd * kBetaLastMax);
|
| + EXPECT_EQ(expected_last_max, LastMaxCongestionWindow());
|
| + if (FLAGS_quic_fix_beta_last_max) {
|
| + EXPECT_LT(expected_cwnd, LastMaxCongestionWindow());
|
| + } else {
|
| + // If we don't scale kLastBetaMax, the current window is exactly
|
| + // equal to the last max congestion window, which would cause us
|
| + // to land above the origin on the next increase.
|
| + EXPECT_EQ(expected_cwnd, LastMaxCongestionWindow());
|
| + }
|
| + // Simulate an increase, and check that we are below the origin.
|
| + current_cwnd = cubic_.CongestionWindowAfterAck(current_cwnd, rtt_min,
|
| + clock_.ApproximateNow());
|
| + if (FLAGS_quic_fix_beta_last_max) {
|
| + EXPECT_GT(LastMaxCongestionWindow(), current_cwnd);
|
| + } else {
|
| + // Without the bug fix, we will be at or above the origin.
|
| + EXPECT_LE(LastMaxCongestionWindow(), current_cwnd);
|
| + }
|
| +
|
| + // On the final loss, simulate the condition where the congestion
|
| + // window had a chance to grow back to the last congestion window.
|
| + current_cwnd = LastMaxCongestionWindow();
|
| + pre_loss_cwnd = current_cwnd;
|
| expected_cwnd = static_cast<QuicPacketCount>(current_cwnd * kNConnectionBeta);
|
| EXPECT_EQ(expected_cwnd,
|
| cubic_.CongestionWindowAfterPacketLoss(current_cwnd));
|
| + ASSERT_EQ(pre_loss_cwnd, LastMaxCongestionWindow());
|
| }
|
|
|
| TEST_P(CubicTest, BelowOrigin) {
|
| @@ -132,18 +193,20 @@ TEST_P(CubicTest, BelowOrigin) {
|
| fix_convex_mode_ ? current_cwnd : current_cwnd + 1;
|
| // Initialize the state.
|
| clock_.AdvanceTime(one_ms_);
|
| - EXPECT_EQ(expected_cwnd,
|
| - cubic_.CongestionWindowAfterAck(current_cwnd, rtt_min));
|
| + EXPECT_EQ(expected_cwnd, cubic_.CongestionWindowAfterAck(
|
| + current_cwnd, rtt_min, clock_.ApproximateNow()));
|
| expected_cwnd = static_cast<QuicPacketCount>(current_cwnd * kNConnectionBeta);
|
| EXPECT_EQ(expected_cwnd,
|
| cubic_.CongestionWindowAfterPacketLoss(current_cwnd));
|
| current_cwnd = expected_cwnd;
|
| // First update after loss to initialize the epoch.
|
| - current_cwnd = cubic_.CongestionWindowAfterAck(current_cwnd, rtt_min);
|
| + current_cwnd = cubic_.CongestionWindowAfterAck(current_cwnd, rtt_min,
|
| + clock_.ApproximateNow());
|
| // Cubic phase.
|
| for (int i = 0; i < 40; ++i) {
|
| clock_.AdvanceTime(hundred_ms_);
|
| - current_cwnd = cubic_.CongestionWindowAfterAck(current_cwnd, rtt_min);
|
| + current_cwnd = cubic_.CongestionWindowAfterAck(current_cwnd, rtt_min,
|
| + clock_.ApproximateNow());
|
| }
|
| expected_cwnd = 399;
|
| EXPECT_EQ(expected_cwnd, current_cwnd);
|
|
|