Skip to content

Commit

Permalink
[android] Measuring the performance of SbPlayer
Browse files Browse the repository at this point in the history
This CL includes the performance metrics as the following:
1. CPU usage: the percentage of time spent executing across all threads of the process. It could exceed 100% on multi-core systems.
2. Dropped frames: the number of dropped video frames.
3. Audio underrun count: the number of audio buffer to underflow and a potential audio glitch or pop.

b/315159208
  • Loading branch information
borongc committed Apr 15, 2024
1 parent d2ab624 commit 7dd6712
Show file tree
Hide file tree
Showing 18 changed files with 1,069 additions and 5 deletions.
45 changes: 40 additions & 5 deletions cobalt/base/statistics.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,12 @@ inline int64_t DefaultSampleToValueFunc(int64_t dividend, int64_t divisor) {

} // namespace internal

typedef struct Percentiles {
int64_t percentile_25th;
int64_t median;
int64_t percentile_75th;
} Percentiles;

// Track the statistics of a series of generic samples reprensented as
// dividends and divisors in integer types. The value of a sample is calculated
// by `SampleToValueFunc` using its dividend and divisor.
Expand Down Expand Up @@ -78,6 +84,8 @@ class Statistics {
int64_t max() const { return 0; }

int64_t GetMedian() const { return 0; }
void GetPercentiles(Percentiles* out_percentiles) {}
size_t GetNumberOfSamples() { return 0; }
};

#else // defined(COBALT_BUILD_TYPE_GOLD)
Expand Down Expand Up @@ -151,14 +159,33 @@ class Statistics {
samples_to_copy -= MaxSamples - first_sample_index_;
copy.insert(copy.end(), samples_, samples_ + samples_to_copy);
}
return GetNthPercentile(copy, number_of_samples_ / 2);
}

std::nth_element(copy.begin(), copy.begin() + number_of_samples_ / 2,
copy.end(), [](const Sample& left, const Sample& right) {
return GetSampleValue(left) < GetSampleValue(right);
});
return GetSampleValue(copy[number_of_samples_ / 2]);
void GetPercentiles(Percentiles* out_percentiles) {
if (number_of_samples_ == 0) {
return;
}
std::vector<Sample> copy;
copy.reserve(number_of_samples_);
if (first_sample_index_ + number_of_samples_ <= MaxSamples) {
copy.assign(samples_ + first_sample_index_,
samples_ + first_sample_index_ + number_of_samples_);
} else {
auto samples_to_copy = number_of_samples_;
copy.assign(samples_ + first_sample_index_, samples_ + MaxSamples);
samples_to_copy -= MaxSamples - first_sample_index_;
copy.insert(copy.end(), samples_, samples_ + samples_to_copy);
}
out_percentiles->percentile_25th =
GetNthPercentile(copy, number_of_samples_ / 4);
out_percentiles->median = GetNthPercentile(copy, number_of_samples_ / 2);
out_percentiles->percentile_75th =
GetNthPercentile(copy, number_of_samples_ * 3 / 4);
}

size_t GetNumberOfSamples() { return number_of_samples_; }

private:
Statistics(const Statistics&) = delete;
Statistics& operator=(const Statistics&) = delete;
Expand All @@ -173,6 +200,14 @@ class Statistics {
static_cast<int64_t>(sample.divisor));
}

static int GetNthPercentile(std::vector<Sample>& copy, int place) {
std::nth_element(copy.begin(), copy.begin() + place, copy.end(),
[](const Sample& left, const Sample& right) {
return GetSampleValue(left) < GetSampleValue(right);
});
return GetSampleValue(copy[place]);
}

bool first_sample_added_ = false;

