Move RTP stats histograms from VieChannel to SendStatisticsProxy.

Also slice for screensharing.

BUG=
R=mflodman@webrtc.org, pbos@webrtc.org

Review URL: https://codereview.webrtc.org/1734933002 .

Cr-Commit-Position: refs/heads/master@{#11822}
This commit is contained in:
Erik Språng 2016-03-01 09:40:42 +01:00
parent 681e20e008
commit 22c2b4814a
7 changed files with 228 additions and 57 deletions

View File

@ -11,6 +11,7 @@
#ifndef WEBRTC_COMMON_TYPES_H_
#define WEBRTC_COMMON_TYPES_H_
#include <assert.h>
#include <stddef.h>
#include <string.h>
@ -791,6 +792,17 @@ struct RtpPacketCounter {
packets += other.packets;
}
void Subtract(const RtpPacketCounter& other) {
assert(header_bytes >= other.header_bytes);
header_bytes -= other.header_bytes;
assert(payload_bytes >= other.payload_bytes);
payload_bytes -= other.payload_bytes;
assert(padding_bytes >= other.padding_bytes);
padding_bytes -= other.padding_bytes;
assert(packets >= other.packets);
packets -= other.packets;
}
void AddPacket(size_t packet_length, const RTPHeader& header) {
++packets;
header_bytes += header.headerLength;
@ -825,6 +837,18 @@ struct StreamDataCounters {
}
}
void Subtract(const StreamDataCounters& other) {
transmitted.Subtract(other.transmitted);
retransmitted.Subtract(other.retransmitted);
fec.Subtract(other.fec);
if (other.first_packet_time_ms != -1 &&
(other.first_packet_time_ms > first_packet_time_ms ||
first_packet_time_ms == -1)) {
// Use youngest time.
first_packet_time_ms = other.first_packet_time_ms;
}
}
int64_t TimeSinceFirstPacketInMs(int64_t now_ms) const {
return (first_packet_time_ms == -1) ? -1 : (now_ms - first_packet_time_ms);
}

View File

@ -2246,20 +2246,19 @@ void EndToEndTest::VerifyHistogramStats(bool use_rtx,
EXPECT_EQ(1, test::NumHistogramSamples(video_prefix + "EncodeTimeInMs"));
EXPECT_EQ(1, test::NumHistogramSamples("WebRTC.Video.DecodeTimeInMs"));
EXPECT_EQ(1, test::NumHistogramSamples(
"WebRTC.Video.BitrateSentInKbps"));
EXPECT_EQ(1, test::NumHistogramSamples(video_prefix + "BitrateSentInKbps"));
EXPECT_EQ(1, test::NumHistogramSamples(
"WebRTC.Video.BitrateReceivedInKbps"));
EXPECT_EQ(1, test::NumHistogramSamples(
"WebRTC.Video.MediaBitrateSentInKbps"));
EXPECT_EQ(1,
test::NumHistogramSamples(video_prefix + "MediaBitrateSentInKbps"));
EXPECT_EQ(1, test::NumHistogramSamples(
"WebRTC.Video.MediaBitrateReceivedInKbps"));
EXPECT_EQ(1, test::NumHistogramSamples(
"WebRTC.Video.PaddingBitrateSentInKbps"));
EXPECT_EQ(
1, test::NumHistogramSamples(video_prefix + "PaddingBitrateSentInKbps"));
EXPECT_EQ(1, test::NumHistogramSamples(
"WebRTC.Video.PaddingBitrateReceivedInKbps"));
EXPECT_EQ(1, test::NumHistogramSamples(
"WebRTC.Video.RetransmittedBitrateSentInKbps"));
EXPECT_EQ(1, test::NumHistogramSamples(video_prefix +
"RetransmittedBitrateSentInKbps"));
EXPECT_EQ(1, test::NumHistogramSamples(
"WebRTC.Video.RetransmittedBitrateReceivedInKbps"));

View File

@ -98,10 +98,26 @@ SendStatisticsProxy::UmaSamplesContainer::UmaSamplesContainer(
input_frame_rate_tracker_(100u, 10u),
sent_frame_rate_tracker_(100u, 10u),
first_rtcp_stats_time_ms_(-1),
first_rtp_stats_time_ms_(-1),
start_stats_(stats) {}
SendStatisticsProxy::UmaSamplesContainer::~UmaSamplesContainer() {}
void AccumulateRtpStats(const VideoSendStream::Stats& stats,
const VideoSendStream::Config& config,
StreamDataCounters* total_rtp_stats,
StreamDataCounters* rtx_stats) {
for (auto it : stats.substreams) {
const std::vector<uint32_t> rtx_ssrcs = config.rtp.rtx.ssrcs;
if (std::find(rtx_ssrcs.begin(), rtx_ssrcs.end(), it.first) !=
rtx_ssrcs.end()) {
rtx_stats->Add(it.second.rtp_stats);
} else {
total_rtp_stats->Add(it.second.rtp_stats);
}
}
}
void SendStatisticsProxy::UmaSamplesContainer::UpdateHistograms(
const VideoSendStream::Config& config,
const VideoSendStream::Stats& current_stats) {
@ -223,6 +239,51 @@ void SendStatisticsProxy::UmaSamplesContainer::UpdateHistograms(
}
}
}
if (first_rtp_stats_time_ms_ != -1) {
int64_t elapsed_sec =
(clock_->TimeInMilliseconds() - first_rtp_stats_time_ms_) / 1000;
if (elapsed_sec >= metrics::kMinRunTimeInSeconds) {
StreamDataCounters rtp;
StreamDataCounters rtx;
AccumulateRtpStats(current_stats, config, &rtp, &rtx);
StreamDataCounters start_rtp;
StreamDataCounters start_rtx;
AccumulateRtpStats(start_stats_, config, &start_rtp, &start_rtx);
rtp.Subtract(start_rtp);
rtx.Subtract(start_rtx);
StreamDataCounters rtp_rtx = rtp;
rtp_rtx.Add(rtx);
RTC_HISTOGRAMS_COUNTS_10000(
kIndex, uma_prefix_ + "BitrateSentInKbps",
static_cast<int>(rtp_rtx.transmitted.TotalBytes() * 8 / elapsed_sec /
1000));
RTC_HISTOGRAMS_COUNTS_10000(
kIndex, uma_prefix_ + "MediaBitrateSentInKbps",
static_cast<int>(rtp.MediaPayloadBytes() * 8 / elapsed_sec / 1000));
RTC_HISTOGRAMS_COUNTS_10000(
kIndex, uma_prefix_ + "PaddingBitrateSentInKbps",
static_cast<int>(rtp_rtx.transmitted.padding_bytes * 8 / elapsed_sec /
1000));
RTC_HISTOGRAMS_COUNTS_10000(
kIndex, uma_prefix_ + "RetransmittedBitrateSentInKbps",
static_cast<int>(rtp_rtx.retransmitted.TotalBytes() * 8 /
elapsed_sec / 1000));
if (!config.rtp.rtx.ssrcs.empty()) {
RTC_HISTOGRAMS_COUNTS_10000(
kIndex, uma_prefix_ + "RtxBitrateSentInKbps",
static_cast<int>(rtx.transmitted.TotalBytes() * 8 / elapsed_sec /
1000));
}
if (config.rtp.fec.red_payload_type != -1) {
RTC_HISTOGRAMS_COUNTS_10000(kIndex,
uma_prefix_ + "FecBitrateSentInKbps",
static_cast<int>(rtp_rtx.fec.TotalBytes() *
8 / elapsed_sec / 1000));
}
}
}
}
void SendStatisticsProxy::SetContentType(
@ -429,6 +490,8 @@ void SendStatisticsProxy::DataCountersUpdated(
<< "DataCountersUpdated reported for unknown ssrc: " << ssrc;
stats->rtp_stats = counters;
if (uma_container_->first_rtp_stats_time_ms_ == -1)
uma_container_->first_rtp_stats_time_ms_ = clock_->TimeInMilliseconds();
}
void SendStatisticsProxy::Notify(const BitrateStatistics& total_stats,

View File

@ -169,6 +169,7 @@ class SendStatisticsProxy : public CpuOveruseMetricsObserver,
rtc::RateTracker input_frame_rate_tracker_;
rtc::RateTracker sent_frame_rate_tracker_;
int64_t first_rtcp_stats_time_ms_;
int64_t first_rtp_stats_time_ms_;
ReportBlockStats report_block_stats_;
const VideoSendStream::Stats start_stats_;
};

View File

@ -47,6 +47,7 @@ class SendStatisticsProxyTest : public ::testing::Test {
config.rtp.ssrcs.push_back(kSecondSsrc);
config.rtp.rtx.ssrcs.push_back(kFirstRtxSsrc);
config.rtp.rtx.ssrcs.push_back(kSecondRtxSsrc);
config.rtp.fec.red_payload_type = 17;
return config;
}
@ -525,4 +526,136 @@ TEST_F(SendStatisticsProxyTest, ResetsRtcpCountersOnContentChange) {
"WebRTC.Video.Screenshare.UniqueNackRequestsReceivedInPercent"));
}
TEST_F(SendStatisticsProxyTest, ResetsRtpCountersOnContentChange) {
StreamDataCountersCallback* proxy =
static_cast<StreamDataCountersCallback*>(statistics_proxy_.get());
StreamDataCounters counters;
StreamDataCounters rtx_counters;
counters.first_packet_time_ms = fake_clock_.TimeInMilliseconds();
proxy->DataCountersUpdated(counters, kFirstSsrc);
proxy->DataCountersUpdated(counters, kSecondSsrc);
proxy->DataCountersUpdated(rtx_counters, kFirstRtxSsrc);
proxy->DataCountersUpdated(rtx_counters, kSecondRtxSsrc);
counters.transmitted.header_bytes = 400;
counters.transmitted.packets = 20;
counters.transmitted.padding_bytes = 1000;
counters.transmitted.payload_bytes = 2000;
counters.retransmitted.header_bytes = 40;
counters.retransmitted.packets = 2;
counters.retransmitted.padding_bytes = 100;
counters.retransmitted.payload_bytes = 200;
counters.fec = counters.retransmitted;
rtx_counters.transmitted = counters.transmitted;
fake_clock_.AdvanceTimeMilliseconds(1000 * metrics::kMinRunTimeInSeconds);
proxy->DataCountersUpdated(counters, kFirstSsrc);
proxy->DataCountersUpdated(counters, kSecondSsrc);
proxy->DataCountersUpdated(rtx_counters, kFirstRtxSsrc);
proxy->DataCountersUpdated(rtx_counters, kSecondRtxSsrc);
// Changing content type causes histograms to be reported.
statistics_proxy_->SetContentType(VideoEncoderConfig::ContentType::kScreen);
EXPECT_EQ(1, test::NumHistogramSamples("WebRTC.Video.BitrateSentInKbps"));
EXPECT_EQ(static_cast<int>((counters.transmitted.TotalBytes() * 4 * 8) /
metrics::kMinRunTimeInSeconds / 1000),
test::LastHistogramSample("WebRTC.Video.BitrateSentInKbps"));
EXPECT_EQ(1,
test::NumHistogramSamples("WebRTC.Video.MediaBitrateSentInKbps"));
EXPECT_EQ(static_cast<int>((counters.MediaPayloadBytes() * 2 * 8) /
metrics::kMinRunTimeInSeconds / 1000),
test::LastHistogramSample("WebRTC.Video.MediaBitrateSentInKbps"));
EXPECT_EQ(1,
test::NumHistogramSamples("WebRTC.Video.PaddingBitrateSentInKbps"));
EXPECT_EQ(static_cast<int>((counters.transmitted.padding_bytes * 4 * 8) /
metrics::kMinRunTimeInSeconds / 1000),
test::LastHistogramSample("WebRTC.Video.PaddingBitrateSentInKbps"));
EXPECT_EQ(1, test::NumHistogramSamples(
"WebRTC.Video.RetransmittedBitrateSentInKbps"));
EXPECT_EQ(
static_cast<int>((counters.retransmitted.TotalBytes() * 2 * 8) /
metrics::kMinRunTimeInSeconds / 1000),
test::LastHistogramSample("WebRTC.Video.RetransmittedBitrateSentInKbps"));
EXPECT_EQ(1, test::NumHistogramSamples("WebRTC.Video.RtxBitrateSentInKbps"));
EXPECT_EQ(static_cast<int>((rtx_counters.transmitted.TotalBytes() * 2 * 8) /
metrics::kMinRunTimeInSeconds / 1000),
test::LastHistogramSample("WebRTC.Video.RtxBitrateSentInKbps"));
EXPECT_EQ(1, test::NumHistogramSamples("WebRTC.Video.FecBitrateSentInKbps"));
EXPECT_EQ(static_cast<int>((rtx_counters.fec.TotalBytes() * 2 * 8) /
metrics::kMinRunTimeInSeconds / 1000),
test::LastHistogramSample("WebRTC.Video.FecBitrateSentInKbps"));
// New start time but same counter values.
proxy->DataCountersUpdated(counters, kFirstSsrc);
proxy->DataCountersUpdated(counters, kSecondSsrc);
proxy->DataCountersUpdated(rtx_counters, kFirstRtxSsrc);
proxy->DataCountersUpdated(rtx_counters, kSecondRtxSsrc);
// Double counter values, this should result in the same counts as before but
// with new histogram names.
StreamDataCounters new_counters = counters;
new_counters.Add(counters);
StreamDataCounters new_rtx_counters = rtx_counters;
new_rtx_counters.Add(rtx_counters);
fake_clock_.AdvanceTimeMilliseconds(1000 * metrics::kMinRunTimeInSeconds);
proxy->DataCountersUpdated(new_counters, kFirstSsrc);
proxy->DataCountersUpdated(new_counters, kSecondSsrc);
proxy->DataCountersUpdated(new_rtx_counters, kFirstRtxSsrc);
proxy->DataCountersUpdated(new_rtx_counters, kSecondRtxSsrc);
SetUp(); // Reset stats proxy also causes histograms to be reported.
EXPECT_EQ(1, test::NumHistogramSamples(
"WebRTC.Video.Screenshare.BitrateSentInKbps"));
EXPECT_EQ(
static_cast<int>((counters.transmitted.TotalBytes() * 4 * 8) /
metrics::kMinRunTimeInSeconds / 1000),
test::LastHistogramSample("WebRTC.Video.Screenshare.BitrateSentInKbps"));
EXPECT_EQ(1, test::NumHistogramSamples(
"WebRTC.Video.Screenshare.MediaBitrateSentInKbps"));
EXPECT_EQ(static_cast<int>((counters.MediaPayloadBytes() * 2 * 8) /
metrics::kMinRunTimeInSeconds / 1000),
test::LastHistogramSample(
"WebRTC.Video.Screenshare.MediaBitrateSentInKbps"));
EXPECT_EQ(1, test::NumHistogramSamples(
"WebRTC.Video.Screenshare.PaddingBitrateSentInKbps"));
EXPECT_EQ(static_cast<int>((counters.transmitted.padding_bytes * 4 * 8) /
metrics::kMinRunTimeInSeconds / 1000),
test::LastHistogramSample(
"WebRTC.Video.Screenshare.PaddingBitrateSentInKbps"));
EXPECT_EQ(1, test::NumHistogramSamples(
"WebRTC.Video.Screenshare.RetransmittedBitrateSentInKbps"));
EXPECT_EQ(static_cast<int>((counters.retransmitted.TotalBytes() * 2 * 8) /
metrics::kMinRunTimeInSeconds / 1000),
test::LastHistogramSample(
"WebRTC.Video.Screenshare.RetransmittedBitrateSentInKbps"));
EXPECT_EQ(1, test::NumHistogramSamples(
"WebRTC.Video.Screenshare.RtxBitrateSentInKbps"));
EXPECT_EQ(static_cast<int>((rtx_counters.transmitted.TotalBytes() * 2 * 8) /
metrics::kMinRunTimeInSeconds / 1000),
test::LastHistogramSample(
"WebRTC.Video.Screenshare.RtxBitrateSentInKbps"));
EXPECT_EQ(1, test::NumHistogramSamples(
"WebRTC.Video.Screenshare.FecBitrateSentInKbps"));
EXPECT_EQ(static_cast<int>((rtx_counters.fec.TotalBytes() * 2 * 8) /
metrics::kMinRunTimeInSeconds / 1000),
test::LastHistogramSample(
"WebRTC.Video.Screenshare.FecBitrateSentInKbps"));
}
} // namespace webrtc

