Add per frame decode time histograms for 4k/HD and VP9/H264
Add new histograms WebRTC.Video.DecodeTimePerFrameInMs.[codec].[resolution].[decoder] These histograms are more explicit than the existing histogram WebRTC.VideoDecodTimeMs, since they allow to see performance per codec/resolution/decoder and also contain per frame statistics instead of an average decode time. There's a killswitch, WebRTC-DecodeTimeHistogramsKillSwitch, that can be used to disable the histograms. Bug: chromium:1007526 Change-Id: I9f75127b4bc5341e9f406c64ed91164564290b26 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/157881 Reviewed-by: Åsa Persson <asapersson@webrtc.org> Commit-Queue: Johannes Kron <kron@webrtc.org> Cr-Commit-Position: refs/heads/master@{#29572}
This commit is contained in:
committed by
Commit Bot
parent
13a8e16247
commit
e76b3abf61
@ -20,6 +20,7 @@
|
||||
#include "rtc_base/strings/string_builder.h"
|
||||
#include "rtc_base/time_utils.h"
|
||||
#include "system_wrappers/include/clock.h"
|
||||
#include "system_wrappers/include/field_trial.h"
|
||||
#include "system_wrappers/include/metrics.h"
|
||||
|
||||
namespace webrtc {
|
||||
@ -85,6 +86,8 @@ ReceiveStatisticsProxy::ReceiveStatisticsProxy(
|
||||
: clock_(clock),
|
||||
config_(*config),
|
||||
start_ms_(clock->TimeInMilliseconds()),
|
||||
enable_decode_time_histograms_(
|
||||
!field_trial::IsEnabled("WebRTC-DecodeTimeHistogramsKillSwitch")),
|
||||
last_sample_time_(clock->TimeInMilliseconds()),
|
||||
fps_threshold_(kLowFpsThreshold,
|
||||
kHighFpsThreshold,
|
||||
@ -553,6 +556,61 @@ void ReceiveStatisticsProxy::UpdateFramerate(int64_t now_ms) const {
|
||||
stats_.network_frame_rate = static_cast<int>(framerate);
|
||||
}
|
||||
|
||||
void ReceiveStatisticsProxy::UpdateDecodeTimeHistograms(
|
||||
int width,
|
||||
int height,
|
||||
int decode_time_ms) const {
|
||||
bool is_4k = (width == 3840 || width == 4096) && height == 2160;
|
||||
bool is_hd = width == 1920 && height == 1080;
|
||||
// Only update histograms for 4k/HD and VP9/H264.
|
||||
if ((is_4k || is_hd) && (last_codec_type_ == kVideoCodecVP9 ||
|
||||
last_codec_type_ == kVideoCodecH264)) {
|
||||
const std::string kDecodeTimeUmaPrefix =
|
||||
"WebRTC.Video.DecodeTimePerFrameInMs.";
|
||||
|
||||
// Each histogram needs its own line for it to not be reused in the wrong
|
||||
// way when the format changes.
|
||||
if (last_codec_type_ == kVideoCodecVP9) {
|
||||
bool is_sw_decoder =
|
||||
stats_.decoder_implementation_name.compare(0, 6, "libvpx") == 0;
|
||||
if (is_4k) {
|
||||
if (is_sw_decoder)
|
||||
RTC_HISTOGRAM_COUNTS_1000(kDecodeTimeUmaPrefix + "Vp9.4k.Sw",
|
||||
decode_time_ms);
|
||||
else
|
||||
RTC_HISTOGRAM_COUNTS_1000(kDecodeTimeUmaPrefix + "Vp9.4k.Hw",
|
||||
decode_time_ms);
|
||||
} else {
|
||||
if (is_sw_decoder)
|
||||
RTC_HISTOGRAM_COUNTS_1000(kDecodeTimeUmaPrefix + "Vp9.Hd.Sw",
|
||||
decode_time_ms);
|
||||
else
|
||||
RTC_HISTOGRAM_COUNTS_1000(kDecodeTimeUmaPrefix + "Vp9.Hd.Hw",
|
||||
decode_time_ms);
|
||||
}
|
||||
} else {
|
||||
bool is_sw_decoder =
|
||||
stats_.decoder_implementation_name.compare(0, 6, "FFmpeg") == 0;
|
||||
if (is_4k) {
|
||||
if (is_sw_decoder)
|
||||
RTC_HISTOGRAM_COUNTS_1000(kDecodeTimeUmaPrefix + "H264.4k.Sw",
|
||||
decode_time_ms);
|
||||
else
|
||||
RTC_HISTOGRAM_COUNTS_1000(kDecodeTimeUmaPrefix + "H264.4k.Hw",
|
||||
decode_time_ms);
|
||||
|
||||
} else {
|
||||
if (is_sw_decoder)
|
||||
RTC_HISTOGRAM_COUNTS_1000(kDecodeTimeUmaPrefix + "H264.Hd.Sw",
|
||||
decode_time_ms);
|
||||
else
|
||||
RTC_HISTOGRAM_COUNTS_1000(kDecodeTimeUmaPrefix + "H264.Hd.Hw",
|
||||
decode_time_ms);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VideoReceiveStream::Stats ReceiveStatisticsProxy::GetStats() const {
|
||||
rtc::CritScope lock(&crit_);
|
||||
// Get current frame rates here, as only updating them on new frames prevents
|
||||
@ -697,6 +755,10 @@ void ReceiveStatisticsProxy::OnDecodedFrame(const VideoFrame& frame,
|
||||
decode_time_counter_.Add(decode_time_ms);
|
||||
stats_.decode_ms = decode_time_ms;
|
||||
stats_.total_decode_time_ms += decode_time_ms;
|
||||
if (enable_decode_time_histograms_) {
|
||||
UpdateDecodeTimeHistograms(frame.width(), frame.height(), decode_time_ms);
|
||||
}
|
||||
|
||||
last_content_type_ = content_type;
|
||||
decode_fps_estimator_.Update(1, now_ms);
|
||||
if (last_decoded_frame_time_ms_) {
|
||||
|
||||
@ -128,6 +128,11 @@ class ReceiveStatisticsProxy : public VCMReceiveStatisticsCallback,
|
||||
void UpdateFramerate(int64_t now_ms) const
|
||||
RTC_EXCLUSIVE_LOCKS_REQUIRED(crit_);
|
||||
|
||||
void UpdateDecodeTimeHistograms(int width,
|
||||
int height,
|
||||
int decode_time_ms) const
|
||||
RTC_EXCLUSIVE_LOCKS_REQUIRED(crit_);
|
||||
|
||||
Clock* const clock_;
|
||||
// Ownership of this object lies with the owner of the ReceiveStatisticsProxy
|
||||
// instance. Lifetime is guaranteed to outlive |this|.
|
||||
@ -138,6 +143,7 @@ class ReceiveStatisticsProxy : public VCMReceiveStatisticsCallback,
|
||||
// then no longer store a pointer to the object).
|
||||
const VideoReceiveStream::Config& config_;
|
||||
const int64_t start_ms_;
|
||||
const bool enable_decode_time_histograms_;
|
||||
|
||||
rtc::CriticalSection crit_;
|
||||
int64_t last_sample_time_ RTC_GUARDED_BY(crit_);
|
||||
|
||||
@ -16,12 +16,14 @@
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
|
||||
#include "absl/types/optional.h"
|
||||
#include "api/scoped_refptr.h"
|
||||
#include "api/video/i420_buffer.h"
|
||||
#include "api/video/video_frame.h"
|
||||
#include "api/video/video_frame_buffer.h"
|
||||
#include "api/video/video_rotation.h"
|
||||
#include "system_wrappers/include/metrics.h"
|
||||
#include "test/field_trial.h"
|
||||
#include "test/gtest.h"
|
||||
|
||||
namespace webrtc {
|
||||
@ -1548,4 +1550,142 @@ TEST_P(ReceiveStatisticsProxyTestWithContent,
|
||||
"WebRTC.Video.InterframeDelayInMs.ExperimentGroup0"));
|
||||
}
|
||||
}
|
||||
|
||||
class DecodeTimeHistogramsKillswitch {
|
||||
public:
|
||||
explicit DecodeTimeHistogramsKillswitch(bool disable_histograms)
|
||||
: field_trial_(disable_histograms
|
||||
? "WebRTC-DecodeTimeHistogramsKillSwitch/Enabled/"
|
||||
: "") {}
|
||||
|
||||
private:
|
||||
webrtc::test::ScopedFieldTrials field_trial_;
|
||||
};
|
||||
|
||||
class ReceiveStatisticsProxyTestWithDecodeTimeHistograms
|
||||
: public DecodeTimeHistogramsKillswitch,
|
||||
public ::testing::WithParamInterface<
|
||||
std::tuple<bool, int, int, int, VideoCodecType, std::string>>,
|
||||
public ReceiveStatisticsProxyTest {
|
||||
public:
|
||||
ReceiveStatisticsProxyTestWithDecodeTimeHistograms()
|
||||
: DecodeTimeHistogramsKillswitch(std::get<0>(GetParam())) {}
|
||||
|
||||
protected:
|
||||
const std::string kUmaPrefix = "WebRTC.Video.DecodeTimePerFrameInMs.";
|
||||
const int expected_number_of_samples_ = {std::get<1>(GetParam())};
|
||||
const int width_ = {std::get<2>(GetParam())};
|
||||
const int height_ = {std::get<3>(GetParam())};
|
||||
const VideoCodecType codec_type_ = {std::get<4>(GetParam())};
|
||||
const std::string implementation_name_ = {std::get<5>(GetParam())};
|
||||
const std::string uma_histogram_name_ =
|
||||
kUmaPrefix + (codec_type_ == kVideoCodecVP9 ? "Vp9." : "H264.") +
|
||||
(height_ == 2160 ? "4k." : "Hd.") +
|
||||
(implementation_name_.compare("ExternalDecoder") == 0 ? "Hw" : "Sw");
|
||||
};
|
||||
|
||||
TEST_P(ReceiveStatisticsProxyTestWithDecodeTimeHistograms,
|
||||
DecodeTimeHistogramsUpdated) {
|
||||
constexpr int kNumberOfFrames = 10;
|
||||
constexpr int kDecodeTimeMs = 7;
|
||||
constexpr int kFrameDurationMs = 1000 / 60;
|
||||
|
||||
webrtc::VideoFrame frame = CreateFrame(width_, height_);
|
||||
|
||||
statistics_proxy_->OnDecoderImplementationName(implementation_name_.c_str());
|
||||
statistics_proxy_->OnPreDecode(codec_type_, /*qp=*/0);
|
||||
|
||||
for (int i = 0; i < kNumberOfFrames; ++i) {
|
||||
statistics_proxy_->OnDecodedFrame(frame, /*qp=*/absl::nullopt,
|
||||
kDecodeTimeMs,
|
||||
VideoContentType::UNSPECIFIED);
|
||||
fake_clock_.AdvanceTimeMilliseconds(kFrameDurationMs);
|
||||
}
|
||||
|
||||
EXPECT_EQ(expected_number_of_samples_,
|
||||
metrics::NumSamples(uma_histogram_name_));
|
||||
EXPECT_EQ(expected_number_of_samples_,
|
||||
metrics::NumEvents(uma_histogram_name_, kDecodeTimeMs));
|
||||
}
|
||||
|
||||
const auto kVp94kHw = std::make_tuple(/*killswitch=*/false,
|
||||
/*expected_number_of_samples=*/10,
|
||||
/*width=*/3840,
|
||||
/*height=*/2160,
|
||||
kVideoCodecVP9,
|
||||
/*implementation=*/"ExternalDecoder");
|
||||
const auto kVp94kSw = std::make_tuple(/*killswitch=*/false,
|
||||
/*expected_number_of_samples=*/10,
|
||||
/*width=*/3840,
|
||||
/*height=*/2160,
|
||||
kVideoCodecVP9,
|
||||
/*implementation=*/"libvpx");
|
||||
const auto kVp9HdHw = std::make_tuple(/*killswitch=*/false,
|
||||
/*expected_number_of_samples=*/10,
|
||||
/*width=*/1920,
|
||||
/*height=*/1080,
|
||||
kVideoCodecVP9,
|
||||
/*implementation=*/"ExternalDecoder");
|
||||
const auto kVp9HdSw = std::make_tuple(/*killswitch=*/false,
|
||||
/*expected_number_of_samples=*/10,
|
||||
/*width=*/1920,
|
||||
/*height=*/1080,
|
||||
kVideoCodecVP9,
|
||||
/*implementation=*/"libvpx");
|
||||
const auto kH2644kHw = std::make_tuple(/*killswitch=*/false,
|
||||
/*expected_number_of_samples=*/10,
|
||||
/*width=*/3840,
|
||||
/*height=*/2160,
|
||||
kVideoCodecH264,
|
||||
/*implementation=*/"ExternalDecoder");
|
||||
const auto kH2644kSw = std::make_tuple(/*killswitch=*/false,
|
||||
/*expected_number_of_samples=*/10,
|
||||
/*width=*/3840,
|
||||
/*height=*/2160,
|
||||
kVideoCodecH264,
|
||||
/*implementation=*/"FFmpeg");
|
||||
const auto kH264HdHw = std::make_tuple(/*killswitch=*/false,
|
||||
/*expected_number_of_samples=*/10,
|
||||
/*width=*/1920,
|
||||
/*height=*/1080,
|
||||
kVideoCodecH264,
|
||||
/*implementation=*/"ExternalDecoder");
|
||||
const auto kH264HdSw = std::make_tuple(/*killswitch=*/false,
|
||||
/*expected_number_of_samples=*/10,
|
||||
/*width=*/1920,
|
||||
/*height=*/1080,
|
||||
kVideoCodecH264,
|
||||
/*implementation=*/"FFmpeg");
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(AllHistogramsPopulated,
|
||||
ReceiveStatisticsProxyTestWithDecodeTimeHistograms,
|
||||
::testing::Values(kVp94kHw,
|
||||
kVp94kSw,
|
||||
kVp9HdHw,
|
||||
kVp9HdSw,
|
||||
kH2644kHw,
|
||||
kH2644kSw,
|
||||
kH264HdHw,
|
||||
kH264HdSw));
|
||||
|
||||
const auto kKillswitchDisabled =
|
||||
std::make_tuple(/*killswitch=*/false,
|
||||
/*expected_number_of_samples=*/10,
|
||||
/*width=*/1920,
|
||||
/*height=*/1080,
|
||||
kVideoCodecVP9,
|
||||
/*implementation=*/"libvpx");
|
||||
const auto kKillswitchEnabled =
|
||||
std::make_tuple(/*killswitch=*/true,
|
||||
/*expected_number_of_samples=*/0,
|
||||
/*width=*/1920,
|
||||
/*height=*/1080,
|
||||
kVideoCodecVP9,
|
||||
/*implementation=*/"libvpx");
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(KillswitchEffective,
|
||||
ReceiveStatisticsProxyTestWithDecodeTimeHistograms,
|
||||
::testing::Values(kKillswitchDisabled,
|
||||
kKillswitchEnabled));
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
Reference in New Issue
Block a user