Index: remoting/test/protocol_perftest.cc |
diff --git a/remoting/test/protocol_perftest.cc b/remoting/test/protocol_perftest.cc |
index e03d389e00eb3c4b8ed5e77c399f7f63a3a41e7f..2145266d4e2b2efc47f7031b82e5428485f53746 100644 |
--- a/remoting/test/protocol_perftest.cc |
+++ b/remoting/test/protocol_perftest.cc |
@@ -2,6 +2,7 @@ |
// Use of this source code is governed by a BSD-style license that can be |
// found in the LICENSE file. |
+#include <numeric> |
#include <utility> |
#include "base/base64.h" |
@@ -24,14 +25,14 @@ |
#include "remoting/client/chromoting_client.h" |
#include "remoting/client/client_context.h" |
#include "remoting/client/client_user_interface.h" |
-#include "remoting/codec/video_decoder_verbatim.h" |
-#include "remoting/codec/video_decoder_vpx.h" |
+#include "remoting/client/software_video_renderer.h" |
#include "remoting/host/chromoting_host.h" |
#include "remoting/host/chromoting_host_context.h" |
#include "remoting/host/fake_desktop_environment.h" |
#include "remoting/protocol/auth_util.h" |
#include "remoting/protocol/client_authentication_config.h" |
#include "remoting/protocol/frame_consumer.h" |
+#include "remoting/protocol/frame_stats.h" |
#include "remoting/protocol/jingle_session_manager.h" |
#include "remoting/protocol/me2me_host_authenticator_factory.h" |
#include "remoting/protocol/session_config.h" |
@@ -86,24 +87,14 @@ class FakeCursorShapeStub : public protocol::CursorShapeStub { |
void SetCursorShape(const protocol::CursorShapeInfo& cursor_shape) override{}; |
}; |
-std::unique_ptr<webrtc::DesktopFrame> DoDecodeFrame( |
- VideoDecoder* decoder, |
- VideoPacket* packet, |
- std::unique_ptr<webrtc::DesktopFrame> frame) { |
- if (!decoder->DecodePacket(*packet, frame.get())) |
- frame.reset(); |
- return frame; |
-} |
- |
} // namespace |
class ProtocolPerfTest |
: public testing::Test, |
public testing::WithParamInterface<NetworkPerformanceParams>, |
public ClientUserInterface, |
- public protocol::VideoRenderer, |
- public protocol::VideoStub, |
public protocol::FrameConsumer, |
+ public protocol::FrameStatsConsumer, |
public HostStatusObserver { |
public: |
ProtocolPerfTest() |
@@ -149,50 +140,6 @@ class ProtocolPerfTest |
return &cursor_shape_stub_; |
} |
- // VideoRenderer interface. |
- bool Initialize(const ClientContext& client_context, |
- protocol::FrameStatsConsumer* stats_consumer) override { |
- return true; |
- } |
- void OnSessionConfig(const protocol::SessionConfig& config) override {} |
- protocol::VideoStub* GetVideoStub() override { return this; } |
- protocol::FrameConsumer* GetFrameConsumer() override { return this; } |
- protocol::FrameStatsConsumer* GetFrameStatsConsumer() override { |
- return nullptr; |
- } |
- |
- // protocol::VideoStub interface. |
- void ProcessVideoPacket(std::unique_ptr<VideoPacket> packet, |
- const base::Closure& done) override { |
- if (packet->data().empty()) { |
- // Ignore keep-alive packets |
- done.Run(); |
- return; |
- } |
- |
- if (packet->format().has_screen_width() && |
- packet->format().has_screen_height()) { |
- frame_size_.set(packet->format().screen_width(), |
- packet->format().screen_height()); |
- } |
- |
- std::unique_ptr<webrtc::DesktopFrame> frame( |
- new webrtc::BasicDesktopFrame(frame_size_)); |
- base::PostTaskAndReplyWithResult( |
- decode_thread_.task_runner().get(), FROM_HERE, |
- base::Bind(&DoDecodeFrame, video_decoder_.get(), packet.get(), |
- base::Passed(&frame)), |
- base::Bind(&ProtocolPerfTest::OnFrameDecoded, base::Unretained(this), |
- base::Passed(&packet), done)); |
- } |
- |
- void OnFrameDecoded(std::unique_ptr<VideoPacket> packet, |
- const base::Closure& done, |
- std::unique_ptr<webrtc::DesktopFrame> frame) { |
- last_video_packet_ = std::move(packet); |
- DrawFrame(std::move(frame), done); |
- } |
- |
// protocol::FrameConsumer interface. |
std::unique_ptr<webrtc::DesktopFrame> AllocateFrame( |
const webrtc::DesktopSize& size) override { |
@@ -212,6 +159,16 @@ class ProtocolPerfTest |
return FORMAT_BGRA; |
} |
+ // FrameStatsConsumer interface. |
+ void OnVideoFrameStats(const protocol::FrameStats& frame_stats) override { |
+ frame_stats_.push_back(frame_stats); |
+ |
+ if (waiting_frame_stats_loop_ && |
+ frame_stats_.size() >= num_expected_frame_stats_) { |
+ waiting_frame_stats_loop_->Quit(); |
+ } |
+ } |
+ |
// HostStatusObserver interface. |
void OnClientConnected(const std::string& jid) override { |
message_loop_.task_runner()->PostTask( |
@@ -242,45 +199,27 @@ class ProtocolPerfTest |
waiting_frames_loop_.reset(new base::RunLoop()); |
on_frame_task_ = waiting_frames_loop_->QuitClosure(); |
waiting_frames_loop_->Run(); |
+ waiting_frames_loop_.reset(); |
EXPECT_TRUE(last_video_frame_); |
return std::move(last_video_frame_); |
} |
- void ReceiveFrameAndGetLatency(base::TimeDelta* latency) { |
- last_video_packet_.reset(); |
- |
- ReceiveFrame(); |
- |
- if (latency) { |
- base::TimeTicks timestamp = |
- base::TimeTicks::FromInternalValue(last_video_packet_->timestamp()); |
- *latency = base::TimeTicks::Now() - timestamp; |
- } |
- } |
- |
- void ReceiveMultipleFramesAndGetMaxLatency(int frames, |
- base::TimeDelta* max_latency) { |
- if (max_latency) |
- *max_latency = base::TimeDelta(); |
- |
- for (int i = 0; i < frames; ++i) { |
- base::TimeDelta latency; |
+ void WaitFrameStats(int num_frames) { |
+ num_expected_frame_stats_ = num_frames; |
- ReceiveFrameAndGetLatency(&latency); |
+ waiting_frame_stats_loop_.reset(new base::RunLoop()); |
+ waiting_frame_stats_loop_->Run(); |
+ waiting_frame_stats_loop_.reset(); |
- if (max_latency && latency > *max_latency) { |
- *max_latency = latency; |
- } |
- } |
+ EXPECT_GE(frame_stats_.size(), num_expected_frame_stats_); |
} |
// Creates test host and client and starts connection between them. Caller |
// should call WaitConnected() to wait until connection is established. The |
// host is started on |host_thread_| while the client works on the main |
// thread. |
- void StartHostAndClient(bool use_webrtc, |
- protocol::ChannelConfig::Codec video_codec) { |
+ void StartHostAndClient(bool use_webrtc) { |
fake_network_dispatcher_ = new FakeNetworkDispatcher(); |
client_signaling_.reset(new FakeSignalStrategy(kClientJid)); |
@@ -289,24 +228,9 @@ class ProtocolPerfTest |
protocol_config_ = protocol::CandidateSessionConfig::CreateDefault(); |
protocol_config_->DisableAudioChannel(); |
- protocol_config_->mutable_video_configs()->clear(); |
- protocol_config_->mutable_video_configs()->push_back( |
- protocol::ChannelConfig( |
- protocol::ChannelConfig::TRANSPORT_STREAM, 2, video_codec)); |
protocol_config_->set_webrtc_supported(use_webrtc); |
protocol_config_->set_ice_supported(!use_webrtc); |
- switch (video_codec) { |
- case ChannelConfig::CODEC_VERBATIM: |
- video_decoder_.reset(new VideoDecoderVerbatim()); |
- break; |
- case ChannelConfig::CODEC_VP8: |
- video_decoder_ = VideoDecoderVpx::CreateForVP8(); |
- break; |
- default: |
- NOTREACHED(); |
- } |
- |
host_thread_.task_runner()->PostTask( |
FROM_HERE, |
base::Bind(&ProtocolPerfTest::StartHost, base::Unretained(this))); |
@@ -384,6 +308,7 @@ class ProtocolPerfTest |
// Initialize client. |
client_context_.reset( |
new ClientContext(base::ThreadTaskRunnerHandle::Get())); |
+ client_context_->Start(); |
std::unique_ptr<FakePortAllocatorFactory> port_allocator_factory( |
new FakePortAllocatorFactory(fake_network_dispatcher_)); |
@@ -403,8 +328,11 @@ class ProtocolPerfTest |
client_auth_config.fetch_secret_callback = |
base::Bind(&ProtocolPerfTest::FetchPin, base::Unretained(this)); |
- client_.reset( |
- new ChromotingClient(client_context_.get(), this, this, nullptr)); |
+ video_renderer_.reset(new SoftwareVideoRenderer(this)); |
+ video_renderer_->Initialize(*client_context_, this); |
+ |
+ client_.reset(new ChromotingClient(client_context_.get(), this, |
+ video_renderer_.get(), nullptr)); |
client_->set_protocol_config(protocol_config_->Clone()); |
client_->Start(client_signaling_.get(), client_auth_config, |
transport_context, kHostJid, std::string()); |
@@ -438,13 +366,15 @@ class ProtocolPerfTest |
std::unique_ptr<ChromotingHost> host_; |
std::unique_ptr<ClientContext> client_context_; |
+ std::unique_ptr<SoftwareVideoRenderer> video_renderer_; |
std::unique_ptr<ChromotingClient> client_; |
- webrtc::DesktopSize frame_size_; |
- std::unique_ptr<VideoDecoder> video_decoder_; |
std::unique_ptr<base::RunLoop> connecting_loop_; |
std::unique_ptr<base::RunLoop> waiting_frames_loop_; |
+ std::unique_ptr<base::RunLoop> waiting_frame_stats_loop_; |
+ size_t num_expected_frame_stats_; |
+ |
bool client_connected_; |
bool host_connected_; |
@@ -452,6 +382,7 @@ class ProtocolPerfTest |
std::unique_ptr<VideoPacket> last_video_packet_; |
std::unique_ptr<webrtc::DesktopFrame> last_video_frame_; |
+ std::vector<protocol::FrameStats> frame_stats_; |
private: |
DISALLOW_COPY_AND_ASSIGN(ProtocolPerfTest); |
@@ -490,23 +421,6 @@ INSTANTIATE_TEST_CASE_P( |
NetworkPerformanceParams(100000, 30000, 130, 5, 0.01), |
NetworkPerformanceParams(100000, 200000, 130, 5, 0.01))); |
-TEST_P(ProtocolPerfTest, StreamFrameRate) { |
- StartHostAndClient(false, protocol::ChannelConfig::CODEC_VP8); |
- ASSERT_NO_FATAL_FAILURE(WaitConnected()); |
- |
- base::TimeDelta latency; |
- |
- ReceiveFrameAndGetLatency(&latency); |
- LOG(INFO) << "First frame latency: " << latency.InMillisecondsF() << "ms"; |
- ReceiveMultipleFramesAndGetMaxLatency(20, nullptr); |
- |
- base::TimeTicks started = base::TimeTicks::Now(); |
- ReceiveMultipleFramesAndGetMaxLatency(40, &latency); |
- base::TimeDelta elapsed = base::TimeTicks::Now() - started; |
- LOG(INFO) << "Frame rate: " << (40.0 / elapsed.InSecondsF()); |
- LOG(INFO) << "Maximum latency: " << latency.InMillisecondsF() << "ms"; |
-} |
- |
const int kIntermittentFrameSize = 100 * 1000; |
// Frame generator that rewrites the whole screen every 60th frame. Should only |
@@ -550,39 +464,6 @@ class IntermittentChangeFrameGenerator |
DISALLOW_COPY_AND_ASSIGN(IntermittentChangeFrameGenerator); |
}; |
-TEST_P(ProtocolPerfTest, IntermittentChanges) { |
- desktop_environment_factory_.set_frame_generator( |
- base::Bind(&IntermittentChangeFrameGenerator::GenerateFrame, |
- new IntermittentChangeFrameGenerator())); |
- |
- StartHostAndClient(false, protocol::ChannelConfig::CODEC_VERBATIM); |
- ASSERT_NO_FATAL_FAILURE(WaitConnected()); |
- |
- ReceiveFrameAndGetLatency(nullptr); |
- |
- base::TimeDelta expected = GetParam().latency_average; |
- if (GetParam().bandwidth > 0) { |
- expected += base::TimeDelta::FromSecondsD(kIntermittentFrameSize / |
- GetParam().bandwidth); |
- } |
- LOG(INFO) << "Expected: " << expected.InMillisecondsF() << "ms"; |
- |
- base::TimeDelta sum; |
- |
- const int kFrames = 5; |
- for (int i = 0; i < kFrames; ++i) { |
- base::TimeDelta latency; |
- ReceiveFrameAndGetLatency(&latency); |
- LOG(INFO) << "Latency: " << latency.InMillisecondsF() |
- << "ms Encode: " << last_video_packet_->encode_time_ms() |
- << "ms Capture: " << last_video_packet_->capture_time_ms() |
- << "ms"; |
- sum += latency; |
- } |
- |
- LOG(INFO) << "Average: " << (sum / kFrames).InMillisecondsF(); |
-} |
- |
// TotalLatency[Ice|Webrtc] tests measure video latency in the case when the |
// whole screen is updated occasionally. It's intended to simulate the case when |
// user actions (e.g. Alt-Tab, click on the task bar) cause whole screen to be |
@@ -595,7 +476,7 @@ void ProtocolPerfTest::MeasureTotalLatency(bool use_webrtc) { |
desktop_environment_factory_.set_frame_generator( |
base::Bind(&test::CyclicFrameGenerator::GenerateFrame, frame_generator)); |
- StartHostAndClient(use_webrtc, protocol::ChannelConfig::CODEC_VP8); |
+ StartHostAndClient(use_webrtc); |
ASSERT_NO_FATAL_FAILURE(WaitConnected()); |
int skipped_frames = 0; |
@@ -662,32 +543,48 @@ void ProtocolPerfTest::MeasureScrollPerformance(bool use_webrtc) { |
desktop_environment_factory_.set_frame_generator( |
base::Bind(&test::ScrollFrameGenerator::GenerateFrame, frame_generator)); |
- StartHostAndClient(use_webrtc, protocol::ChannelConfig::CODEC_VP8); |
+ StartHostAndClient(use_webrtc); |
ASSERT_NO_FATAL_FAILURE(WaitConnected()); |
+ int warm_up_frames = 0; |
+ |
base::TimeTicks start_time = base::TimeTicks::Now(); |
const base::TimeDelta kWarmUpTime = base::TimeDelta::FromSeconds(2); |
while ((base::TimeTicks::Now() - start_time) < kWarmUpTime) { |
ReceiveFrame(); |
+ ++warm_up_frames; |
} |
// Run the test for 2 seconds. |
const base::TimeDelta kTestTime = base::TimeDelta::FromSeconds(2); |
int num_frames = 0; |
- base::TimeDelta total_latency; |
+ base::TimeDelta latency_sum; |
start_time = base::TimeTicks::Now(); |
while ((base::TimeTicks::Now() - start_time) < kTestTime) { |
std::unique_ptr<webrtc::DesktopFrame> frame = ReceiveFrame(); |
++num_frames; |
- total_latency += frame_generator->GetFrameLatency(*frame); |
+ latency_sum += frame_generator->GetFrameLatency(*frame); |
} |
- VLOG(0) << "FPS: " |
- << num_frames / (base::TimeTicks::Now() - start_time).InSecondsF(); |
+ base::TimeDelta total_time = (base::TimeTicks::Now() - start_time); |
+ |
+ WaitFrameStats(warm_up_frames + num_frames); |
+ |
+ int total_size = |
+ std::accumulate(frame_stats_.begin() + warm_up_frames, |
+ frame_stats_.begin() + warm_up_frames + num_frames, 0, |
+ [](int sum, const protocol::FrameStats& stats) { |
+ return sum + stats.host_stats.frame_size; |
+ }); |
- VLOG(0) << "Average latency: " |
- << (total_latency).InMillisecondsF() / num_frames; |
+ VLOG(0) << "FPS: " << num_frames / total_time.InSecondsF(); |
+ VLOG(0) << "Average latency: " << latency_sum.InMillisecondsF() / num_frames |
+ << " ms"; |
+ VLOG(0) << "Total size: " << total_size << " bytes"; |
+ VLOG(0) << "Bandwidth utilization: " |
+ << 100 * total_size / (total_time.InSecondsF() * GetParam().bandwidth) |
+ << "%"; |
} |
TEST_P(ProtocolPerfTest, ScrollPerformanceIce) { |