-
Notifications
You must be signed in to change notification settings - Fork 121
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[android] Measuring the performance of SbPlayer
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
Showing
15 changed files
with
770 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,189 @@ | ||
// 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/sbplayer_perf.h" | ||
|
||
#include "base/bind.h" | ||
#include "base/logging.h" | ||
#include "cobalt/base/statistics.h" | ||
#include "starboard/extension/player_perf.h" | ||
#include "starboard/once.h" | ||
#include "starboard/player.h" | ||
#include "starboard/system.h" | ||
|
||
namespace cobalt { | ||
namespace media { | ||
|
||
namespace { | ||
|
||
// Sampling every 1 second | ||
const base::TimeDelta sampling_interval = base::Seconds(1); | ||
|
||
// Measuring for 2 minutes | ||
const int64_t kMaxMeasurementSamples = 20; | ||
|
||
class StatisticsWrapper { | ||
public: | ||
static StatisticsWrapper* GetInstance(); | ||
base::Statistics<double, int, 1024> cpu_usage{"Media.CPUUsage"}; | ||
base::Statistics<double, int, 1024> decoded_speed{"Media.decoded_speed"}; | ||
}; | ||
|
||
} // namespace | ||
|
||
SB_ONCE_INITIALIZE_FUNCTION(StatisticsWrapper, StatisticsWrapper::GetInstance); | ||
|
||
void SbPlayerPerf::Start() { | ||
task_runner_->PostTask( | ||
FROM_HERE, base::Bind(&SbPlayerPerf::StartTask, base::Unretained(this))); | ||
} | ||
|
||
void SbPlayerPerf::StartTask() { | ||
DCHECK(task_runner_->BelongsToCurrentThread()); | ||
start_timestamp_ = Time::Now(); | ||
timer_.Start(FROM_HERE, sampling_interval, this, | ||
&SbPlayerPerf::GetPlatformIndependentCPUUsage); | ||
} | ||
|
||
void SbPlayerPerf::Stop() { | ||
task_runner_->PostTask( | ||
FROM_HERE, base::Bind(&SbPlayerPerf::StopTask, base::Unretained(this))); | ||
} | ||
|
||
void SbPlayerPerf::StopTask() { | ||
DCHECK(task_runner_->BelongsToCurrentThread()); | ||
timer_.Stop(); | ||
} | ||
|
||
void SbPlayerPerf::GetPlatformIndependentCPUUsage() { | ||
DCHECK(task_runner_->BelongsToCurrentThread()); | ||
|
||
const StarboardExtensionPlayerPerfApi* player_perf_extension = | ||
static_cast<const StarboardExtensionPlayerPerfApi*>( | ||
SbSystemGetExtension(kStarboardExtensionPlayerPerfName)); | ||
if (player_perf_extension && | ||
strcmp(player_perf_extension->name, kStarboardExtensionPlayerPerfName) == | ||
0 && | ||
player_perf_extension->version >= 1) { | ||
Time timestamp_now = Time::Now(); | ||
base::Percentiles cpu_out_percentiles, decoded_speed_out_percentiles; | ||
double cpu_usage_perf = | ||
player_perf_extension->GetPlatformIndependentCPUUsage(); | ||
#if SB_API_VERSION >= 15 | ||
SbPlayerInfo info; | ||
#else // SB_API_VERSION >= 15 | ||
SbPlayerInfo2 info; | ||
#endif // SB_API_VERSION >= 15 | ||
interface_->GetInfo(player_, &info); | ||
if (cpu_usage_perf == 0.0 && data_count_ == 0 && | ||
decoded_frames_last_ == 0) { | ||
// The first sample is 0, so skip it | ||
decoded_frames_last_ = info.total_video_frames; | ||
timestamp_last_ = timestamp_now; | ||
return; | ||
} | ||
StatisticsWrapper::GetInstance()->cpu_usage.AddSample(cpu_usage_perf, 1); | ||
int decoded_frames = info.total_video_frames - decoded_frames_last_; | ||
TimeDelta interval = timestamp_now - timestamp_last_; | ||
if (decoded_frames > 0 && interval.InSeconds() > 0) { | ||
double decoded_speed = static_cast<double>(decoded_frames) / | ||
static_cast<double>(interval.InSeconds()); | ||
StatisticsWrapper::GetInstance()->decoded_speed.AddSample(decoded_speed, | ||
1); | ||
} | ||
decoded_frames_last_ = info.total_video_frames; | ||
timestamp_last_ = timestamp_now; | ||
|
||
data_count_ += 1; | ||
if (data_count_ == kMaxMeasurementSamples) { | ||
StatisticsWrapper::GetInstance()->cpu_usage.GetPercentiles( | ||
&cpu_out_percentiles); | ||
StatisticsWrapper::GetInstance()->decoded_speed.GetPercentiles( | ||
&decoded_speed_out_percentiles); | ||
double dropped_frame_percentage = | ||
100.0 * static_cast<double>(info.dropped_video_frames) / | ||
static_cast<double>(info.total_video_frames); | ||
TimeDelta duration = Time::Now() - start_timestamp_; | ||
LOG(ERROR) | ||
<< "Brown Brand/model_name: " << sb_system_property_brand_name_ << "_" | ||
<< sb_system_property_model_name_ | ||
<< ", platform_name: " << sb_system_property_platform_name_ | ||
<< ", num_of_processors: " << sb_number_of_processors_ | ||
<< ", duration: " << duration.InSeconds() << "s, audio_codec: " | ||
<< player_perf_extension->GetCurrentMediaAudioCodecName() | ||
<< ", video_codec: " | ||
<< player_perf_extension->GetCurrentMediaVideoCodecName() | ||
<< ", should_be_paused: " | ||
<< player_perf_extension->GetCountShouldBePaused() | ||
<< ", dropped_frames(%): " << dropped_frame_percentage | ||
<< "%, dropped_frames: " << info.dropped_video_frames | ||
<< ", total_frames: " << info.total_video_frames | ||
<< ", audio_underrun_count: " | ||
<< player_perf_extension->GetAudioUnderrunCount() | ||
<< ", playback_rate: " << info.playback_rate | ||
<< ", use_neon: " << player_perf_extension->IsSIMDEnabled() | ||
<< ", force_tunnel_mode: " | ||
<< player_perf_extension->IsForceTunnelMode() | ||
<< ", CPU usage statistics(%): min: " | ||
<< StatisticsWrapper::GetInstance()->cpu_usage.min() | ||
<< "%, 25th_p: " << cpu_out_percentiles.percentile_25th | ||
<< "%, 50th_p: " << cpu_out_percentiles.median | ||
<< "%, 75th_p: " << cpu_out_percentiles.percentile_75th | ||
<< "%, average: " | ||
<< StatisticsWrapper::GetInstance()->cpu_usage.average() | ||
<< "%, max: " << StatisticsWrapper::GetInstance()->cpu_usage.max() | ||
<< "%, decoded_speed (fps): min: " | ||
<< StatisticsWrapper::GetInstance()->decoded_speed.min() | ||
<< ", 25th_p: " << decoded_speed_out_percentiles.percentile_25th | ||
<< ", 50th_p: " << decoded_speed_out_percentiles.median | ||
<< ", 75th_p: " << decoded_speed_out_percentiles.percentile_75th | ||
<< ", average: " | ||
<< StatisticsWrapper::GetInstance()->decoded_speed.average() | ||
<< ", max: " << StatisticsWrapper::GetInstance()->decoded_speed.max(); | ||
} | ||
} | ||
} | ||
|
||
std::string SbPlayerPerf::GetSbSystemProperty(SbSystemPropertyId property_id) { | ||
char property[1024] = {0}; | ||
std::string result = ""; | ||
if (!SbSystemGetProperty(property_id, property, | ||
SB_ARRAY_SIZE_INT(property))) { | ||
DLOG(FATAL) << "Failed to get kSbSystemPropertyPlatformName."; | ||
return result; | ||
} | ||
result = property; | ||
return result; | ||
} | ||
|
||
SbPlayerPerf::SbPlayerPerf( | ||
SbPlayerInterface* interface, SbPlayer player, | ||
const scoped_refptr<base::SingleThreadTaskRunner>& task_runner) | ||
: task_runner_(task_runner), | ||
data_count_(0), | ||
interface_(interface), | ||
player_(player), | ||
decoded_frames_last_(0), | ||
sb_number_of_processors_(SbSystemGetNumberOfProcessors()), | ||
sb_system_property_brand_name_( | ||
GetSbSystemProperty(kSbSystemPropertyBrandName)), | ||
sb_system_property_model_name_( | ||
GetSbSystemProperty(kSbSystemPropertyModelName)), | ||
sb_system_property_platform_name_( | ||
GetSbSystemProperty(kSbSystemPropertyPlatformName)) {} | ||
|
||
SbPlayerPerf::~SbPlayerPerf() {} | ||
|
||
} // namespace media | ||
} // namespace cobalt |
Oops, something went wrong.