Skip to content

Commit

Permalink
Cherry pick PR #2954: Added UMA telemetry for Format Queries (#3053)
Browse files Browse the repository at this point in the history
Refer to the original PR: #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

---------

Co-authored-by: Drew Thomas <[email protected]>
  • Loading branch information
cobalt-github-releaser-bot and at-ninja authored Apr 23, 2024
1 parent 160902e commit d8e8b05
Show file tree
Hide file tree
Showing 6 changed files with 194 additions and 41 deletions.
1 change: 1 addition & 0 deletions cobalt/media/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,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",
"file_data_source_test.cc",
"progressive/demuxer_extension_wrapper_test.cc",
Expand Down
85 changes: 68 additions & 17 deletions cobalt/media/base/format_support_query_metrics.cc
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,10 @@
#include <algorithm>

#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 {
Expand All @@ -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,
SbTimeMonotonic query_duration) {
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:
Expand All @@ -47,34 +62,68 @@ 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);
get_support_type_str(support_type), query_duration.InMicroseconds());
}

} // namespace

// static
SbTimeMonotonic FormatSupportQueryMetrics::cached_query_durations_
base::TimeDelta FormatSupportQueryMetrics::cached_query_durations_
[kMaxCachedQueryDurations] = {};
char FormatSupportQueryMetrics::max_query_description_
[kMaxQueryDescriptionLength] = {};
SbTimeMonotonic FormatSupportQueryMetrics::max_query_duration_ = 0;
SbTimeMonotonic FormatSupportQueryMetrics::total_query_duration_ = 0;
base::TimeDelta FormatSupportQueryMetrics::max_query_duration_ =
base::TimeDelta();
base::TimeDelta FormatSupportQueryMetrics::total_query_duration_ =
base::TimeDelta();
int FormatSupportQueryMetrics::total_num_queries_ = 0;

FormatSupportQueryMetrics::FormatSupportQueryMetrics() {
start_time_ = SbTimeGetMonotonicNow();
#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) {
SbTimeMonotonic query_duration = SbTimeGetMonotonicNow() - 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_)) {
Expand All @@ -88,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;
Expand All @@ -116,13 +167,13 @@ void FormatSupportQueryMetrics::PrintAndResetMetrics() {
<< " us\n\tMedian query time: ~" << get_median()
<< " us\n\tLongest query: " << max_query_description_;

max_query_description_[0] = 0;
max_query_duration_ = 0;
total_query_duration_ = 0;
total_num_queries_ = 0;
max_query_description_[0] = {};
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
41 changes: 21 additions & 20 deletions cobalt/media/base/format_support_query_metrics.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,51 +17,52 @@

#include <string>

#include "base/time/default_tick_clock.h"
#include "base/time/tick_clock.h"
#include "base/time/time.h"
#include "starboard/media.h"
#include "starboard/time.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;

static SbTimeMonotonic cached_query_durations_[kMaxCachedQueryDurations];
static base::TimeDelta cached_query_durations_[kMaxCachedQueryDurations];
static char max_query_description_[kMaxQueryDescriptionLength];
static SbTimeMonotonic max_query_duration_;
static SbTimeMonotonic total_query_duration_;
static base::TimeDelta max_query_duration_;
static base::TimeDelta total_query_duration_;
static int total_num_queries_;
#endif // !defined(COBALT_BUILD_TYPE_GOLD)

SbTimeMonotonic start_time_ = 0;
base::TimeTicks start_time_;
const base::TickClock* clock_;
};

#endif // defined(COBALT_BUILD_TYPE_GOLD)

} // namespace media
} // namespace cobalt
Expand Down
76 changes: 76 additions & 0 deletions cobalt/media/base/format_support_query_metrics_test.cc
Original file line number Diff line number Diff line change
@@ -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 <memory>

#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
10 changes: 6 additions & 4 deletions cobalt/media/media_module.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand All @@ -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;
}

Expand Down
22 changes: 22 additions & 0 deletions tools/metrics/histograms/metadata/cobalt/histograms.xml
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,28 @@ Always run the pretty print utility on this file after editing:
</summary>
</histogram>

<histogram name="Cobalt.Media.HTMLMediaElement.CanPlayType.Timing"
units="microseconds" expires_after="never">
<!-- expires-never: Needed for long-term tracking of format query latency. -->

<owner>[email protected]</owner>
<owner>[email protected]</owner>
<summary>
Timing data for calls to `HTMLMediaElement.canPlayType`.
</summary>
</histogram>

<histogram name="Cobalt.Media.MediaSource.IsTypeSupported.Timing"
units="microseconds" expires_after="never">
<!-- expires-never: Needed for long-term tracking of format query latency. -->

<owner>[email protected]</owner>
<owner>[email protected]</owner>
<summary>
Timing data for calls to `MediaSource.isTypeSupported`.
</summary>
</histogram>

<histogram name="Cobalt.Media.PipelineStatus.AudioOnly" enum="PipelineStatus"
expires_after="never">
<!-- expires-never: Needed for baseline Media pipeline health metric. -->
Expand Down

0 comments on commit d8e8b05

Please sign in to comment.