Implement CpuOveruseMetrics as callbacks.

Adds avg_encode_ms and encode_usage_percent in WebRtcVideoEngine2 and
corresponding stats to VideoSendStream::Stats.

BUG=1667, 1788
R=asapersson@webrtc.org, mflodman@webrtc.org

Review URL: https://webrtc-codereview.appspot.com/42429004

Cr-Commit-Position: refs/heads/master@{#8513}
git-svn-id: http://webrtc.googlecode.com/svn/trunk@8513 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
pbos@webrtc.org 2015-02-26 12:19:31 +00:00
parent 60f295fcb1
commit 3e6e271ec3
17 changed files with 152 additions and 66 deletions

View File

@ -699,6 +699,8 @@ class FakeWebRtcVideoEngine
return 0;
}
WEBRTC_STUB(GetCpuOveruseMetrics, (int, webrtc::CpuOveruseMetrics*));
WEBRTC_VOID_STUB(RegisterCpuOveruseMetricsObserver,
(int, webrtc::CpuOveruseMetricsObserver*));
WEBRTC_FUNC(SetCpuOveruseOptions,
(int channel, const webrtc::CpuOveruseOptions& options)) {
WEBRTC_CHECK_CHANNEL(channel);

View File

@ -1774,6 +1774,8 @@ WebRtcVideoChannel2::WebRtcVideoSendStream::GetVideoSenderInfo() {
}
info.framerate_input = stats.input_frame_rate;
info.framerate_sent = stats.encode_frame_rate;
info.avg_encode_ms = stats.avg_encode_time_ms;
info.encode_usage_percent = stats.encode_usage_percent;
info.nominal_bitrate = stats.media_bitrate_bps;

View File

@ -2038,6 +2038,19 @@ TEST_F(WebRtcVideoChannel2Test, OnReadyToSendSignalsNetworkState) {
EXPECT_EQ(webrtc::Call::kNetworkUp, fake_call_->GetNetworkState());
}
TEST_F(WebRtcVideoChannel2Test, GetStatsReportsCpuOveruseMetrics) {
FakeVideoSendStream* stream = AddSendStream();
webrtc::VideoSendStream::Stats stats;
stats.avg_encode_time_ms = 13;
stats.encode_usage_percent = 42;
stream->SetStats(stats);
cricket::VideoMediaInfo info;
ASSERT_TRUE(channel_->GetStats(cricket::StatsOptions(), &info));
EXPECT_EQ(stats.avg_encode_time_ms, info.senders[0].avg_encode_ms);
EXPECT_EQ(stats.encode_usage_percent, info.senders[0].encode_usage_percent);
}
TEST_F(WebRtcVideoChannel2Test, GetStatsReportsUpperResolution) {
FakeVideoSendStream* stream = AddSendStream();
webrtc::VideoSendStream::Stats stats;

View File

@ -1660,6 +1660,9 @@ TEST_F(EndToEndTest, GetStats) {
send_stats_filled_["NumStreams"] |=
stats.substreams.size() == expected_send_ssrcs_.size();
send_stats_filled_["CpuOveruseMetrics"] |=
stats.avg_encode_time_ms != 0 || stats.encode_usage_percent != 0;
for (std::map<uint32_t, VideoSendStream::StreamStats>::const_iterator it =
stats.substreams.begin();
it != stats.substreams.end(); ++it) {

View File

@ -38,6 +38,13 @@ void SendStatisticsProxy::OutgoingRate(const int video_channel,
stats_.media_bitrate_bps = bitrate;
}
void SendStatisticsProxy::CpuOveruseMetricsUpdated(
const CpuOveruseMetrics& metrics) {
CriticalSectionScoped lock(crit_.get());
stats_.avg_encode_time_ms = metrics.avg_encode_time_ms;
stats_.encode_usage_percent = metrics.encode_usage_percent;
}
void SendStatisticsProxy::SuspendChange(int video_channel, bool is_suspended) {
CriticalSectionScoped lock(crit_.get());
stats_.suspended = is_suspended;

View File

@ -18,6 +18,7 @@
#include "webrtc/modules/video_coding/codecs/interface/video_codec_interface.h"
#include "webrtc/system_wrappers/interface/clock.h"
#include "webrtc/system_wrappers/interface/scoped_ptr.h"
#include "webrtc/video_engine/include/vie_base.h"
#include "webrtc/video_engine/include/vie_capture.h"
#include "webrtc/video_engine/include/vie_codec.h"
#include "webrtc/video_send_stream.h"
@ -26,7 +27,8 @@ namespace webrtc {
class CriticalSectionWrapper;
class SendStatisticsProxy : public RtcpStatisticsCallback,
class SendStatisticsProxy : public CpuOveruseMetricsObserver,
public RtcpStatisticsCallback,
public RtcpPacketTypeCounterObserver,
public StreamDataCountersCallback,
public BitrateStatisticsObserver,
@ -46,6 +48,8 @@ class SendStatisticsProxy : public RtcpStatisticsCallback,
const RTPVideoHeader* rtp_video_header);
protected:
// From CpuOveruseMetricsObserver.
void CpuOveruseMetricsUpdated(const CpuOveruseMetrics& metrics) OVERRIDE;
// From RtcpStatisticsCallback.
virtual void StatisticsUpdated(const RtcpStatistics& statistics,
uint32_t ssrc) OVERRIDE;

View File

@ -210,6 +210,9 @@ VideoSendStream::VideoSendStream(
if (overuse_observer)
video_engine_base_->RegisterCpuOveruseObserver(channel_, overuse_observer);
// Registered regardless of monitoring, used for stats.
video_engine_base_->RegisterCpuOveruseMetricsObserver(channel_,
&stats_proxy_);
video_engine_base_->RegisterSendSideDelayObserver(channel_, &stats_proxy_);
video_engine_base_->RegisterSendStatisticsProxy(channel_, &stats_proxy_);

View File

@ -112,7 +112,6 @@ struct CpuOveruseMetrics {
: capture_jitter_ms(-1),
avg_encode_time_ms(-1),
encode_usage_percent(-1),
encode_rsd(-1),
capture_queue_delay_ms_per_s(-1) {}
int capture_jitter_ms; // The current estimated jitter in ms based on
@ -120,14 +119,18 @@ struct CpuOveruseMetrics {
int avg_encode_time_ms; // The average encode time in ms.
int encode_usage_percent; // The average encode time divided by the average
// time difference between incoming captured frames.
// TODO(asapersson): Remove metric, not used.
int encode_rsd; // The relative std dev of encode time of frames.
int capture_queue_delay_ms_per_s; // The current time delay between an
// incoming captured frame until the frame
// is being processed. The delay is
// expressed in ms delay per second.
};
class CpuOveruseMetricsObserver {
public:
virtual ~CpuOveruseMetricsObserver() {}
virtual void CpuOveruseMetricsUpdated(const CpuOveruseMetrics& metrics) = 0;
};
class WEBRTC_DLLEXPORT VideoEngine {
public:
// Creates a VideoEngine object, which can then be used to acquire subAPIs.
@ -208,6 +211,9 @@ class WEBRTC_DLLEXPORT ViEBase {
// Gets cpu overuse measures.
virtual int GetCpuOveruseMetrics(int channel, CpuOveruseMetrics* metrics) = 0;
virtual void RegisterCpuOveruseMetricsObserver(
int channel,
CpuOveruseMetricsObserver* observer) = 0;
// Registers a callback which is called when send-side delay statistics has
// been updated.

View File

@ -317,8 +317,11 @@ class OveruseFrameDetector::CaptureQueueDelay {
scoped_ptr<rtc::ExpFilter> filtered_delay_ms_per_s_;
};
OveruseFrameDetector::OveruseFrameDetector(Clock* clock)
OveruseFrameDetector::OveruseFrameDetector(
Clock* clock,
CpuOveruseMetricsObserver* metrics_observer)
: observer_(NULL),
metrics_observer_(metrics_observer),
clock_(clock),
next_process_time_(clock_->TimeInMilliseconds()),
num_process_times_(0),
@ -336,6 +339,7 @@ OveruseFrameDetector::OveruseFrameDetector(Clock* clock)
frame_queue_(new FrameQueue()),
last_sample_time_ms_(0),
capture_queue_delay_(new CaptureQueueDelay()) {
DCHECK(metrics_observer != nullptr);
processing_thread_.DetachFromThread();
}
@ -374,14 +378,13 @@ int OveruseFrameDetector::FramesInQueue() const {
return frame_queue_->NumFrames();
}
void OveruseFrameDetector::GetCpuOveruseMetrics(
CpuOveruseMetrics* metrics) const {
rtc::CritScope cs(&crit_);
metrics->capture_jitter_ms = static_cast<int>(capture_deltas_.StdDev() + 0.5);
metrics->avg_encode_time_ms = encode_time_->Value();
metrics->encode_rsd = 0;
metrics->encode_usage_percent = usage_->Value();
metrics->capture_queue_delay_ms_per_s = capture_queue_delay_->Value();
void OveruseFrameDetector::UpdateCpuOveruseMetrics() {
metrics_.capture_jitter_ms = static_cast<int>(capture_deltas_.StdDev() + 0.5);
metrics_.avg_encode_time_ms = encode_time_->Value();
metrics_.encode_usage_percent = usage_->Value();
metrics_.capture_queue_delay_ms_per_s = capture_queue_delay_->Value();
metrics_observer_->CpuOveruseMetricsUpdated(metrics_);
}
int64_t OveruseFrameDetector::TimeUntilNextProcess() {
@ -411,6 +414,7 @@ void OveruseFrameDetector::ResetAll(int num_pixels) {
capture_queue_delay_->ClearFrames();
last_capture_time_ = 0;
num_process_times_ = 0;
UpdateCpuOveruseMetrics();
}
void OveruseFrameDetector::FrameCaptured(int width,
@ -434,6 +438,7 @@ void OveruseFrameDetector::FrameCaptured(int width,
if (options_.enable_extended_processing_usage) {
frame_queue_->Start(capture_time_ms, now);
}
UpdateCpuOveruseMetrics();
}
void OveruseFrameDetector::FrameProcessingStarted() {
@ -453,6 +458,7 @@ void OveruseFrameDetector::FrameEncoded(int encode_time_ms) {
if (!options_.enable_extended_processing_usage) {
AddProcessingTime(encode_time_ms);
}
UpdateCpuOveruseMetrics();
}
void OveruseFrameDetector::FrameSent(int64_t capture_time_ms) {
@ -465,6 +471,7 @@ void OveruseFrameDetector::FrameSent(int64_t capture_time_ms) {
if (delay_ms > 0) {
AddProcessingTime(delay_ms);
}
UpdateCpuOveruseMetrics();
}
void OveruseFrameDetector::AddProcessingTime(int elapsed_ms) {
@ -492,6 +499,7 @@ int32_t OveruseFrameDetector::Process() {
++num_process_times_;
capture_queue_delay_->CalculateDelayChange(diff_ms);
UpdateCpuOveruseMetrics();
if (num_process_times_ <= options_.min_process_count) {
return 0;
@ -537,6 +545,7 @@ int32_t OveruseFrameDetector::Process() {
<< " encode usage " << usage_->Value()
<< " overuse detections " << num_overuse_detections_
<< " rampup delay " << rampup_delay;
return 0;
}

View File

@ -52,7 +52,8 @@ class Statistics {
// Use to detect system overuse based on jitter in incoming frames.
class OveruseFrameDetector : public Module {
public:
explicit OveruseFrameDetector(Clock* clock);
OveruseFrameDetector(Clock* clock,
CpuOveruseMetricsObserver* metrics_observer);
~OveruseFrameDetector();
// Registers an observer receiving overuse and underuse callbacks. Set
@ -74,26 +75,6 @@ class OveruseFrameDetector : public Module {
// Called for each sent frame.
void FrameSent(int64_t capture_time_ms);
// Accessors.
// Returns CpuOveruseMetrics where
// capture_jitter_ms: The estimated jitter based on incoming captured frames.
// avg_encode_time_ms: Running average of reported encode time
// (FrameEncoded()). Only used for stats.
// TODO(asapersson): Rename metric.
// encode_usage_percent: The average processing time of a frame on the
// send-side divided by the average time difference
// between incoming captured frames.
// capture_queue_delay_ms_per_s: The current time delay between an incoming
// captured frame (FrameCaptured()) until the
// frame is being processed
// (FrameProcessingStarted()). (Note: if a new
// frame is received before an old frame has
// been processed, the old frame is skipped).
// The delay is expressed in ms delay per sec.
// Only used for stats.
void GetCpuOveruseMetrics(CpuOveruseMetrics* metrics) const;
// Only public for testing.
int CaptureQueueDelayMsPerS() const;
int LastProcessingTimeMs() const;
@ -109,6 +90,8 @@ class OveruseFrameDetector : public Module {
class CaptureQueueDelay;
class FrameQueue;
void UpdateCpuOveruseMetrics() EXCLUSIVE_LOCKS_REQUIRED(crit_);
// TODO(asapersson): This method is only used on one thread, so it shouldn't
// need a guard.
void AddProcessingTime(int elapsed_ms) EXCLUSIVE_LOCKS_REQUIRED(crit_);
@ -136,6 +119,10 @@ class OveruseFrameDetector : public Module {
CpuOveruseOptions options_ GUARDED_BY(crit_);
// Stats metrics.
CpuOveruseMetricsObserver* const metrics_observer_;
CpuOveruseMetrics metrics_ GUARDED_BY(crit_);
Clock* const clock_;
int64_t next_process_time_; // Only accessed on the processing thread.
int64_t num_process_times_ GUARDED_BY(crit_);

View File

@ -47,12 +47,13 @@ class CpuOveruseObserverImpl : public CpuOveruseObserver {
int normaluse_;
};
class OveruseFrameDetectorTest : public ::testing::Test {
class OveruseFrameDetectorTest : public ::testing::Test,
public CpuOveruseMetricsObserver {
protected:
virtual void SetUp() {
clock_.reset(new SimulatedClock(1234));
observer_.reset(new MockCpuOveruseObserver());
overuse_detector_.reset(new OveruseFrameDetector(clock_.get()));
overuse_detector_.reset(new OveruseFrameDetector(clock_.get(), this));
options_.low_capture_jitter_threshold_ms = 10.0f;
options_.high_capture_jitter_threshold_ms = 15.0f;
@ -61,6 +62,11 @@ class OveruseFrameDetectorTest : public ::testing::Test {
overuse_detector_->SetObserver(observer_.get());
}
virtual void CpuOveruseMetricsUpdated(
const CpuOveruseMetrics& metrics) override {
metrics_ = metrics;
}
int InitialJitter() {
return ((options_.low_capture_jitter_threshold_ms +
options_.high_capture_jitter_threshold_ms) / 2.0f) + 0.5;
@ -124,28 +130,17 @@ class OveruseFrameDetectorTest : public ::testing::Test {
overuse_detector_->Process();
}
int CaptureJitterMs() {
CpuOveruseMetrics metrics;
overuse_detector_->GetCpuOveruseMetrics(&metrics);
return metrics.capture_jitter_ms;
}
int CaptureJitterMs() { return metrics_.capture_jitter_ms; }
int AvgEncodeTimeMs() {
CpuOveruseMetrics metrics;
overuse_detector_->GetCpuOveruseMetrics(&metrics);
return metrics.avg_encode_time_ms;
}
int AvgEncodeTimeMs() { return metrics_.avg_encode_time_ms; }
int UsagePercent() {
CpuOveruseMetrics metrics;
overuse_detector_->GetCpuOveruseMetrics(&metrics);
return metrics.encode_usage_percent;
}
int UsagePercent() { return metrics_.encode_usage_percent; }
CpuOveruseOptions options_;
scoped_ptr<SimulatedClock> clock_;
scoped_ptr<MockCpuOveruseObserver> observer_;
scoped_ptr<OveruseFrameDetector> overuse_detector_;
CpuOveruseMetrics metrics_;
};
// enable_capture_jitter_method = true;
@ -257,16 +252,6 @@ TEST_F(OveruseFrameDetectorTest, IncorrectConsecutiveCountTriggersNoOveruse) {
TriggerOveruse(1);
}
TEST_F(OveruseFrameDetectorTest, GetCpuOveruseMetrics) {
CpuOveruseMetrics metrics;
overuse_detector_->GetCpuOveruseMetrics(&metrics);
EXPECT_GT(metrics.capture_jitter_ms, 0);
EXPECT_GT(metrics.avg_encode_time_ms, 0);
EXPECT_GT(metrics.encode_usage_percent, 0);
EXPECT_GE(metrics.capture_queue_delay_ms_per_s, 0);
EXPECT_GE(metrics.encode_rsd, 0);
}
TEST_F(OveruseFrameDetectorTest, CaptureJitter) {
EXPECT_EQ(InitialJitter(), CaptureJitterMs());
InsertFramesWithInterval(1000, kFrameInterval33ms, kWidth, kHeight);

View File

@ -120,6 +120,23 @@ int ViEBaseImpl::SetCpuOveruseOptions(int video_channel,
return -1;
}
void ViEBaseImpl::RegisterCpuOveruseMetricsObserver(
int video_channel,
CpuOveruseMetricsObserver* observer) {
ViEChannelManagerScoped cs(*(shared_data_.channel_manager()));
ViEEncoder* vie_encoder = cs.Encoder(video_channel);
assert(vie_encoder);
ViEInputManagerScoped is(*(shared_data_.input_manager()));
ViEFrameProviderBase* provider = is.FrameProvider(vie_encoder);
assert(provider != NULL);
ViECapturer* capturer = is.Capture(provider->Id());
assert(capturer);
capturer->RegisterCpuOveruseMetricsObserver(observer);
}
int ViEBaseImpl::GetCpuOveruseMetrics(int video_channel,
CpuOveruseMetrics* metrics) {
ViEChannelManagerScoped cs(*(shared_data_.channel_manager()));

View File

@ -35,6 +35,9 @@ class ViEBaseImpl
CpuOveruseObserver* observer);
virtual int SetCpuOveruseOptions(int channel,
const CpuOveruseOptions& options);
virtual void RegisterCpuOveruseMetricsObserver(
int channel,
CpuOveruseMetricsObserver* observer) override;
virtual int GetCpuOveruseMetrics(int channel,
CpuOveruseMetrics* metrics);
virtual void RegisterSendSideDelayObserver(int channel,

View File

@ -32,6 +32,32 @@ namespace webrtc {
const int kThreadWaitTimeMs = 100;
class RegistrableCpuOveruseMetricsObserver : public CpuOveruseMetricsObserver {
public:
virtual void CpuOveruseMetricsUpdated(
const CpuOveruseMetrics& metrics) override {
rtc::CritScope lock(&crit_);
if (observer_)
observer_->CpuOveruseMetricsUpdated(metrics);
metrics_ = metrics;
}
CpuOveruseMetrics GetCpuOveruseMetrics() const {
rtc::CritScope lock(&crit_);
return metrics_;
}
void Set(CpuOveruseMetricsObserver* observer) {
rtc::CritScope lock(&crit_);
observer_ = observer;
}
private:
mutable rtc::CriticalSection crit_;
CpuOveruseMetricsObserver* observer_ GUARDED_BY(crit_) = nullptr;
CpuOveruseMetrics metrics_ GUARDED_BY(crit_);
};
ViECapturer::ViECapturer(int capture_id,
int engine_id,
const Config& config,
@ -45,7 +71,8 @@ ViECapturer::ViECapturer(int capture_id,
capture_id_(capture_id),
incoming_frame_cs_(CriticalSectionWrapper::CreateCriticalSection()),
capture_thread_(*ThreadWrapper::CreateThread(ViECaptureThreadFunction,
this, kHighPriority,
this,
kHighPriority,
"ViECaptureThread")),
capture_event_(*EventWrapper::Create()),
deliver_event_(*EventWrapper::Create()),
@ -59,7 +86,10 @@ ViECapturer::ViECapturer(int capture_id,
reported_brightness_level_(Normal),
observer_cs_(CriticalSectionWrapper::CreateCriticalSection()),
observer_(NULL),
overuse_detector_(new OveruseFrameDetector(Clock::GetRealTimeClock())) {
cpu_overuse_metrics_observer_(new RegistrableCpuOveruseMetricsObserver()),
overuse_detector_(
new OveruseFrameDetector(Clock::GetRealTimeClock(),
cpu_overuse_metrics_observer_.get())) {
unsigned int t_id = 0;
if (!capture_thread_.Start(t_id)) {
assert(false);
@ -246,8 +276,13 @@ void ViECapturer::SetCpuOveruseOptions(const CpuOveruseOptions& options) {
overuse_detector_->SetOptions(options);
}
void ViECapturer::RegisterCpuOveruseMetricsObserver(
CpuOveruseMetricsObserver* observer) {
cpu_overuse_metrics_observer_->Set(observer);
}
void ViECapturer::GetCpuOveruseMetrics(CpuOveruseMetrics* metrics) const {
overuse_detector_->GetCpuOveruseMetrics(metrics);
*metrics = cpu_overuse_metrics_observer_->GetCpuOveruseMetrics();
}
int32_t ViECapturer::SetCaptureDelay(int32_t delay_ms) {

View File

@ -13,6 +13,7 @@
#include <vector>
#include "webrtc/base/criticalsection.h"
#include "webrtc/base/thread_annotations.h"
#include "webrtc/common_types.h"
#include "webrtc/engine_configurations.h"
@ -20,6 +21,7 @@
#include "webrtc/modules/video_coding/codecs/interface/video_codec_interface.h"
#include "webrtc/modules/video_coding/main/interface/video_coding.h"
#include "webrtc/modules/video_processing/main/interface/video_processing.h"
#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
#include "webrtc/system_wrappers/interface/scoped_ptr.h"
#include "webrtc/typedefs.h"
#include "webrtc/video_engine/include/vie_base.h"
@ -39,6 +41,7 @@ class ThreadWrapper;
class ViEEffectFilter;
class ViEEncoder;
struct ViEPicture;
class RegistrableCpuOveruseMetricsObserver;
class ViECapturer
: public ViEFrameProviderBase,
@ -107,6 +110,7 @@ class ViECapturer
void RegisterCpuOveruseObserver(CpuOveruseObserver* observer);
void SetCpuOveruseOptions(const CpuOveruseOptions& options);
void RegisterCpuOveruseMetricsObserver(CpuOveruseMetricsObserver* observer);
void GetCpuOveruseMetrics(CpuOveruseMetrics* metrics) const;
protected:
@ -187,6 +191,9 @@ class ViECapturer
CaptureCapability requested_capability_;
// Must be declared before overuse_detector_ where it's registered.
const scoped_ptr<RegistrableCpuOveruseMetricsObserver>
cpu_overuse_metrics_observer_;
scoped_ptr<OveruseFrameDetector> overuse_detector_;
};

View File

@ -442,8 +442,7 @@ class ViEChannel
if (callback_)
callback_->Notify(total_stats, retransmit_stats, ssrc);
}
}
send_bitrate_observer_;
} send_bitrate_observer_;
class RegisterableFrameCountObserver
: public RegisterableCallback<FrameCountObserver> {

View File

@ -55,10 +55,14 @@ class VideoSendStream {
Stats()
: input_frame_rate(0),
encode_frame_rate(0),
avg_encode_time_ms(0),
encode_usage_percent(0),
media_bitrate_bps(0),
suspended(false) {}
int input_frame_rate;
int encode_frame_rate;
int avg_encode_time_ms;
int encode_usage_percent;
int media_bitrate_bps;
bool suspended;
std::map<uint32_t, StreamStats> substreams;