Add histogram stats for number of cpu/quality adapt changes per minute for sent video streams:
- "WebRTC.Video.AdaptChangesPerMinute.Cpu" - "WebRTC.Video.AdaptChangesPerMinute.Quality" BUG=webrtc:6634 Review-Url: https://codereview.webrtc.org/2786593003 Cr-Commit-Position: refs/heads/master@{#17535}
This commit is contained in:
parent
d48dbda434
commit
6eca98b7e5
@ -293,6 +293,24 @@ void SendStatisticsProxy::UmaSamplesContainer::UpdateHistograms(
|
||||
}
|
||||
}
|
||||
|
||||
quality_scaling_timer_.Stop(clock_->TimeInMilliseconds());
|
||||
int64_t elapsed_sec = quality_scaling_timer_.total_ms / 1000;
|
||||
if (elapsed_sec >= metrics::kMinRunTimeInSeconds) {
|
||||
int quality_changes = current_stats.number_of_quality_adapt_changes -
|
||||
start_stats_.number_of_quality_adapt_changes;
|
||||
RTC_HISTOGRAMS_COUNTS_100(kIndex,
|
||||
uma_prefix_ + "AdaptChangesPerMinute.Quality",
|
||||
quality_changes * 60 / elapsed_sec);
|
||||
}
|
||||
cpu_scaling_timer_.Stop(clock_->TimeInMilliseconds());
|
||||
elapsed_sec = cpu_scaling_timer_.total_ms / 1000;
|
||||
if (elapsed_sec >= metrics::kMinRunTimeInSeconds) {
|
||||
int cpu_changes = current_stats.number_of_cpu_adapt_changes -
|
||||
start_stats_.number_of_cpu_adapt_changes;
|
||||
RTC_HISTOGRAMS_COUNTS_100(kIndex, uma_prefix_ + "AdaptChangesPerMinute.Cpu",
|
||||
cpu_changes * 60 / elapsed_sec);
|
||||
}
|
||||
|
||||
if (first_rtcp_stats_time_ms_ != -1) {
|
||||
int64_t elapsed_sec =
|
||||
(clock_->TimeInMilliseconds() - first_rtcp_stats_time_ms_) / 1000;
|
||||
@ -684,15 +702,29 @@ void SendStatisticsProxy::OnIncomingFrame(int width, int height) {
|
||||
"ssrc", rtp_config_.ssrcs[0]);
|
||||
}
|
||||
|
||||
void SendStatisticsProxy::SetCpuScalingStats(bool cpu_restricted_resolution) {
|
||||
void SendStatisticsProxy::SetCpuScalingStats(int num_cpu_downscales) {
|
||||
rtc::CritScope lock(&crit_);
|
||||
stats_.cpu_limited_resolution = cpu_restricted_resolution;
|
||||
stats_.cpu_limited_resolution = num_cpu_downscales > 0;
|
||||
|
||||
if (num_cpu_downscales >= 0) {
|
||||
// Scaling enabled.
|
||||
uma_container_->cpu_scaling_timer_.Start(clock_->TimeInMilliseconds());
|
||||
} else {
|
||||
uma_container_->cpu_scaling_timer_.Stop(clock_->TimeInMilliseconds());
|
||||
}
|
||||
}
|
||||
|
||||
void SendStatisticsProxy::SetQualityScalingStats(int num_quality_downscales) {
|
||||
rtc::CritScope lock(&crit_);
|
||||
quality_downscales_ = num_quality_downscales;
|
||||
stats_.bw_limited_resolution = quality_downscales_ > 0;
|
||||
|
||||
if (num_quality_downscales >= 0) {
|
||||
// Scaling enabled.
|
||||
uma_container_->quality_scaling_timer_.Start(clock_->TimeInMilliseconds());
|
||||
} else {
|
||||
uma_container_->quality_scaling_timer_.Stop(clock_->TimeInMilliseconds());
|
||||
}
|
||||
}
|
||||
|
||||
void SendStatisticsProxy::OnCpuRestrictedResolutionChanged(
|
||||
@ -700,7 +732,7 @@ void SendStatisticsProxy::OnCpuRestrictedResolutionChanged(
|
||||
rtc::CritScope lock(&crit_);
|
||||
stats_.cpu_limited_resolution = cpu_restricted_resolution;
|
||||
++stats_.number_of_cpu_adapt_changes;
|
||||
TRACE_EVENT_INSTANT0("webrtc_stats", "WebRTC.Video.AdaptationChanges");
|
||||
TRACE_EVENT_INSTANT0("webrtc_stats", "WebRTC.Video.CpuAdaptationChanges");
|
||||
}
|
||||
|
||||
void SendStatisticsProxy::OnQualityRestrictedResolutionChanged(
|
||||
@ -761,8 +793,12 @@ void SendStatisticsProxy::DataCountersUpdated(
|
||||
}
|
||||
|
||||
stats->rtp_stats = counters;
|
||||
if (uma_container_->first_rtp_stats_time_ms_ == -1)
|
||||
uma_container_->first_rtp_stats_time_ms_ = clock_->TimeInMilliseconds();
|
||||
if (uma_container_->first_rtp_stats_time_ms_ == -1) {
|
||||
int64_t now_ms = clock_->TimeInMilliseconds();
|
||||
uma_container_->first_rtp_stats_time_ms_ = now_ms;
|
||||
uma_container_->cpu_scaling_timer_.Restart(now_ms);
|
||||
uma_container_->quality_scaling_timer_.Restart(now_ms);
|
||||
}
|
||||
|
||||
uma_container_->total_byte_counter_.Set(counters.transmitted.TotalBytes(),
|
||||
ssrc);
|
||||
@ -818,6 +854,24 @@ void SendStatisticsProxy::SendSideDelayUpdated(int avg_delay_ms,
|
||||
uma_container_->max_delay_counter_.Add(max_delay_ms);
|
||||
}
|
||||
|
||||
void SendStatisticsProxy::StatsTimer::Start(int64_t now_ms) {
|
||||
if (start_ms == -1)
|
||||
start_ms = now_ms;
|
||||
}
|
||||
|
||||
void SendStatisticsProxy::StatsTimer::Stop(int64_t now_ms) {
|
||||
if (start_ms != -1) {
|
||||
total_ms += now_ms - start_ms;
|
||||
start_ms = -1;
|
||||
}
|
||||
}
|
||||
|
||||
void SendStatisticsProxy::StatsTimer::Restart(int64_t now_ms) {
|
||||
total_ms = 0;
|
||||
if (start_ms != -1)
|
||||
start_ms = now_ms;
|
||||
}
|
||||
|
||||
void SendStatisticsProxy::SampleCounter::Add(int sample) {
|
||||
sum += sample;
|
||||
++num_samples;
|
||||
|
||||
@ -59,7 +59,7 @@ class SendStatisticsProxy : public CpuOveruseMetricsObserver,
|
||||
|
||||
void OnCpuRestrictedResolutionChanged(bool cpu_restricted_resolution);
|
||||
void OnQualityRestrictedResolutionChanged(int num_quality_downscales);
|
||||
void SetCpuScalingStats(bool cpu_restricted_resolution);
|
||||
void SetCpuScalingStats(int num_cpu_downscales); // -1: disabled.
|
||||
void SetQualityScalingStats(int num_quality_downscales); // -1: disabled.
|
||||
|
||||
void OnEncoderStatsUpdate(uint32_t framerate, uint32_t bitrate);
|
||||
@ -144,10 +144,17 @@ class SendStatisticsProxy : public CpuOveruseMetricsObserver,
|
||||
bool last_paused_or_resumed;
|
||||
int64_t last_ms;
|
||||
};
|
||||
struct StatsTimer {
|
||||
void Start(int64_t now_ms);
|
||||
void Stop(int64_t now_ms);
|
||||
void Restart(int64_t now_ms);
|
||||
int64_t start_ms = -1;
|
||||
int64_t total_ms = 0;
|
||||
};
|
||||
struct QpCounters {
|
||||
SampleCounter vp8; // QP range: 0-127
|
||||
SampleCounter vp9; // QP range: 0-255
|
||||
SampleCounter h264; // QP range: 0-51
|
||||
SampleCounter vp8; // QP range: 0-127.
|
||||
SampleCounter vp9; // QP range: 0-255.
|
||||
SampleCounter h264; // QP range: 0-51.
|
||||
};
|
||||
void PurgeOldStats() EXCLUSIVE_LOCKS_REQUIRED(crit_);
|
||||
VideoSendStream::StreamStats* GetStatsEntry(uint32_t ssrc)
|
||||
@ -207,6 +214,8 @@ class SendStatisticsProxy : public CpuOveruseMetricsObserver,
|
||||
RateAccCounter fec_byte_counter_;
|
||||
int64_t first_rtcp_stats_time_ms_;
|
||||
int64_t first_rtp_stats_time_ms_;
|
||||
StatsTimer cpu_scaling_timer_;
|
||||
StatsTimer quality_scaling_timer_;
|
||||
BoolSampleCounter paused_time_counter_;
|
||||
TargetRateUpdates target_rate_updates_;
|
||||
ReportBlockStats report_block_stats_;
|
||||
|
||||
@ -369,10 +369,12 @@ TEST_F(SendStatisticsProxyTest, OnSendEncodedImageWithoutQpQpSumWontExist) {
|
||||
|
||||
TEST_F(SendStatisticsProxyTest, SetCpuScalingUpdatesStats) {
|
||||
EXPECT_FALSE(statistics_proxy_->GetStats().cpu_limited_resolution);
|
||||
statistics_proxy_->SetCpuScalingStats(true);
|
||||
EXPECT_TRUE(statistics_proxy_->GetStats().cpu_limited_resolution);
|
||||
statistics_proxy_->SetCpuScalingStats(false);
|
||||
statistics_proxy_->SetCpuScalingStats(-1);
|
||||
EXPECT_FALSE(statistics_proxy_->GetStats().cpu_limited_resolution);
|
||||
statistics_proxy_->SetCpuScalingStats(0);
|
||||
EXPECT_FALSE(statistics_proxy_->GetStats().cpu_limited_resolution);
|
||||
statistics_proxy_->SetCpuScalingStats(1);
|
||||
EXPECT_TRUE(statistics_proxy_->GetStats().cpu_limited_resolution);
|
||||
}
|
||||
|
||||
TEST_F(SendStatisticsProxyTest, SetQualityScalingUpdatesStats) {
|
||||
@ -419,6 +421,191 @@ TEST_F(SendStatisticsProxyTest, GetStatsReportsQualityResolutionChanges) {
|
||||
EXPECT_EQ(4, statistics_proxy_->GetStats().number_of_quality_adapt_changes);
|
||||
}
|
||||
|
||||
TEST_F(SendStatisticsProxyTest, AdaptChangesNotReported_ScalingNotEnabled) {
|
||||
// Min runtime has passed.
|
||||
fake_clock_.AdvanceTimeMilliseconds(metrics::kMinRunTimeInSeconds * 1000);
|
||||
statistics_proxy_.reset();
|
||||
EXPECT_EQ(0, metrics::NumSamples("WebRTC.Video.AdaptChangesPerMinute.Cpu"));
|
||||
EXPECT_EQ(0,
|
||||
metrics::NumSamples("WebRTC.Video.AdaptChangesPerMinute.Quality"));
|
||||
}
|
||||
|
||||
TEST_F(SendStatisticsProxyTest, AdaptChangesNotReported_MinRuntimeNotPassed) {
|
||||
// Enable scaling.
|
||||
statistics_proxy_->SetQualityScalingStats(0);
|
||||
statistics_proxy_->SetCpuScalingStats(0);
|
||||
// Min runtime has not passed.
|
||||
fake_clock_.AdvanceTimeMilliseconds(metrics::kMinRunTimeInSeconds * 1000 - 1);
|
||||
statistics_proxy_.reset();
|
||||
EXPECT_EQ(0, metrics::NumSamples("WebRTC.Video.AdaptChangesPerMinute.Cpu"));
|
||||
EXPECT_EQ(0,
|
||||
metrics::NumSamples("WebRTC.Video.AdaptChangesPerMinute.Quality"));
|
||||
}
|
||||
|
||||
TEST_F(SendStatisticsProxyTest, ZeroCpuAdaptChangesReported) {
|
||||
// Enable scaling.
|
||||
statistics_proxy_->SetCpuScalingStats(0);
|
||||
// Min runtime has passed.
|
||||
fake_clock_.AdvanceTimeMilliseconds(metrics::kMinRunTimeInSeconds * 1000);
|
||||
statistics_proxy_.reset();
|
||||
EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.AdaptChangesPerMinute.Cpu"));
|
||||
EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.AdaptChangesPerMinute.Cpu", 0));
|
||||
}
|
||||
|
||||
TEST_F(SendStatisticsProxyTest, ZeroQualityAdaptChangesReported) {
|
||||
// Enable scaling.
|
||||
statistics_proxy_->SetQualityScalingStats(0);
|
||||
// Min runtime has passed.
|
||||
fake_clock_.AdvanceTimeMilliseconds(metrics::kMinRunTimeInSeconds * 1000);
|
||||
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, CpuAdaptChangesReported) {
|
||||
// Enable scaling.
|
||||
// Adapt changes: 1, elapsed time: 10 ms => 6 per minute.
|
||||
statistics_proxy_->SetCpuScalingStats(0);
|
||||
statistics_proxy_->OnCpuRestrictedResolutionChanged(true);
|
||||
fake_clock_.AdvanceTimeMilliseconds(10000);
|
||||
statistics_proxy_.reset();
|
||||
EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.AdaptChangesPerMinute.Cpu"));
|
||||
EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.AdaptChangesPerMinute.Cpu", 6));
|
||||
}
|
||||
|
||||
TEST_F(SendStatisticsProxyTest, AdaptChangesStatsExcludesDisabledTime) {
|
||||
// Disable scaling.
|
||||
statistics_proxy_->SetQualityScalingStats(-1);
|
||||
fake_clock_.AdvanceTimeMilliseconds(10000);
|
||||
|
||||
// Enable scaling.
|
||||
// Adapt changes: 2, elapsed time: 20 ms.
|
||||
statistics_proxy_->SetQualityScalingStats(0);
|
||||
fake_clock_.AdvanceTimeMilliseconds(5000);
|
||||
statistics_proxy_->SetQualityScalingStats(1);
|
||||
fake_clock_.AdvanceTimeMilliseconds(9000);
|
||||
statistics_proxy_->OnQualityRestrictedResolutionChanged(1);
|
||||
fake_clock_.AdvanceTimeMilliseconds(6000);
|
||||
statistics_proxy_->OnQualityRestrictedResolutionChanged(2);
|
||||
|
||||
// Disable scaling.
|
||||
statistics_proxy_->SetQualityScalingStats(-1);
|
||||
fake_clock_.AdvanceTimeMilliseconds(30000);
|
||||
|
||||
// Enable scaling.
|
||||
// Adapt changes: 1, elapsed time: 10 ms.
|
||||
statistics_proxy_->SetQualityScalingStats(0);
|
||||
statistics_proxy_->OnQualityRestrictedResolutionChanged(1);
|
||||
fake_clock_.AdvanceTimeMilliseconds(10000);
|
||||
|
||||
// Disable scaling.
|
||||
statistics_proxy_->SetQualityScalingStats(-1);
|
||||
fake_clock_.AdvanceTimeMilliseconds(5000);
|
||||
statistics_proxy_->SetQualityScalingStats(-1);
|
||||
fake_clock_.AdvanceTimeMilliseconds(20000);
|
||||
|
||||
// Adapt changes: 3, elapsed time: 30 ms => 6 per minute.
|
||||
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, AdaptChangesStatsRestartsOnFirstSentPacket) {
|
||||
StreamDataCounters counters;
|
||||
StreamDataCountersCallback* proxy =
|
||||
static_cast<StreamDataCountersCallback*>(statistics_proxy_.get());
|
||||
|
||||
// Send first packet, scaling enabled.
|
||||
// Elapsed time before first packet is sent should be excluded.
|
||||
statistics_proxy_->SetQualityScalingStats(0);
|
||||
fake_clock_.AdvanceTimeMilliseconds(10000);
|
||||
proxy->DataCountersUpdated(counters, kFirstSsrc);
|
||||
|
||||
// Adapt changes: 1, elapsed time: 10 ms.
|
||||
fake_clock_.AdvanceTimeMilliseconds(10000);
|
||||
statistics_proxy_->OnQualityRestrictedResolutionChanged(1);
|
||||
proxy->DataCountersUpdated(counters, kFirstSsrc);
|
||||
|
||||
// Adapt changes: 1, elapsed time: 10 ms => 6 per minute.
|
||||
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, AdaptChangesStatsStartedAfterFirstSentPacket) {
|
||||
StreamDataCounters counters;
|
||||
StreamDataCountersCallback* proxy =
|
||||
static_cast<StreamDataCountersCallback*>(statistics_proxy_.get());
|
||||
|
||||
// Enable and disable scaling.
|
||||
statistics_proxy_->SetCpuScalingStats(0);
|
||||
fake_clock_.AdvanceTimeMilliseconds(60000);
|
||||
statistics_proxy_->SetCpuScalingStats(-1);
|
||||
|
||||
// Send first packet, scaling disabled.
|
||||
// Elapsed time before first packet is sent should be excluded.
|
||||
proxy->DataCountersUpdated(counters, kFirstSsrc);
|
||||
fake_clock_.AdvanceTimeMilliseconds(60000);
|
||||
|
||||
// Enable scaling.
|
||||
statistics_proxy_->SetCpuScalingStats(0);
|
||||
fake_clock_.AdvanceTimeMilliseconds(10000);
|
||||
proxy->DataCountersUpdated(counters, kFirstSsrc);
|
||||
|
||||
// Adapt changes: 1, elapsed time: 20 ms.
|
||||
fake_clock_.AdvanceTimeMilliseconds(10000);
|
||||
statistics_proxy_->OnCpuRestrictedResolutionChanged(true);
|
||||
|
||||
// Adapt changes: 1, elapsed time: 20 ms => 3 per minute.
|
||||
statistics_proxy_.reset();
|
||||
EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.AdaptChangesPerMinute.Cpu"));
|
||||
EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.AdaptChangesPerMinute.Cpu", 3));
|
||||
}
|
||||
|
||||
TEST_F(SendStatisticsProxyTest, AdaptChangesReportedAfterContentSwitch) {
|
||||
// Enable scaling.
|
||||
statistics_proxy_->SetCpuScalingStats(0);
|
||||
|
||||
// Adapt changes: 2, elapsed time: 15 ms => 8 per minute.
|
||||
statistics_proxy_->OnCpuRestrictedResolutionChanged(true);
|
||||
fake_clock_.AdvanceTimeMilliseconds(6000);
|
||||
statistics_proxy_->OnCpuRestrictedResolutionChanged(true);
|
||||
fake_clock_.AdvanceTimeMilliseconds(9000);
|
||||
|
||||
// Switch content type, real-time stats should be updated.
|
||||
VideoEncoderConfig config;
|
||||
config.content_type = VideoEncoderConfig::ContentType::kScreen;
|
||||
statistics_proxy_->OnEncoderReconfigured(config, 50);
|
||||
EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.AdaptChangesPerMinute.Cpu"));
|
||||
EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.AdaptChangesPerMinute.Cpu", 8));
|
||||
EXPECT_EQ(0,
|
||||
metrics::NumSamples("WebRTC.Video.AdaptChangesPerMinute.Quality"));
|
||||
|
||||
// Enable scaling.
|
||||
statistics_proxy_->SetCpuScalingStats(0);
|
||||
|
||||
// Adapt changes: 4, elapsed time: 120 ms => 2 per minute.
|
||||
statistics_proxy_->OnCpuRestrictedResolutionChanged(true);
|
||||
statistics_proxy_->OnCpuRestrictedResolutionChanged(true);
|
||||
statistics_proxy_->OnCpuRestrictedResolutionChanged(true);
|
||||
statistics_proxy_->OnCpuRestrictedResolutionChanged(true);
|
||||
fake_clock_.AdvanceTimeMilliseconds(120000);
|
||||
|
||||
statistics_proxy_.reset();
|
||||
EXPECT_EQ(1, metrics::NumSamples(
|
||||
"WebRTC.Video.Screenshare.AdaptChangesPerMinute.Cpu"));
|
||||
EXPECT_EQ(1, metrics::NumEvents(
|
||||
"WebRTC.Video.Screenshare.AdaptChangesPerMinute.Cpu", 2));
|
||||
EXPECT_EQ(0, metrics::NumSamples(
|
||||
"WebRTC.Video.Screenshare.AdaptChangesPerMinute.Quality"));
|
||||
}
|
||||
|
||||
TEST_F(SendStatisticsProxyTest, SwitchContentTypeUpdatesHistograms) {
|
||||
for (int i = 0; i < SendStatisticsProxy::kMinRequiredMetricsSamples; ++i)
|
||||
statistics_proxy_->OnIncomingFrame(kWidth, kHeight);
|
||||
|
||||
@ -541,7 +541,7 @@ void ViEEncoder::ConfigureQualityScaler() {
|
||||
|
||||
const std::vector<int>& scale_counters = GetScaleCounters();
|
||||
stats_proxy_->SetCpuScalingStats(
|
||||
degradation_preference_allows_scaling ? scale_counters[kCpu] > 0 : false);
|
||||
degradation_preference_allows_scaling ? scale_counters[kCpu] : -1);
|
||||
stats_proxy_->SetQualityScalingStats(
|
||||
quality_scaling_allowed ? scale_counters[kQuality] : -1);
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user