Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include <numeric> | 5 #include <numeric> |
| 6 #include <utility> | 6 #include <utility> |
| 7 | 7 |
| 8 #include "base/base64.h" | 8 #include "base/base64.h" |
| 9 #include "base/files/file_util.h" | 9 #include "base/files/file_util.h" |
| 10 #include "base/macros.h" | 10 #include "base/macros.h" |
| (...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 156 if (!done.is_null()) | 156 if (!done.is_null()) |
| 157 done.Run(); | 157 done.Run(); |
| 158 } | 158 } |
| 159 | 159 |
| 160 protocol::FrameConsumer::PixelFormat GetPixelFormat() override { | 160 protocol::FrameConsumer::PixelFormat GetPixelFormat() override { |
| 161 return FORMAT_BGRA; | 161 return FORMAT_BGRA; |
| 162 } | 162 } |
| 163 | 163 |
| 164 // FrameStatsConsumer interface. | 164 // FrameStatsConsumer interface. |
| 165 void OnVideoFrameStats(const protocol::FrameStats& frame_stats) override { | 165 void OnVideoFrameStats(const protocol::FrameStats& frame_stats) override { |
| 166 // Ignore store stats for empty frames. | |
| 167 if (!frame_stats.host_stats.frame_size) | |
| 168 return; | |
| 169 | |
| 166 frame_stats_.push_back(frame_stats); | 170 frame_stats_.push_back(frame_stats); |
| 167 | 171 |
| 168 if (waiting_frame_stats_loop_ && | 172 if (waiting_frame_stats_loop_ && |
| 169 frame_stats_.size() >= num_expected_frame_stats_) { | 173 frame_stats_.size() >= num_expected_frame_stats_) { |
| 170 waiting_frame_stats_loop_->Quit(); | 174 waiting_frame_stats_loop_->Quit(); |
| 171 } | 175 } |
| 172 } | 176 } |
| 173 | 177 |
| 174 // HostStatusObserver interface. | 178 // HostStatusObserver interface. |
| 175 void OnClientConnected(const std::string& jid) override { | 179 void OnClientConnected(const std::string& jid) override { |
| 180 if (event_timestamp_source_) { | |
| 181 auto& session = host_->client_sessions_for_tests().front(); | |
| 182 session->SetEventTimestampsSourceForTests( | |
| 183 std::move(event_timestamp_source_)); | |
| 184 } | |
| 185 | |
| 176 message_loop_.task_runner()->PostTask( | 186 message_loop_.task_runner()->PostTask( |
| 177 FROM_HERE, base::Bind(&ProtocolPerfTest::OnHostConnectedMainThread, | 187 FROM_HERE, base::Bind(&ProtocolPerfTest::OnHostConnectedMainThread, |
| 178 base::Unretained(this))); | 188 base::Unretained(this))); |
| 179 } | 189 } |
| 180 | 190 |
| 181 protected: | 191 protected: |
| 182 void WaitConnected() { | 192 void WaitConnected() { |
| 183 client_connected_ = false; | 193 client_connected_ = false; |
| 184 host_connected_ = false; | 194 host_connected_ = false; |
| 185 | 195 |
| (...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 353 base::MessageLoopForIO message_loop_; | 363 base::MessageLoopForIO message_loop_; |
| 354 | 364 |
| 355 scoped_refptr<FakeNetworkDispatcher> fake_network_dispatcher_; | 365 scoped_refptr<FakeNetworkDispatcher> fake_network_dispatcher_; |
| 356 | 366 |
| 357 base::Thread host_thread_; | 367 base::Thread host_thread_; |
| 358 base::Thread capture_thread_; | 368 base::Thread capture_thread_; |
| 359 base::Thread encode_thread_; | 369 base::Thread encode_thread_; |
| 360 base::Thread decode_thread_; | 370 base::Thread decode_thread_; |
| 361 std::unique_ptr<FakeDesktopEnvironmentFactory> desktop_environment_factory_; | 371 std::unique_ptr<FakeDesktopEnvironmentFactory> desktop_environment_factory_; |
| 362 | 372 |
| 373 scoped_refptr<protocol::InputEventTimestampsSource> event_timestamp_source_; | |
| 374 | |
| 363 FakeCursorShapeStub cursor_shape_stub_; | 375 FakeCursorShapeStub cursor_shape_stub_; |
| 364 | 376 |
| 365 std::unique_ptr<protocol::CandidateSessionConfig> protocol_config_; | 377 std::unique_ptr<protocol::CandidateSessionConfig> protocol_config_; |
| 366 | 378 |
| 367 std::unique_ptr<FakeSignalStrategy> host_signaling_; | 379 std::unique_ptr<FakeSignalStrategy> host_signaling_; |
| 368 std::unique_ptr<FakeSignalStrategy> client_signaling_; | 380 std::unique_ptr<FakeSignalStrategy> client_signaling_; |
| 369 | 381 |
| 370 std::unique_ptr<ChromotingHost> host_; | 382 std::unique_ptr<ChromotingHost> host_; |
| 371 std::unique_ptr<ClientContext> client_context_; | 383 std::unique_ptr<ClientContext> client_context_; |
| 372 std::unique_ptr<SoftwareVideoRenderer> video_renderer_; | 384 std::unique_ptr<SoftwareVideoRenderer> video_renderer_; |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 429 NetworkPerformanceParams(100000, 30000, 130, 5, 0.00), | 441 NetworkPerformanceParams(100000, 30000, 130, 5, 0.00), |
| 430 NetworkPerformanceParams(100000, 200000, 130, 5, 0.00))); | 442 NetworkPerformanceParams(100000, 200000, 130, 5, 0.00))); |
| 431 | 443 |
| 432 // TotalLatency[Ice|Webrtc] tests measure video latency in the case when the | 444 // TotalLatency[Ice|Webrtc] tests measure video latency in the case when the |
| 433 // whole screen is updated occasionally. It's intended to simulate the case when | 445 // whole screen is updated occasionally. It's intended to simulate the case when |
| 434 // user actions (e.g. Alt-Tab, click on the task bar) cause whole screen to be | 446 // user actions (e.g. Alt-Tab, click on the task bar) cause whole screen to be |
| 435 // updated. | 447 // updated. |
| 436 void ProtocolPerfTest::MeasureTotalLatency(bool use_webrtc) { | 448 void ProtocolPerfTest::MeasureTotalLatency(bool use_webrtc) { |
| 437 scoped_refptr<test::CyclicFrameGenerator> frame_generator = | 449 scoped_refptr<test::CyclicFrameGenerator> frame_generator = |
| 438 test::CyclicFrameGenerator::Create(); | 450 test::CyclicFrameGenerator::Create(); |
| 439 frame_generator->set_draw_barcode(true); | |
| 440 | |
| 441 desktop_environment_factory_->set_frame_generator( | 451 desktop_environment_factory_->set_frame_generator( |
| 442 base::Bind(&test::CyclicFrameGenerator::GenerateFrame, frame_generator)); | 452 base::Bind(&test::CyclicFrameGenerator::GenerateFrame, frame_generator)); |
| 453 event_timestamp_source_ = frame_generator; | |
| 443 | 454 |
| 444 StartHostAndClient(use_webrtc); | 455 StartHostAndClient(use_webrtc); |
| 445 ASSERT_NO_FATAL_FAILURE(WaitConnected()); | 456 ASSERT_NO_FATAL_FAILURE(WaitConnected()); |
| 446 | 457 |
| 447 int skipped_frames = 0; | 458 int warm_up_frames = 0; |
| 448 while (skipped_frames < 10) { | 459 int total_frames = 0; |
| 449 std::unique_ptr<webrtc::DesktopFrame> frame = ReceiveFrame(); | 460 |
| 450 test::CyclicFrameGenerator::ChangeInfoList changes = | 461 base::TimeTicks start_time = base::TimeTicks::Now(); |
| 451 frame_generator->GetChangeList(frame.get()); | 462 const base::TimeDelta kWarmUpTime = base::TimeDelta::FromSeconds(2); |
| 452 skipped_frames += changes.size(); | 463 while ((base::TimeTicks::Now() - start_time) < kWarmUpTime) { |
| 464 ReceiveFrame(); | |
| 465 ++warm_up_frames; | |
| 466 ++total_frames; | |
| 453 } | 467 } |
|
Jamie
2016/10/14 23:26:07
Please add a comment explaining why warm-up frames
Sergey Ulanov
2016/10/17 22:40:26
Done. Also simplified this code to avoid duplicate
| |
| 454 | 468 |
| 455 base::TimeDelta total_latency_big_frames; | 469 start_time = base::TimeTicks::Now(); |
| 456 int big_frame_count = 0; | 470 const base::TimeDelta kTestTime = base::TimeDelta::FromSeconds(5); |
| 457 base::TimeDelta total_latency_small_frames; | 471 while ((base::TimeTicks::Now() - start_time) < kTestTime) { |
| 458 int small_frame_count = 0; | 472 ReceiveFrame(); |
| 473 ++total_frames; | |
| 474 } | |
| 459 | 475 |
| 460 while (big_frame_count + small_frame_count < 30) { | 476 WaitFrameStats(total_frames); |
| 461 std::unique_ptr<webrtc::DesktopFrame> frame = ReceiveFrame(); | 477 |
| 462 base::TimeTicks frame_received_time = base::TimeTicks::Now(); | 478 int big_update_count = 0; |
| 479 base::TimeDelta total_latency_big_updates; | |
| 480 int small_update_count = 0; | |
| 481 base::TimeDelta total_latency_small_updates; | |
| 482 for (int i = 0; i < total_frames; ++i) { | |
| 483 const protocol::FrameStats& stats = frame_stats_[i]; | |
| 484 if (stats.host_stats.latest_event_timestamp.is_null()) | |
| 485 continue; | |
|
Jamie
2016/10/14 23:26:07
Under what circumstances do we expect this to be n
Sergey Ulanov
2016/10/17 22:40:26
Actually it should never be null because CyclicFra
| |
| 463 test::CyclicFrameGenerator::ChangeInfoList changes = | 486 test::CyclicFrameGenerator::ChangeInfoList changes = |
| 464 frame_generator->GetChangeList(frame.get()); | 487 frame_generator->GetChangeList(stats.host_stats.latest_event_timestamp); |
| 488 if (i < warm_up_frames) | |
| 489 continue; | |
| 490 | |
| 465 for (auto& change_info : changes) { | 491 for (auto& change_info : changes) { |
| 466 base::TimeDelta latency = frame_received_time - change_info.timestamp; | 492 base::TimeDelta latency = |
| 493 stats.client_stats.time_rendered - change_info.timestamp; | |
| 467 switch (change_info.type) { | 494 switch (change_info.type) { |
| 468 case test::CyclicFrameGenerator::ChangeType::NO_CHANGES: | 495 case test::CyclicFrameGenerator::ChangeType::NO_CHANGES: |
| 469 NOTREACHED(); | 496 NOTREACHED(); |
| 470 break; | 497 break; |
| 471 case test::CyclicFrameGenerator::ChangeType::FULL: | 498 case test::CyclicFrameGenerator::ChangeType::FULL: |
| 472 total_latency_big_frames += latency; | 499 total_latency_big_updates += latency; |
| 473 ++big_frame_count; | 500 ++big_update_count; |
| 474 break; | 501 break; |
| 475 case test::CyclicFrameGenerator::ChangeType::CURSOR: | 502 case test::CyclicFrameGenerator::ChangeType::CURSOR: |
| 476 total_latency_small_frames += latency; | 503 total_latency_small_updates += latency; |
| 477 ++small_frame_count; | 504 ++small_update_count; |
| 478 break; | 505 break; |
| 479 } | 506 } |
| 480 } | 507 } |
| 481 } | 508 } |
| 482 | 509 |
| 483 CHECK(big_frame_count); | 510 CHECK(big_update_count); |
| 484 VLOG(0) << "Average latency for big frames: " | 511 VLOG(0) << "Average latency for big updates: " |
| 485 << (total_latency_big_frames / big_frame_count).InMillisecondsF(); | 512 << (total_latency_big_updates / big_update_count).InMillisecondsF() |
| 513 << " " << big_update_count; | |
| 486 | 514 |
| 487 if (small_frame_count) { | 515 if (small_update_count) { |
| 488 VLOG(0) | 516 VLOG(0) |
| 489 << "Average latency for small frames: " | 517 << "Average latency for small updates: " |
| 490 << (total_latency_small_frames / small_frame_count).InMillisecondsF(); | 518 << (total_latency_small_updates / small_update_count).InMillisecondsF() |
| 519 << " " << small_update_count; | |
| 491 } | 520 } |
| 492 } | 521 } |
| 493 | 522 |
| 494 TEST_P(ProtocolPerfTest, TotalLatencyIce) { | 523 TEST_P(ProtocolPerfTest, TotalLatencyIce) { |
| 495 MeasureTotalLatency(false); | 524 MeasureTotalLatency(false); |
| 496 } | 525 } |
| 497 | 526 |
| 498 TEST_P(ProtocolPerfTest, TotalLatencyWebrtc) { | 527 TEST_P(ProtocolPerfTest, TotalLatencyWebrtc) { |
| 499 MeasureTotalLatency(true); | 528 MeasureTotalLatency(true); |
| 500 } | 529 } |
| 501 | 530 |
| 502 // ScrollPerformance[Ice|Webrtc] tests simulate whole screen being scrolled | 531 // ScrollPerformance[Ice|Webrtc] tests simulate whole screen being scrolled |
| 503 // continuously. They measure FPS and video latency. | 532 // continuously. They measure FPS and video latency. |
| 504 void ProtocolPerfTest::MeasureScrollPerformance(bool use_webrtc) { | 533 void ProtocolPerfTest::MeasureScrollPerformance(bool use_webrtc) { |
| 505 scoped_refptr<test::ScrollFrameGenerator> frame_generator = | 534 scoped_refptr<test::ScrollFrameGenerator> frame_generator = |
| 506 new test::ScrollFrameGenerator(); | 535 new test::ScrollFrameGenerator(); |
| 507 | |
| 508 desktop_environment_factory_->set_frame_generator( | 536 desktop_environment_factory_->set_frame_generator( |
| 509 base::Bind(&test::ScrollFrameGenerator::GenerateFrame, frame_generator)); | 537 base::Bind(&test::ScrollFrameGenerator::GenerateFrame, frame_generator)); |
| 538 event_timestamp_source_ = frame_generator; | |
| 510 | 539 |
| 511 StartHostAndClient(use_webrtc); | 540 StartHostAndClient(use_webrtc); |
| 512 ASSERT_NO_FATAL_FAILURE(WaitConnected()); | 541 ASSERT_NO_FATAL_FAILURE(WaitConnected()); |
| 513 | 542 |
| 514 int warm_up_frames = 0; | 543 int warm_up_frames = 0; |
| 515 | 544 |
| 516 base::TimeTicks start_time = base::TimeTicks::Now(); | 545 base::TimeTicks start_time = base::TimeTicks::Now(); |
| 517 const base::TimeDelta kWarmUpTime = base::TimeDelta::FromSeconds(2); | 546 const base::TimeDelta kWarmUpTime = base::TimeDelta::FromSeconds(2); |
| 518 while ((base::TimeTicks::Now() - start_time) < kWarmUpTime) { | 547 while ((base::TimeTicks::Now() - start_time) < kWarmUpTime) { |
| 519 ReceiveFrame(); | 548 ReceiveFrame(); |
| 520 ++warm_up_frames; | 549 ++warm_up_frames; |
| 521 } | 550 } |
| 522 | 551 |
| 523 client_socket_factory_->ResetStats(); | 552 client_socket_factory_->ResetStats(); |
| 524 | 553 |
| 525 // Run the test for 2 seconds. | 554 // Run the test for 2 seconds. |
| 526 const base::TimeDelta kTestTime = base::TimeDelta::FromSeconds(2); | 555 const base::TimeDelta kTestTime = base::TimeDelta::FromSeconds(2); |
| 527 | 556 |
| 528 int num_frames = 0; | 557 int num_frames = 0; |
| 529 base::TimeDelta latency_sum; | |
| 530 start_time = base::TimeTicks::Now(); | 558 start_time = base::TimeTicks::Now(); |
| 531 while ((base::TimeTicks::Now() - start_time) < kTestTime) { | 559 while ((base::TimeTicks::Now() - start_time) < kTestTime) { |
| 532 std::unique_ptr<webrtc::DesktopFrame> frame = ReceiveFrame(); | 560 std::unique_ptr<webrtc::DesktopFrame> frame = ReceiveFrame(); |
| 533 ++num_frames; | 561 ++num_frames; |
| 534 latency_sum += frame_generator->GetFrameLatency(*frame); | |
| 535 } | 562 } |
| 536 | 563 |
| 537 base::TimeDelta total_time = (base::TimeTicks::Now() - start_time); | 564 base::TimeDelta total_time = (base::TimeTicks::Now() - start_time); |
| 538 | 565 |
| 539 WaitFrameStats(warm_up_frames + num_frames); | 566 WaitFrameStats(warm_up_frames + num_frames); |
| 540 | 567 |
| 541 int total_size = | 568 int total_size = |
| 542 std::accumulate(frame_stats_.begin() + warm_up_frames, | 569 std::accumulate(frame_stats_.begin() + warm_up_frames, |
| 543 frame_stats_.begin() + warm_up_frames + num_frames, 0, | 570 frame_stats_.begin() + warm_up_frames + num_frames, 0, |
| 544 [](int sum, const protocol::FrameStats& stats) { | 571 [](int sum, const protocol::FrameStats& stats) { |
| 545 return sum + stats.host_stats.frame_size; | 572 return sum + stats.host_stats.frame_size; |
| 546 }); | 573 }); |
| 547 | 574 |
| 575 base::TimeDelta latency_sum = std::accumulate( | |
| 576 frame_stats_.begin() + warm_up_frames, | |
| 577 frame_stats_.begin() + warm_up_frames + num_frames, base::TimeDelta(), | |
| 578 [](base::TimeDelta sum, const protocol::FrameStats& stats) { | |
| 579 return sum + (stats.client_stats.time_rendered - | |
| 580 stats.host_stats.latest_event_timestamp); | |
| 581 }); | |
| 582 | |
| 548 VLOG(0) << "FPS: " << num_frames / total_time.InSecondsF(); | 583 VLOG(0) << "FPS: " << num_frames / total_time.InSecondsF(); |
| 549 VLOG(0) << "Average latency: " << latency_sum.InMillisecondsF() / num_frames | 584 VLOG(0) << "Average latency: " << latency_sum.InMillisecondsF() / num_frames |
| 550 << " ms"; | 585 << " ms"; |
| 551 VLOG(0) << "Total size: " << total_size << " bytes"; | 586 VLOG(0) << "Total size: " << total_size << " bytes"; |
| 552 VLOG(0) << "Bandwidth utilization: " | 587 VLOG(0) << "Bandwidth utilization: " |
| 553 << 100 * total_size / (total_time.InSecondsF() * GetParam().bandwidth) | 588 << 100 * total_size / (total_time.InSecondsF() * GetParam().bandwidth) |
| 554 << "%"; | 589 << "%"; |
| 555 VLOG(0) << "Network buffer delay (bufferbloat), average: " | 590 VLOG(0) << "Network buffer delay (bufferbloat), average: " |
| 556 << client_socket_factory_->average_buffer_delay().InMilliseconds() | 591 << client_socket_factory_->average_buffer_delay().InMilliseconds() |
| 557 << " ms, max:" | 592 << " ms, max:" |
| 558 << client_socket_factory_->max_buffer_delay().InMilliseconds() | 593 << client_socket_factory_->max_buffer_delay().InMilliseconds() |
| 559 << " ms"; | 594 << " ms"; |
| 560 VLOG(0) << "Packet drop rate: " << client_socket_factory_->drop_rate(); | 595 VLOG(0) << "Packet drop rate: " << client_socket_factory_->drop_rate(); |
| 561 } | 596 } |
| 562 | 597 |
| 563 TEST_P(ProtocolPerfTest, ScrollPerformanceIce) { | 598 TEST_P(ProtocolPerfTest, ScrollPerformanceIce) { |
| 564 MeasureScrollPerformance(false); | 599 MeasureScrollPerformance(false); |
| 565 } | 600 } |
| 566 | 601 |
| 567 TEST_P(ProtocolPerfTest, ScrollPerformanceWebrtc) { | 602 TEST_P(ProtocolPerfTest, ScrollPerformanceWebrtc) { |
| 568 MeasureScrollPerformance(true); | 603 MeasureScrollPerformance(true); |
| 569 } | 604 } |
| 570 | 605 |
| 571 } // namespace remoting | 606 } // namespace remoting |
| OLD | NEW |