blob: 7f966fe0b2099fcdf5e21724342ebe769a91f820 [file] [log] [blame]
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "remoting/test/fake_connection_event_logger.h"
#include <string>
#include <utility>
#include "base/atomicops.h"
#include "base/callback.h"
#include "base/macros.h"
#include "base/time/time.h"
#include "remoting/proto/audio.pb.h"
#include "remoting/proto/control.pb.h"
#include "remoting/proto/video.pb.h"
#ifndef ARCH_CPU_64_BITS
#include "base/synchronization/lock.h"
#endif
namespace remoting {
namespace test {
namespace {
template <typename T>
class NoBarrierAtomic {
public:
T operator++() {
return base::subtle::NoBarrier_AtomicIncrement(&i_, 1) - 1;
}
T operator++(int) {
return base::subtle::NoBarrier_AtomicIncrement(&i_, 1);
}
T operator--() {
return base::subtle::NoBarrier_AtomicIncrement(&i_, -1) - 1;
}
T operator--(int) {
return base::subtle::NoBarrier_AtomicIncrement(&i_, -1);
}
T operator+=(T other) {
return base::subtle::NoBarrier_AtomicIncrement(&i_, other);
}
T operator-=(T other) {
return base::subtle::NoBarrier_AtomicIncrement(&i_, -other);
}
T operator*() const {
return base::subtle::NoBarrier_Load(&i_);
}
private:
volatile T i_;
};
class NoBarrierAtomicInt32 : public NoBarrierAtomic<base::subtle::Atomic32> {};
#ifdef ARCH_CPU_64_BITS
class NoBarrierAtomicInt64 : public NoBarrierAtomic<base::subtle::Atomic64> {};
#else // ifdef ARCH_CPU_64_BITS
using base::AutoLock;
// A barriered, lock based implementation
class NoBarrierAtomicInt64 {
public:
int64_t operator++();
int64_t operator++(int);
int64_t operator--();
int64_t operator--(int);
int64_t operator+=(int64_t other);
int64_t operator-=(int64_t other);
int64_t operator*() const;
private:
volatile int64_t i_ = 0;
mutable base::Lock lock_; // field is used in operator*() const
};
int64_t NoBarrierAtomicInt64::operator++() {
AutoLock l(lock_);
return i_++;
}
int64_t NoBarrierAtomicInt64::operator++(int) {
AutoLock l(lock_);
return ++i_;
}
int64_t NoBarrierAtomicInt64::operator--() {
AutoLock l(lock_);
return i_--;
}
int64_t NoBarrierAtomicInt64::operator--(int) {
AutoLock l(lock_);
return --i_;
}
int64_t NoBarrierAtomicInt64::operator+=(int64_t other) {
AutoLock l(lock_);
return (i_ += other);
}
int64_t NoBarrierAtomicInt64::operator-=(int64_t other) {
AutoLock l(lock_);
return (i_ -= other);
}
int64_t NoBarrierAtomicInt64::operator*() const {
AutoLock l(lock_);
return i_;
}
#endif // ifdef ARCH_CPU_64_BITS
class MessageCounter {
public:
MessageCounter(const char* name, const char* unit);
explicit MessageCounter(const char* name);
int message_count() const { return *count_; }
int64_t message_size() const { return *size_; }
int last_message_size() const { return last_size_; }
double DurationSeconds() const;
double MessagesPerSecond() const;
double SizePerSecond() const;
double AverageMessageSize() const;
void LogMessage(const ::google::protobuf::MessageLite& message);
void LogMessage(int size);
virtual void DisplayStatistics(std::ostream& os);
private:
const std::string name_;
const std::string unit_;
NoBarrierAtomicInt32 count_;
NoBarrierAtomicInt64 size_;
int last_size_ = 0;
base::Time start_time_;
// Copy or assign the start_time_ of a MessageCounter is senseless.
DISALLOW_COPY_AND_ASSIGN(MessageCounter);
};
MessageCounter::MessageCounter(const char* name, const char* unit)
: name_(name),
unit_(unit),
count_(),
size_(),
start_time_(base::Time::Now()) {}
MessageCounter::MessageCounter(const char* name)
: MessageCounter(name, "bytes") {}
double MessageCounter::DurationSeconds() const {
return (base::Time::Now() - start_time_).InSecondsF();
}
double MessageCounter::MessagesPerSecond() const {
return static_cast<double>(message_count()) / DurationSeconds();
}
double MessageCounter::SizePerSecond() const {
return static_cast<double>(message_size()) / DurationSeconds();
}
double MessageCounter::AverageMessageSize() const {
return static_cast<double>(message_size()) / message_count();
}
void MessageCounter::LogMessage(
const ::google::protobuf::MessageLite& message) {
LogMessage(message.ByteSize());
}
void MessageCounter::LogMessage(int size) {
count_++;
last_size_ = size;
size_ += size;
}
void MessageCounter::DisplayStatistics(std::ostream& os) {
os << name_ << ": " << message_size() << " " << unit_ << " in "
<< message_count() << " packages, last package " << last_message_size()
<< " " << unit_ << ", " << AverageMessageSize() << " " << unit_
<< "/package, " << MessagesPerSecond() << " packages/sec, "
<< SizePerSecond() << " " << unit_ << "/sec" << std::endl;
}
} // namespace
// Analyzes messages from DeliverHostMessage function.
class FakeConnectionEventLogger::CounterClientStub
: public protocol::ClientStub, public MessageCounter {
public:
CounterClientStub();
private:
void DeliverHostMessage(const protocol::ExtensionMessage& message) override;
void InjectClipboardEvent(const protocol::ClipboardEvent& event) override {}
void SetCapabilities(const protocol::Capabilities& capabilities) override {}
void SetCursorShape(const protocol::CursorShapeInfo& cursor_shape) override {}
void SetKeyboardLayout(const protocol::KeyboardLayout& layout) override {}
void SetPairingResponse(const protocol::PairingResponse& response) override {}
void SetVideoLayout(const protocol::VideoLayout& video_layout) override {}
void SetTransportInfo(
const protocol::TransportInfo& transport_info) override {}
};
FakeConnectionEventLogger::CounterClientStub::CounterClientStub()
: MessageCounter("client") {}
void FakeConnectionEventLogger::CounterClientStub::DeliverHostMessage(
const protocol::ExtensionMessage& message) {
LogMessage(message);
}
// Analyzes messages from DeliverClientMessage function.
class FakeConnectionEventLogger::CounterHostStub
: public protocol::HostStub, public MessageCounter {
public:
CounterHostStub();
private:
void ControlAudio(const protocol::AudioControl& audio_control) override {}
void ControlVideo(const protocol::VideoControl& video_control) override {}
void DeliverClientMessage(const protocol::ExtensionMessage& message) override;
void NotifyClientResolution(
const protocol::ClientResolution& resolution) override {}
void RequestPairing(
const protocol::PairingRequest& pairing_request) override {}
void SetCapabilities(const protocol::Capabilities& capabilities) override {}
void SelectDesktopDisplay(
const protocol::SelectDesktopDisplayRequest& select_display) override {}
};
FakeConnectionEventLogger::CounterHostStub::CounterHostStub()
: MessageCounter("host") {}
void FakeConnectionEventLogger::CounterHostStub::DeliverClientMessage(
const protocol::ExtensionMessage& message) {
LogMessage(message);
}
// Analyzes messages from ProcessAudioPacket function.
class FakeConnectionEventLogger::CounterAudioStub
: public protocol::AudioStub, public MessageCounter {
public:
CounterAudioStub();
private:
void ProcessAudioPacket(std::unique_ptr<AudioPacket> audio_packet,
base::OnceClosure done) override;
};
FakeConnectionEventLogger::CounterAudioStub::CounterAudioStub()
: MessageCounter("audio") {}
void FakeConnectionEventLogger::CounterAudioStub::ProcessAudioPacket(
std::unique_ptr<AudioPacket> audio_packet,
base::OnceClosure done) {
if (audio_packet) {
LogMessage(*audio_packet);
}
std::move(done).Run();
}
// Analyzes messages from ProcessVideoPacket function.
class FakeConnectionEventLogger::CounterVideoStub
: public protocol::VideoStub, public MessageCounter {
public:
CounterVideoStub(protocol::FakeConnectionToClient* connection);
void DisplayStatistics(std::ostream& os) override;
private:
void ProcessVideoPacket(std::unique_ptr<VideoPacket> video_packet,
base::OnceClosure done) override;
protocol::FakeConnectionToClient* connection_ = nullptr;
MessageCounter video_data_;
MessageCounter capture_time_;
MessageCounter encode_time_;
};
FakeConnectionEventLogger::CounterVideoStub::CounterVideoStub(
protocol::FakeConnectionToClient* connection)
: MessageCounter("video"),
connection_(connection),
video_data_("video-data"),
capture_time_("capture-time", "ms"),
encode_time_("encode-time", "ms") {}
void FakeConnectionEventLogger::CounterVideoStub::DisplayStatistics(
std::ostream& os) {
MessageCounter::DisplayStatistics(os);
video_data_.DisplayStatistics(os);
capture_time_.DisplayStatistics(os);
encode_time_.DisplayStatistics(os);
}
void FakeConnectionEventLogger::CounterVideoStub::ProcessVideoPacket(
std::unique_ptr<VideoPacket> video_packet,
base::OnceClosure done) {
if (video_packet && video_packet->has_capture_overhead_time_ms()) {
// Not a keepalive packet.
if (connection_ &&
connection_->video_feedback_stub()) {
std::unique_ptr<VideoAck> ack(new VideoAck());
ack->set_frame_id(video_packet->frame_id());
connection_->video_feedback_stub()->ProcessVideoAck(std::move(ack));
}
LogMessage(*video_packet);
video_data_.LogMessage(video_packet->data().size());
capture_time_.LogMessage(video_packet->capture_time_ms());
encode_time_.LogMessage(video_packet->encode_time_ms());
}
std::move(done).Run();
}
FakeConnectionEventLogger::FakeConnectionEventLogger(
protocol::FakeConnectionToClient* connection)
: client_stub_(new CounterClientStub()),
host_stub_(new CounterHostStub()),
audio_stub_(new CounterAudioStub()),
video_stub_(new CounterVideoStub(connection)) {}
FakeConnectionEventLogger::~FakeConnectionEventLogger() {}
protocol::ClientStub* FakeConnectionEventLogger::client_stub() {
return client_stub_.get();
}
protocol::HostStub* FakeConnectionEventLogger::host_stub() {
return host_stub_.get();
}
protocol::AudioStub* FakeConnectionEventLogger::audio_stub() {
return audio_stub_.get();
}
protocol::VideoStub* FakeConnectionEventLogger::video_stub() {
return video_stub_.get();
}
std::ostream& operator<<(std::ostream& os,
const FakeConnectionEventLogger& logger) {
logger.audio_stub_->DisplayStatistics(os);
logger.video_stub_->DisplayStatistics(os);
logger.client_stub_->DisplayStatistics(os);
logger.host_stub_->DisplayStatistics(os);
return os;
}
} // namespace test
} // namespace remoting