int64_t accumulated_dividend_ = 0;
Expand Down
2 changes: 2 additions & 0 deletions cobalt/media/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ component("media") {
"base/sbplayer_bridge.h",
"base/sbplayer_interface.cc",
"base/sbplayer_interface.h",
"base/sbplayer_perf.cc",
"base/sbplayer_perf.h",
"base/sbplayer_pipeline.cc",
"base/sbplayer_pipeline.h",
"base/sbplayer_set_bounds_helper.cc",
Expand Down
45 changes: 45 additions & 0 deletions cobalt/media/base/sbplayer_bridge.cc
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#include "starboard/common/player.h"
#include "starboard/common/string.h"
#include "starboard/configuration.h"
#include "starboard/extension/player_perf.h"
#include "starboard/extension/player_set_max_video_input_size.h"
#include "starboard/memory.h"
#include "starboard/once.h"
Expand All @@ -45,6 +46,12 @@ using base::TimeDelta;
using starboard::FormatString;
using starboard::GetPlayerOutputModeName;

#if !defined(COBALT_BUILD_TYPE_GOLD)
constexpr bool kForceCPUUtilizationMeasure = true;
#else
constexpr bool kForceCPUUtilizationMeasure = false;
#endif // !defined(COBALT_BUILD_TYPE_GOLD)

class StatisticsWrapper {
public:
static StatisticsWrapper* GetInstance();
Expand Down Expand Up @@ -251,6 +258,7 @@ SbPlayerBridge::SbPlayerBridge(
decode_target_provider_(decode_target_provider),
max_video_capabilities_(max_video_capabilities),
max_video_input_size_(max_video_input_size),
perf_thread_("sbplayer_perf"),
cval_stats_(&interface->cval_stats_),
pipeline_identifier_(pipeline_identifier)
#if SB_HAS(PLAYER_WITH_URL)
Expand All @@ -274,6 +282,19 @@ SbPlayerBridge::SbPlayerBridge(
UpdateVideoConfig(video_config, video_mime_type);
}

const StarboardExtensionPlayerPerfApi* player_perf_extension =
static_cast<const StarboardExtensionPlayerPerfApi*>(
SbSystemGetExtension(kStarboardExtensionPlayerPerfName));
if (kForceCPUUtilizationMeasure && player_perf_extension &&
strcmp(player_perf_extension->name, kStarboardExtensionPlayerPerfName) ==
0 &&
player_perf_extension->version >= 1) {
perf_thread_.Start();
player_perf_extension->AddThreadID(
perf_thread_.thread_name().c_str(),
static_cast<int32_t>(perf_thread_.GetThreadId()));
}

output_mode_ = ComputeSbPlayerOutputMode(default_output_mode);

CreatePlayer();
Expand All @@ -289,6 +310,19 @@ SbPlayerBridge::SbPlayerBridge(
SbPlayerBridge::~SbPlayerBridge() {
DCHECK(task_runner_->BelongsToCurrentThread());

const StarboardExtensionPlayerPerfApi* player_perf_extension =
static_cast<const StarboardExtensionPlayerPerfApi*>(
SbSystemGetExtension(kStarboardExtensionPlayerPerfName));
if (kForceCPUUtilizationMeasure && player_perf_extension &&
strcmp(player_perf_extension->name, kStarboardExtensionPlayerPerfName) ==
0 &&
player_perf_extension->version >= 1) {
if (sbplayer_perf_) {
sbplayer_perf_->Stop();
}
perf_thread_.Stop();
}

callback_helper_->ResetPlayer();
set_bounds_helper_->SetPlayerBridge(NULL);

Expand Down Expand Up @@ -795,6 +829,17 @@ void SbPlayerBridge::CreatePlayer() {
&SbPlayerBridge::DecoderStatusCB, &SbPlayerBridge::PlayerStatusCB,
&SbPlayerBridge::PlayerErrorCB, this,
get_decode_target_graphics_context_provider_func_.Run());
const StarboardExtensionPlayerPerfApi* player_perf_extension =
static_cast<const StarboardExtensionPlayerPerfApi*>(
SbSystemGetExtension(kStarboardExtensionPlayerPerfName));
if (kForceCPUUtilizationMeasure && player_perf_extension &&
strcmp(player_perf_extension->name, kStarboardExtensionPlayerPerfName) ==
0 &&
player_perf_extension->version >= 1) {
sbplayer_perf_ = new SbPlayerPerf(sbplayer_interface_, player_,
perf_thread_.task_runner());
sbplayer_perf_->Start();
}
cval_stats_->StopTimer(MediaTiming::SbPlayerCreate, pipeline_identifier_);

is_creating_player_ = false;
Expand Down
4 changes: 4 additions & 0 deletions cobalt/media/base/sbplayer_bridge.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include "cobalt/media/base/decode_target_provider.h"
#include "cobalt/media/base/decoder_buffer_cache.h"
#include "cobalt/media/base/sbplayer_interface.h"
#include "cobalt/media/base/sbplayer_perf.h"
#include "cobalt/media/base/sbplayer_set_bounds_helper.h"
#include "media/base/audio_decoder_config.h"
#include "media/base/decoder_buffer.h"
Expand Down Expand Up @@ -325,6 +326,9 @@ class SbPlayerBridge {
bool pending_audio_eos_buffer_ = false;
bool pending_video_eos_buffer_ = false;

base::Thread perf_thread_;
SbPlayerPerf* sbplayer_perf_;

CValStats* cval_stats_;
std::string pipeline_identifier_;
};
Expand Down
Loading

0 comments on commit 7dd6712

Please sign in to comment.