1 // Copyright (c) 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "net/quic/congestion_control/cubic_bytes.h"
7 #include "base/basictypes.h"
8 #include "base/logging.h"
9 #include "net/quic/quic_connection_stats.h"
10 #include "net/quic/test_tools/mock_clock.h"
11 #include "testing/gtest/include/gtest/gtest.h"
16 const float kBeta
= 0.7f
; // Default Cubic backoff factor.
17 const uint32 kNumConnections
= 2;
18 const float kNConnectionBeta
= (kNumConnections
- 1 + kBeta
) / kNumConnections
;
19 const float kNConnectionAlpha
= 3 * kNumConnections
* kNumConnections
*
20 (1 - kNConnectionBeta
) / (1 + kNConnectionBeta
);
22 class CubicBytesTest
: public ::testing::Test
{
25 : one_ms_(QuicTime::Delta::FromMilliseconds(1)),
26 hundred_ms_(QuicTime::Delta::FromMilliseconds(100)),
28 const QuicTime::Delta one_ms_
;
29 const QuicTime::Delta hundred_ms_
;
34 TEST_F(CubicBytesTest
, AboveOrigin
) {
36 const QuicTime::Delta rtt_min
= hundred_ms_
;
37 QuicByteCount current_cwnd
= 10 * kDefaultTCPMSS
;
38 QuicByteCount expected_cwnd
= current_cwnd
+ kDefaultTCPMSS
;
39 // Initialize the state.
40 clock_
.AdvanceTime(one_ms_
);
41 EXPECT_EQ(expected_cwnd
, cubic_
.CongestionWindowAfterAck(
42 kDefaultTCPMSS
, current_cwnd
, rtt_min
));
43 current_cwnd
= expected_cwnd
;
45 for (int i
= 0; i
< 48; ++i
) {
46 for (QuicPacketCount n
= 1;
47 n
< current_cwnd
/ kDefaultTCPMSS
/ kNConnectionAlpha
; ++n
) {
49 EXPECT_NEAR(current_cwnd
, cubic_
.CongestionWindowAfterAck(
50 kDefaultTCPMSS
, current_cwnd
, rtt_min
),
53 clock_
.AdvanceTime(hundred_ms_
);
55 cubic_
.CongestionWindowAfterAck(kDefaultTCPMSS
, current_cwnd
, rtt_min
);
56 EXPECT_NEAR(expected_cwnd
, current_cwnd
, kDefaultTCPMSS
);
57 expected_cwnd
+= kDefaultTCPMSS
;
60 for (int i
= 0; i
< 52; ++i
) {
61 for (QuicPacketCount n
= 1; n
< current_cwnd
/ kDefaultTCPMSS
; ++n
) {
63 EXPECT_NEAR(current_cwnd
, cubic_
.CongestionWindowAfterAck(
64 kDefaultTCPMSS
, current_cwnd
, rtt_min
),
67 clock_
.AdvanceTime(hundred_ms_
);
69 cubic_
.CongestionWindowAfterAck(kDefaultTCPMSS
, current_cwnd
, rtt_min
);
71 // Total time elapsed so far; add min_rtt (0.1s) here as well.
72 float elapsed_time_s
= 10.0f
+ 0.1f
;
73 // |expected_cwnd| is initial value of cwnd + K * t^3, where K = 0.4.
75 11 + (elapsed_time_s
* elapsed_time_s
* elapsed_time_s
* 410) / 1024;
76 EXPECT_EQ(expected_cwnd
, current_cwnd
/ kDefaultTCPMSS
);
79 TEST_F(CubicBytesTest
, CwndIncreaseStatsDuringConvexRegion
) {
80 const QuicTime::Delta rtt_min
= hundred_ms_
;
81 QuicByteCount current_cwnd
= 10 * kDefaultTCPMSS
;
82 QuicByteCount expected_cwnd
= current_cwnd
+ kDefaultTCPMSS
;
83 // Initialize controller state.
84 clock_
.AdvanceTime(one_ms_
);
86 cubic_
.CongestionWindowAfterAck(kDefaultTCPMSS
, current_cwnd
, rtt_min
);
87 current_cwnd
= expected_cwnd
;
88 // Testing Reno mode increase.
89 for (int i
= 0; i
< 48; ++i
) {
90 for (QuicPacketCount n
= 1;
91 n
< current_cwnd
/ kDefaultTCPMSS
/ kNConnectionAlpha
; ++n
) {
92 // Call once per ACK, causing cwnd growth in Reno mode.
93 cubic_
.CongestionWindowAfterAck(kDefaultTCPMSS
, current_cwnd
, rtt_min
);
95 // Advance current time so that cwnd update is allowed to happen by Cubic.
96 clock_
.AdvanceTime(hundred_ms_
);
98 cubic_
.CongestionWindowAfterAck(kDefaultTCPMSS
, current_cwnd
, rtt_min
);
99 expected_cwnd
+= kDefaultTCPMSS
;
102 // Testing Cubic mode increase.
103 for (int i
= 0; i
< 52; ++i
) {
104 for (QuicPacketCount n
= 1; n
< current_cwnd
/ kDefaultTCPMSS
; ++n
) {
105 // Call once per ACK.
106 cubic_
.CongestionWindowAfterAck(kDefaultTCPMSS
, current_cwnd
, rtt_min
);
108 clock_
.AdvanceTime(hundred_ms_
);
110 cubic_
.CongestionWindowAfterAck(kDefaultTCPMSS
, current_cwnd
, rtt_min
);
114 TEST_F(CubicBytesTest
, LossEvents
) {
115 const QuicTime::Delta rtt_min
= hundred_ms_
;
116 QuicByteCount current_cwnd
= 422 * kDefaultTCPMSS
;
117 QuicPacketCount expected_cwnd
= current_cwnd
+ kDefaultTCPMSS
;
118 // Initialize the state.
119 clock_
.AdvanceTime(one_ms_
);
120 EXPECT_EQ(expected_cwnd
, cubic_
.CongestionWindowAfterAck(
121 kDefaultTCPMSS
, current_cwnd
, rtt_min
));
122 expected_cwnd
= static_cast<QuicPacketCount
>(current_cwnd
* kNConnectionBeta
);
123 EXPECT_EQ(expected_cwnd
,
124 cubic_
.CongestionWindowAfterPacketLoss(current_cwnd
));
125 expected_cwnd
= static_cast<QuicPacketCount
>(current_cwnd
* kNConnectionBeta
);
126 EXPECT_EQ(expected_cwnd
,
127 cubic_
.CongestionWindowAfterPacketLoss(current_cwnd
));
130 TEST_F(CubicBytesTest
, BelowOrigin
) {
132 const QuicTime::Delta rtt_min
= hundred_ms_
;
133 QuicByteCount current_cwnd
= 422 * kDefaultTCPMSS
;
134 QuicPacketCount expected_cwnd
= current_cwnd
+ kDefaultTCPMSS
;
135 // Initialize the state.
136 clock_
.AdvanceTime(one_ms_
);
137 EXPECT_EQ(expected_cwnd
, cubic_
.CongestionWindowAfterAck(
138 kDefaultTCPMSS
, current_cwnd
, rtt_min
));
139 expected_cwnd
= static_cast<QuicPacketCount
>(current_cwnd
* kNConnectionBeta
);
140 EXPECT_EQ(expected_cwnd
,
141 cubic_
.CongestionWindowAfterPacketLoss(current_cwnd
));
142 current_cwnd
= expected_cwnd
;
143 // First update after loss to initialize the epoch.
145 cubic_
.CongestionWindowAfterAck(kDefaultTCPMSS
, current_cwnd
, rtt_min
);
147 for (int i
= 0; i
< 40; ++i
) {
148 clock_
.AdvanceTime(hundred_ms_
);
150 cubic_
.CongestionWindowAfterAck(kDefaultTCPMSS
, current_cwnd
, rtt_min
);
152 expected_cwnd
= 422 * kDefaultTCPMSS
;
153 EXPECT_EQ(expected_cwnd
, current_cwnd
);