1 /*
2 * Copyright (c) Facebook, Inc. and its affiliates.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <folly/executors/Codel.h>
18
19 #include <chrono>
20 #include <thread>
21
22 #include <folly/portability/GFlags.h>
23 #include <folly/portability/GTest.h>
24
25 DECLARE_int32(codel_target_delay);
26
27 using std::chrono::milliseconds;
28 using std::this_thread::sleep_for;
29
TEST(CodelTest,Basic)30 TEST(CodelTest, Basic) {
31 folly::Codel c;
32 std::this_thread::sleep_for(milliseconds(110));
33 // This interval is overloaded
34 EXPECT_FALSE(c.overloaded(milliseconds(100)));
35 std::this_thread::sleep_for(milliseconds(90));
36 // At least two requests must happen in an interval before they will fail
37 EXPECT_FALSE(c.overloaded(milliseconds(50)));
38 EXPECT_TRUE(c.overloaded(milliseconds(50)));
39 std::this_thread::sleep_for(milliseconds(110));
40 // Previous interval is overloaded, but 2ms isn't enough to fail
41 EXPECT_FALSE(c.overloaded(milliseconds(2)));
42 std::this_thread::sleep_for(milliseconds(90));
43 // 20 ms > target interval * 2
44 EXPECT_TRUE(c.overloaded(milliseconds(20)));
45 }
46
TEST(CodelTest,highLoad)47 TEST(CodelTest, highLoad) {
48 folly::Codel c;
49 c.overloaded(milliseconds(40));
50 EXPECT_EQ(100, c.getLoad());
51 }
52
TEST(CodelTest,mediumLoad)53 TEST(CodelTest, mediumLoad) {
54 folly::Codel c;
55 c.overloaded(milliseconds(20));
56 sleep_for(milliseconds(90));
57 // this is overloaded but this request shouldn't drop because it's not >
58 // slough timeout
59 EXPECT_FALSE(c.overloaded(milliseconds(8)));
60 EXPECT_GT(100, c.getLoad());
61 }
62
TEST(CodelTest,reducingLoad)63 TEST(CodelTest, reducingLoad) {
64 folly::Codel c;
65 c.overloaded(milliseconds(20));
66 sleep_for(milliseconds(90));
67 EXPECT_FALSE(c.overloaded(milliseconds(4)));
68 }
69
TEST(CodelTest,oneRequestNoDrop)70 TEST(CodelTest, oneRequestNoDrop) {
71 folly::Codel c;
72 EXPECT_FALSE(c.overloaded(milliseconds(20)));
73 }
74
TEST(CodelTest,getLoadSanity)75 TEST(CodelTest, getLoadSanity) {
76 folly::Codel c;
77 // should be 100% but leave a litte wiggle room.
78 c.overloaded(milliseconds(10));
79 EXPECT_LT(99, c.getLoad());
80 EXPECT_GT(101, c.getLoad());
81
82 // should be 70% but leave a litte wiggle room.
83 c.overloaded(milliseconds(7));
84 EXPECT_LT(60, c.getLoad());
85 EXPECT_GT(80, c.getLoad());
86
87 // should be 20% but leave a litte wiggle room.
88 c.overloaded(milliseconds(2));
89 EXPECT_LT(10, c.getLoad());
90 EXPECT_GT(30, c.getLoad());
91
92 // this test demonstrates how silly getLoad() is, but silly isn't
93 // necessarily useless
94 }
95
TEST(CodelTest,updateTargetDelay)96 TEST(CodelTest, updateTargetDelay) {
97 folly::Codel c;
98 folly::Codel::Options opts;
99 c.overloaded(milliseconds(40));
100 EXPECT_EQ(100, c.getLoad());
101 EXPECT_EQ(milliseconds(5), c.getOptions().targetDelay());
102
103 // Increase the target delay and test again.
104 opts.setTargetDelay(std::chrono::milliseconds(40));
105 opts.setInterval(std::chrono::milliseconds(100));
106 c.setOptions(opts);
107 EXPECT_EQ(milliseconds(40), c.getOptions().targetDelay());
108 EXPECT_FALSE(c.overloaded(milliseconds(40)));
109
110 // Decrease the target delay and test again.
111 opts.setTargetDelay(std::chrono::milliseconds(5));
112 c.setOptions(opts);
113 EXPECT_EQ(milliseconds(5), c.getOptions().targetDelay());
114 sleep_for(milliseconds(110));
115 EXPECT_FALSE(c.overloaded(milliseconds(40)));
116 EXPECT_TRUE(c.overloaded(milliseconds(40)));
117 }
118
TEST(CodelTest,updateInterval)119 TEST(CodelTest, updateInterval) {
120 folly::Codel c;
121 folly::Codel::Options opts;
122 c.overloaded(milliseconds(50));
123 EXPECT_EQ(100, c.getLoad());
124
125 // Make sure the default interval is correct.
126 EXPECT_EQ(milliseconds(100), c.getOptions().interval());
127 sleep_for(milliseconds(110));
128
129 // Two delayed requests lead to overload.
130 EXPECT_FALSE(c.overloaded(milliseconds(50)));
131 EXPECT_TRUE(c.overloaded(milliseconds(50)));
132
133 // Increase the interval to 200 ms and test again.
134 opts.setInterval(std::chrono::milliseconds(200));
135 opts.setTargetDelay(std::chrono::milliseconds(FLAGS_codel_target_delay));
136
137 c.setOptions(opts);
138 EXPECT_EQ(milliseconds(200), c.getOptions().interval());
139 sleep_for(milliseconds(100));
140 EXPECT_FALSE(c.overloaded(milliseconds(20)));
141 EXPECT_TRUE(c.overloaded(milliseconds(20)));
142 }
143
TEST(CodelTest,invalidParamUpdates)144 TEST(CodelTest, invalidParamUpdates) {
145 folly::Codel c;
146 folly::Codel::Options opts = c.getOptions();
147 EXPECT_EQ(milliseconds(5), c.getOptions().targetDelay());
148 EXPECT_EQ(milliseconds(100), c.getOptions().interval());
149
150 // Set target delay to an invalid value.
151 // Can't be greater than the existing interval period.
152 opts.setTargetDelay(std::chrono::milliseconds(110));
153 try {
154 c.setOptions(opts);
155 FAIL() << "Expected a std::runtime_error";
156 } catch (std::invalid_argument const& err) {
157 std::string error = err.what();
158 EXPECT_EQ("Invalid arguments provided", error);
159 }
160 EXPECT_EQ(milliseconds(5), c.getOptions().targetDelay());
161
162 // Set the target delay to a valid value.
163 opts.setTargetDelay(std::chrono::milliseconds(20));
164 opts.setInterval(std::chrono::milliseconds(100));
165 c.setOptions(opts);
166 EXPECT_EQ(milliseconds(20), c.getOptions().targetDelay());
167
168 // Set the interval to a value smaller than the target delay.
169 opts.setInterval(std::chrono::milliseconds(5));
170 try {
171 c.setOptions(opts);
172 FAIL() << "Expected a std::runtime_error";
173 } catch (std::invalid_argument const& err) {
174 std::string error = err.what();
175 EXPECT_EQ("Invalid arguments provided", error);
176 }
177 EXPECT_EQ(milliseconds(100), c.getOptions().interval());
178
179 // Set the params to a valid combination.
180 opts.setInterval(std::chrono::milliseconds(200));
181 opts.setTargetDelay(std::chrono::milliseconds(10));
182
183 c.setOptions(opts);
184 EXPECT_EQ(milliseconds(10), c.getOptions().targetDelay());
185 EXPECT_EQ(milliseconds(200), c.getOptions().interval());
186 }
187