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 "testing/gmock/include/gmock/gmock.h" 12 #include "testing/gtest/include/gtest/gtest.h" 13 14 #include "webrtc/system_wrappers/interface/clock.h" 15 #include "webrtc/system_wrappers/interface/scoped_ptr.h" 16 #include "webrtc/video_engine/include/vie_base.h" 17 #include "webrtc/video_engine/overuse_frame_detector.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 } // namespace 26 27 class MockCpuOveruseObserver : public CpuOveruseObserver { 28 public: 29 MockCpuOveruseObserver() {} 30 virtual ~MockCpuOveruseObserver() {} 31 32 MOCK_METHOD0(OveruseDetected, void()); 33 MOCK_METHOD0(NormalUsage, void()); 34 }; 35 36 class CpuOveruseObserverImpl : public CpuOveruseObserver { 37 public: 38 CpuOveruseObserverImpl() : 39 overuse_(0), 40 normaluse_(0) {} 41 virtual ~CpuOveruseObserverImpl() {} 42 43 void OveruseDetected() { ++overuse_; } 44 void NormalUsage() { ++normaluse_; } 45 46 int overuse_; 47 int normaluse_; 48 }; 49 50 class OveruseFrameDetectorTest : public ::testing::Test { 51 protected: 52 virtual void SetUp() { 53 clock_.reset(new SimulatedClock(1234)); 54 observer_.reset(new MockCpuOveruseObserver()); 55 overuse_detector_.reset(new OveruseFrameDetector(clock_.get())); 56 57 options_.low_capture_jitter_threshold_ms = 10.0f; 58 options_.high_capture_jitter_threshold_ms = 15.0f; 59 options_.min_process_count = 0; 60 overuse_detector_->SetOptions(options_); 61 overuse_detector_->SetObserver(observer_.get()); 62 } 63 64 int InitialJitter() { 65 return ((options_.low_capture_jitter_threshold_ms + 66 options_.high_capture_jitter_threshold_ms) / 2.0f) + 0.5; 67 } 68 69 int InitialEncodeUsage() { 70 return ((options_.low_encode_usage_threshold_percent + 71 options_.high_encode_usage_threshold_percent) / 2.0f) + 0.5; 72 } 73 74 int InitialEncodeRsd() { 75 return std::max( 76 ((options_.low_encode_time_rsd_threshold + 77 options_.high_encode_time_rsd_threshold) / 2.0f) + 0.5f, 0.0f); 78 } 79 80 void InsertFramesWithInterval( 81 size_t num_frames, int interval_ms, int width, int height) { 82 while (num_frames-- > 0) { 83 clock_->AdvanceTimeMilliseconds(interval_ms); 84 overuse_detector_->FrameCaptured(width, height); 85 } 86 } 87 88 void InsertAndEncodeFramesWithInterval( 89 int num_frames, int interval_ms, int width, int height, int encode_ms) { 90 while (num_frames-- > 0) { 91 overuse_detector_->FrameCaptured(width, height); 92 clock_->AdvanceTimeMilliseconds(encode_ms); 93 overuse_detector_->FrameEncoded(encode_ms); 94 clock_->AdvanceTimeMilliseconds(interval_ms - encode_ms); 95 } 96 } 97 98 void TriggerOveruse(int num_times) { 99 for (int i = 0; i < num_times; ++i) { 100 InsertFramesWithInterval(200, kFrameInterval33ms, kWidth, kHeight); 101 InsertFramesWithInterval(50, 110, kWidth, kHeight); 102 overuse_detector_->Process(); 103 } 104 } 105 106 void TriggerNormalUsage() { 107 InsertFramesWithInterval(900, kFrameInterval33ms, kWidth, kHeight); 108 overuse_detector_->Process(); 109 } 110 111 void TriggerOveruseWithEncodeUsage(int num_times) { 112 const int kEncodeTimeMs = 32; 113 for (int i = 0; i < num_times; ++i) { 114 InsertAndEncodeFramesWithInterval( 115 1000, kFrameInterval33ms, kWidth, kHeight, kEncodeTimeMs); 116 overuse_detector_->Process(); 117 } 118 } 119 120 void TriggerOveruseWithEncodeRsd(int num_times) { 121 const int kEncodeTimeMs1 = 10; 122 const int kEncodeTimeMs2 = 25; 123 for (int i = 0; i < num_times; ++i) { 124 InsertAndEncodeFramesWithInterval( 125 200, kFrameInterval33ms, kWidth, kHeight, kEncodeTimeMs1); 126 InsertAndEncodeFramesWithInterval( 127 10, kFrameInterval33ms, kWidth, kHeight, kEncodeTimeMs2); 128 overuse_detector_->Process(); 129 } 130 } 131 132 void TriggerNormalUsageWithEncodeTime() { 133 const int kEncodeTimeMs = 5; 134 InsertAndEncodeFramesWithInterval( 135 1000, kFrameInterval33ms, kWidth, kHeight, kEncodeTimeMs); 136 overuse_detector_->Process(); 137 } 138 139 int CaptureJitterMs() { 140 CpuOveruseMetrics metrics; 141 overuse_detector_->GetCpuOveruseMetrics(&metrics); 142 return metrics.capture_jitter_ms; 143 } 144 145 int AvgEncodeTimeMs() { 146 CpuOveruseMetrics metrics; 147 overuse_detector_->GetCpuOveruseMetrics(&metrics); 148 return metrics.avg_encode_time_ms; 149 } 150 151 int EncodeUsagePercent() { 152 CpuOveruseMetrics metrics; 153 overuse_detector_->GetCpuOveruseMetrics(&metrics); 154 return metrics.encode_usage_percent; 155 } 156 157 int EncodeRsd() { 158 CpuOveruseMetrics metrics; 159 overuse_detector_->GetCpuOveruseMetrics(&metrics); 160 return metrics.encode_rsd; 161 } 162 163 CpuOveruseOptions options_; 164 scoped_ptr<SimulatedClock> clock_; 165 scoped_ptr<MockCpuOveruseObserver> observer_; 166 scoped_ptr<OveruseFrameDetector> overuse_detector_; 167 }; 168 169 // enable_capture_jitter_method = true; 170 // CaptureJitterMs() > high_capture_jitter_threshold_ms => overuse. 171 // CaptureJitterMs() < low_capture_jitter_threshold_ms => underuse. 172 TEST_F(OveruseFrameDetectorTest, TriggerOveruse) { 173 // capture_jitter > high => overuse 174 EXPECT_CALL(*(observer_.get()), OveruseDetected()).Times(1); 175 TriggerOveruse(options_.high_threshold_consecutive_count); 176 } 177 178 TEST_F(OveruseFrameDetectorTest, OveruseAndRecover) { 179 // capture_jitter > high => overuse 180 EXPECT_CALL(*(observer_.get()), OveruseDetected()).Times(1); 181 TriggerOveruse(options_.high_threshold_consecutive_count); 182 // capture_jitter < low => underuse 183 EXPECT_CALL(*(observer_.get()), NormalUsage()).Times(testing::AtLeast(1)); 184 TriggerNormalUsage(); 185 } 186 187 TEST_F(OveruseFrameDetectorTest, OveruseAndRecoverWithNoObserver) { 188 overuse_detector_->SetObserver(NULL); 189 EXPECT_CALL(*(observer_.get()), OveruseDetected()).Times(0); 190 TriggerOveruse(options_.high_threshold_consecutive_count); 191 EXPECT_CALL(*(observer_.get()), NormalUsage()).Times(0); 192 TriggerNormalUsage(); 193 } 194 195 TEST_F(OveruseFrameDetectorTest, OveruseAndRecoverWithMethodDisabled) { 196 options_.enable_capture_jitter_method = false; 197 options_.enable_encode_usage_method = false; 198 overuse_detector_->SetOptions(options_); 199 EXPECT_CALL(*(observer_.get()), OveruseDetected()).Times(0); 200 TriggerOveruse(options_.high_threshold_consecutive_count); 201 EXPECT_CALL(*(observer_.get()), NormalUsage()).Times(0); 202 TriggerNormalUsage(); 203 } 204 205 TEST_F(OveruseFrameDetectorTest, DoubleOveruseAndRecover) { 206 EXPECT_CALL(*(observer_.get()), OveruseDetected()).Times(2); 207 TriggerOveruse(options_.high_threshold_consecutive_count); 208 TriggerOveruse(options_.high_threshold_consecutive_count); 209 EXPECT_CALL(*(observer_.get()), NormalUsage()).Times(testing::AtLeast(1)); 210 TriggerNormalUsage(); 211 } 212 213 TEST_F(OveruseFrameDetectorTest, TriggerNormalUsageWithMinProcessCount) { 214 CpuOveruseObserverImpl overuse_observer_; 215 overuse_detector_->SetObserver(&overuse_observer_); 216 options_.min_process_count = 1; 217 overuse_detector_->SetOptions(options_); 218 InsertFramesWithInterval(900, kFrameInterval33ms, kWidth, kHeight); 219 overuse_detector_->Process(); 220 EXPECT_EQ(0, overuse_observer_.normaluse_); 221 clock_->AdvanceTimeMilliseconds(kProcessIntervalMs); 222 overuse_detector_->Process(); 223 EXPECT_EQ(1, overuse_observer_.normaluse_); 224 } 225 226 TEST_F(OveruseFrameDetectorTest, ConstantOveruseGivesNoNormalUsage) { 227 EXPECT_CALL(*(observer_.get()), NormalUsage()).Times(0); 228 EXPECT_CALL(*(observer_.get()), OveruseDetected()).Times(64); 229 for(size_t i = 0; i < 64; ++i) { 230 TriggerOveruse(options_.high_threshold_consecutive_count); 231 } 232 } 233 234 TEST_F(OveruseFrameDetectorTest, ConsecutiveCountTriggersOveruse) { 235 EXPECT_CALL(*(observer_.get()), OveruseDetected()).Times(1); 236 options_.high_threshold_consecutive_count = 2; 237 overuse_detector_->SetOptions(options_); 238 TriggerOveruse(2); 239 } 240 241 TEST_F(OveruseFrameDetectorTest, IncorrectConsecutiveCountTriggersNoOveruse) { 242 EXPECT_CALL(*(observer_.get()), OveruseDetected()).Times(0); 243 options_.high_threshold_consecutive_count = 2; 244 overuse_detector_->SetOptions(options_); 245 TriggerOveruse(1); 246 } 247 248 TEST_F(OveruseFrameDetectorTest, GetCpuOveruseMetrics) { 249 CpuOveruseMetrics metrics; 250 overuse_detector_->GetCpuOveruseMetrics(&metrics); 251 EXPECT_GT(metrics.capture_jitter_ms, 0); 252 EXPECT_GT(metrics.avg_encode_time_ms, 0); 253 EXPECT_GT(metrics.encode_usage_percent, 0); 254 EXPECT_GE(metrics.capture_queue_delay_ms_per_s, 0); 255 EXPECT_GE(metrics.encode_rsd, 0); 256 } 257 258 TEST_F(OveruseFrameDetectorTest, CaptureJitter) { 259 EXPECT_EQ(InitialJitter(), CaptureJitterMs()); 260 InsertFramesWithInterval(1000, kFrameInterval33ms, kWidth, kHeight); 261 EXPECT_NE(InitialJitter(), CaptureJitterMs()); 262 } 263 264 TEST_F(OveruseFrameDetectorTest, CaptureJitterResetAfterResolutionChange) { 265 EXPECT_EQ(InitialJitter(), CaptureJitterMs()); 266 InsertFramesWithInterval(1000, kFrameInterval33ms, kWidth, kHeight); 267 EXPECT_NE(InitialJitter(), CaptureJitterMs()); 268 // Verify reset. 269 InsertFramesWithInterval(1, kFrameInterval33ms, kWidth, kHeight + 1); 270 EXPECT_EQ(InitialJitter(), CaptureJitterMs()); 271 } 272 273 TEST_F(OveruseFrameDetectorTest, CaptureJitterResetAfterFrameTimeout) { 274 EXPECT_EQ(InitialJitter(), CaptureJitterMs()); 275 InsertFramesWithInterval(1000, kFrameInterval33ms, kWidth, kHeight); 276 EXPECT_NE(InitialJitter(), CaptureJitterMs()); 277 InsertFramesWithInterval( 278 1, options_.frame_timeout_interval_ms, kWidth, kHeight); 279 EXPECT_NE(InitialJitter(), CaptureJitterMs()); 280 // Verify reset. 281 InsertFramesWithInterval( 282 1, options_.frame_timeout_interval_ms + 1, kWidth, kHeight); 283 EXPECT_EQ(InitialJitter(), CaptureJitterMs()); 284 } 285 286 TEST_F(OveruseFrameDetectorTest, CaptureJitterResetAfterChangingThreshold) { 287 EXPECT_EQ(InitialJitter(), CaptureJitterMs()); 288 options_.high_capture_jitter_threshold_ms = 90.0f; 289 overuse_detector_->SetOptions(options_); 290 EXPECT_EQ(InitialJitter(), CaptureJitterMs()); 291 options_.low_capture_jitter_threshold_ms = 30.0f; 292 overuse_detector_->SetOptions(options_); 293 EXPECT_EQ(InitialJitter(), CaptureJitterMs()); 294 } 295 296 TEST_F(OveruseFrameDetectorTest, MinFrameSamplesBeforeUpdatingCaptureJitter) { 297 options_.min_frame_samples = 40; 298 overuse_detector_->SetOptions(options_); 299 InsertFramesWithInterval(40, kFrameInterval33ms, kWidth, kHeight); 300 EXPECT_EQ(InitialJitter(), CaptureJitterMs()); 301 } 302 303 TEST_F(OveruseFrameDetectorTest, NoCaptureQueueDelay) { 304 EXPECT_EQ(overuse_detector_->CaptureQueueDelayMsPerS(), 0); 305 overuse_detector_->FrameCaptured(kWidth, kHeight); 306 overuse_detector_->FrameProcessingStarted(); 307 EXPECT_EQ(overuse_detector_->CaptureQueueDelayMsPerS(), 0); 308 } 309 310 TEST_F(OveruseFrameDetectorTest, CaptureQueueDelay) { 311 overuse_detector_->FrameCaptured(kWidth, kHeight); 312 clock_->AdvanceTimeMilliseconds(100); 313 overuse_detector_->FrameProcessingStarted(); 314 EXPECT_EQ(overuse_detector_->CaptureQueueDelayMsPerS(), 100); 315 } 316 317 TEST_F(OveruseFrameDetectorTest, CaptureQueueDelayMultipleFrames) { 318 overuse_detector_->FrameCaptured(kWidth, kHeight); 319 clock_->AdvanceTimeMilliseconds(10); 320 overuse_detector_->FrameCaptured(kWidth, kHeight); 321 clock_->AdvanceTimeMilliseconds(20); 322 323 overuse_detector_->FrameProcessingStarted(); 324 EXPECT_EQ(overuse_detector_->CaptureQueueDelayMsPerS(), 30); 325 overuse_detector_->FrameProcessingStarted(); 326 EXPECT_EQ(overuse_detector_->CaptureQueueDelayMsPerS(), 20); 327 } 328 329 TEST_F(OveruseFrameDetectorTest, CaptureQueueDelayResetAtResolutionSwitch) { 330 overuse_detector_->FrameCaptured(kWidth, kHeight); 331 clock_->AdvanceTimeMilliseconds(10); 332 overuse_detector_->FrameCaptured(kWidth, kHeight + 1); 333 clock_->AdvanceTimeMilliseconds(20); 334 335 overuse_detector_->FrameProcessingStarted(); 336 EXPECT_EQ(overuse_detector_->CaptureQueueDelayMsPerS(), 20); 337 } 338 339 TEST_F(OveruseFrameDetectorTest, CaptureQueueDelayNoMatchingCapturedFrame) { 340 overuse_detector_->FrameCaptured(kWidth, kHeight); 341 clock_->AdvanceTimeMilliseconds(100); 342 overuse_detector_->FrameProcessingStarted(); 343 EXPECT_EQ(overuse_detector_->CaptureQueueDelayMsPerS(), 100); 344 // No new captured frame. The last delay should be reported. 345 overuse_detector_->FrameProcessingStarted(); 346 EXPECT_EQ(overuse_detector_->CaptureQueueDelayMsPerS(), 100); 347 } 348 349 TEST_F(OveruseFrameDetectorTest, EncodedFrame) { 350 const int kInitialAvgEncodeTimeInMs = 5; 351 EXPECT_EQ(kInitialAvgEncodeTimeInMs, AvgEncodeTimeMs()); 352 for (int i = 0; i < 30; i++) { 353 clock_->AdvanceTimeMilliseconds(33); 354 overuse_detector_->FrameEncoded(2); 355 } 356 EXPECT_EQ(2, AvgEncodeTimeMs()); 357 } 358 359 TEST_F(OveruseFrameDetectorTest, InitialEncodeUsage) { 360 EXPECT_EQ(InitialEncodeUsage(), EncodeUsagePercent()); 361 } 362 363 TEST_F(OveruseFrameDetectorTest, EncodedUsage) { 364 const int kEncodeTimeMs = 5; 365 InsertAndEncodeFramesWithInterval( 366 1000, kFrameInterval33ms, kWidth, kHeight, kEncodeTimeMs); 367 EXPECT_EQ(kEncodeTimeMs * 100 / kFrameInterval33ms, EncodeUsagePercent()); 368 } 369 370 TEST_F(OveruseFrameDetectorTest, EncodeUsageResetAfterChangingThreshold) { 371 EXPECT_EQ(InitialEncodeUsage(), EncodeUsagePercent()); 372 options_.high_encode_usage_threshold_percent = 100; 373 overuse_detector_->SetOptions(options_); 374 EXPECT_EQ(InitialEncodeUsage(), EncodeUsagePercent()); 375 options_.low_encode_usage_threshold_percent = 20; 376 overuse_detector_->SetOptions(options_); 377 EXPECT_EQ(InitialEncodeUsage(), EncodeUsagePercent()); 378 } 379 380 // enable_encode_usage_method = true; 381 // EncodeUsagePercent() > high_encode_usage_threshold_percent => overuse. 382 // EncodeUsagePercent() < low_encode_usage_threshold_percent => underuse. 383 TEST_F(OveruseFrameDetectorTest, TriggerOveruseWithEncodeUsage) { 384 options_.enable_capture_jitter_method = false; 385 options_.enable_encode_usage_method = true; 386 overuse_detector_->SetOptions(options_); 387 // usage > high => overuse 388 EXPECT_CALL(*(observer_.get()), OveruseDetected()).Times(1); 389 TriggerOveruseWithEncodeUsage(options_.high_threshold_consecutive_count); 390 } 391 392 TEST_F(OveruseFrameDetectorTest, OveruseAndRecoverWithEncodeUsage) { 393 options_.enable_capture_jitter_method = false; 394 options_.enable_encode_usage_method = true; 395 overuse_detector_->SetOptions(options_); 396 // usage > high => overuse 397 EXPECT_CALL(*(observer_.get()), OveruseDetected()).Times(1); 398 TriggerOveruseWithEncodeUsage(options_.high_threshold_consecutive_count); 399 // usage < low => underuse 400 EXPECT_CALL(*(observer_.get()), NormalUsage()).Times(testing::AtLeast(1)); 401 TriggerNormalUsageWithEncodeTime(); 402 } 403 404 TEST_F(OveruseFrameDetectorTest, 405 OveruseAndRecoverWithEncodeUsageMethodDisabled) { 406 options_.enable_capture_jitter_method = false; 407 options_.enable_encode_usage_method = false; 408 overuse_detector_->SetOptions(options_); 409 // usage > high => overuse 410 EXPECT_CALL(*(observer_.get()), OveruseDetected()).Times(0); 411 TriggerOveruseWithEncodeUsage(options_.high_threshold_consecutive_count); 412 // usage < low => underuse 413 EXPECT_CALL(*(observer_.get()), NormalUsage()).Times(0); 414 TriggerNormalUsageWithEncodeTime(); 415 } 416 417 TEST_F(OveruseFrameDetectorTest, EncodeRsdResetAfterChangingThreshold) { 418 EXPECT_EQ(InitialEncodeRsd(), EncodeRsd()); 419 options_.high_encode_time_rsd_threshold = 100; 420 overuse_detector_->SetOptions(options_); 421 EXPECT_EQ(InitialEncodeRsd(), EncodeRsd()); 422 options_.low_encode_time_rsd_threshold = 20; 423 overuse_detector_->SetOptions(options_); 424 EXPECT_EQ(InitialEncodeRsd(), EncodeRsd()); 425 } 426 427 // enable_encode_usage_method = true; 428 // low/high_encode_time_rsd_threshold >= 0 429 // EncodeUsagePercent() > high_encode_usage_threshold_percent || 430 // EncodeRsd() > high_encode_time_rsd_threshold => overuse. 431 // EncodeUsagePercent() < low_encode_usage_threshold_percent && 432 // EncodeRsd() < low_encode_time_rsd_threshold => underuse. 433 TEST_F(OveruseFrameDetectorTest, TriggerOveruseWithEncodeRsd) { 434 options_.enable_capture_jitter_method = false; 435 options_.enable_encode_usage_method = true; 436 options_.high_encode_time_rsd_threshold = 80; 437 overuse_detector_->SetOptions(options_); 438 // rsd > high, usage < high => overuse 439 EXPECT_CALL(*(observer_.get()), OveruseDetected()).Times(1); 440 TriggerOveruseWithEncodeRsd(options_.high_threshold_consecutive_count); 441 EXPECT_LT(EncodeUsagePercent(), options_.high_encode_usage_threshold_percent); 442 } 443 444 TEST_F(OveruseFrameDetectorTest, OveruseAndRecoverWithEncodeRsd) { 445 options_.enable_capture_jitter_method = false; 446 options_.enable_encode_usage_method = true; 447 options_.low_encode_time_rsd_threshold = 20; 448 options_.high_encode_time_rsd_threshold = 80; 449 overuse_detector_->SetOptions(options_); 450 // rsd > high, usage < high => overuse 451 EXPECT_CALL(*(observer_.get()), OveruseDetected()).Times(1); 452 TriggerOveruseWithEncodeRsd(options_.high_threshold_consecutive_count); 453 EXPECT_LT(EncodeUsagePercent(), options_.high_encode_usage_threshold_percent); 454 // rsd < low, usage < low => underuse 455 EXPECT_CALL(*(observer_.get()), NormalUsage()).Times(testing::AtLeast(1)); 456 TriggerNormalUsageWithEncodeTime(); 457 } 458 459 TEST_F(OveruseFrameDetectorTest, NoUnderuseWithEncodeRsd_UsageGtLowThreshold) { 460 options_.enable_capture_jitter_method = false; 461 options_.enable_encode_usage_method = true; 462 options_.low_encode_usage_threshold_percent = 1; 463 options_.low_encode_time_rsd_threshold = 20; 464 options_.high_encode_time_rsd_threshold = 90; 465 overuse_detector_->SetOptions(options_); 466 // rsd < low, usage > low => no underuse 467 EXPECT_CALL(*(observer_.get()), NormalUsage()).Times(0); 468 TriggerNormalUsageWithEncodeTime(); 469 EXPECT_LT(EncodeRsd(), options_.low_encode_time_rsd_threshold); 470 EXPECT_GT(EncodeUsagePercent(), options_.low_encode_usage_threshold_percent); 471 } 472 473 TEST_F(OveruseFrameDetectorTest, NoUnderuseWithEncodeRsd_RsdGtLowThreshold) { 474 options_.enable_capture_jitter_method = false; 475 options_.enable_encode_usage_method = true; 476 options_.low_encode_usage_threshold_percent = 20; 477 options_.low_encode_time_rsd_threshold = 1; 478 options_.high_encode_time_rsd_threshold = 90; 479 overuse_detector_->SetOptions(options_); 480 // rsd > low, usage < low => no underuse 481 EXPECT_CALL(*(observer_.get()), NormalUsage()).Times(0); 482 TriggerNormalUsageWithEncodeTime(); 483 EXPECT_GT(EncodeRsd(), options_.low_encode_time_rsd_threshold); 484 EXPECT_LT(EncodeUsagePercent(), options_.low_encode_usage_threshold_percent); 485 } 486 } // namespace webrtc 487