Exclude initial adapt downs in stats for quality adapt changes per minute.

Make WebRTC.Video.AdaptChangesPerMinute.Quality stats only based on changes during a call.

Discard initial quality adapt changes due to bitrate (MaximumFrameSizeForBitrate).
Makes stats only based on changes determined by the quality scaler.

Bug: none
Change-Id: I461b65e65634565ade87b1336cf5206aa14926ff
Reviewed-on: https://webrtc-review.googlesource.com/37660
Reviewed-by: Rasmus Brandt <brandtr@webrtc.org>
Commit-Queue: Åsa Persson <asapersson@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#21585}
This commit is contained in:
Åsa Persson 2018-01-08 08:49:53 +01:00 committed by Commit Bot
parent 34814c728f
commit 875841d9d8
4 changed files with 136 additions and 0 deletions

View File

@ -439,6 +439,11 @@ void SendStatisticsProxy::UmaSamplesContainer::UpdateHistograms(
if (elapsed_sec >= metrics::kMinRunTimeInSeconds) {
int quality_changes = current_stats.number_of_quality_adapt_changes -
start_stats_.number_of_quality_adapt_changes;
// Only base stats on changes during a call, discard initial changes.
int initial_changes =
initial_quality_changes_.down + initial_quality_changes_.up;
if (initial_changes <= quality_changes)
quality_changes -= initial_changes;
RTC_HISTOGRAMS_COUNTS_100(kIndex,
uma_prefix_ + "AdaptChangesPerMinute.Quality",
quality_changes * 60 / elapsed_sec);
@ -987,6 +992,7 @@ void SendStatisticsProxy::OnQualityAdaptationChanged(
const VideoStreamEncoder::AdaptCounts& cpu_counts,
const VideoStreamEncoder::AdaptCounts& quality_counts) {
rtc::CritScope lock(&crit_);
TryUpdateInitialQualityResolutionAdaptUp(quality_counts);
++stats_.number_of_quality_adapt_changes;
UpdateAdaptationStats(cpu_counts, quality_counts);
}
@ -1003,6 +1009,27 @@ void SendStatisticsProxy::UpdateAdaptationStats(
stats_.bw_limited_framerate = quality_counts.fps > 0;
}
// TODO(asapersson): Include fps changes.
void SendStatisticsProxy::OnInitialQualityResolutionAdaptDown() {
rtc::CritScope lock(&crit_);
++uma_container_->initial_quality_changes_.down;
}
void SendStatisticsProxy::TryUpdateInitialQualityResolutionAdaptUp(
const VideoStreamEncoder::AdaptCounts& quality_counts) {
if (uma_container_->initial_quality_changes_.down == 0)
return;
if (quality_downscales_ > 0 &&
quality_counts.resolution < quality_downscales_) {
// Adapting up in quality.
if (uma_container_->initial_quality_changes_.down >
uma_container_->initial_quality_changes_.up) {
++uma_container_->initial_quality_changes_.up;
}
}
}
void SendStatisticsProxy::SetAdaptTimer(
const VideoStreamEncoder::AdaptCounts& counts,
StatsTimer* timer) {

View File

@ -74,6 +74,7 @@ class SendStatisticsProxy : public CpuOveruseMetricsObserver,
const VideoStreamEncoder::AdaptCounts& cpu_counts,
const VideoStreamEncoder::AdaptCounts& quality_counts);
void OnMinPixelLimitReached();
void OnInitialQualityResolutionAdaptDown();
void OnSuspendChange(bool is_suspended);
void OnInactiveSsrc(uint32_t ssrc);
@ -181,6 +182,10 @@ class SendStatisticsProxy : public CpuOveruseMetricsObserver,
SampleCounter vp9; // QP range: 0-255.
SampleCounter h264; // QP range: 0-51.
};
struct AdaptChanges {
int down = 0;
int up = 0;
};
// Map holding encoded frames (mapped by timestamp).
// If simulcast layers are encoded on different threads, there is no guarantee
@ -217,6 +222,9 @@ class SendStatisticsProxy : public CpuOveruseMetricsObserver,
const VideoStreamEncoder::AdaptCounts& cpu_counts,
const VideoStreamEncoder::AdaptCounts& quality_counts)
RTC_EXCLUSIVE_LOCKS_REQUIRED(crit_);
void TryUpdateInitialQualityResolutionAdaptUp(
const VideoStreamEncoder::AdaptCounts& quality_counts)
RTC_EXCLUSIVE_LOCKS_REQUIRED(crit_);
void UpdateEncoderFallbackStats(const CodecSpecificInfo* codec_info,
int pixels)
@ -298,6 +306,7 @@ class SendStatisticsProxy : public CpuOveruseMetricsObserver,
size_t num_streams_; // Number of configured streams to encoder.
size_t num_pixels_highest_stream_;
EncodedFrameMap encoded_frames_;
AdaptChanges initial_quality_changes_;
std::map<int, QpCounters>
qp_counters_; // QP counters mapped by spatial idx.

