From 5e14755c9e0b53f15fd6638a4ca2add9c0320339 Mon Sep 17 00:00:00 2001 From: Drew Thomas Date: Tue, 23 Apr 2024 10:11:12 -0700 Subject: [PATCH] Added UMA telemetry for Format Queries (#2954) Modifies the existing class `media::FormatSupportQueryMetrics` to report latency stats to UMA histograms, and does so on Gold builds. The existing log reporting has been retained for non-Gold builds. Added basic unit tests to verify that the UMA histograms are being reported correctly. b/329439820 Change-Id: Ie7f4e2e6c518d1c6c058fcbf62f046b56ea5f298 --- cobalt/media/BUILD.gn | 1 + .../base/format_support_query_metrics.cc | 65 ++++++++++++++-- .../media/base/format_support_query_metrics.h | 34 ++++----- .../base/format_support_query_metrics_test.cc | 76 +++++++++++++++++++ cobalt/media/media_module.cc | 10 ++- .../histograms/metadata/cobalt/histograms.xml | 22 ++++++ 6 files changed, 179 insertions(+), 29 deletions(-) create mode 100644 cobalt/media/base/format_support_query_metrics_test.cc diff --git a/cobalt/media/BUILD.gn b/cobalt/media/BUILD.gn index 3cb7629196f1..a362d9a47094 100644 --- a/cobalt/media/BUILD.gn +++ b/cobalt/media/BUILD.gn @@ -123,6 +123,7 @@ target(gtest_target_type, "media_test") { sources = [ "base/cval_stats_test.cc", "base/decoder_buffer_cache_test.cc", + "base/format_support_query_metrics_test.cc", "base/metrics_provider_test.cc", "bidirectional_fit_reuse_allocator_test.cc", "file_data_source_test.cc", diff --git a/cobalt/media/base/format_support_query_metrics.cc b/cobalt/media/base/format_support_query_metrics.cc index d3659c5ba029..294c9338e588 100644 --- a/cobalt/media/base/format_support_query_metrics.cc +++ b/cobalt/media/base/format_support_query_metrics.cc @@ -17,7 +17,10 @@ #include #include "base/logging.h" +#include "base/metrics/histogram_macros.h" #include "base/strings/string_util.h" +#include "base/time/tick_clock.h" +#include "base/time/time.h" #include "starboard/common/string.h" namespace cobalt { @@ -27,11 +30,23 @@ namespace media { namespace { -std::string CreateQueryDescription(const char* query_name, +std::string CreateQueryDescription(FormatSupportQueryAction query_action, const std::string& mime_type, const std::string& key_system, SbMediaSupportType support_type, base::TimeDelta query_duration) { + auto get_query_name_str = [](FormatSupportQueryAction query_action) { + switch (query_action) { + case FormatSupportQueryAction::HTML_MEDIA_ELEMENT_CAN_PLAY_TYPE: + return "HTMLMediaElement::canPlayType"; + case FormatSupportQueryAction::MEDIA_SOURCE_IS_TYPE_SUPPORTED: + return "MediaSource::isTypeSupported"; + case FormatSupportQueryAction::UNKNOWN_ACTION: + default: + return "Unknown Action"; + } + }; + auto get_support_type_str = [](SbMediaSupportType support_type) { switch (support_type) { case kSbMediaSupportTypeNotSupported: @@ -47,7 +62,8 @@ std::string CreateQueryDescription(const char* query_name, }; return starboard::FormatString( - "%s(%s%s%s, %" PRId64 " us", query_name, mime_type.c_str(), + "%s(%s%s%s, %" PRId64 " us", get_query_name_str(query_action), + mime_type.c_str(), (key_system.empty() ? ")" : ", " + key_system + ")").c_str(), get_support_type_str(support_type), query_duration.InMicroseconds()); } @@ -65,18 +81,49 @@ base::TimeDelta FormatSupportQueryMetrics::total_query_duration_ = base::TimeDelta(); int FormatSupportQueryMetrics::total_num_queries_ = 0; -FormatSupportQueryMetrics::FormatSupportQueryMetrics() { - start_time_ = base::Time::Now(); +#endif // !defined(COBALT_BUILD_TYPE_GOLD) + +FormatSupportQueryMetrics::FormatSupportQueryMetrics( + const base::TickClock* clock) + : clock_(clock) { + start_time_ = clock->NowTicks(); +} + +void FormatSupportQueryMetrics::RecordQueryLatencyUMA( + FormatSupportQueryAction query_action, base::TimeDelta action_duration) { + switch (query_action) { + case FormatSupportQueryAction::MEDIA_SOURCE_IS_TYPE_SUPPORTED: { + UMA_HISTOGRAM_CUSTOM_MICROSECONDS_TIMES( + "Cobalt.Media.MediaSource.IsTypeSupported.Timing", action_duration, + base::TimeDelta::FromMicroseconds(1), + base::TimeDelta::FromMilliseconds(5), 50); + break; + } + case FormatSupportQueryAction::HTML_MEDIA_ELEMENT_CAN_PLAY_TYPE: { + UMA_HISTOGRAM_CUSTOM_MICROSECONDS_TIMES( + "Cobalt.Media.HTMLMediaElement.CanPlayType.Timing", action_duration, + base::TimeDelta::FromMicroseconds(1), + base::TimeDelta::FromMilliseconds(5), 50); + break; + } + case FormatSupportQueryAction::UNKNOWN_ACTION: + default: + break; + } } void FormatSupportQueryMetrics::RecordAndLogQuery( - const char* query_name, const std::string& mime_type, + FormatSupportQueryAction query_action, const std::string& mime_type, const std::string& key_system, SbMediaSupportType support_type) { - base::TimeDelta query_duration = base::Time::Now() - start_time_; + base::TimeDelta query_duration = clock_->NowTicks() - start_time_; + + RecordQueryLatencyUMA(query_action, query_duration); + +#if !defined(COBALT_BUILD_TYPE_GOLD) total_query_duration_ += query_duration; std::string query_description = CreateQueryDescription( - query_name, mime_type, key_system, support_type, query_duration); + query_action, mime_type, key_system, support_type, query_duration); LOG(INFO) << query_description; if (total_num_queries_ < SB_ARRAY_SIZE_INT(cached_query_durations_)) { @@ -90,10 +137,12 @@ void FormatSupportQueryMetrics::RecordAndLogQuery( } ++total_num_queries_; +#endif // !defined(COBALT_BUILD_TYPE_GOLD) } // static void FormatSupportQueryMetrics::PrintAndResetMetrics() { +#if !defined(COBALT_BUILD_TYPE_GOLD) if (total_num_queries_ == 0) { LOG(INFO) << "Format support query metrics:\n\tNumber of queries: 0"; return; @@ -122,9 +171,9 @@ void FormatSupportQueryMetrics::PrintAndResetMetrics() { max_query_duration_ = {}; total_query_duration_ = {}; total_num_queries_ = {}; +#endif // !defined(COBALT_BUILD_TYPE_GOLD) } -#endif // !defined(COBALT_BUILD_TYPE_GOLD) } // namespace media } // namespace cobalt diff --git a/cobalt/media/base/format_support_query_metrics.h b/cobalt/media/base/format_support_query_metrics.h index c601ba005b30..c70f6801cd8e 100644 --- a/cobalt/media/base/format_support_query_metrics.h +++ b/cobalt/media/base/format_support_query_metrics.h @@ -17,38 +17,37 @@ #include +#include "base/time/default_tick_clock.h" +#include "base/time/tick_clock.h" #include "base/time/time.h" #include "starboard/media.h" namespace cobalt { namespace media { -#if defined(COBALT_BUILD_TYPE_GOLD) - -class FormatSupportQueryMetrics { - public: - FormatSupportQueryMetrics() = default; - ~FormatSupportQueryMetrics() = default; - - void RecordAndLogQuery(const char* query_name, const std::string& mime_type, - const std::string& key_system, - SbMediaSupportType support_type) {} - static void PrintAndResetMetrics() {} +enum class FormatSupportQueryAction : uint8_t { + UNKNOWN_ACTION, + HTML_MEDIA_ELEMENT_CAN_PLAY_TYPE, + MEDIA_SOURCE_IS_TYPE_SUPPORTED, }; -#else // defined(COBALT_BUILD_TYPE_GOLD) - class FormatSupportQueryMetrics { public: - FormatSupportQueryMetrics(); + FormatSupportQueryMetrics( + const base::TickClock* clock = base::DefaultTickClock::GetInstance()); ~FormatSupportQueryMetrics() = default; - void RecordAndLogQuery(const char* query_name, const std::string& mime_type, + void RecordAndLogQuery(FormatSupportQueryAction query_action, + const std::string& mime_type, const std::string& key_system, SbMediaSupportType support_type); static void PrintAndResetMetrics(); private: + void RecordQueryLatencyUMA(FormatSupportQueryAction query_action, + base::TimeDelta action_duration); + +#if !defined(COBALT_BUILD_TYPE_GOLD) static constexpr int kMaxCachedQueryDurations = 150; static constexpr int kMaxQueryDescriptionLength = 350; @@ -57,11 +56,12 @@ class FormatSupportQueryMetrics { static base::TimeDelta max_query_duration_; static base::TimeDelta total_query_duration_; static int total_num_queries_; +#endif // !defined(COBALT_BUILD_TYPE_GOLD) - base::Time start_time_{}; + base::TimeTicks start_time_; + const base::TickClock* clock_; }; -#endif // defined(COBALT_BUILD_TYPE_GOLD) } // namespace media } // namespace cobalt diff --git a/cobalt/media/base/format_support_query_metrics_test.cc b/cobalt/media/base/format_support_query_metrics_test.cc new file mode 100644 index 000000000000..cbf26eec8f9e --- /dev/null +++ b/cobalt/media/base/format_support_query_metrics_test.cc @@ -0,0 +1,76 @@ +// Copyright 2024 The Cobalt Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "cobalt/media/base/format_support_query_metrics.h" + +#include + +#include "base/test/metrics/histogram_tester.h" +#include "base/test/simple_test_tick_clock.h" +#include "base/time/tick_clock.h" +#include "base/time/time.h" +#include "starboard/media.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace cobalt { +namespace media { +namespace { + +constexpr char kUmaPrefix[] = "Cobalt.Media."; + +class FormatSupportQueryMetricsTest : public ::testing::Test { + protected: + FormatSupportQueryMetricsTest() : metrics_(&clock_) {} + + void SetUp() override { clock_.SetNowTicks(base::TimeTicks()); } + + base::HistogramTester histogram_tester_; + base::SimpleTestTickClock clock_; + + FormatSupportQueryMetrics metrics_; +}; + +TEST_F(FormatSupportQueryMetricsTest, + ReportsMediaSourceIsTypeSupportedLatencyToUMA) { + clock_.Advance(base::TimeDelta::FromMicroseconds(50)); + + metrics_.RecordAndLogQuery( + FormatSupportQueryAction::MEDIA_SOURCE_IS_TYPE_SUPPORTED, "", "", + kSbMediaSupportTypeNotSupported); + + auto counts = histogram_tester_.GetTotalCountsForPrefix(kUmaPrefix); + EXPECT_EQ(1, counts.size()); + + histogram_tester_.ExpectUniqueSample( + std::string(kUmaPrefix) + "MediaSource.IsTypeSupported.Timing", 50, 1); +} + +TEST_F(FormatSupportQueryMetricsTest, + ReportsHTMLMediaElementCanPlayTypeLatencyToUMA) { + clock_.Advance(base::TimeDelta::FromMicroseconds(50)); + + metrics_.RecordAndLogQuery( + FormatSupportQueryAction::HTML_MEDIA_ELEMENT_CAN_PLAY_TYPE, "", "", + kSbMediaSupportTypeNotSupported); + + auto counts = histogram_tester_.GetTotalCountsForPrefix(kUmaPrefix); + EXPECT_EQ(1, counts.size()); + + histogram_tester_.ExpectUniqueSample( + std::string(kUmaPrefix) + "HTMLMediaElement.CanPlayType.Timing", 50, 1); +} + +} // namespace +} // namespace media +} // namespace cobalt diff --git a/cobalt/media/media_module.cc b/cobalt/media/media_module.cc index 0c426dd64bb6..868603ee2e2c 100644 --- a/cobalt/media/media_module.cc +++ b/cobalt/media/media_module.cc @@ -127,8 +127,9 @@ class CanPlayTypeHandlerStarboard : public CanPlayTypeHandler { } else { support_type = CanPlayType(mime_type, ""); } - metrics.RecordAndLogQuery("HTMLMediaElement::canPlayType", mime_type, "", - support_type); + metrics.RecordAndLogQuery( + FormatSupportQueryAction::HTML_MEDIA_ELEMENT_CAN_PLAY_TYPE, mime_type, + "", support_type); return support_type; } @@ -137,8 +138,9 @@ class CanPlayTypeHandlerStarboard : public CanPlayTypeHandler { const std::string& key_system) const override { media::FormatSupportQueryMetrics metrics; SbMediaSupportType support_type = CanPlayType(mime_type, key_system); - metrics.RecordAndLogQuery("MediaSource::IsTypeSupported", mime_type, - key_system, support_type); + metrics.RecordAndLogQuery( + FormatSupportQueryAction::MEDIA_SOURCE_IS_TYPE_SUPPORTED, mime_type, + key_system, support_type); return support_type; } diff --git a/tools/metrics/histograms/metadata/cobalt/histograms.xml b/tools/metrics/histograms/metadata/cobalt/histograms.xml index 4063965b107d..a9eb60140628 100644 --- a/tools/metrics/histograms/metadata/cobalt/histograms.xml +++ b/tools/metrics/histograms/metadata/cobalt/histograms.xml @@ -67,6 +67,28 @@ Always run the pretty print utility on this file after editing: + + + + async@google.com + cobalt-team@google.com + + Timing data for calls to `HTMLMediaElement.canPlayType`. + + + + + + + async@google.com + cobalt-team@google.com + + Timing data for calls to `MediaSource.isTypeSupported`. + + +