View File

@ -163,7 +163,6 @@ int32_t ViEChannel::Init() {
}
ViEChannel::~ViEChannel() {
UpdateHistograms();
// Make sure we don't get more callbacks from the RTP module.
module_process_thread_->DeRegisterModule(
vie_receiver_.GetReceiveStatistics());
@ -177,52 +176,6 @@ ViEChannel::~ViEChannel() {
}
}
void ViEChannel::UpdateHistograms() {
if (sender_) {
StreamDataCounters rtp;
StreamDataCounters rtx;
GetSendStreamDataCounters(&rtp, &rtx);
StreamDataCounters rtp_rtx = rtp;
rtp_rtx.Add(rtx);
int64_t elapsed_sec = rtp_rtx.TimeSinceFirstPacketInMs(
Clock::GetRealTimeClock()->TimeInMilliseconds()) /
1000;
if (elapsed_sec > metrics::kMinRunTimeInSeconds) {
RTC_HISTOGRAM_COUNTS_100000(
"WebRTC.Video.BitrateSentInKbps",
static_cast<int>(rtp_rtx.transmitted.TotalBytes() * 8 / elapsed_sec /
1000));
RTC_HISTOGRAM_COUNTS_10000(
"WebRTC.Video.MediaBitrateSentInKbps",
static_cast<int>(rtp.MediaPayloadBytes() * 8 / elapsed_sec / 1000));
RTC_HISTOGRAM_COUNTS_10000(
"WebRTC.Video.PaddingBitrateSentInKbps",
static_cast<int>(rtp_rtx.transmitted.padding_bytes * 8 / elapsed_sec /
1000));
RTC_HISTOGRAM_COUNTS_10000(
"WebRTC.Video.RetransmittedBitrateSentInKbps",
static_cast<int>(rtp_rtx.retransmitted.TotalBytes() * 8 /
elapsed_sec / 1000));
if (rtp_rtcp_modules_[0]->RtxSendStatus() != kRtxOff) {
RTC_HISTOGRAM_COUNTS_10000(
"WebRTC.Video.RtxBitrateSentInKbps",
static_cast<int>(rtx.transmitted.TotalBytes() * 8 / elapsed_sec /
1000));
}
bool fec_enabled = false;
uint8_t pltype_red;
uint8_t pltype_fec;
rtp_rtcp_modules_[0]->GenericFECStatus(&fec_enabled, &pltype_red,
&pltype_fec);
if (fec_enabled) {
RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.FecBitrateSentInKbps",
static_cast<int>(rtp_rtx.fec.TotalBytes() *
8 / elapsed_sec / 1000));
}
}
}
}
int32_t ViEChannel::SetSendCodec(const VideoCodec& video_codec,
bool new_stream) {
RTC_DCHECK(sender_);

View File

@ -200,8 +200,6 @@ class ViEChannel : public VCMFrameTypeCallback,
// Compute NACK list parameters for the buffering mode.
int GetRequiredNackListSize(int target_delay_ms);
void UpdateHistograms();
// ViEChannel exposes methods that allow to modify observers and callbacks
// to be modified. Such an API-style is cumbersome to implement and maintain
// at all the levels when comparing to only setting them at construction. As