• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
3  *
4  *  Use of this source code is governed by a BSD-style license
5  *  that can be found in the LICENSE file in the root of the source
6  *  tree. An additional intellectual property rights grant can be found
7  *  in the file PATENTS.  All contributing project authors may
8  *  be found in the AUTHORS file in the root of the source tree.
9  */
10 
11 #include "rtc_base/rate_limiter.h"
12 
13 #include <memory>
14 
15 #include "rtc_base/event.h"
16 #include "rtc_base/platform_thread.h"
17 #include "system_wrappers/include/clock.h"
18 #include "test/gtest.h"
19 
20 namespace webrtc {
21 
22 class RateLimitTest : public ::testing::Test {
23  public:
RateLimitTest()24   RateLimitTest()
25       : clock_(0), rate_limiter(new RateLimiter(&clock_, kWindowSizeMs)) {}
~RateLimitTest()26   ~RateLimitTest() override {}
27 
SetUp()28   void SetUp() override { rate_limiter->SetMaxRate(kMaxRateBps); }
29 
30  protected:
31   static constexpr int64_t kWindowSizeMs = 1000;
32   static constexpr uint32_t kMaxRateBps = 100000;
33   // Bytes needed to completely saturate the rate limiter.
34   static constexpr size_t kRateFillingBytes =
35       (kMaxRateBps * kWindowSizeMs) / (8 * 1000);
36   SimulatedClock clock_;
37   std::unique_ptr<RateLimiter> rate_limiter;
38 };
39 
TEST_F(RateLimitTest,IncreasingMaxRate)40 TEST_F(RateLimitTest, IncreasingMaxRate) {
41   // Fill rate, extend window to full size.
42   EXPECT_TRUE(rate_limiter->TryUseRate(kRateFillingBytes / 2));
43   clock_.AdvanceTimeMilliseconds(kWindowSizeMs - 1);
44   EXPECT_TRUE(rate_limiter->TryUseRate(kRateFillingBytes / 2));
45 
46   // All rate consumed.
47   EXPECT_FALSE(rate_limiter->TryUseRate(1));
48 
49   // Double the available rate and fill that too.
50   rate_limiter->SetMaxRate(kMaxRateBps * 2);
51   EXPECT_TRUE(rate_limiter->TryUseRate(kRateFillingBytes));
52 
53   // All rate consumed again.
54   EXPECT_FALSE(rate_limiter->TryUseRate(1));
55 }
56 
TEST_F(RateLimitTest,DecreasingMaxRate)57 TEST_F(RateLimitTest, DecreasingMaxRate) {
58   // Fill rate, extend window to full size.
59   EXPECT_TRUE(rate_limiter->TryUseRate(kRateFillingBytes / 2));
60   clock_.AdvanceTimeMilliseconds(kWindowSizeMs - 1);
61   EXPECT_TRUE(rate_limiter->TryUseRate(kRateFillingBytes / 2));
62 
63   // All rate consumed.
64   EXPECT_FALSE(rate_limiter->TryUseRate(1));
65 
66   // Halve the available rate and move window so half of the data falls out.
67   rate_limiter->SetMaxRate(kMaxRateBps / 2);
68   clock_.AdvanceTimeMilliseconds(1);
69 
70   // All rate still consumed.
71   EXPECT_FALSE(rate_limiter->TryUseRate(1));
72 }
73 
TEST_F(RateLimitTest,ChangingWindowSize)74 TEST_F(RateLimitTest, ChangingWindowSize) {
75   // Fill rate, extend window to full size.
76   EXPECT_TRUE(rate_limiter->TryUseRate(kRateFillingBytes / 2));
77   clock_.AdvanceTimeMilliseconds(kWindowSizeMs - 1);
78   EXPECT_TRUE(rate_limiter->TryUseRate(kRateFillingBytes / 2));
79 
80   // All rate consumed.
81   EXPECT_FALSE(rate_limiter->TryUseRate(1));
82 
83   // Decrease window size so half of the data falls out.
84   rate_limiter->SetWindowSize(kWindowSizeMs / 2);
85   // Average rate should still be the same, so rate is still all consumed.
86   EXPECT_FALSE(rate_limiter->TryUseRate(1));
87 
88   // Increase window size again. Now the rate is only half used (removed data
89   // points don't come back to life).
90   rate_limiter->SetWindowSize(kWindowSizeMs);
91   EXPECT_TRUE(rate_limiter->TryUseRate(kRateFillingBytes / 2));
92 
93   // All rate consumed again.
94   EXPECT_FALSE(rate_limiter->TryUseRate(1));
95 }
96 
TEST_F(RateLimitTest,SingleUsageAlwaysOk)97 TEST_F(RateLimitTest, SingleUsageAlwaysOk) {
98   // Using more bytes than can fit in a window is OK for a single packet.
99   EXPECT_TRUE(rate_limiter->TryUseRate(kRateFillingBytes + 1));
100 }
101 
TEST_F(RateLimitTest,WindowSizeLimits)102 TEST_F(RateLimitTest, WindowSizeLimits) {
103   EXPECT_TRUE(rate_limiter->SetWindowSize(1));
104   EXPECT_FALSE(rate_limiter->SetWindowSize(0));
105   EXPECT_TRUE(rate_limiter->SetWindowSize(kWindowSizeMs));
106   EXPECT_FALSE(rate_limiter->SetWindowSize(kWindowSizeMs + 1));
107 }
108 
109 static const int64_t kMaxTimeoutMs = 30000;
110 
111 class ThreadTask {
112  public:
ThreadTask(RateLimiter * rate_limiter)113   explicit ThreadTask(RateLimiter* rate_limiter)
114       : rate_limiter_(rate_limiter) {}
~ThreadTask()115   virtual ~ThreadTask() {}
116 
Run()117   void Run() {
118     start_signal_.Wait(kMaxTimeoutMs);
119     DoRun();
120     end_signal_.Set();
121   }
122 
123   virtual void DoRun() = 0;
124 
125   RateLimiter* const rate_limiter_;
126   rtc::Event start_signal_;
127   rtc::Event end_signal_;
128 };
129 
RunTask(void * thread_task)130 void RunTask(void* thread_task) {
131   reinterpret_cast<ThreadTask*>(thread_task)->Run();
132 }
133 
TEST_F(RateLimitTest,MultiThreadedUsage)134 TEST_F(RateLimitTest, MultiThreadedUsage) {
135   // Simple sanity test, with different threads calling the various methods.
136   // Runs a few simple tasks, each on its own thread, but coordinated with
137   // events so that they run in a serialized order. Intended to catch data
138   // races when run with tsan et al.
139 
140   // Half window size, double rate -> same amount of bytes needed to fill rate.
141 
142   class SetWindowSizeTask : public ThreadTask {
143    public:
144     explicit SetWindowSizeTask(RateLimiter* rate_limiter)
145         : ThreadTask(rate_limiter) {}
146     ~SetWindowSizeTask() override {}
147 
148     void DoRun() override {
149       EXPECT_TRUE(rate_limiter_->SetWindowSize(kWindowSizeMs / 2));
150     }
151   } set_window_size_task(rate_limiter.get());
152   rtc::PlatformThread thread1(RunTask, &set_window_size_task, "Thread1");
153   thread1.Start();
154 
155   class SetMaxRateTask : public ThreadTask {
156    public:
157     explicit SetMaxRateTask(RateLimiter* rate_limiter)
158         : ThreadTask(rate_limiter) {}
159     ~SetMaxRateTask() override {}
160 
161     void DoRun() override { rate_limiter_->SetMaxRate(kMaxRateBps * 2); }
162   } set_max_rate_task(rate_limiter.get());
163   rtc::PlatformThread thread2(RunTask, &set_max_rate_task, "Thread2");
164   thread2.Start();
165 
166   class UseRateTask : public ThreadTask {
167    public:
168     UseRateTask(RateLimiter* rate_limiter, SimulatedClock* clock)
169         : ThreadTask(rate_limiter), clock_(clock) {}
170     ~UseRateTask() override {}
171 
172     void DoRun() override {
173       EXPECT_TRUE(rate_limiter_->TryUseRate(kRateFillingBytes / 2));
174       clock_->AdvanceTimeMilliseconds((kWindowSizeMs / 2) - 1);
175       EXPECT_TRUE(rate_limiter_->TryUseRate(kRateFillingBytes / 2));
176     }
177 
178     SimulatedClock* const clock_;
179   } use_rate_task(rate_limiter.get(), &clock_);
180   rtc::PlatformThread thread3(RunTask, &use_rate_task, "Thread3");
181   thread3.Start();
182 
183   set_window_size_task.start_signal_.Set();
184   EXPECT_TRUE(set_window_size_task.end_signal_.Wait(kMaxTimeoutMs));
185 
186   set_max_rate_task.start_signal_.Set();
187   EXPECT_TRUE(set_max_rate_task.end_signal_.Wait(kMaxTimeoutMs));
188 
189   use_rate_task.start_signal_.Set();
190   EXPECT_TRUE(use_rate_task.end_signal_.Wait(kMaxTimeoutMs));
191 
192   // All rate consumed.
193   EXPECT_FALSE(rate_limiter->TryUseRate(1));
194 
195   thread1.Stop();
196   thread2.Stop();
197   thread3.Stop();
198 }
199 
200 }  // namespace webrtc
201