View File

@ -513,6 +513,102 @@ TEST_F(SendStatisticsProxyTest, CpuAdaptChangesReported) {
EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.AdaptChangesPerMinute.Cpu", 6));
}
TEST_F(SendStatisticsProxyTest, ExcludesInitialQualityAdaptDownChange) {
// First RTP packet sent.
UpdateDataCounters(kFirstSsrc);
// Enable adaptation.
VideoStreamEncoder::AdaptCounts cpu_counts;
VideoStreamEncoder::AdaptCounts quality_counts;
statistics_proxy_->SetAdaptationStats(cpu_counts, quality_counts);
// Adapt changes: 1 (1 initial) = 0, elapsed time: 10 sec => 0 per minute.
statistics_proxy_->OnQualityAdaptationChanged(cpu_counts, quality_counts);
statistics_proxy_->OnInitialQualityResolutionAdaptDown();
fake_clock_.AdvanceTimeMilliseconds(10000);
statistics_proxy_.reset();
EXPECT_EQ(1,
metrics::NumSamples("WebRTC.Video.AdaptChangesPerMinute.Quality"));
EXPECT_EQ(
1, metrics::NumEvents("WebRTC.Video.AdaptChangesPerMinute.Quality", 0));
}
TEST_F(SendStatisticsProxyTest, ExcludesInitialQualityAdaptDownChanges) {
// First RTP packet sent.
UpdateDataCounters(kFirstSsrc);
// Enable adaptation.
VideoStreamEncoder::AdaptCounts cpu_counts;
VideoStreamEncoder::AdaptCounts quality_counts;
statistics_proxy_->SetAdaptationStats(cpu_counts, quality_counts);
// Adapt changes: 3 (2 initial) = 1, elapsed time: 10 sec => 6 per minute.
quality_counts.resolution = 1;
statistics_proxy_->OnQualityAdaptationChanged(cpu_counts, quality_counts);
statistics_proxy_->OnInitialQualityResolutionAdaptDown();
quality_counts.resolution = 2;
statistics_proxy_->OnQualityAdaptationChanged(cpu_counts, quality_counts);
statistics_proxy_->OnInitialQualityResolutionAdaptDown();
quality_counts.resolution = 3;
statistics_proxy_->OnQualityAdaptationChanged(cpu_counts, quality_counts);
fake_clock_.AdvanceTimeMilliseconds(10000);
statistics_proxy_.reset();
EXPECT_EQ(1,
metrics::NumSamples("WebRTC.Video.AdaptChangesPerMinute.Quality"));
EXPECT_EQ(
1, metrics::NumEvents("WebRTC.Video.AdaptChangesPerMinute.Quality", 6));
}
TEST_F(SendStatisticsProxyTest, InitialQualityAdaptChangesNotExcludedOnError) {
// First RTP packet sent.
UpdateDataCounters(kFirstSsrc);
// Enable adaptation.
VideoStreamEncoder::AdaptCounts cpu_counts;
VideoStreamEncoder::AdaptCounts quality_counts;
statistics_proxy_->SetAdaptationStats(cpu_counts, quality_counts);
// Adapt changes: 1 (2 initial) = 1, elapsed time: 10 sec => 6 per minute.
statistics_proxy_->OnQualityAdaptationChanged(cpu_counts, quality_counts);
statistics_proxy_->OnInitialQualityResolutionAdaptDown();
statistics_proxy_->OnInitialQualityResolutionAdaptDown();
fake_clock_.AdvanceTimeMilliseconds(10000);
statistics_proxy_.reset();
EXPECT_EQ(1,
metrics::NumSamples("WebRTC.Video.AdaptChangesPerMinute.Quality"));
EXPECT_EQ(
1, metrics::NumEvents("WebRTC.Video.AdaptChangesPerMinute.Quality", 6));
}
TEST_F(SendStatisticsProxyTest, ExcludesInitialQualityAdaptDownAndUpChanges) {
// First RTP packet sent.
UpdateDataCounters(kFirstSsrc);
// Enable adaptation.
VideoStreamEncoder::AdaptCounts cpu_counts;
VideoStreamEncoder::AdaptCounts quality_counts;
statistics_proxy_->SetAdaptationStats(cpu_counts, quality_counts);
// Adapt changes: 8 (4 initial) = 4, elapsed time: 10 sec => 24 per minute.
quality_counts.resolution = 1;
statistics_proxy_->OnQualityAdaptationChanged(cpu_counts, quality_counts);
statistics_proxy_->OnInitialQualityResolutionAdaptDown();
quality_counts.resolution = 2;
statistics_proxy_->OnQualityAdaptationChanged(cpu_counts, quality_counts);
statistics_proxy_->OnInitialQualityResolutionAdaptDown();
quality_counts.resolution = 3;
statistics_proxy_->OnQualityAdaptationChanged(cpu_counts, quality_counts);
quality_counts.fps = 1;
statistics_proxy_->OnQualityAdaptationChanged(cpu_counts, quality_counts);
quality_counts.fps = 0;
statistics_proxy_->OnQualityAdaptationChanged(cpu_counts, quality_counts);
quality_counts.resolution = 2; // Initial resolution up.
statistics_proxy_->OnQualityAdaptationChanged(cpu_counts, quality_counts);
quality_counts.resolution = 1; // Initial resolution up.
statistics_proxy_->OnQualityAdaptationChanged(cpu_counts, quality_counts);
quality_counts.resolution = 0;
statistics_proxy_->OnQualityAdaptationChanged(cpu_counts, quality_counts);
fake_clock_.AdvanceTimeMilliseconds(10000);
statistics_proxy_.reset();
EXPECT_EQ(1,
metrics::NumSamples("WebRTC.Video.AdaptChangesPerMinute.Quality"));
EXPECT_EQ(
1, metrics::NumEvents("WebRTC.Video.AdaptChangesPerMinute.Quality", 24));
}
TEST_F(SendStatisticsProxyTest, AdaptChangesStatsExcludesDisabledTime) {
// First RTP packet sent.
UpdateDataCounters(kFirstSsrc);

View File

@ -767,7 +767,11 @@ void VideoStreamEncoder::EncodeVideoFrame(const VideoFrame& video_frame,
video_frame.size() >
MaximumFrameSizeForBitrate(encoder_start_bitrate_bps_ / 1000)) {
RTC_LOG(LS_INFO) << "Dropping frame. Too large for target bitrate.";
int count = GetConstAdaptCounter().ResolutionCount(kQuality);
AdaptDown(kQuality);
if (GetConstAdaptCounter().ResolutionCount(kQuality) > count) {
stats_proxy_->OnInitialQualityResolutionAdaptDown();
}
++initial_rampup_;
return;
}