protocol_perftest.cc 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666
  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
  3. // found in the LICENSE file.
  4. #include <memory>
  5. #include <numeric>
  6. #include <utility>
  7. #include "base/base64.h"
  8. #include "base/bind.h"
  9. #include "base/files/file_util.h"
  10. #include "base/logging.h"
  11. #include "base/memory/raw_ptr.h"
  12. #include "base/message_loop/message_pump_type.h"
  13. #include "base/rand_util.h"
  14. #include "base/run_loop.h"
  15. #include "base/synchronization/waitable_event.h"
  16. #include "base/task/single_thread_task_runner.h"
  17. #include "base/task/task_runner_util.h"
  18. #include "base/task/thread_pool/thread_pool_instance.h"
  19. #include "base/test/task_environment.h"
  20. #include "base/threading/thread_task_runner_handle.h"
  21. #include "base/time/time.h"
  22. #include "components/webrtc/thread_wrapper.h"
  23. #include "net/base/network_change_notifier.h"
  24. #include "net/test/test_data_directory.h"
  25. #include "net/url_request/url_request_context_getter.h"
  26. #include "remoting/base/rsa_key_pair.h"
  27. #include "remoting/base/url_request.h"
  28. #include "remoting/client/audio/audio_player.h"
  29. #include "remoting/client/chromoting_client.h"
  30. #include "remoting/client/client_context.h"
  31. #include "remoting/client/client_user_interface.h"
  32. #include "remoting/client/software_video_renderer.h"
  33. #include "remoting/host/chromoting_host.h"
  34. #include "remoting/host/chromoting_host_context.h"
  35. #include "remoting/host/fake_desktop_environment.h"
  36. #include "remoting/protocol/auth_util.h"
  37. #include "remoting/protocol/client_authentication_config.h"
  38. #include "remoting/protocol/frame_consumer.h"
  39. #include "remoting/protocol/frame_stats.h"
  40. #include "remoting/protocol/jingle_session_manager.h"
  41. #include "remoting/protocol/me2me_host_authenticator_factory.h"
  42. #include "remoting/protocol/session_config.h"
  43. #include "remoting/protocol/transport_context.h"
  44. #include "remoting/protocol/video_frame_pump.h"
  45. #include "remoting/protocol/video_renderer.h"
  46. #include "remoting/signaling/fake_signal_strategy.h"
  47. #include "remoting/test/cyclic_frame_generator.h"
  48. #include "remoting/test/fake_network_dispatcher.h"
  49. #include "remoting/test/fake_port_allocator.h"
  50. #include "remoting/test/fake_socket_factory.h"
  51. #include "remoting/test/scroll_frame_generator.h"
  52. #include "services/network/public/cpp/shared_url_loader_factory.h"
  53. #include "testing/gtest/include/gtest/gtest.h"
  54. namespace remoting {
  55. using base::test::TaskEnvironment;
  56. using protocol::ChannelConfig;
  57. namespace {
  58. const char kHostJid[] = "host_jid@example.com/host";
  59. const char kHostOwner[] = "jane.doe@example.com";
  60. const char kClientJid[] = "jane.doe@example.com/client";
  61. const char kHostId[] = "ABC123";
  62. const char kHostPin[] = "123456";
  63. struct NetworkPerformanceParams {
  64. // |buffer_s| defines buffer size in seconds. actual buffer size is calculated
  65. // based on bandwidth_kbps
  66. NetworkPerformanceParams(int bandwidth_kbps,
  67. double buffer_s,
  68. double latency_average_ms,
  69. double latency_stddev_ms,
  70. double out_of_order_rate,
  71. double signaling_latency_ms)
  72. : bandwidth_kbps(bandwidth_kbps),
  73. max_buffers(buffer_s * bandwidth_kbps * 1000 / 8),
  74. latency_average(base::Milliseconds(latency_average_ms)),
  75. latency_stddev(base::Milliseconds(latency_stddev_ms)),
  76. out_of_order_rate(out_of_order_rate),
  77. signaling_latency(base::Milliseconds(signaling_latency_ms)) {}
  78. int bandwidth_kbps;
  79. int max_buffers;
  80. base::TimeDelta latency_average;
  81. base::TimeDelta latency_stddev;
  82. double out_of_order_rate;
  83. base::TimeDelta signaling_latency;
  84. };
  85. class FakeCursorShapeStub : public protocol::CursorShapeStub {
  86. public:
  87. FakeCursorShapeStub() = default;
  88. ~FakeCursorShapeStub() override = default;
  89. // protocol::CursorShapeStub interface.
  90. void SetCursorShape(const protocol::CursorShapeInfo& cursor_shape) override {}
  91. };
  92. } // namespace
  93. class ProtocolPerfTest
  94. : public testing::Test,
  95. public testing::WithParamInterface<NetworkPerformanceParams>,
  96. public ClientUserInterface,
  97. public protocol::FrameConsumer,
  98. public protocol::FrameStatsConsumer,
  99. public HostStatusObserver {
  100. public:
  101. ProtocolPerfTest()
  102. : task_environment_(TaskEnvironment::MainThreadType::IO),
  103. host_thread_("host"),
  104. capture_thread_("capture"),
  105. encode_thread_("encode"),
  106. decode_thread_("decode") {
  107. host_thread_.StartWithOptions(
  108. base::Thread::Options(base::MessagePumpType::IO, 0));
  109. capture_thread_.Start();
  110. encode_thread_.Start();
  111. decode_thread_.Start();
  112. network_change_notifier_ = net::NetworkChangeNotifier::CreateIfNeeded();
  113. desktop_environment_factory_ =
  114. std::make_unique<FakeDesktopEnvironmentFactory>(
  115. capture_thread_.task_runner());
  116. }
  117. ProtocolPerfTest(const ProtocolPerfTest&) = delete;
  118. ProtocolPerfTest& operator=(const ProtocolPerfTest&) = delete;
  119. virtual ~ProtocolPerfTest() {
  120. host_thread_.task_runner()->DeleteSoon(FROM_HERE, host_.release());
  121. host_thread_.task_runner()->DeleteSoon(FROM_HERE,
  122. host_signaling_.release());
  123. base::RunLoop().RunUntilIdle();
  124. }
  125. // ClientUserInterface interface.
  126. void OnConnectionState(protocol::ConnectionToHost::State state,
  127. protocol::ErrorCode error) override {
  128. if (state == protocol::ConnectionToHost::CONNECTED) {
  129. client_connected_ = true;
  130. if (host_connected_)
  131. connecting_loop_->Quit();
  132. }
  133. }
  134. void OnConnectionReady(bool ready) override {}
  135. void OnRouteChanged(const std::string& channel_name,
  136. const protocol::TransportRoute& route) override {}
  137. void SetCapabilities(const std::string& capabilities) override {}
  138. void SetPairingResponse(
  139. const protocol::PairingResponse& pairing_response) override {}
  140. void DeliverHostMessage(const protocol::ExtensionMessage& message) override {}
  141. void SetDesktopSize(const webrtc::DesktopSize& size,
  142. const webrtc::DesktopVector& dpi) override {}
  143. protocol::ClipboardStub* GetClipboardStub() override { return nullptr; }
  144. protocol::CursorShapeStub* GetCursorShapeStub() override {
  145. return &cursor_shape_stub_;
  146. }
  147. protocol::KeyboardLayoutStub* GetKeyboardLayoutStub() override {
  148. return nullptr;
  149. }
  150. // protocol::FrameConsumer interface.
  151. std::unique_ptr<webrtc::DesktopFrame> AllocateFrame(
  152. const webrtc::DesktopSize& size) override {
  153. return std::make_unique<webrtc::BasicDesktopFrame>(size);
  154. }
  155. void DrawFrame(std::unique_ptr<webrtc::DesktopFrame> frame,
  156. base::OnceClosure done) override {
  157. last_video_frame_ = std::move(frame);
  158. if (on_frame_task_)
  159. on_frame_task_.Run();
  160. if (done)
  161. std::move(done).Run();
  162. }
  163. protocol::FrameConsumer::PixelFormat GetPixelFormat() override {
  164. return FORMAT_BGRA;
  165. }
  166. // FrameStatsConsumer interface.
  167. void OnVideoFrameStats(const protocol::FrameStats& frame_stats) override {
  168. // Ignore store stats for empty frames.
  169. if (!frame_stats.host_stats.frame_size)
  170. return;
  171. frame_stats_.push_back(frame_stats);
  172. if (waiting_frame_stats_loop_ &&
  173. frame_stats_.size() >= num_expected_frame_stats_) {
  174. waiting_frame_stats_loop_->Quit();
  175. }
  176. }
  177. // HostStatusObserver interface.
  178. void OnClientAuthenticated(const std::string& jid) override {
  179. if (event_timestamp_source_) {
  180. auto& session = host_->client_sessions_for_tests().front();
  181. session->SetEventTimestampsSourceForTests(
  182. std::move(event_timestamp_source_));
  183. }
  184. }
  185. void OnClientConnected(const std::string& jid) override {
  186. task_environment_.GetMainThreadTaskRunner()->PostTask(
  187. FROM_HERE, base::BindOnce(&ProtocolPerfTest::OnHostConnectedMainThread,
  188. base::Unretained(this)));
  189. }
  190. protected:
  191. void WaitConnected() {
  192. client_connected_ = false;
  193. host_connected_ = false;
  194. connecting_loop_ = std::make_unique<base::RunLoop>();
  195. connecting_loop_->Run();
  196. ASSERT_TRUE(client_connected_ && host_connected_);
  197. }
  198. void OnHostConnectedMainThread() {
  199. host_connected_ = true;
  200. if (client_connected_)
  201. connecting_loop_->Quit();
  202. }
  203. std::unique_ptr<webrtc::DesktopFrame> ReceiveFrame() {
  204. last_video_frame_.reset();
  205. waiting_frames_loop_ = std::make_unique<base::RunLoop>();
  206. on_frame_task_ = waiting_frames_loop_->QuitClosure();
  207. waiting_frames_loop_->Run();
  208. waiting_frames_loop_.reset();
  209. EXPECT_TRUE(last_video_frame_);
  210. return std::move(last_video_frame_);
  211. }
  212. void WaitFrameStats(int num_frames) {
  213. num_expected_frame_stats_ = num_frames;
  214. waiting_frame_stats_loop_ = std::make_unique<base::RunLoop>();
  215. waiting_frame_stats_loop_->Run();
  216. waiting_frame_stats_loop_.reset();
  217. EXPECT_GE(frame_stats_.size(), num_expected_frame_stats_);
  218. }
  219. // Creates test host and client and starts connection between them. Caller
  220. // should call WaitConnected() to wait until connection is established. The
  221. // host is started on |host_thread_| while the client works on the main
  222. // thread.
  223. void StartHostAndClient(bool use_webrtc) {
  224. fake_network_dispatcher_ = new FakeNetworkDispatcher();
  225. client_signaling_ =
  226. std::make_unique<FakeSignalStrategy>(SignalingAddress(kClientJid));
  227. webrtc::ThreadWrapper::EnsureForCurrentMessageLoop();
  228. protocol_config_ = protocol::CandidateSessionConfig::CreateDefault();
  229. protocol_config_->DisableAudioChannel();
  230. protocol_config_->set_webrtc_supported(use_webrtc);
  231. protocol_config_->set_ice_supported(!use_webrtc);
  232. host_thread_.task_runner()->PostTask(
  233. FROM_HERE,
  234. base::BindOnce(&ProtocolPerfTest::StartHost, base::Unretained(this)));
  235. }
  236. void StartHost() {
  237. DCHECK(host_thread_.task_runner()->BelongsToCurrentThread());
  238. webrtc::ThreadWrapper::EnsureForCurrentMessageLoop();
  239. host_signaling_ =
  240. std::make_unique<FakeSignalStrategy>(SignalingAddress(kHostJid));
  241. host_signaling_->set_send_delay(GetParam().signaling_latency);
  242. host_signaling_->ConnectTo(client_signaling_.get());
  243. protocol::NetworkSettings network_settings(
  244. protocol::NetworkSettings::NAT_TRAVERSAL_OUTGOING);
  245. std::unique_ptr<FakePortAllocatorFactory> port_allocator_factory(
  246. new FakePortAllocatorFactory(fake_network_dispatcher_));
  247. port_allocator_factory->socket_factory()->SetBandwidth(
  248. GetParam().bandwidth_kbps * 1000 / 8, GetParam().max_buffers);
  249. port_allocator_factory->socket_factory()->SetLatency(
  250. GetParam().latency_average, GetParam().latency_stddev);
  251. port_allocator_factory->socket_factory()->set_out_of_order_rate(
  252. GetParam().out_of_order_rate);
  253. scoped_refptr<protocol::TransportContext> transport_context(
  254. new protocol::TransportContext(
  255. std::move(port_allocator_factory),
  256. webrtc::ThreadWrapper::current()->SocketServer(), nullptr, nullptr,
  257. network_settings, protocol::TransportRole::SERVER));
  258. std::unique_ptr<protocol::SessionManager> session_manager(
  259. new protocol::JingleSessionManager(host_signaling_.get()));
  260. session_manager->set_protocol_config(protocol_config_->Clone());
  261. // Encoder runs on a separate thread, main thread is used for everything
  262. // else.
  263. host_ = std::make_unique<ChromotingHost>(
  264. desktop_environment_factory_.get(), std::move(session_manager),
  265. transport_context, host_thread_.task_runner(),
  266. encode_thread_.task_runner(),
  267. DesktopEnvironmentOptions::CreateDefault());
  268. base::FilePath certs_dir(net::GetTestCertsDirectory());
  269. std::string host_cert;
  270. ASSERT_TRUE(base::ReadFileToString(
  271. certs_dir.AppendASCII("unittest.selfsigned.der"), &host_cert));
  272. base::FilePath key_path = certs_dir.AppendASCII("unittest.key.bin");
  273. std::string key_string;
  274. ASSERT_TRUE(base::ReadFileToString(key_path, &key_string));
  275. std::string key_base64;
  276. base::Base64Encode(key_string, &key_base64);
  277. scoped_refptr<RsaKeyPair> key_pair = RsaKeyPair::FromString(key_base64);
  278. ASSERT_TRUE(key_pair.get());
  279. std::string host_pin_hash =
  280. protocol::GetSharedSecretHash(kHostId, kHostPin);
  281. std::unique_ptr<protocol::AuthenticatorFactory> auth_factory =
  282. protocol::Me2MeHostAuthenticatorFactory::CreateWithPin(
  283. kHostOwner, host_cert, key_pair, std::vector<std::string>(),
  284. host_pin_hash, nullptr);
  285. host_->SetAuthenticatorFactory(std::move(auth_factory));
  286. host_->status_monitor()->AddStatusObserver(this);
  287. host_->Start(kHostOwner);
  288. task_environment_.GetMainThreadTaskRunner()->PostTask(
  289. FROM_HERE, base::BindOnce(&ProtocolPerfTest::StartClientAfterHost,
  290. base::Unretained(this)));
  291. }
  292. void StartClientAfterHost() {
  293. client_signaling_->set_send_delay(GetParam().signaling_latency);
  294. client_signaling_->ConnectTo(host_signaling_.get());
  295. protocol::NetworkSettings network_settings(
  296. protocol::NetworkSettings::NAT_TRAVERSAL_OUTGOING);
  297. // Initialize client.
  298. client_context_ =
  299. std::make_unique<ClientContext>(base::ThreadTaskRunnerHandle::Get());
  300. client_context_->Start();
  301. std::unique_ptr<FakePortAllocatorFactory> port_allocator_factory(
  302. new FakePortAllocatorFactory(fake_network_dispatcher_));
  303. client_socket_factory_ = port_allocator_factory->socket_factory();
  304. port_allocator_factory->socket_factory()->SetBandwidth(
  305. GetParam().bandwidth_kbps * 1000 / 8, GetParam().max_buffers);
  306. port_allocator_factory->socket_factory()->SetLatency(
  307. GetParam().latency_average, GetParam().latency_stddev);
  308. port_allocator_factory->socket_factory()->set_out_of_order_rate(
  309. GetParam().out_of_order_rate);
  310. scoped_refptr<protocol::TransportContext> transport_context(
  311. new protocol::TransportContext(
  312. std::move(port_allocator_factory),
  313. webrtc::ThreadWrapper::current()->SocketServer(), nullptr, nullptr,
  314. network_settings, protocol::TransportRole::CLIENT));
  315. protocol::ClientAuthenticationConfig client_auth_config;
  316. client_auth_config.host_id = kHostId;
  317. client_auth_config.fetch_secret_callback = base::BindRepeating(
  318. &ProtocolPerfTest::FetchPin, base::Unretained(this));
  319. video_renderer_ = std::make_unique<SoftwareVideoRenderer>(this);
  320. video_renderer_->Initialize(*client_context_, this);
  321. client_ = std::make_unique<ChromotingClient>(
  322. client_context_.get(), this, video_renderer_.get(), nullptr);
  323. client_->set_protocol_config(protocol_config_->Clone());
  324. client_->Start(client_signaling_.get(), client_auth_config,
  325. transport_context, kHostJid, std::string());
  326. }
  327. void FetchPin(
  328. bool pairing_supported,
  329. const protocol::SecretFetchedCallback& secret_fetched_callback) {
  330. secret_fetched_callback.Run(kHostPin);
  331. }
  332. void MeasureTotalLatency(bool use_webrtc);
  333. void MeasureScrollPerformance(bool use_webrtc);
  334. TaskEnvironment task_environment_;
  335. scoped_refptr<FakeNetworkDispatcher> fake_network_dispatcher_;
  336. base::Thread host_thread_;
  337. base::Thread capture_thread_;
  338. base::Thread encode_thread_;
  339. base::Thread decode_thread_;
  340. std::unique_ptr<FakeDesktopEnvironmentFactory> desktop_environment_factory_;
  341. scoped_refptr<protocol::InputEventTimestampsSource> event_timestamp_source_;
  342. FakeCursorShapeStub cursor_shape_stub_;
  343. std::unique_ptr<protocol::CandidateSessionConfig> protocol_config_;
  344. std::unique_ptr<FakeSignalStrategy> host_signaling_;
  345. std::unique_ptr<FakeSignalStrategy> client_signaling_;
  346. std::unique_ptr<ChromotingHost> host_;
  347. std::unique_ptr<ClientContext> client_context_;
  348. std::unique_ptr<SoftwareVideoRenderer> video_renderer_;
  349. std::unique_ptr<ChromotingClient> client_;
  350. raw_ptr<FakePacketSocketFactory> client_socket_factory_;
  351. std::unique_ptr<base::RunLoop> connecting_loop_;
  352. std::unique_ptr<base::RunLoop> waiting_frames_loop_;
  353. std::unique_ptr<base::RunLoop> waiting_frame_stats_loop_;
  354. size_t num_expected_frame_stats_;
  355. bool client_connected_;
  356. bool host_connected_;
  357. base::RepeatingClosure on_frame_task_;
  358. std::unique_ptr<VideoPacket> last_video_packet_;
  359. std::unique_ptr<webrtc::DesktopFrame> last_video_frame_;
  360. std::vector<protocol::FrameStats> frame_stats_;
  361. std::unique_ptr<net::NetworkChangeNotifier> network_change_notifier_;
  362. };
  363. INSTANTIATE_TEST_SUITE_P(
  364. NoDelay,
  365. ProtocolPerfTest,
  366. ::testing::Values(NetworkPerformanceParams(0, 0, 0, 0, 0.0, 0)));
  367. INSTANTIATE_TEST_SUITE_P(
  368. HighLatency,
  369. ProtocolPerfTest,
  370. ::testing::Values(NetworkPerformanceParams(0, 0, 300, 30, 0.0, 0),
  371. NetworkPerformanceParams(0, 0, 30, 10, 0.0, 0)));
  372. INSTANTIATE_TEST_SUITE_P(
  373. OutOfOrder,
  374. ProtocolPerfTest,
  375. ::testing::Values(NetworkPerformanceParams(0, 0, 2, 0, 0.01, 0),
  376. NetworkPerformanceParams(0, 0, 30, 1, 0.01, 0),
  377. NetworkPerformanceParams(0, 0, 30, 1, 0.1, 0),
  378. NetworkPerformanceParams(0, 0, 300, 20, 0.01, 0),
  379. NetworkPerformanceParams(0, 0, 300, 20, 0.1, 0)));
  380. INSTANTIATE_TEST_SUITE_P(
  381. LimitedBandwidth,
  382. ProtocolPerfTest,
  383. ::testing::Values(
  384. // 100 Mbps
  385. NetworkPerformanceParams(100000, 0.25, 2, 1, 0.0, 0),
  386. NetworkPerformanceParams(100000, 1.0, 2, 1, 0.0, 0),
  387. // 8 Mbps
  388. NetworkPerformanceParams(8000, 0.25, 30, 5, 0.01, 0),
  389. NetworkPerformanceParams(8000, 1.0, 30, 5, 0.01, 0),
  390. // 2 Mbps
  391. NetworkPerformanceParams(2000, 0.25, 30, 5, 0.01, 0),
  392. NetworkPerformanceParams(2000, 1.0, 30, 5, 0.01, 0),
  393. // 800 kbps
  394. NetworkPerformanceParams(800, 0.25, 130, 5, 0.00, 0),
  395. NetworkPerformanceParams(800, 1.0, 130, 5, 0.00, 0)));
  396. INSTANTIATE_TEST_SUITE_P(
  397. SlowSignaling,
  398. ProtocolPerfTest,
  399. ::testing::Values(NetworkPerformanceParams(8000, 0.25, 30, 0, 0.0, 50),
  400. NetworkPerformanceParams(8000, 0.25, 30, 0, 0.0, 500)));
  401. // TotalLatency[Ice|Webrtc] tests measure video latency in the case when the
  402. // whole screen is updated occasionally. It's intended to simulate the case when
  403. // user actions (e.g. Alt-Tab, click on the task bar) cause whole screen to be
  404. // updated.
  405. void ProtocolPerfTest::MeasureTotalLatency(bool use_webrtc) {
  406. scoped_refptr<test::CyclicFrameGenerator> frame_generator =
  407. test::CyclicFrameGenerator::Create();
  408. desktop_environment_factory_->set_frame_generator(base::BindRepeating(
  409. &test::CyclicFrameGenerator::GenerateFrame, frame_generator));
  410. event_timestamp_source_ = frame_generator;
  411. StartHostAndClient(use_webrtc);
  412. ASSERT_NO_FATAL_FAILURE(WaitConnected());
  413. int total_frames = 0;
  414. const base::TimeDelta kWarmUpTime = base::Seconds(2);
  415. const base::TimeDelta kTestTime = base::Seconds(5);
  416. base::TimeTicks start_time = base::TimeTicks::Now();
  417. while ((base::TimeTicks::Now() - start_time) < (kWarmUpTime + kTestTime)) {
  418. ReceiveFrame();
  419. ++total_frames;
  420. }
  421. WaitFrameStats(total_frames);
  422. int warm_up_frames = 0;
  423. int big_update_count = 0;
  424. base::TimeDelta total_latency_big_updates;
  425. int small_update_count = 0;
  426. base::TimeDelta total_latency_small_updates;
  427. for (int i = 0; i < total_frames; ++i) {
  428. const protocol::FrameStats& stats = frame_stats_[i];
  429. // CyclicFrameGenerator::TakeLastEventTimestamps() always returns non-null
  430. // timestamps.
  431. CHECK(!stats.host_stats.latest_event_timestamp.is_null());
  432. test::CyclicFrameGenerator::ChangeInfoList changes =
  433. frame_generator->GetChangeList(stats.host_stats.latest_event_timestamp);
  434. // Allow 2 seconds for the connection to warm-up, e.g. to get bandwidth
  435. // estimate, etc. These frames are ignored when calculating stats below.
  436. if (stats.client_stats.time_rendered < (start_time + kWarmUpTime)) {
  437. ++warm_up_frames;
  438. continue;
  439. }
  440. for (auto& change_info : changes) {
  441. base::TimeDelta latency =
  442. stats.client_stats.time_rendered - change_info.timestamp;
  443. switch (change_info.type) {
  444. case test::CyclicFrameGenerator::ChangeType::NO_CHANGES:
  445. NOTREACHED();
  446. break;
  447. case test::CyclicFrameGenerator::ChangeType::FULL:
  448. total_latency_big_updates += latency;
  449. ++big_update_count;
  450. break;
  451. case test::CyclicFrameGenerator::ChangeType::CURSOR:
  452. total_latency_small_updates += latency;
  453. ++small_update_count;
  454. break;
  455. }
  456. }
  457. }
  458. WaitFrameStats(total_frames);
  459. CHECK(big_update_count);
  460. VLOG(0) << "Average latency for big updates: "
  461. << (total_latency_big_updates / big_update_count).InMillisecondsF();
  462. if (small_update_count) {
  463. VLOG(0)
  464. << "Average latency for small updates: "
  465. << (total_latency_small_updates / small_update_count).InMillisecondsF();
  466. }
  467. double average_bwe =
  468. std::accumulate(frame_stats_.begin() + warm_up_frames,
  469. frame_stats_.begin() + total_frames, 0.0,
  470. [](double sum, const protocol::FrameStats& stats) {
  471. return sum + stats.host_stats.bandwidth_estimate_kbps;
  472. }) /
  473. (total_frames - warm_up_frames);
  474. VLOG(0) << "Average BW estimate: " << average_bwe
  475. << " (actual: " << GetParam().bandwidth_kbps << ")";
  476. }
  477. TEST_P(ProtocolPerfTest, TotalLatencyIce) {
  478. MeasureTotalLatency(false);
  479. }
  480. TEST_P(ProtocolPerfTest, TotalLatencyWebrtc) {
  481. MeasureTotalLatency(true);
  482. }
  483. // ScrollPerformance[Ice|Webrtc] tests simulate whole screen being scrolled
  484. // continuously. They measure FPS and video latency.
  485. void ProtocolPerfTest::MeasureScrollPerformance(bool use_webrtc) {
  486. scoped_refptr<test::ScrollFrameGenerator> frame_generator =
  487. new test::ScrollFrameGenerator();
  488. desktop_environment_factory_->set_frame_generator(base::BindRepeating(
  489. &test::ScrollFrameGenerator::GenerateFrame, frame_generator));
  490. event_timestamp_source_ = frame_generator;
  491. StartHostAndClient(use_webrtc);
  492. ASSERT_NO_FATAL_FAILURE(WaitConnected());
  493. const base::TimeDelta kWarmUpTime = base::Seconds(2);
  494. const base::TimeDelta kTestTime = base::Seconds(2);
  495. int num_frames = 0;
  496. int warm_up_frames = 0;
  497. base::TimeTicks start_time = base::TimeTicks::Now();
  498. while ((base::TimeTicks::Now() - start_time) < (kTestTime + kWarmUpTime)) {
  499. ReceiveFrame();
  500. ++num_frames;
  501. // Allow 2 seconds for the connection to warm-up, e.g. to get bandwidth
  502. // estimate, etc. These frames are ignored when calculating stats below.
  503. if ((base::TimeTicks::Now() - start_time) < kWarmUpTime) {
  504. ++warm_up_frames;
  505. client_socket_factory_->ResetStats();
  506. }
  507. }
  508. base::TimeDelta total_time = (base::TimeTicks::Now() - start_time);
  509. WaitFrameStats(warm_up_frames + num_frames);
  510. int total_size =
  511. std::accumulate(frame_stats_.begin() + warm_up_frames,
  512. frame_stats_.begin() + warm_up_frames + num_frames, 0,
  513. [](int sum, const protocol::FrameStats& stats) {
  514. return sum + stats.host_stats.frame_size;
  515. });
  516. base::TimeDelta latency_sum = std::accumulate(
  517. frame_stats_.begin() + warm_up_frames,
  518. frame_stats_.begin() + warm_up_frames + num_frames, base::TimeDelta(),
  519. [](base::TimeDelta sum, const protocol::FrameStats& stats) {
  520. return sum + (stats.client_stats.time_rendered -
  521. stats.host_stats.latest_event_timestamp);
  522. });
  523. double average_bwe =
  524. std::accumulate(frame_stats_.begin() + warm_up_frames,
  525. frame_stats_.begin() + warm_up_frames + num_frames, 0.0,
  526. [](double sum, const protocol::FrameStats& stats) {
  527. return sum + stats.host_stats.bandwidth_estimate_kbps;
  528. }) /
  529. num_frames;
  530. VLOG(0) << "FPS: " << num_frames / total_time.InSecondsF();
  531. VLOG(0) << "Average latency: " << latency_sum.InMillisecondsF() / num_frames
  532. << " ms";
  533. VLOG(0) << "Total size: " << total_size << " bytes";
  534. VLOG(0) << "Bandwidth utilization: "
  535. << 100 * total_size / (total_time.InSecondsF() *
  536. GetParam().bandwidth_kbps * 1000 / 8)
  537. << "%";
  538. VLOG(0) << "Network buffer delay (bufferbloat), average: "
  539. << client_socket_factory_->average_buffer_delay().InMilliseconds()
  540. << " ms, max:"
  541. << client_socket_factory_->max_buffer_delay().InMilliseconds()
  542. << " ms";
  543. VLOG(0) << "Packet drop rate: " << client_socket_factory_->drop_rate();
  544. VLOG(0) << "Average BW estimate: " << average_bwe
  545. << " (actual: " << GetParam().bandwidth_kbps << ")";
  546. }
  547. TEST_P(ProtocolPerfTest, ScrollPerformanceIce) {
  548. MeasureScrollPerformance(false);
  549. }
  550. TEST_P(ProtocolPerfTest, ScrollPerformanceWebrtc) {
  551. MeasureScrollPerformance(true);
  552. }
  553. } // namespace remoting