| OLD | NEW |
| (Empty) |
| 1 /* | |
| 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 | |
| 11 #include "webrtc/video_engine/overuse_frame_detector.h" | |
| 12 | |
| 13 #include "testing/gmock/include/gmock/gmock.h" | |
| 14 #include "testing/gtest/include/gtest/gtest.h" | |
| 15 | |
| 16 #include "webrtc/base/scoped_ptr.h" | |
| 17 #include "webrtc/system_wrappers/include/clock.h" | |
| 18 | |
| 19 namespace webrtc { | |
| 20 namespace { | |
| 21 const int kWidth = 640; | |
| 22 const int kHeight = 480; | |
| 23 const int kFrameInterval33ms = 33; | |
| 24 const int kProcessIntervalMs = 5000; | |
| 25 const int kProcessTime5ms = 5; | |
| 26 } // namespace | |
| 27 | |
| 28 class MockCpuOveruseObserver : public CpuOveruseObserver { | |
| 29 public: | |
| 30 MockCpuOveruseObserver() {} | |
| 31 virtual ~MockCpuOveruseObserver() {} | |
| 32 | |
| 33 MOCK_METHOD0(OveruseDetected, void()); | |
| 34 MOCK_METHOD0(NormalUsage, void()); | |
| 35 }; | |
| 36 | |
| 37 class CpuOveruseObserverImpl : public CpuOveruseObserver { | |
| 38 public: | |
| 39 CpuOveruseObserverImpl() : | |
| 40 overuse_(0), | |
| 41 normaluse_(0) {} | |
| 42 virtual ~CpuOveruseObserverImpl() {} | |
| 43 | |
| 44 void OveruseDetected() { ++overuse_; } | |
| 45 void NormalUsage() { ++normaluse_; } | |
| 46 | |
| 47 int overuse_; | |
| 48 int normaluse_; | |
| 49 }; | |
| 50 | |
| 51 class OveruseFrameDetectorTest : public ::testing::Test, | |
| 52 public CpuOveruseMetricsObserver { | |
| 53 protected: | |
| 54 virtual void SetUp() { | |
| 55 clock_.reset(new SimulatedClock(1234)); | |
| 56 observer_.reset(new MockCpuOveruseObserver()); | |
| 57 options_.min_process_count = 0; | |
| 58 ReinitializeOveruseDetector(); | |
| 59 } | |
| 60 | |
| 61 void ReinitializeOveruseDetector() { | |
| 62 overuse_detector_.reset(new OveruseFrameDetector(clock_.get(), options_, | |
| 63 observer_.get(), this)); | |
| 64 } | |
| 65 | |
| 66 void CpuOveruseMetricsUpdated(const CpuOveruseMetrics& metrics) override { | |
| 67 metrics_ = metrics; | |
| 68 } | |
| 69 | |
| 70 int InitialUsage() { | |
| 71 return ((options_.low_encode_usage_threshold_percent + | |
| 72 options_.high_encode_usage_threshold_percent) / 2.0f) + 0.5; | |
| 73 } | |
| 74 | |
| 75 void InsertAndSendFramesWithInterval( | |
| 76 int num_frames, int interval_ms, int width, int height, int delay_ms) { | |
| 77 while (num_frames-- > 0) { | |
| 78 int64_t capture_time_ms = clock_->TimeInMilliseconds(); | |
| 79 overuse_detector_->FrameCaptured(width, height, capture_time_ms); | |
| 80 clock_->AdvanceTimeMilliseconds(delay_ms); | |
| 81 overuse_detector_->FrameEncoded(delay_ms); | |
| 82 overuse_detector_->FrameSent(capture_time_ms); | |
| 83 clock_->AdvanceTimeMilliseconds(interval_ms - delay_ms); | |
| 84 } | |
| 85 } | |
| 86 | |
| 87 void TriggerOveruse(int num_times) { | |
| 88 const int kDelayMs = 32; | |
| 89 for (int i = 0; i < num_times; ++i) { | |
| 90 InsertAndSendFramesWithInterval( | |
| 91 1000, kFrameInterval33ms, kWidth, kHeight, kDelayMs); | |
| 92 overuse_detector_->Process(); | |
| 93 } | |
| 94 } | |
| 95 | |
| 96 void TriggerUnderuse() { | |
| 97 const int kDelayMs1 = 5; | |
| 98 const int kDelayMs2 = 6; | |
| 99 InsertAndSendFramesWithInterval( | |
| 100 1300, kFrameInterval33ms, kWidth, kHeight, kDelayMs1); | |
| 101 InsertAndSendFramesWithInterval( | |
| 102 1, kFrameInterval33ms, kWidth, kHeight, kDelayMs2); | |
| 103 overuse_detector_->Process(); | |
| 104 } | |
| 105 | |
| 106 int UsagePercent() { return metrics_.encode_usage_percent; } | |
| 107 | |
| 108 CpuOveruseOptions options_; | |
| 109 rtc::scoped_ptr<SimulatedClock> clock_; | |
| 110 rtc::scoped_ptr<MockCpuOveruseObserver> observer_; | |
| 111 rtc::scoped_ptr<OveruseFrameDetector> overuse_detector_; | |
| 112 CpuOveruseMetrics metrics_; | |
| 113 }; | |
| 114 | |
| 115 | |
| 116 // enable_encode_usage_method = true; | |
| 117 // enable_extended_processing_usage = false; | |
| 118 // UsagePercent() > high_encode_usage_threshold_percent => overuse. | |
| 119 // UsagePercent() < low_encode_usage_threshold_percent => underuse. | |
| 120 TEST_F(OveruseFrameDetectorTest, TriggerOveruse) { | |
| 121 options_.enable_extended_processing_usage = false; | |
| 122 ReinitializeOveruseDetector(); | |
| 123 // usage > high => overuse | |
| 124 EXPECT_CALL(*(observer_.get()), OveruseDetected()).Times(1); | |
| 125 TriggerOveruse(options_.high_threshold_consecutive_count); | |
| 126 } | |
| 127 | |
| 128 TEST_F(OveruseFrameDetectorTest, OveruseAndRecover) { | |
| 129 options_.enable_extended_processing_usage = false; | |
| 130 ReinitializeOveruseDetector(); | |
| 131 // usage > high => overuse | |
| 132 EXPECT_CALL(*(observer_.get()), OveruseDetected()).Times(1); | |
| 133 TriggerOveruse(options_.high_threshold_consecutive_count); | |
| 134 // usage < low => underuse | |
| 135 EXPECT_CALL(*(observer_.get()), NormalUsage()).Times(testing::AtLeast(1)); | |
| 136 TriggerUnderuse(); | |
| 137 } | |
| 138 | |
| 139 TEST_F(OveruseFrameDetectorTest, OveruseAndRecoverWithNoObserver) { | |
| 140 options_.enable_extended_processing_usage = false; | |
| 141 overuse_detector_.reset( | |
| 142 new OveruseFrameDetector(clock_.get(), options_, nullptr, this)); | |
| 143 EXPECT_CALL(*(observer_.get()), OveruseDetected()).Times(0); | |
| 144 TriggerOveruse(options_.high_threshold_consecutive_count); | |
| 145 EXPECT_CALL(*(observer_.get()), NormalUsage()).Times(0); | |
| 146 TriggerUnderuse(); | |
| 147 } | |
| 148 | |
| 149 TEST_F(OveruseFrameDetectorTest, OveruseAndRecoverWithMethodDisabled) { | |
| 150 options_.enable_encode_usage_method = false; | |
| 151 options_.enable_extended_processing_usage = false; | |
| 152 ReinitializeOveruseDetector(); | |
| 153 EXPECT_CALL(*(observer_.get()), OveruseDetected()).Times(0); | |
| 154 TriggerOveruse(options_.high_threshold_consecutive_count); | |
| 155 EXPECT_CALL(*(observer_.get()), NormalUsage()).Times(0); | |
| 156 TriggerUnderuse(); | |
| 157 } | |
| 158 | |
| 159 TEST_F(OveruseFrameDetectorTest, DoubleOveruseAndRecover) { | |
| 160 options_.enable_extended_processing_usage = false; | |
| 161 ReinitializeOveruseDetector(); | |
| 162 EXPECT_CALL(*(observer_.get()), OveruseDetected()).Times(2); | |
| 163 TriggerOveruse(options_.high_threshold_consecutive_count); | |
| 164 TriggerOveruse(options_.high_threshold_consecutive_count); | |
| 165 EXPECT_CALL(*(observer_.get()), NormalUsage()).Times(testing::AtLeast(1)); | |
| 166 TriggerUnderuse(); | |
| 167 } | |
| 168 | |
| 169 TEST_F(OveruseFrameDetectorTest, TriggerUnderuseWithMinProcessCount) { | |
| 170 options_.enable_extended_processing_usage = false; | |
| 171 options_.min_process_count = 1; | |
| 172 CpuOveruseObserverImpl overuse_observer; | |
| 173 overuse_detector_.reset(new OveruseFrameDetector(clock_.get(), options_, | |
| 174 &overuse_observer, this)); | |
| 175 InsertAndSendFramesWithInterval( | |
| 176 1200, kFrameInterval33ms, kWidth, kHeight, kProcessTime5ms); | |
| 177 overuse_detector_->Process(); | |
| 178 EXPECT_EQ(0, overuse_observer.normaluse_); | |
| 179 clock_->AdvanceTimeMilliseconds(kProcessIntervalMs); | |
| 180 overuse_detector_->Process(); | |
| 181 EXPECT_EQ(1, overuse_observer.normaluse_); | |
| 182 } | |
| 183 | |
| 184 TEST_F(OveruseFrameDetectorTest, ConstantOveruseGivesNoNormalUsage) { | |
| 185 options_.enable_extended_processing_usage = false; | |
| 186 ReinitializeOveruseDetector(); | |
| 187 EXPECT_CALL(*(observer_.get()), NormalUsage()).Times(0); | |
| 188 EXPECT_CALL(*(observer_.get()), OveruseDetected()).Times(64); | |
| 189 for (size_t i = 0; i < 64; ++i) { | |
| 190 TriggerOveruse(options_.high_threshold_consecutive_count); | |
| 191 } | |
| 192 } | |
| 193 | |
| 194 TEST_F(OveruseFrameDetectorTest, ConsecutiveCountTriggersOveruse) { | |
| 195 EXPECT_CALL(*(observer_.get()), OveruseDetected()).Times(1); | |
| 196 options_.enable_extended_processing_usage = false; | |
| 197 options_.high_threshold_consecutive_count = 2; | |
| 198 ReinitializeOveruseDetector(); | |
| 199 TriggerOveruse(2); | |
| 200 } | |
| 201 | |
| 202 TEST_F(OveruseFrameDetectorTest, IncorrectConsecutiveCountTriggersNoOveruse) { | |
| 203 EXPECT_CALL(*(observer_.get()), OveruseDetected()).Times(0); | |
| 204 options_.enable_extended_processing_usage = false; | |
| 205 options_.high_threshold_consecutive_count = 2; | |
| 206 ReinitializeOveruseDetector(); | |
| 207 TriggerOveruse(1); | |
| 208 } | |
| 209 | |
| 210 TEST_F(OveruseFrameDetectorTest, ProcessingUsage) { | |
| 211 InsertAndSendFramesWithInterval( | |
| 212 1000, kFrameInterval33ms, kWidth, kHeight, kProcessTime5ms); | |
| 213 EXPECT_EQ(kProcessTime5ms * 100 / kFrameInterval33ms, UsagePercent()); | |
| 214 } | |
| 215 | |
| 216 TEST_F(OveruseFrameDetectorTest, ResetAfterResolutionChange) { | |
| 217 EXPECT_EQ(InitialUsage(), UsagePercent()); | |
| 218 InsertAndSendFramesWithInterval( | |
| 219 1000, kFrameInterval33ms, kWidth, kHeight, kProcessTime5ms); | |
| 220 EXPECT_NE(InitialUsage(), UsagePercent()); | |
| 221 // Verify reset. | |
| 222 InsertAndSendFramesWithInterval( | |
| 223 1, kFrameInterval33ms, kWidth, kHeight + 1, kProcessTime5ms); | |
| 224 EXPECT_EQ(InitialUsage(), UsagePercent()); | |
| 225 } | |
| 226 | |
| 227 TEST_F(OveruseFrameDetectorTest, ResetAfterFrameTimeout) { | |
| 228 EXPECT_EQ(InitialUsage(), UsagePercent()); | |
| 229 InsertAndSendFramesWithInterval( | |
| 230 1000, kFrameInterval33ms, kWidth, kHeight, kProcessTime5ms); | |
| 231 EXPECT_NE(InitialUsage(), UsagePercent()); | |
| 232 InsertAndSendFramesWithInterval( | |
| 233 2, options_.frame_timeout_interval_ms, kWidth, kHeight, kProcessTime5ms); | |
| 234 EXPECT_NE(InitialUsage(), UsagePercent()); | |
| 235 // Verify reset. | |
| 236 InsertAndSendFramesWithInterval( | |
| 237 2, options_.frame_timeout_interval_ms + 1, kWidth, kHeight, | |
| 238 kProcessTime5ms); | |
| 239 EXPECT_EQ(InitialUsage(), UsagePercent()); | |
| 240 } | |
| 241 | |
| 242 TEST_F(OveruseFrameDetectorTest, MinFrameSamplesBeforeUpdating) { | |
| 243 options_.min_frame_samples = 40; | |
| 244 ReinitializeOveruseDetector(); | |
| 245 InsertAndSendFramesWithInterval( | |
| 246 40, kFrameInterval33ms, kWidth, kHeight, kProcessTime5ms); | |
| 247 EXPECT_EQ(InitialUsage(), UsagePercent()); | |
| 248 InsertAndSendFramesWithInterval( | |
| 249 1, kFrameInterval33ms, kWidth, kHeight, kProcessTime5ms); | |
| 250 EXPECT_NE(InitialUsage(), UsagePercent()); | |
| 251 } | |
| 252 | |
| 253 TEST_F(OveruseFrameDetectorTest, InitialProcessingUsage) { | |
| 254 EXPECT_EQ(InitialUsage(), UsagePercent()); | |
| 255 } | |
| 256 | |
| 257 TEST_F(OveruseFrameDetectorTest, FrameDelay_OneFrameDisabled) { | |
| 258 options_.enable_extended_processing_usage = false; | |
| 259 ReinitializeOveruseDetector(); | |
| 260 const int kProcessingTimeMs = 100; | |
| 261 overuse_detector_->FrameCaptured(kWidth, kHeight, 33); | |
| 262 clock_->AdvanceTimeMilliseconds(kProcessingTimeMs); | |
| 263 overuse_detector_->FrameSent(33); | |
| 264 EXPECT_EQ(-1, overuse_detector_->LastProcessingTimeMs()); | |
| 265 } | |
| 266 | |
| 267 TEST_F(OveruseFrameDetectorTest, FrameDelay_OneFrame) { | |
| 268 options_.enable_extended_processing_usage = true; | |
| 269 ReinitializeOveruseDetector(); | |
| 270 const int kProcessingTimeMs = 100; | |
| 271 overuse_detector_->FrameCaptured(kWidth, kHeight, 33); | |
| 272 clock_->AdvanceTimeMilliseconds(kProcessingTimeMs); | |
| 273 EXPECT_EQ(-1, overuse_detector_->LastProcessingTimeMs()); | |
| 274 overuse_detector_->FrameSent(33); | |
| 275 EXPECT_EQ(kProcessingTimeMs, overuse_detector_->LastProcessingTimeMs()); | |
| 276 EXPECT_EQ(0, overuse_detector_->FramesInQueue()); | |
| 277 } | |
| 278 | |
| 279 TEST_F(OveruseFrameDetectorTest, FrameDelay_TwoFrames) { | |
| 280 options_.enable_extended_processing_usage = true; | |
| 281 ReinitializeOveruseDetector(); | |
| 282 const int kProcessingTimeMs1 = 100; | |
| 283 const int kProcessingTimeMs2 = 50; | |
| 284 const int kTimeBetweenFramesMs = 200; | |
| 285 overuse_detector_->FrameCaptured(kWidth, kHeight, 33); | |
| 286 clock_->AdvanceTimeMilliseconds(kProcessingTimeMs1); | |
| 287 overuse_detector_->FrameSent(33); | |
| 288 EXPECT_EQ(kProcessingTimeMs1, overuse_detector_->LastProcessingTimeMs()); | |
| 289 clock_->AdvanceTimeMilliseconds(kTimeBetweenFramesMs); | |
| 290 overuse_detector_->FrameCaptured(kWidth, kHeight, 66); | |
| 291 clock_->AdvanceTimeMilliseconds(kProcessingTimeMs2); | |
| 292 overuse_detector_->FrameSent(66); | |
| 293 EXPECT_EQ(kProcessingTimeMs2, overuse_detector_->LastProcessingTimeMs()); | |
| 294 } | |
| 295 | |
| 296 TEST_F(OveruseFrameDetectorTest, FrameDelay_MaxQueueSize) { | |
| 297 options_.enable_extended_processing_usage = true; | |
| 298 ReinitializeOveruseDetector(); | |
| 299 const int kMaxQueueSize = 91; | |
| 300 for (int i = 0; i < kMaxQueueSize * 2; ++i) { | |
| 301 overuse_detector_->FrameCaptured(kWidth, kHeight, i); | |
| 302 } | |
| 303 EXPECT_EQ(kMaxQueueSize, overuse_detector_->FramesInQueue()); | |
| 304 } | |
| 305 | |
| 306 TEST_F(OveruseFrameDetectorTest, FrameDelay_NonProcessedFramesRemoved) { | |
| 307 options_.enable_extended_processing_usage = true; | |
| 308 ReinitializeOveruseDetector(); | |
| 309 const int kProcessingTimeMs = 100; | |
| 310 overuse_detector_->FrameCaptured(kWidth, kHeight, 33); | |
| 311 clock_->AdvanceTimeMilliseconds(kProcessingTimeMs); | |
| 312 overuse_detector_->FrameCaptured(kWidth, kHeight, 35); | |
| 313 clock_->AdvanceTimeMilliseconds(kProcessingTimeMs); | |
| 314 overuse_detector_->FrameCaptured(kWidth, kHeight, 66); | |
| 315 clock_->AdvanceTimeMilliseconds(kProcessingTimeMs); | |
| 316 overuse_detector_->FrameCaptured(kWidth, kHeight, 99); | |
| 317 clock_->AdvanceTimeMilliseconds(kProcessingTimeMs); | |
| 318 EXPECT_EQ(-1, overuse_detector_->LastProcessingTimeMs()); | |
| 319 EXPECT_EQ(4, overuse_detector_->FramesInQueue()); | |
| 320 overuse_detector_->FrameSent(66); | |
| 321 // Frame 33, 35 removed, 66 processed, 99 not processed. | |
| 322 EXPECT_EQ(2 * kProcessingTimeMs, overuse_detector_->LastProcessingTimeMs()); | |
| 323 EXPECT_EQ(1, overuse_detector_->FramesInQueue()); | |
| 324 overuse_detector_->FrameSent(99); | |
| 325 EXPECT_EQ(kProcessingTimeMs, overuse_detector_->LastProcessingTimeMs()); | |
| 326 EXPECT_EQ(0, overuse_detector_->FramesInQueue()); | |
| 327 } | |
| 328 | |
| 329 TEST_F(OveruseFrameDetectorTest, FrameDelay_ResetClearsFrames) { | |
| 330 options_.enable_extended_processing_usage = true; | |
| 331 ReinitializeOveruseDetector(); | |
| 332 const int kProcessingTimeMs = 100; | |
| 333 overuse_detector_->FrameCaptured(kWidth, kHeight, 33); | |
| 334 EXPECT_EQ(1, overuse_detector_->FramesInQueue()); | |
| 335 clock_->AdvanceTimeMilliseconds(kProcessingTimeMs); | |
| 336 // Verify reset (resolution changed). | |
| 337 overuse_detector_->FrameCaptured(kWidth, kHeight + 1, 66); | |
| 338 EXPECT_EQ(1, overuse_detector_->FramesInQueue()); | |
| 339 clock_->AdvanceTimeMilliseconds(kProcessingTimeMs); | |
| 340 overuse_detector_->FrameSent(66); | |
| 341 EXPECT_EQ(kProcessingTimeMs, overuse_detector_->LastProcessingTimeMs()); | |
| 342 EXPECT_EQ(0, overuse_detector_->FramesInQueue()); | |
| 343 } | |
| 344 | |
| 345 TEST_F(OveruseFrameDetectorTest, FrameDelay_NonMatchingSendFrameIgnored) { | |
| 346 options_.enable_extended_processing_usage = true; | |
| 347 ReinitializeOveruseDetector(); | |
| 348 const int kProcessingTimeMs = 100; | |
| 349 overuse_detector_->FrameCaptured(kWidth, kHeight, 33); | |
| 350 clock_->AdvanceTimeMilliseconds(kProcessingTimeMs); | |
| 351 overuse_detector_->FrameSent(34); | |
| 352 EXPECT_EQ(-1, overuse_detector_->LastProcessingTimeMs()); | |
| 353 overuse_detector_->FrameSent(33); | |
| 354 EXPECT_EQ(kProcessingTimeMs, overuse_detector_->LastProcessingTimeMs()); | |
| 355 } | |
| 356 | |
| 357 // enable_encode_usage_method = true; | |
| 358 // enable_extended_processing_usage = true; | |
| 359 // UsagePercent() > high_encode_usage_threshold_percent => overuse. | |
| 360 // UsagePercent() < low_encode_usage_threshold_percent => underuse. | |
| 361 TEST_F(OveruseFrameDetectorTest, TriggerOveruseWithExtendedProcessingUsage) { | |
| 362 options_.enable_extended_processing_usage = true; | |
| 363 ReinitializeOveruseDetector(); | |
| 364 // usage > high => overuse | |
| 365 EXPECT_CALL(*(observer_.get()), OveruseDetected()).Times(1); | |
| 366 TriggerOveruse(options_.high_threshold_consecutive_count); | |
| 367 } | |
| 368 | |
| 369 TEST_F(OveruseFrameDetectorTest, OveruseAndRecoverWithExtendedProcessingUsage) { | |
| 370 options_.enable_extended_processing_usage = true; | |
| 371 ReinitializeOveruseDetector(); | |
| 372 // usage > high => overuse | |
| 373 EXPECT_CALL(*(observer_.get()), OveruseDetected()).Times(1); | |
| 374 TriggerOveruse(options_.high_threshold_consecutive_count); | |
| 375 // usage < low => underuse | |
| 376 EXPECT_CALL(*(observer_.get()), NormalUsage()).Times(testing::AtLeast(1)); | |
| 377 TriggerUnderuse(); | |
| 378 } | |
| 379 | |
| 380 TEST_F(OveruseFrameDetectorTest, | |
| 381 OveruseAndRecoverWithExtendedProcessingUsageMethodDisabled) { | |
| 382 options_.enable_encode_usage_method = false; | |
| 383 options_.enable_extended_processing_usage = true; | |
| 384 ReinitializeOveruseDetector(); | |
| 385 // usage > high => overuse | |
| 386 EXPECT_CALL(*(observer_.get()), OveruseDetected()).Times(0); | |
| 387 TriggerOveruse(options_.high_threshold_consecutive_count); | |
| 388 // usage < low => underuse | |
| 389 EXPECT_CALL(*(observer_.get()), NormalUsage()).Times(0); | |
| 390 TriggerUnderuse(); | |
| 391 } | |
| 392 | |
| 393 } // namespace webrtc | |
| OLD | NEW |