blob: 9fb53e1347e0f3bc4b00c7052f7b8988931f36c6 [file] [log] [blame]
mflodman@webrtc.orge6168f52013-06-26 11:23:01 +00001/*
2 * Copyright (c) 2013 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
kwiberg27f982b2016-03-01 11:52:33 -080011#include <memory>
12
Niels Möller4dc66c52018-10-05 14:17:58 +020013#include "api/video/encoded_image.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020014#include "api/video/i420_buffer.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020015#include "modules/video_coding/utility/quality_scaler.h"
16#include "rtc_base/event.h"
17#include "rtc_base/fakeclock.h"
Niels Möllere541be72017-12-13 13:03:10 +010018#include "rtc_base/random.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020019#include "test/gmock.h"
20#include "test/gtest.h"
21#include "video/overuse_frame_detector.h"
mflodman@webrtc.orge6168f52013-06-26 11:23:01 +000022
mflodman@webrtc.orge6168f52013-06-26 11:23:01 +000023namespace webrtc {
perkjd52063f2016-09-07 06:32:18 -070024
kthelgason876222f2016-11-29 01:44:11 -080025using ::testing::InvokeWithoutArgs;
Niels Möllere541be72017-12-13 13:03:10 +010026using ::testing::_;
perkjd52063f2016-09-07 06:32:18 -070027
asapersson@webrtc.org8a8c3ef2014-03-20 13:15:01 +000028namespace {
Yves Gerey665174f2018-06-19 15:03:05 +020029const int kWidth = 640;
30const int kHeight = 480;
31// Corresponds to load of 15%
32const int kFrameIntervalUs = 33 * rtc::kNumMicrosecsPerMillisec;
33const int kProcessTimeUs = 5 * rtc::kNumMicrosecsPerMillisec;
asapersson@webrtc.org8a8c3ef2014-03-20 13:15:01 +000034} // namespace
mflodman@webrtc.orge6168f52013-06-26 11:23:01 +000035
sprangb1ca0732017-02-01 08:38:12 -080036class MockCpuOveruseObserver : public AdaptationObserverInterface {
mflodman@webrtc.orge6168f52013-06-26 11:23:01 +000037 public:
mflodman@webrtc.org6879c8a2013-07-23 11:35:00 +000038 MockCpuOveruseObserver() {}
39 virtual ~MockCpuOveruseObserver() {}
mflodman@webrtc.orge6168f52013-06-26 11:23:01 +000040
sprangb1ca0732017-02-01 08:38:12 -080041 MOCK_METHOD1(AdaptUp, void(AdaptReason));
42 MOCK_METHOD1(AdaptDown, void(AdaptReason));
mflodman@webrtc.orge6168f52013-06-26 11:23:01 +000043};
44
sprangb1ca0732017-02-01 08:38:12 -080045class CpuOveruseObserverImpl : public AdaptationObserverInterface {
asapersson@webrtc.org8a8c3ef2014-03-20 13:15:01 +000046 public:
Yves Gerey665174f2018-06-19 15:03:05 +020047 CpuOveruseObserverImpl() : overuse_(0), normaluse_(0) {}
asapersson@webrtc.org8a8c3ef2014-03-20 13:15:01 +000048 virtual ~CpuOveruseObserverImpl() {}
49
sprangb1ca0732017-02-01 08:38:12 -080050 void AdaptDown(AdaptReason) { ++overuse_; }
51 void AdaptUp(AdaptReason) { ++normaluse_; }
asapersson@webrtc.org8a8c3ef2014-03-20 13:15:01 +000052
53 int overuse_;
54 int normaluse_;
55};
56
perkjd52063f2016-09-07 06:32:18 -070057class OveruseFrameDetectorUnderTest : public OveruseFrameDetector {
58 public:
Niels Möllerd1f7eb62018-03-28 16:40:58 +020059 explicit OveruseFrameDetectorUnderTest(
60 CpuOveruseMetricsObserver* metrics_observer)
61 : OveruseFrameDetector(metrics_observer) {}
perkjd52063f2016-09-07 06:32:18 -070062 ~OveruseFrameDetectorUnderTest() {}
63
64 using OveruseFrameDetector::CheckForOveruse;
Niels Möllerd1f7eb62018-03-28 16:40:58 +020065 using OveruseFrameDetector::SetOptions;
perkjd52063f2016-09-07 06:32:18 -070066};
67
pbos@webrtc.org3e6e2712015-02-26 12:19:31 +000068class OveruseFrameDetectorTest : public ::testing::Test,
69 public CpuOveruseMetricsObserver {
mflodman@webrtc.orge6168f52013-06-26 11:23:01 +000070 protected:
nisseef8b61e2016-04-29 06:09:15 -070071 void SetUp() override {
Niels Möller73f29cb2018-01-31 16:09:31 +010072 observer_ = &mock_observer_;
asapersson@webrtc.org8a8c3ef2014-03-20 13:15:01 +000073 options_.min_process_count = 0;
Karl Wiberg918f50c2018-07-05 11:40:33 +020074 overuse_detector_ = absl::make_unique<OveruseFrameDetectorUnderTest>(this);
Niels Möllerd1f7eb62018-03-28 16:40:58 +020075 // Unfortunately, we can't call SetOptions here, since that would break
76 // single-threading requirements in the RunOnTqNormalUsage test.
mflodman@webrtc.orge6168f52013-06-26 11:23:01 +000077 }
mflodman@webrtc.orgd4412fe2013-07-31 16:42:21 +000078
Peter Boströme4499152016-02-05 11:13:28 +010079 void OnEncodedFrameTimeMeasured(int encode_time_ms,
Niels Möller213618e2018-07-24 09:29:58 +020080 int encode_usage_percent) override {
81 encode_usage_percent_ = encode_usage_percent;
pbos@webrtc.org3e6e2712015-02-26 12:19:31 +000082 }
83
asapersson@webrtc.org9aed0022014-10-16 06:57:12 +000084 int InitialUsage() {
asapersson@webrtc.orgce12f1f2014-03-24 21:59:16 +000085 return ((options_.low_encode_usage_threshold_percent +
Yves Gerey665174f2018-06-19 15:03:05 +020086 options_.high_encode_usage_threshold_percent) /
87 2.0f) +
88 0.5;
asapersson@webrtc.orgce12f1f2014-03-24 21:59:16 +000089 }
90
Niels Möller83dbeac2017-12-14 16:39:44 +010091 virtual void InsertAndSendFramesWithInterval(int num_frames,
92 int interval_us,
93 int width,
94 int height,
95 int delay_us) {
Niels Möller7dc26b72017-12-06 10:27:48 +010096 VideoFrame frame(I420Buffer::Create(width, height),
97 webrtc::kVideoRotation_0, 0);
98 uint32_t timestamp = 0;
asapersson@webrtc.orgce12f1f2014-03-24 21:59:16 +000099 while (num_frames-- > 0) {
Niels Möller7dc26b72017-12-06 10:27:48 +0100100 frame.set_timestamp(timestamp);
Niels Möller83dbeac2017-12-14 16:39:44 +0100101 int64_t capture_time_us = rtc::TimeMicros();
102 overuse_detector_->FrameCaptured(frame, capture_time_us);
Niels Möller7dc26b72017-12-06 10:27:48 +0100103 clock_.AdvanceTimeMicros(delay_us);
Niels Möller83dbeac2017-12-14 16:39:44 +0100104 overuse_detector_->FrameSent(timestamp, rtc::TimeMicros(),
105 capture_time_us, delay_us);
Niels Möller7dc26b72017-12-06 10:27:48 +0100106 clock_.AdvanceTimeMicros(interval_us - delay_us);
107 timestamp += interval_us * 90 / 1000;
asapersson@webrtc.orgce12f1f2014-03-24 21:59:16 +0000108 }
109 }
110
Niels Möllerf5033ad2018-08-14 17:00:46 +0200111 virtual void InsertAndSendSimulcastFramesWithInterval(
112 int num_frames,
113 int interval_us,
114 int width,
115 int height,
116 // One element per layer
117 rtc::ArrayView<const int> delays_us) {
118 VideoFrame frame(I420Buffer::Create(width, height),
119 webrtc::kVideoRotation_0, 0);
120 uint32_t timestamp = 0;
121 while (num_frames-- > 0) {
122 frame.set_timestamp(timestamp);
123 int64_t capture_time_us = rtc::TimeMicros();
124 overuse_detector_->FrameCaptured(frame, capture_time_us);
125 int max_delay_us = 0;
126 for (int delay_us : delays_us) {
127 if (delay_us > max_delay_us) {
128 clock_.AdvanceTimeMicros(delay_us - max_delay_us);
129 max_delay_us = delay_us;
130 }
131
132 overuse_detector_->FrameSent(timestamp, rtc::TimeMicros(),
133 capture_time_us, delay_us);
134 }
135 overuse_detector_->CheckForOveruse(observer_);
136 clock_.AdvanceTimeMicros(interval_us - max_delay_us);
137 timestamp += interval_us * 90 / 1000;
138 }
139 }
140
Niels Möller83dbeac2017-12-14 16:39:44 +0100141 virtual void InsertAndSendFramesWithRandomInterval(int num_frames,
142 int min_interval_us,
143 int max_interval_us,
144 int width,
145 int height,
146 int delay_us) {
Niels Möllere541be72017-12-13 13:03:10 +0100147 webrtc::Random random(17);
148
149 VideoFrame frame(I420Buffer::Create(width, height),
150 webrtc::kVideoRotation_0, 0);
151 uint32_t timestamp = 0;
152 while (num_frames-- > 0) {
153 frame.set_timestamp(timestamp);
154 int interval_us = random.Rand(min_interval_us, max_interval_us);
Niels Möller83dbeac2017-12-14 16:39:44 +0100155 int64_t capture_time_us = rtc::TimeMicros();
156 overuse_detector_->FrameCaptured(frame, capture_time_us);
Niels Möllere541be72017-12-13 13:03:10 +0100157 clock_.AdvanceTimeMicros(delay_us);
Niels Möller83dbeac2017-12-14 16:39:44 +0100158 overuse_detector_->FrameSent(timestamp, rtc::TimeMicros(),
159 capture_time_us,
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200160 absl::optional<int>(delay_us));
Niels Möllere541be72017-12-13 13:03:10 +0100161
Niels Möller73f29cb2018-01-31 16:09:31 +0100162 overuse_detector_->CheckForOveruse(observer_);
Niels Möllere541be72017-12-13 13:03:10 +0100163 // Avoid turning clock backwards.
164 if (interval_us > delay_us)
165 clock_.AdvanceTimeMicros(interval_us - delay_us);
166
167 timestamp += interval_us * 90 / 1000;
168 }
169 }
170
Niels Möller83dbeac2017-12-14 16:39:44 +0100171 virtual void ForceUpdate(int width, int height) {
Niels Möller7dc26b72017-12-06 10:27:48 +0100172 // Insert one frame, wait a second and then put in another to force update
173 // the usage. From the tests where these are used, adding another sample
174 // doesn't affect the expected outcome (this is mainly to check initial
175 // values and whether the overuse detector has been reset or not).
Yves Gerey665174f2018-06-19 15:03:05 +0200176 InsertAndSendFramesWithInterval(2, rtc::kNumMicrosecsPerSec, width, height,
177 kFrameIntervalUs);
Peter Boströme4499152016-02-05 11:13:28 +0100178 }
asapersson@webrtc.org8a8c3ef2014-03-20 13:15:01 +0000179 void TriggerOveruse(int num_times) {
nissee0e3bdf2017-01-18 02:16:20 -0800180 const int kDelayUs = 32 * rtc::kNumMicrosecsPerMillisec;
asapersson@webrtc.orgce12f1f2014-03-24 21:59:16 +0000181 for (int i = 0; i < num_times; ++i) {
Yves Gerey665174f2018-06-19 15:03:05 +0200182 InsertAndSendFramesWithInterval(1000, kFrameIntervalUs, kWidth, kHeight,
183 kDelayUs);
Niels Möller73f29cb2018-01-31 16:09:31 +0100184 overuse_detector_->CheckForOveruse(observer_);
asapersson@webrtc.orgce12f1f2014-03-24 21:59:16 +0000185 }
186 }
187
Åsa Persson746210f2015-09-08 10:52:42 +0200188 void TriggerUnderuse() {
nissee0e3bdf2017-01-18 02:16:20 -0800189 const int kDelayUs1 = 5000;
190 const int kDelayUs2 = 6000;
Yves Gerey665174f2018-06-19 15:03:05 +0200191 InsertAndSendFramesWithInterval(1300, kFrameIntervalUs, kWidth, kHeight,
192 kDelayUs1);
193 InsertAndSendFramesWithInterval(1, kFrameIntervalUs, kWidth, kHeight,
194 kDelayUs2);
Niels Möller73f29cb2018-01-31 16:09:31 +0100195 overuse_detector_->CheckForOveruse(observer_);
asapersson@webrtc.orgce12f1f2014-03-24 21:59:16 +0000196 }
197
Niels Möller213618e2018-07-24 09:29:58 +0200198 int UsagePercent() { return encode_usage_percent_; }
asapersson@webrtc.orgab6bf4f2014-05-27 07:43:15 +0000199
sprangfda496a2017-06-15 04:21:07 -0700200 int64_t OveruseProcessingTimeLimitForFramerate(int fps) const {
201 int64_t frame_interval = rtc::kNumMicrosecsPerSec / fps;
202 int64_t max_processing_time_us =
203 (frame_interval * options_.high_encode_usage_threshold_percent) / 100;
204 return max_processing_time_us;
205 }
206
207 int64_t UnderuseProcessingTimeLimitForFramerate(int fps) const {
208 int64_t frame_interval = rtc::kNumMicrosecsPerSec / fps;
209 int64_t max_processing_time_us =
210 (frame_interval * options_.low_encode_usage_threshold_percent) / 100;
211 return max_processing_time_us;
212 }
213
asapersson@webrtc.org8a8c3ef2014-03-20 13:15:01 +0000214 CpuOveruseOptions options_;
nissee0e3bdf2017-01-18 02:16:20 -0800215 rtc::ScopedFakeClock clock_;
Niels Möller73f29cb2018-01-31 16:09:31 +0100216 MockCpuOveruseObserver mock_observer_;
217 AdaptationObserverInterface* observer_;
perkjd52063f2016-09-07 06:32:18 -0700218 std::unique_ptr<OveruseFrameDetectorUnderTest> overuse_detector_;
Niels Möller213618e2018-07-24 09:29:58 +0200219 int encode_usage_percent_ = -1;
kthelgason876222f2016-11-29 01:44:11 -0800220
sprangb1ca0732017-02-01 08:38:12 -0800221 static const auto reason_ = AdaptationObserverInterface::AdaptReason::kCpu;
mflodman@webrtc.orge6168f52013-06-26 11:23:01 +0000222};
223
Åsa Persson746210f2015-09-08 10:52:42 +0200224// UsagePercent() > high_encode_usage_threshold_percent => overuse.
225// UsagePercent() < low_encode_usage_threshold_percent => underuse.
mflodman@webrtc.orge6168f52013-06-26 11:23:01 +0000226TEST_F(OveruseFrameDetectorTest, TriggerOveruse) {
Åsa Persson746210f2015-09-08 10:52:42 +0200227 // usage > high => overuse
Niels Möllerd1f7eb62018-03-28 16:40:58 +0200228 overuse_detector_->SetOptions(options_);
Niels Möller73f29cb2018-01-31 16:09:31 +0100229 EXPECT_CALL(mock_observer_, AdaptDown(reason_)).Times(1);
asapersson@webrtc.org8a8c3ef2014-03-20 13:15:01 +0000230 TriggerOveruse(options_.high_threshold_consecutive_count);
mflodman@webrtc.orgd4412fe2013-07-31 16:42:21 +0000231}
232
233TEST_F(OveruseFrameDetectorTest, OveruseAndRecover) {
Åsa Persson746210f2015-09-08 10:52:42 +0200234 // usage > high => overuse
Niels Möllerd1f7eb62018-03-28 16:40:58 +0200235 overuse_detector_->SetOptions(options_);
Niels Möller73f29cb2018-01-31 16:09:31 +0100236 EXPECT_CALL(mock_observer_, AdaptDown(reason_)).Times(1);
asapersson@webrtc.org8a8c3ef2014-03-20 13:15:01 +0000237 TriggerOveruse(options_.high_threshold_consecutive_count);
Åsa Persson746210f2015-09-08 10:52:42 +0200238 // usage < low => underuse
Niels Möller73f29cb2018-01-31 16:09:31 +0100239 EXPECT_CALL(mock_observer_, AdaptUp(reason_)).Times(testing::AtLeast(1));
asapersson@webrtc.org9aed0022014-10-16 06:57:12 +0000240 TriggerUnderuse();
asapersson@webrtc.org8a8c3ef2014-03-20 13:15:01 +0000241}
242
mflodman@webrtc.orgd4412fe2013-07-31 16:42:21 +0000243TEST_F(OveruseFrameDetectorTest, DoubleOveruseAndRecover) {
Niels Möllerd1f7eb62018-03-28 16:40:58 +0200244 overuse_detector_->SetOptions(options_);
Niels Möller73f29cb2018-01-31 16:09:31 +0100245 EXPECT_CALL(mock_observer_, AdaptDown(reason_)).Times(2);
asapersson@webrtc.org8a8c3ef2014-03-20 13:15:01 +0000246 TriggerOveruse(options_.high_threshold_consecutive_count);
247 TriggerOveruse(options_.high_threshold_consecutive_count);
Niels Möller73f29cb2018-01-31 16:09:31 +0100248 EXPECT_CALL(mock_observer_, AdaptUp(reason_)).Times(testing::AtLeast(1));
asapersson@webrtc.org9aed0022014-10-16 06:57:12 +0000249 TriggerUnderuse();
pbos@webrtc.orga9575702013-08-30 17:16:32 +0000250}
mflodman@webrtc.orgd4412fe2013-07-31 16:42:21 +0000251
asapersson@webrtc.org9aed0022014-10-16 06:57:12 +0000252TEST_F(OveruseFrameDetectorTest, TriggerUnderuseWithMinProcessCount) {
nissee0e3bdf2017-01-18 02:16:20 -0800253 const int kProcessIntervalUs = 5 * rtc::kNumMicrosecsPerSec;
asapersson@webrtc.org8a8c3ef2014-03-20 13:15:01 +0000254 options_.min_process_count = 1;
Peter Boström4b91bd02015-06-26 06:58:16 +0200255 CpuOveruseObserverImpl overuse_observer;
Niels Möller73f29cb2018-01-31 16:09:31 +0100256 observer_ = nullptr;
Niels Möllerd1f7eb62018-03-28 16:40:58 +0200257 overuse_detector_->SetOptions(options_);
Yves Gerey665174f2018-06-19 15:03:05 +0200258 InsertAndSendFramesWithInterval(1200, kFrameIntervalUs, kWidth, kHeight,
259 kProcessTimeUs);
Niels Möller73f29cb2018-01-31 16:09:31 +0100260 overuse_detector_->CheckForOveruse(&overuse_observer);
Peter Boström4b91bd02015-06-26 06:58:16 +0200261 EXPECT_EQ(0, overuse_observer.normaluse_);
nissee0e3bdf2017-01-18 02:16:20 -0800262 clock_.AdvanceTimeMicros(kProcessIntervalUs);
Niels Möller73f29cb2018-01-31 16:09:31 +0100263 overuse_detector_->CheckForOveruse(&overuse_observer);
Peter Boström4b91bd02015-06-26 06:58:16 +0200264 EXPECT_EQ(1, overuse_observer.normaluse_);
asapersson@webrtc.orgb60346e2014-02-17 19:02:15 +0000265}
266
pbos@webrtc.orga9575702013-08-30 17:16:32 +0000267TEST_F(OveruseFrameDetectorTest, ConstantOveruseGivesNoNormalUsage) {
Niels Möllerd1f7eb62018-03-28 16:40:58 +0200268 overuse_detector_->SetOptions(options_);
Niels Möller73f29cb2018-01-31 16:09:31 +0100269 EXPECT_CALL(mock_observer_, AdaptUp(reason_)).Times(0);
270 EXPECT_CALL(mock_observer_, AdaptDown(reason_)).Times(64);
kjellander@webrtc.org0fcaf992015-11-26 15:24:52 +0100271 for (size_t i = 0; i < 64; ++i) {
asapersson@webrtc.org8a8c3ef2014-03-20 13:15:01 +0000272 TriggerOveruse(options_.high_threshold_consecutive_count);
273 }
mflodman@webrtc.orgd4412fe2013-07-31 16:42:21 +0000274}
275
asapersson@webrtc.org8a8c3ef2014-03-20 13:15:01 +0000276TEST_F(OveruseFrameDetectorTest, ConsecutiveCountTriggersOveruse) {
Niels Möllerd1f7eb62018-03-28 16:40:58 +0200277 overuse_detector_->SetOptions(options_);
Niels Möller73f29cb2018-01-31 16:09:31 +0100278 EXPECT_CALL(mock_observer_, AdaptDown(reason_)).Times(1);
asapersson@webrtc.org8a8c3ef2014-03-20 13:15:01 +0000279 options_.high_threshold_consecutive_count = 2;
Niels Möllerd1f7eb62018-03-28 16:40:58 +0200280 overuse_detector_->SetOptions(options_);
asapersson@webrtc.org8a8c3ef2014-03-20 13:15:01 +0000281 TriggerOveruse(2);
282}
283
284TEST_F(OveruseFrameDetectorTest, IncorrectConsecutiveCountTriggersNoOveruse) {
Niels Möllerd1f7eb62018-03-28 16:40:58 +0200285 overuse_detector_->SetOptions(options_);
Niels Möller73f29cb2018-01-31 16:09:31 +0100286 EXPECT_CALL(mock_observer_, AdaptDown(reason_)).Times(0);
asapersson@webrtc.org8a8c3ef2014-03-20 13:15:01 +0000287 options_.high_threshold_consecutive_count = 2;
Niels Möllerd1f7eb62018-03-28 16:40:58 +0200288 overuse_detector_->SetOptions(options_);
asapersson@webrtc.org8a8c3ef2014-03-20 13:15:01 +0000289 TriggerOveruse(1);
290}
291
Åsa Persson746210f2015-09-08 10:52:42 +0200292TEST_F(OveruseFrameDetectorTest, ProcessingUsage) {
Niels Möllerd1f7eb62018-03-28 16:40:58 +0200293 overuse_detector_->SetOptions(options_);
Yves Gerey665174f2018-06-19 15:03:05 +0200294 InsertAndSendFramesWithInterval(1000, kFrameIntervalUs, kWidth, kHeight,
295 kProcessTimeUs);
nissee0e3bdf2017-01-18 02:16:20 -0800296 EXPECT_EQ(kProcessTimeUs * 100 / kFrameIntervalUs, UsagePercent());
asapersson@webrtc.org8a8c3ef2014-03-20 13:15:01 +0000297}
298
Åsa Persson746210f2015-09-08 10:52:42 +0200299TEST_F(OveruseFrameDetectorTest, ResetAfterResolutionChange) {
Niels Möllerd1f7eb62018-03-28 16:40:58 +0200300 overuse_detector_->SetOptions(options_);
Peter Boströme4499152016-02-05 11:13:28 +0100301 ForceUpdate(kWidth, kHeight);
Åsa Persson746210f2015-09-08 10:52:42 +0200302 EXPECT_EQ(InitialUsage(), UsagePercent());
Yves Gerey665174f2018-06-19 15:03:05 +0200303 InsertAndSendFramesWithInterval(1000, kFrameIntervalUs, kWidth, kHeight,
304 kProcessTimeUs);
Åsa Persson746210f2015-09-08 10:52:42 +0200305 EXPECT_NE(InitialUsage(), UsagePercent());
Peter Boströme4499152016-02-05 11:13:28 +0100306 // Verify reset (with new width/height).
307 ForceUpdate(kWidth, kHeight + 1);
Åsa Persson746210f2015-09-08 10:52:42 +0200308 EXPECT_EQ(InitialUsage(), UsagePercent());
asapersson@webrtc.org8a8c3ef2014-03-20 13:15:01 +0000309}
310
Åsa Persson746210f2015-09-08 10:52:42 +0200311TEST_F(OveruseFrameDetectorTest, ResetAfterFrameTimeout) {
Niels Möllerd1f7eb62018-03-28 16:40:58 +0200312 overuse_detector_->SetOptions(options_);
Peter Boströme4499152016-02-05 11:13:28 +0100313 ForceUpdate(kWidth, kHeight);
Åsa Persson746210f2015-09-08 10:52:42 +0200314 EXPECT_EQ(InitialUsage(), UsagePercent());
Yves Gerey665174f2018-06-19 15:03:05 +0200315 InsertAndSendFramesWithInterval(1000, kFrameIntervalUs, kWidth, kHeight,
316 kProcessTimeUs);
Åsa Persson746210f2015-09-08 10:52:42 +0200317 EXPECT_NE(InitialUsage(), UsagePercent());
318 InsertAndSendFramesWithInterval(
Yves Gerey665174f2018-06-19 15:03:05 +0200319 2, options_.frame_timeout_interval_ms * rtc::kNumMicrosecsPerMillisec,
320 kWidth, kHeight, kProcessTimeUs);
Åsa Persson746210f2015-09-08 10:52:42 +0200321 EXPECT_NE(InitialUsage(), UsagePercent());
asapersson@webrtc.org8a8c3ef2014-03-20 13:15:01 +0000322 // Verify reset.
Åsa Persson746210f2015-09-08 10:52:42 +0200323 InsertAndSendFramesWithInterval(
Yves Gerey665174f2018-06-19 15:03:05 +0200324 2,
325 (options_.frame_timeout_interval_ms + 1) * rtc::kNumMicrosecsPerMillisec,
326 kWidth, kHeight, kProcessTimeUs);
Peter Boströme4499152016-02-05 11:13:28 +0100327 ForceUpdate(kWidth, kHeight);
Åsa Persson746210f2015-09-08 10:52:42 +0200328 EXPECT_EQ(InitialUsage(), UsagePercent());
asapersson@webrtc.org8a8c3ef2014-03-20 13:15:01 +0000329}
330
Niels Möller7dc26b72017-12-06 10:27:48 +0100331TEST_F(OveruseFrameDetectorTest, MinFrameSamplesBeforeUpdating) {
332 options_.min_frame_samples = 40;
Niels Möllerd1f7eb62018-03-28 16:40:58 +0200333 overuse_detector_->SetOptions(options_);
Yves Gerey665174f2018-06-19 15:03:05 +0200334 InsertAndSendFramesWithInterval(40, kFrameIntervalUs, kWidth, kHeight,
335 kProcessTimeUs);
Niels Möller7dc26b72017-12-06 10:27:48 +0100336 EXPECT_EQ(InitialUsage(), UsagePercent());
337 // Pass time far enough to digest all previous samples.
338 clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec);
339 InsertAndSendFramesWithInterval(1, kFrameIntervalUs, kWidth, kHeight,
340 kProcessTimeUs);
341 // The last sample has not been processed here.
342 EXPECT_EQ(InitialUsage(), UsagePercent());
343
344 // Pass time far enough to digest all previous samples, 41 in total.
345 clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec);
Yves Gerey665174f2018-06-19 15:03:05 +0200346 InsertAndSendFramesWithInterval(1, kFrameIntervalUs, kWidth, kHeight,
347 kProcessTimeUs);
Niels Möller7dc26b72017-12-06 10:27:48 +0100348 EXPECT_NE(InitialUsage(), UsagePercent());
349}
350
Åsa Persson746210f2015-09-08 10:52:42 +0200351TEST_F(OveruseFrameDetectorTest, InitialProcessingUsage) {
Niels Möllerd1f7eb62018-03-28 16:40:58 +0200352 overuse_detector_->SetOptions(options_);
Peter Boströme4499152016-02-05 11:13:28 +0100353 ForceUpdate(kWidth, kHeight);
Åsa Persson746210f2015-09-08 10:52:42 +0200354 EXPECT_EQ(InitialUsage(), UsagePercent());
asapersson@webrtc.orgb24d3352013-11-20 13:51:40 +0000355}
356
Niels Möller7dc26b72017-12-06 10:27:48 +0100357TEST_F(OveruseFrameDetectorTest, MeasuresMultipleConcurrentSamples) {
Niels Möllerd1f7eb62018-03-28 16:40:58 +0200358 overuse_detector_->SetOptions(options_);
Yves Gerey665174f2018-06-19 15:03:05 +0200359 EXPECT_CALL(mock_observer_, AdaptDown(reason_)).Times(testing::AtLeast(1));
Niels Möller7dc26b72017-12-06 10:27:48 +0100360 static const int kIntervalUs = 33 * rtc::kNumMicrosecsPerMillisec;
361 static const size_t kNumFramesEncodingDelay = 3;
362 VideoFrame frame(I420Buffer::Create(kWidth, kHeight),
363 webrtc::kVideoRotation_0, 0);
364 for (size_t i = 0; i < 1000; ++i) {
365 // Unique timestamps.
366 frame.set_timestamp(static_cast<uint32_t>(i));
Niels Möller83dbeac2017-12-14 16:39:44 +0100367 int64_t capture_time_us = rtc::TimeMicros();
368 overuse_detector_->FrameCaptured(frame, capture_time_us);
Niels Möller7dc26b72017-12-06 10:27:48 +0100369 clock_.AdvanceTimeMicros(kIntervalUs);
370 if (i > kNumFramesEncodingDelay) {
371 overuse_detector_->FrameSent(
Niels Möller83dbeac2017-12-14 16:39:44 +0100372 static_cast<uint32_t>(i - kNumFramesEncodingDelay), rtc::TimeMicros(),
373 capture_time_us, kIntervalUs);
Niels Möller7dc26b72017-12-06 10:27:48 +0100374 }
Niels Möller73f29cb2018-01-31 16:09:31 +0100375 overuse_detector_->CheckForOveruse(observer_);
Niels Möller7dc26b72017-12-06 10:27:48 +0100376 }
377}
378
379TEST_F(OveruseFrameDetectorTest, UpdatesExistingSamples) {
380 // >85% encoding time should trigger overuse.
Niels Möllerd1f7eb62018-03-28 16:40:58 +0200381 overuse_detector_->SetOptions(options_);
Yves Gerey665174f2018-06-19 15:03:05 +0200382 EXPECT_CALL(mock_observer_, AdaptDown(reason_)).Times(testing::AtLeast(1));
Niels Möller7dc26b72017-12-06 10:27:48 +0100383 static const int kIntervalUs = 33 * rtc::kNumMicrosecsPerMillisec;
384 static const int kDelayUs = 30 * rtc::kNumMicrosecsPerMillisec;
385 VideoFrame frame(I420Buffer::Create(kWidth, kHeight),
386 webrtc::kVideoRotation_0, 0);
387 uint32_t timestamp = 0;
388 for (size_t i = 0; i < 1000; ++i) {
389 frame.set_timestamp(timestamp);
Niels Möller83dbeac2017-12-14 16:39:44 +0100390 int64_t capture_time_us = rtc::TimeMicros();
391 overuse_detector_->FrameCaptured(frame, capture_time_us);
Niels Möller7dc26b72017-12-06 10:27:48 +0100392 // Encode and send first parts almost instantly.
393 clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerMillisec);
Niels Möller83dbeac2017-12-14 16:39:44 +0100394 overuse_detector_->FrameSent(timestamp, rtc::TimeMicros(), capture_time_us,
395 rtc::kNumMicrosecsPerMillisec);
Niels Möller7dc26b72017-12-06 10:27:48 +0100396 // Encode heavier part, resulting in >85% usage total.
397 clock_.AdvanceTimeMicros(kDelayUs - rtc::kNumMicrosecsPerMillisec);
Niels Möller83dbeac2017-12-14 16:39:44 +0100398 overuse_detector_->FrameSent(timestamp, rtc::TimeMicros(), capture_time_us,
399 kDelayUs);
Niels Möller7dc26b72017-12-06 10:27:48 +0100400 clock_.AdvanceTimeMicros(kIntervalUs - kDelayUs);
401 timestamp += kIntervalUs * 90 / 1000;
Niels Möller73f29cb2018-01-31 16:09:31 +0100402 overuse_detector_->CheckForOveruse(observer_);
Niels Möller7dc26b72017-12-06 10:27:48 +0100403 }
404}
405
perkjd52063f2016-09-07 06:32:18 -0700406TEST_F(OveruseFrameDetectorTest, RunOnTqNormalUsage) {
407 rtc::TaskQueue queue("OveruseFrameDetectorTestQueue");
408
409 rtc::Event event(false, false);
410 queue.PostTask([this, &event] {
Niels Möllerd1f7eb62018-03-28 16:40:58 +0200411 overuse_detector_->StartCheckForOveruse(options_, observer_);
perkjd52063f2016-09-07 06:32:18 -0700412 event.Set();
413 });
414 event.Wait(rtc::Event::kForever);
415
416 // Expect NormalUsage(). When called, stop the |overuse_detector_| and then
417 // set |event| to end the test.
Niels Möller73f29cb2018-01-31 16:09:31 +0100418 EXPECT_CALL(mock_observer_, AdaptUp(reason_))
kthelgason876222f2016-11-29 01:44:11 -0800419 .WillOnce(InvokeWithoutArgs([this, &event] {
perkjd52063f2016-09-07 06:32:18 -0700420 overuse_detector_->StopCheckForOveruse();
421 event.Set();
422 }));
423
eladalon1cc5fc32017-08-23 04:15:18 -0700424 queue.PostTask([this] {
nissee0e3bdf2017-01-18 02:16:20 -0800425 const int kDelayUs1 = 5 * rtc::kNumMicrosecsPerMillisec;
426 const int kDelayUs2 = 6 * rtc::kNumMicrosecsPerMillisec;
427 InsertAndSendFramesWithInterval(1300, kFrameIntervalUs, kWidth, kHeight,
428 kDelayUs1);
429 InsertAndSendFramesWithInterval(1, kFrameIntervalUs, kWidth, kHeight,
430 kDelayUs2);
perkjd52063f2016-09-07 06:32:18 -0700431 });
432
433 EXPECT_TRUE(event.Wait(10000));
434}
435
Niels Möller7dc26b72017-12-06 10:27:48 +0100436TEST_F(OveruseFrameDetectorTest, MaxIntervalScalesWithFramerate) {
437 const int kCapturerMaxFrameRate = 30;
438 const int kEncodeMaxFrameRate = 20; // Maximum fps the encoder can sustain.
sprangfda496a2017-06-15 04:21:07 -0700439
Niels Möllerd1f7eb62018-03-28 16:40:58 +0200440 overuse_detector_->SetOptions(options_);
Niels Möller7dc26b72017-12-06 10:27:48 +0100441 // Trigger overuse.
442 int64_t frame_interval_us = rtc::kNumMicrosecsPerSec / kCapturerMaxFrameRate;
443 // Processing time just below over use limit given kEncodeMaxFrameRate.
444 int64_t processing_time_us =
445 (98 * OveruseProcessingTimeLimitForFramerate(kEncodeMaxFrameRate)) / 100;
Niels Möller73f29cb2018-01-31 16:09:31 +0100446 EXPECT_CALL(mock_observer_, AdaptDown(reason_)).Times(1);
Niels Möller7dc26b72017-12-06 10:27:48 +0100447 for (int i = 0; i < options_.high_threshold_consecutive_count; ++i) {
448 InsertAndSendFramesWithInterval(1200, frame_interval_us, kWidth, kHeight,
449 processing_time_us);
Niels Möller73f29cb2018-01-31 16:09:31 +0100450 overuse_detector_->CheckForOveruse(observer_);
sprangfda496a2017-06-15 04:21:07 -0700451 }
Niels Möller7dc26b72017-12-06 10:27:48 +0100452
453 // Simulate frame rate reduction and normal usage.
454 frame_interval_us = rtc::kNumMicrosecsPerSec / kEncodeMaxFrameRate;
455 overuse_detector_->OnTargetFramerateUpdated(kEncodeMaxFrameRate);
Niels Möller73f29cb2018-01-31 16:09:31 +0100456 EXPECT_CALL(mock_observer_, AdaptDown(reason_)).Times(0);
Niels Möller7dc26b72017-12-06 10:27:48 +0100457 for (int i = 0; i < options_.high_threshold_consecutive_count; ++i) {
458 InsertAndSendFramesWithInterval(1200, frame_interval_us, kWidth, kHeight,
459 processing_time_us);
Niels Möller73f29cb2018-01-31 16:09:31 +0100460 overuse_detector_->CheckForOveruse(observer_);
Niels Möller7dc26b72017-12-06 10:27:48 +0100461 }
462
463 // Reduce processing time to trigger underuse.
464 processing_time_us =
465 (98 * UnderuseProcessingTimeLimitForFramerate(kEncodeMaxFrameRate)) / 100;
Niels Möller73f29cb2018-01-31 16:09:31 +0100466 EXPECT_CALL(mock_observer_, AdaptUp(reason_)).Times(1);
Niels Möller7dc26b72017-12-06 10:27:48 +0100467 InsertAndSendFramesWithInterval(1200, frame_interval_us, kWidth, kHeight,
468 processing_time_us);
Niels Möller73f29cb2018-01-31 16:09:31 +0100469 overuse_detector_->CheckForOveruse(observer_);
sprangfda496a2017-06-15 04:21:07 -0700470}
471
Niels Möller7dc26b72017-12-06 10:27:48 +0100472TEST_F(OveruseFrameDetectorTest, RespectsMinFramerate) {
473 const int kMinFrameRate = 7; // Minimum fps allowed by current detector impl.
Niels Möllerd1f7eb62018-03-28 16:40:58 +0200474 overuse_detector_->SetOptions(options_);
Niels Möller7dc26b72017-12-06 10:27:48 +0100475 overuse_detector_->OnTargetFramerateUpdated(kMinFrameRate);
sprangfda496a2017-06-15 04:21:07 -0700476
Niels Möller7dc26b72017-12-06 10:27:48 +0100477 // Normal usage just at the limit.
478 int64_t frame_interval_us = rtc::kNumMicrosecsPerSec / kMinFrameRate;
479 // Processing time just below over use limit given kEncodeMaxFrameRate.
480 int64_t processing_time_us =
481 (98 * OveruseProcessingTimeLimitForFramerate(kMinFrameRate)) / 100;
Niels Möller73f29cb2018-01-31 16:09:31 +0100482 EXPECT_CALL(mock_observer_, AdaptDown(reason_)).Times(0);
Niels Möller7dc26b72017-12-06 10:27:48 +0100483 for (int i = 0; i < options_.high_threshold_consecutive_count; ++i) {
484 InsertAndSendFramesWithInterval(1200, frame_interval_us, kWidth, kHeight,
485 processing_time_us);
Niels Möller73f29cb2018-01-31 16:09:31 +0100486 overuse_detector_->CheckForOveruse(observer_);
sprangfda496a2017-06-15 04:21:07 -0700487 }
Niels Möller7dc26b72017-12-06 10:27:48 +0100488
489 // Over the limit to overuse.
490 processing_time_us =
491 (102 * OveruseProcessingTimeLimitForFramerate(kMinFrameRate)) / 100;
Niels Möller73f29cb2018-01-31 16:09:31 +0100492 EXPECT_CALL(mock_observer_, AdaptDown(reason_)).Times(1);
Niels Möller7dc26b72017-12-06 10:27:48 +0100493 for (int i = 0; i < options_.high_threshold_consecutive_count; ++i) {
494 InsertAndSendFramesWithInterval(1200, frame_interval_us, kWidth, kHeight,
495 processing_time_us);
Niels Möller73f29cb2018-01-31 16:09:31 +0100496 overuse_detector_->CheckForOveruse(observer_);
Niels Möller7dc26b72017-12-06 10:27:48 +0100497 }
498
499 // Reduce input frame rate. Should still trigger overuse.
500 overuse_detector_->OnTargetFramerateUpdated(kMinFrameRate - 1);
Niels Möller73f29cb2018-01-31 16:09:31 +0100501 EXPECT_CALL(mock_observer_, AdaptDown(reason_)).Times(1);
Niels Möller7dc26b72017-12-06 10:27:48 +0100502 for (int i = 0; i < options_.high_threshold_consecutive_count; ++i) {
503 InsertAndSendFramesWithInterval(1200, frame_interval_us, kWidth, kHeight,
504 processing_time_us);
Niels Möller73f29cb2018-01-31 16:09:31 +0100505 overuse_detector_->CheckForOveruse(observer_);
Niels Möller7dc26b72017-12-06 10:27:48 +0100506 }
507}
508
509TEST_F(OveruseFrameDetectorTest, LimitsMaxFrameInterval) {
510 const int kMaxFrameRate = 20;
Niels Möllerd1f7eb62018-03-28 16:40:58 +0200511 overuse_detector_->SetOptions(options_);
Niels Möller7dc26b72017-12-06 10:27:48 +0100512 overuse_detector_->OnTargetFramerateUpdated(kMaxFrameRate);
513 int64_t frame_interval_us = rtc::kNumMicrosecsPerSec / kMaxFrameRate;
514 // Maximum frame interval allowed is 35% above ideal.
515 int64_t max_frame_interval_us = (135 * frame_interval_us) / 100;
516 // Maximum processing time, without triggering overuse, allowed with the above
517 // frame interval.
518 int64_t max_processing_time_us =
519 (max_frame_interval_us * options_.high_encode_usage_threshold_percent) /
520 100;
521
522 // Processing time just below overuse limit given kMaxFrameRate.
523 int64_t processing_time_us = (98 * max_processing_time_us) / 100;
Niels Möller73f29cb2018-01-31 16:09:31 +0100524 EXPECT_CALL(mock_observer_, AdaptDown(reason_)).Times(0);
Niels Möller7dc26b72017-12-06 10:27:48 +0100525 for (int i = 0; i < options_.high_threshold_consecutive_count; ++i) {
526 InsertAndSendFramesWithInterval(1200, max_frame_interval_us, kWidth,
527 kHeight, processing_time_us);
Niels Möller73f29cb2018-01-31 16:09:31 +0100528 overuse_detector_->CheckForOveruse(observer_);
Niels Möller7dc26b72017-12-06 10:27:48 +0100529 }
530
531 // Go above limit, trigger overuse.
532 processing_time_us = (102 * max_processing_time_us) / 100;
Niels Möller73f29cb2018-01-31 16:09:31 +0100533 EXPECT_CALL(mock_observer_, AdaptDown(reason_)).Times(1);
Niels Möller7dc26b72017-12-06 10:27:48 +0100534 for (int i = 0; i < options_.high_threshold_consecutive_count; ++i) {
535 InsertAndSendFramesWithInterval(1200, max_frame_interval_us, kWidth,
536 kHeight, processing_time_us);
Niels Möller73f29cb2018-01-31 16:09:31 +0100537 overuse_detector_->CheckForOveruse(observer_);
Niels Möller7dc26b72017-12-06 10:27:48 +0100538 }
539
540 // Increase frame interval, should still trigger overuse.
541 max_frame_interval_us *= 2;
Niels Möller73f29cb2018-01-31 16:09:31 +0100542 EXPECT_CALL(mock_observer_, AdaptDown(reason_)).Times(1);
Niels Möller7dc26b72017-12-06 10:27:48 +0100543 for (int i = 0; i < options_.high_threshold_consecutive_count; ++i) {
544 InsertAndSendFramesWithInterval(1200, max_frame_interval_us, kWidth,
545 kHeight, processing_time_us);
Niels Möller73f29cb2018-01-31 16:09:31 +0100546 overuse_detector_->CheckForOveruse(observer_);
Niels Möller7dc26b72017-12-06 10:27:48 +0100547 }
sprangfda496a2017-06-15 04:21:07 -0700548}
549
Niels Möllere541be72017-12-13 13:03:10 +0100550// Models screencast, with irregular arrival of frames which are heavy
551// to encode.
552TEST_F(OveruseFrameDetectorTest, NoOveruseForLargeRandomFrameInterval) {
553 // TODO(bugs.webrtc.org/8504): When new estimator is relanded,
554 // behavior is improved in this scenario, with only AdaptUp events,
555 // and estimated load closer to the true average.
556
Niels Möller73f29cb2018-01-31 16:09:31 +0100557 // EXPECT_CALL(mock_observer_, AdaptDown(_)).Times(0);
558 // EXPECT_CALL(mock_observer_, AdaptUp(reason_))
Niels Möllere541be72017-12-13 13:03:10 +0100559 // .Times(testing::AtLeast(1));
Niels Möllerd1f7eb62018-03-28 16:40:58 +0200560 overuse_detector_->SetOptions(options_);
Niels Möllere541be72017-12-13 13:03:10 +0100561
562 const int kNumFrames = 500;
563 const int kEncodeTimeUs = 100 * rtc::kNumMicrosecsPerMillisec;
564
565 const int kMinIntervalUs = 30 * rtc::kNumMicrosecsPerMillisec;
566 const int kMaxIntervalUs = 1000 * rtc::kNumMicrosecsPerMillisec;
567
568 const int kTargetFramerate = 5;
569
570 overuse_detector_->OnTargetFramerateUpdated(kTargetFramerate);
571
Yves Gerey665174f2018-06-19 15:03:05 +0200572 InsertAndSendFramesWithRandomInterval(kNumFrames, kMinIntervalUs,
573 kMaxIntervalUs, kWidth, kHeight,
574 kEncodeTimeUs);
Niels Möllere541be72017-12-13 13:03:10 +0100575 // Average usage 19%. Check that estimate is in the right ball park.
576 // EXPECT_NEAR(UsagePercent(), 20, 10);
577 EXPECT_NEAR(UsagePercent(), 20, 35);
578}
579
580// Models screencast, with irregular arrival of frames, often
581// exceeding the timeout interval.
582TEST_F(OveruseFrameDetectorTest, NoOveruseForRandomFrameIntervalWithReset) {
583 // TODO(bugs.webrtc.org/8504): When new estimator is relanded,
584 // behavior is improved in this scenario, and we get AdaptUp events.
Niels Möllerd1f7eb62018-03-28 16:40:58 +0200585 overuse_detector_->SetOptions(options_);
Niels Möller73f29cb2018-01-31 16:09:31 +0100586 EXPECT_CALL(mock_observer_, AdaptDown(_)).Times(0);
587 // EXPECT_CALL(mock_observer_, AdaptUp(reason_))
Niels Möllere541be72017-12-13 13:03:10 +0100588 // .Times(testing::AtLeast(1));
589
590 const int kNumFrames = 500;
591 const int kEncodeTimeUs = 100 * rtc::kNumMicrosecsPerMillisec;
592
593 const int kMinIntervalUs = 30 * rtc::kNumMicrosecsPerMillisec;
594 const int kMaxIntervalUs = 3000 * rtc::kNumMicrosecsPerMillisec;
595
596 const int kTargetFramerate = 5;
597
598 overuse_detector_->OnTargetFramerateUpdated(kTargetFramerate);
599
Yves Gerey665174f2018-06-19 15:03:05 +0200600 InsertAndSendFramesWithRandomInterval(kNumFrames, kMinIntervalUs,
601 kMaxIntervalUs, kWidth, kHeight,
602 kEncodeTimeUs);
Niels Möllere541be72017-12-13 13:03:10 +0100603
604 // Average usage 6.6%, but since the frame_timeout_interval_ms is
605 // only 1500 ms, we often reset the estimate to the initial value.
606 // Check that estimate is in the right ball park.
607 EXPECT_GE(UsagePercent(), 1);
608 EXPECT_LE(UsagePercent(), InitialUsage() + 5);
609}
610
Niels Möllerf5033ad2018-08-14 17:00:46 +0200611// Models simulcast, with multiple encoded frames for each input frame.
612// Load estimate should be based on the maximum encode time per input frame.
613TEST_F(OveruseFrameDetectorTest, NoOveruseForSimulcast) {
614 overuse_detector_->SetOptions(options_);
615 EXPECT_CALL(mock_observer_, AdaptDown(_)).Times(0);
616
617 constexpr int kNumFrames = 500;
618 constexpr int kEncodeTimesUs[] = {
619 10 * rtc::kNumMicrosecsPerMillisec, 8 * rtc::kNumMicrosecsPerMillisec,
620 12 * rtc::kNumMicrosecsPerMillisec,
621 };
622 constexpr int kIntervalUs = 30 * rtc::kNumMicrosecsPerMillisec;
623
624 InsertAndSendSimulcastFramesWithInterval(kNumFrames, kIntervalUs, kWidth,
625 kHeight, kEncodeTimesUs);
626
627 // Average usage 40%. 12 ms / 30 ms.
628 EXPECT_GE(UsagePercent(), 35);
629 EXPECT_LE(UsagePercent(), 45);
630}
631
Niels Möller83dbeac2017-12-14 16:39:44 +0100632// Tests using new cpu load estimator
633class OveruseFrameDetectorTest2 : public OveruseFrameDetectorTest {
634 protected:
635 void SetUp() override {
636 options_.filter_time_ms = 5 * rtc::kNumMillisecsPerSec;
637 OveruseFrameDetectorTest::SetUp();
638 }
639
640 void InsertAndSendFramesWithInterval(int num_frames,
641 int interval_us,
642 int width,
643 int height,
644 int delay_us) override {
645 VideoFrame frame(I420Buffer::Create(width, height),
646 webrtc::kVideoRotation_0, 0);
647 while (num_frames-- > 0) {
648 int64_t capture_time_us = rtc::TimeMicros();
649 overuse_detector_->FrameCaptured(frame, capture_time_us /* ignored */);
650 overuse_detector_->FrameSent(0 /* ignored timestamp */,
651 0 /* ignored send_time_us */,
652 capture_time_us, delay_us);
653 clock_.AdvanceTimeMicros(interval_us);
654 }
655 }
656
657 void InsertAndSendFramesWithRandomInterval(int num_frames,
658 int min_interval_us,
659 int max_interval_us,
660 int width,
661 int height,
662 int delay_us) override {
663 webrtc::Random random(17);
664
665 VideoFrame frame(I420Buffer::Create(width, height),
666 webrtc::kVideoRotation_0, 0);
667 for (int i = 0; i < num_frames; i++) {
668 int interval_us = random.Rand(min_interval_us, max_interval_us);
669 int64_t capture_time_us = rtc::TimeMicros();
670 overuse_detector_->FrameCaptured(frame, capture_time_us);
671 overuse_detector_->FrameSent(0 /* ignored timestamp */,
672 0 /* ignored send_time_us */,
673 capture_time_us, delay_us);
674
Niels Möller73f29cb2018-01-31 16:09:31 +0100675 overuse_detector_->CheckForOveruse(observer_);
Niels Möller83dbeac2017-12-14 16:39:44 +0100676 clock_.AdvanceTimeMicros(interval_us);
677 }
678 }
679
680 void ForceUpdate(int width, int height) override {
681 // This is mainly to check initial values and whether the overuse
682 // detector has been reset or not.
683 InsertAndSendFramesWithInterval(1, rtc::kNumMicrosecsPerSec, width, height,
684 kFrameIntervalUs);
685 }
686};
687
688// UsagePercent() > high_encode_usage_threshold_percent => overuse.
689// UsagePercent() < low_encode_usage_threshold_percent => underuse.
690TEST_F(OveruseFrameDetectorTest2, TriggerOveruse) {
691 // usage > high => overuse
Niels Möllerd1f7eb62018-03-28 16:40:58 +0200692 overuse_detector_->SetOptions(options_);
Niels Möller73f29cb2018-01-31 16:09:31 +0100693 EXPECT_CALL(mock_observer_, AdaptDown(reason_)).Times(1);
Niels Möller83dbeac2017-12-14 16:39:44 +0100694 TriggerOveruse(options_.high_threshold_consecutive_count);
695}
696
697TEST_F(OveruseFrameDetectorTest2, OveruseAndRecover) {
698 // usage > high => overuse
Niels Möllerd1f7eb62018-03-28 16:40:58 +0200699 overuse_detector_->SetOptions(options_);
Niels Möller73f29cb2018-01-31 16:09:31 +0100700 EXPECT_CALL(mock_observer_, AdaptDown(reason_)).Times(1);
Niels Möller83dbeac2017-12-14 16:39:44 +0100701 TriggerOveruse(options_.high_threshold_consecutive_count);
702 // usage < low => underuse
Niels Möller73f29cb2018-01-31 16:09:31 +0100703 EXPECT_CALL(mock_observer_, AdaptUp(reason_)).Times(testing::AtLeast(1));
Niels Möller83dbeac2017-12-14 16:39:44 +0100704 TriggerUnderuse();
705}
706
707TEST_F(OveruseFrameDetectorTest2, DoubleOveruseAndRecover) {
Niels Möllerd1f7eb62018-03-28 16:40:58 +0200708 overuse_detector_->SetOptions(options_);
Niels Möller73f29cb2018-01-31 16:09:31 +0100709 EXPECT_CALL(mock_observer_, AdaptDown(reason_)).Times(2);
Niels Möller83dbeac2017-12-14 16:39:44 +0100710 TriggerOveruse(options_.high_threshold_consecutive_count);
711 TriggerOveruse(options_.high_threshold_consecutive_count);
Niels Möller73f29cb2018-01-31 16:09:31 +0100712 EXPECT_CALL(mock_observer_, AdaptUp(reason_)).Times(testing::AtLeast(1));
Niels Möller83dbeac2017-12-14 16:39:44 +0100713 TriggerUnderuse();
714}
715
716TEST_F(OveruseFrameDetectorTest2, TriggerUnderuseWithMinProcessCount) {
717 const int kProcessIntervalUs = 5 * rtc::kNumMicrosecsPerSec;
718 options_.min_process_count = 1;
719 CpuOveruseObserverImpl overuse_observer;
Niels Möller73f29cb2018-01-31 16:09:31 +0100720 observer_ = nullptr;
Niels Möllerd1f7eb62018-03-28 16:40:58 +0200721 overuse_detector_->SetOptions(options_);
Yves Gerey665174f2018-06-19 15:03:05 +0200722 InsertAndSendFramesWithInterval(1200, kFrameIntervalUs, kWidth, kHeight,
723 kProcessTimeUs);
Niels Möller73f29cb2018-01-31 16:09:31 +0100724 overuse_detector_->CheckForOveruse(&overuse_observer);
Niels Möller83dbeac2017-12-14 16:39:44 +0100725 EXPECT_EQ(0, overuse_observer.normaluse_);
726 clock_.AdvanceTimeMicros(kProcessIntervalUs);
Niels Möller73f29cb2018-01-31 16:09:31 +0100727 overuse_detector_->CheckForOveruse(&overuse_observer);
Niels Möller83dbeac2017-12-14 16:39:44 +0100728 EXPECT_EQ(1, overuse_observer.normaluse_);
729}
730
731TEST_F(OveruseFrameDetectorTest2, ConstantOveruseGivesNoNormalUsage) {
Niels Möllerd1f7eb62018-03-28 16:40:58 +0200732 overuse_detector_->SetOptions(options_);
Niels Möller73f29cb2018-01-31 16:09:31 +0100733 EXPECT_CALL(mock_observer_, AdaptUp(reason_)).Times(0);
734 EXPECT_CALL(mock_observer_, AdaptDown(reason_)).Times(64);
Niels Möller83dbeac2017-12-14 16:39:44 +0100735 for (size_t i = 0; i < 64; ++i) {
736 TriggerOveruse(options_.high_threshold_consecutive_count);
737 }
738}
739
740TEST_F(OveruseFrameDetectorTest2, ConsecutiveCountTriggersOveruse) {
Niels Möller73f29cb2018-01-31 16:09:31 +0100741 EXPECT_CALL(mock_observer_, AdaptDown(reason_)).Times(1);
Niels Möller83dbeac2017-12-14 16:39:44 +0100742 options_.high_threshold_consecutive_count = 2;
Niels Möllerd1f7eb62018-03-28 16:40:58 +0200743 overuse_detector_->SetOptions(options_);
Niels Möller83dbeac2017-12-14 16:39:44 +0100744 TriggerOveruse(2);
745}
746
747TEST_F(OveruseFrameDetectorTest2, IncorrectConsecutiveCountTriggersNoOveruse) {
Niels Möller73f29cb2018-01-31 16:09:31 +0100748 EXPECT_CALL(mock_observer_, AdaptDown(reason_)).Times(0);
Niels Möller83dbeac2017-12-14 16:39:44 +0100749 options_.high_threshold_consecutive_count = 2;
Niels Möllerd1f7eb62018-03-28 16:40:58 +0200750 overuse_detector_->SetOptions(options_);
Niels Möller83dbeac2017-12-14 16:39:44 +0100751 TriggerOveruse(1);
752}
753
754TEST_F(OveruseFrameDetectorTest2, ProcessingUsage) {
Niels Möllerd1f7eb62018-03-28 16:40:58 +0200755 overuse_detector_->SetOptions(options_);
Yves Gerey665174f2018-06-19 15:03:05 +0200756 InsertAndSendFramesWithInterval(1000, kFrameIntervalUs, kWidth, kHeight,
757 kProcessTimeUs);
Niels Möller83dbeac2017-12-14 16:39:44 +0100758 EXPECT_EQ(kProcessTimeUs * 100 / kFrameIntervalUs, UsagePercent());
759}
760
761TEST_F(OveruseFrameDetectorTest2, ResetAfterResolutionChange) {
Niels Möllerd1f7eb62018-03-28 16:40:58 +0200762 overuse_detector_->SetOptions(options_);
Niels Möller83dbeac2017-12-14 16:39:44 +0100763 ForceUpdate(kWidth, kHeight);
764 EXPECT_EQ(InitialUsage(), UsagePercent());
Yves Gerey665174f2018-06-19 15:03:05 +0200765 InsertAndSendFramesWithInterval(1000, kFrameIntervalUs, kWidth, kHeight,
766 kProcessTimeUs);
Niels Möller83dbeac2017-12-14 16:39:44 +0100767 EXPECT_NE(InitialUsage(), UsagePercent());
768 // Verify reset (with new width/height).
769 ForceUpdate(kWidth, kHeight + 1);
770 EXPECT_EQ(InitialUsage(), UsagePercent());
771}
772
773TEST_F(OveruseFrameDetectorTest2, ResetAfterFrameTimeout) {
Niels Möllerd1f7eb62018-03-28 16:40:58 +0200774 overuse_detector_->SetOptions(options_);
Niels Möller83dbeac2017-12-14 16:39:44 +0100775 ForceUpdate(kWidth, kHeight);
776 EXPECT_EQ(InitialUsage(), UsagePercent());
Yves Gerey665174f2018-06-19 15:03:05 +0200777 InsertAndSendFramesWithInterval(1000, kFrameIntervalUs, kWidth, kHeight,
778 kProcessTimeUs);
Niels Möller83dbeac2017-12-14 16:39:44 +0100779 EXPECT_NE(InitialUsage(), UsagePercent());
780 InsertAndSendFramesWithInterval(
Yves Gerey665174f2018-06-19 15:03:05 +0200781 2, options_.frame_timeout_interval_ms * rtc::kNumMicrosecsPerMillisec,
782 kWidth, kHeight, kProcessTimeUs);
Niels Möller83dbeac2017-12-14 16:39:44 +0100783 EXPECT_NE(InitialUsage(), UsagePercent());
784 // Verify reset.
785 InsertAndSendFramesWithInterval(
Yves Gerey665174f2018-06-19 15:03:05 +0200786 2,
787 (options_.frame_timeout_interval_ms + 1) * rtc::kNumMicrosecsPerMillisec,
788 kWidth, kHeight, kProcessTimeUs);
Niels Möller83dbeac2017-12-14 16:39:44 +0100789 ForceUpdate(kWidth, kHeight);
790 EXPECT_EQ(InitialUsage(), UsagePercent());
791}
792
793TEST_F(OveruseFrameDetectorTest2, ConvergesSlowly) {
Niels Möllerd1f7eb62018-03-28 16:40:58 +0200794 overuse_detector_->SetOptions(options_);
Niels Möller83dbeac2017-12-14 16:39:44 +0100795 InsertAndSendFramesWithInterval(1, kFrameIntervalUs, kWidth, kHeight,
796 kProcessTimeUs);
797 // No update for the first sample.
798 EXPECT_EQ(InitialUsage(), UsagePercent());
799
800 // Total time approximately 40 * 33ms = 1.3s, significantly less
801 // than the 5s time constant.
Yves Gerey665174f2018-06-19 15:03:05 +0200802 InsertAndSendFramesWithInterval(40, kFrameIntervalUs, kWidth, kHeight,
803 kProcessTimeUs);
Niels Möller83dbeac2017-12-14 16:39:44 +0100804
805 // Should have started to approach correct load of 15%, but not very far.
806 EXPECT_LT(UsagePercent(), InitialUsage());
807 EXPECT_GT(UsagePercent(), (InitialUsage() * 3 + 15) / 4);
808
809 // Run for roughly 10s more, should now be closer.
Yves Gerey665174f2018-06-19 15:03:05 +0200810 InsertAndSendFramesWithInterval(300, kFrameIntervalUs, kWidth, kHeight,
811 kProcessTimeUs);
Niels Möller83dbeac2017-12-14 16:39:44 +0100812 EXPECT_NEAR(UsagePercent(), 20, 5);
813}
814
815TEST_F(OveruseFrameDetectorTest2, InitialProcessingUsage) {
Niels Möllerd1f7eb62018-03-28 16:40:58 +0200816 overuse_detector_->SetOptions(options_);
Niels Möller83dbeac2017-12-14 16:39:44 +0100817 ForceUpdate(kWidth, kHeight);
818 EXPECT_EQ(InitialUsage(), UsagePercent());
819}
820
821TEST_F(OveruseFrameDetectorTest2, MeasuresMultipleConcurrentSamples) {
Niels Möllerd1f7eb62018-03-28 16:40:58 +0200822 overuse_detector_->SetOptions(options_);
Yves Gerey665174f2018-06-19 15:03:05 +0200823 EXPECT_CALL(mock_observer_, AdaptDown(reason_)).Times(testing::AtLeast(1));
Niels Möller83dbeac2017-12-14 16:39:44 +0100824 static const int kIntervalUs = 33 * rtc::kNumMicrosecsPerMillisec;
825 static const size_t kNumFramesEncodingDelay = 3;
826 VideoFrame frame(I420Buffer::Create(kWidth, kHeight),
827 webrtc::kVideoRotation_0, 0);
828 for (size_t i = 0; i < 1000; ++i) {
829 // Unique timestamps.
830 frame.set_timestamp(static_cast<uint32_t>(i));
831 int64_t capture_time_us = rtc::TimeMicros();
832 overuse_detector_->FrameCaptured(frame, capture_time_us);
833 clock_.AdvanceTimeMicros(kIntervalUs);
834 if (i > kNumFramesEncodingDelay) {
835 overuse_detector_->FrameSent(
836 static_cast<uint32_t>(i - kNumFramesEncodingDelay), rtc::TimeMicros(),
837 capture_time_us, kIntervalUs);
838 }
Niels Möller73f29cb2018-01-31 16:09:31 +0100839 overuse_detector_->CheckForOveruse(observer_);
Niels Möller83dbeac2017-12-14 16:39:44 +0100840 }
841}
842
843TEST_F(OveruseFrameDetectorTest2, UpdatesExistingSamples) {
844 // >85% encoding time should trigger overuse.
Niels Möllerd1f7eb62018-03-28 16:40:58 +0200845 overuse_detector_->SetOptions(options_);
Yves Gerey665174f2018-06-19 15:03:05 +0200846 EXPECT_CALL(mock_observer_, AdaptDown(reason_)).Times(testing::AtLeast(1));
Niels Möller83dbeac2017-12-14 16:39:44 +0100847 static const int kIntervalUs = 33 * rtc::kNumMicrosecsPerMillisec;
848 static const int kDelayUs = 30 * rtc::kNumMicrosecsPerMillisec;
849 VideoFrame frame(I420Buffer::Create(kWidth, kHeight),
850 webrtc::kVideoRotation_0, 0);
851 uint32_t timestamp = 0;
852 for (size_t i = 0; i < 1000; ++i) {
853 frame.set_timestamp(timestamp);
854 int64_t capture_time_us = rtc::TimeMicros();
855 overuse_detector_->FrameCaptured(frame, capture_time_us);
856 // Encode and send first parts almost instantly.
857 clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerMillisec);
858 overuse_detector_->FrameSent(timestamp, rtc::TimeMicros(), capture_time_us,
859 rtc::kNumMicrosecsPerMillisec);
860 // Encode heavier part, resulting in >85% usage total.
861 clock_.AdvanceTimeMicros(kDelayUs - rtc::kNumMicrosecsPerMillisec);
862 overuse_detector_->FrameSent(timestamp, rtc::TimeMicros(), capture_time_us,
863 kDelayUs);
864 clock_.AdvanceTimeMicros(kIntervalUs - kDelayUs);
865 timestamp += kIntervalUs * 90 / 1000;
Niels Möller73f29cb2018-01-31 16:09:31 +0100866 overuse_detector_->CheckForOveruse(observer_);
Niels Möller83dbeac2017-12-14 16:39:44 +0100867 }
868}
869
870TEST_F(OveruseFrameDetectorTest2, RunOnTqNormalUsage) {
871 rtc::TaskQueue queue("OveruseFrameDetectorTestQueue");
872
873 rtc::Event event(false, false);
874 queue.PostTask([this, &event] {
Niels Möllerd1f7eb62018-03-28 16:40:58 +0200875 overuse_detector_->StartCheckForOveruse(options_, observer_);
Niels Möller83dbeac2017-12-14 16:39:44 +0100876 event.Set();
877 });
878 event.Wait(rtc::Event::kForever);
879
880 // Expect NormalUsage(). When called, stop the |overuse_detector_| and then
881 // set |event| to end the test.
Niels Möller73f29cb2018-01-31 16:09:31 +0100882 EXPECT_CALL(mock_observer_, AdaptUp(reason_))
Niels Möller83dbeac2017-12-14 16:39:44 +0100883 .WillOnce(InvokeWithoutArgs([this, &event] {
884 overuse_detector_->StopCheckForOveruse();
885 event.Set();
886 }));
887
888 queue.PostTask([this] {
889 const int kDelayUs1 = 5 * rtc::kNumMicrosecsPerMillisec;
890 const int kDelayUs2 = 6 * rtc::kNumMicrosecsPerMillisec;
891 InsertAndSendFramesWithInterval(1300, kFrameIntervalUs, kWidth, kHeight,
892 kDelayUs1);
893 InsertAndSendFramesWithInterval(1, kFrameIntervalUs, kWidth, kHeight,
894 kDelayUs2);
895 });
896
897 EXPECT_TRUE(event.Wait(10000));
898}
899
900// Models screencast, with irregular arrival of frames which are heavy
901// to encode.
902TEST_F(OveruseFrameDetectorTest2, NoOveruseForLargeRandomFrameInterval) {
Niels Möllerd1f7eb62018-03-28 16:40:58 +0200903 overuse_detector_->SetOptions(options_);
Niels Möller73f29cb2018-01-31 16:09:31 +0100904 EXPECT_CALL(mock_observer_, AdaptDown(_)).Times(0);
Yves Gerey665174f2018-06-19 15:03:05 +0200905 EXPECT_CALL(mock_observer_, AdaptUp(reason_)).Times(testing::AtLeast(1));
Niels Möller83dbeac2017-12-14 16:39:44 +0100906
907 const int kNumFrames = 500;
908 const int kEncodeTimeUs = 100 * rtc::kNumMicrosecsPerMillisec;
909
910 const int kMinIntervalUs = 30 * rtc::kNumMicrosecsPerMillisec;
911 const int kMaxIntervalUs = 1000 * rtc::kNumMicrosecsPerMillisec;
912
Yves Gerey665174f2018-06-19 15:03:05 +0200913 InsertAndSendFramesWithRandomInterval(kNumFrames, kMinIntervalUs,
914 kMaxIntervalUs, kWidth, kHeight,
915 kEncodeTimeUs);
Niels Möller83dbeac2017-12-14 16:39:44 +0100916 // Average usage 19%. Check that estimate is in the right ball park.
917 EXPECT_NEAR(UsagePercent(), 20, 10);
918}
919
920// Models screencast, with irregular arrival of frames, often
921// exceeding the timeout interval.
922TEST_F(OveruseFrameDetectorTest2, NoOveruseForRandomFrameIntervalWithReset) {
Niels Möllerd1f7eb62018-03-28 16:40:58 +0200923 overuse_detector_->SetOptions(options_);
Niels Möller73f29cb2018-01-31 16:09:31 +0100924 EXPECT_CALL(mock_observer_, AdaptDown(_)).Times(0);
Yves Gerey665174f2018-06-19 15:03:05 +0200925 EXPECT_CALL(mock_observer_, AdaptUp(reason_)).Times(testing::AtLeast(1));
Niels Möller83dbeac2017-12-14 16:39:44 +0100926
927 const int kNumFrames = 500;
928 const int kEncodeTimeUs = 100 * rtc::kNumMicrosecsPerMillisec;
929
930 const int kMinIntervalUs = 30 * rtc::kNumMicrosecsPerMillisec;
931 const int kMaxIntervalUs = 3000 * rtc::kNumMicrosecsPerMillisec;
932
Yves Gerey665174f2018-06-19 15:03:05 +0200933 InsertAndSendFramesWithRandomInterval(kNumFrames, kMinIntervalUs,
934 kMaxIntervalUs, kWidth, kHeight,
935 kEncodeTimeUs);
Niels Möller83dbeac2017-12-14 16:39:44 +0100936
937 // Average usage 6.6%, but since the frame_timeout_interval_ms is
938 // only 1500 ms, we often reset the estimate to the initial value.
939 // Check that estimate is in the right ball park.
940 EXPECT_GE(UsagePercent(), 1);
941 EXPECT_LE(UsagePercent(), InitialUsage() + 5);
942}
943
Niels Möller58d2a5e2018-08-07 16:37:18 +0200944TEST_F(OveruseFrameDetectorTest2, ToleratesOutOfOrderFrames) {
945 overuse_detector_->SetOptions(options_);
946 // Represents a cpu utilization close to 100%. First input frame results in
947 // three encoded frames, and the last of those isn't finished until after the
948 // first encoded frame corresponding to the next input frame.
949 const int kEncodeTimeUs = 30 * rtc::kNumMicrosecsPerMillisec;
950 const int kCaptureTimesMs[] = { 33, 33, 66, 33 };
951
952 for (int capture_time_ms : kCaptureTimesMs) {
953 overuse_detector_->FrameSent(
954 0, 0, capture_time_ms * rtc::kNumMicrosecsPerMillisec, kEncodeTimeUs);
955 }
956 EXPECT_GE(UsagePercent(), InitialUsage());
957}
958
Niels Möllerf5033ad2018-08-14 17:00:46 +0200959// Models simulcast, with multiple encoded frames for each input frame.
960// Load estimate should be based on the maximum encode time per input frame.
961TEST_F(OveruseFrameDetectorTest2, NoOveruseForSimulcast) {
962 overuse_detector_->SetOptions(options_);
963 EXPECT_CALL(mock_observer_, AdaptDown(_)).Times(0);
964
965 constexpr int kNumFrames = 500;
966 constexpr int kEncodeTimesUs[] = {
967 10 * rtc::kNumMicrosecsPerMillisec, 8 * rtc::kNumMicrosecsPerMillisec,
968 12 * rtc::kNumMicrosecsPerMillisec,
969 };
970 constexpr int kIntervalUs = 30 * rtc::kNumMicrosecsPerMillisec;
971
972 InsertAndSendSimulcastFramesWithInterval(kNumFrames, kIntervalUs, kWidth,
973 kHeight, kEncodeTimesUs);
974
975 // Average usage 40%. 12 ms / 30 ms.
976 EXPECT_GE(UsagePercent(), 35);
977 EXPECT_LE(UsagePercent(), 45);
978}
979
mflodman@webrtc.orge6168f52013-06-26 11:23:01 +0000980} // namespace webrtc