blob: 7c9cea097c9bb8753a6f4495da31b33f0e787188 [file] [log] [blame]
// Copyright 2022 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <lib/async/default.h>
#include <lib/media/codec_impl/codec_diagnostics.h>
#include <lib/media/codec_impl/log.h>
#include <lib/vfs/cpp/pseudo_dir.h>
#include <lib/vfs/cpp/service.h>
ComponentCodecDiagnostics::ComponentCodecDiagnostics(CodecDiagnostics& driver_diagnostics,
inspect::Node root)
: driver_diagnostics_(driver_diagnostics),
root_(std::move(root)),
creation_time_(
root_.CreateUint(kCreationTime, static_cast<uint64_t>(zx_clock_get_monotonic()))) {}
ComponentCodecDiagnostics::~ComponentCodecDiagnostics() { driver_diagnostics_.get().RemoveCodec(); }
std::atomic<trace_counter_id_t> DriverCodecDiagnostics::CurrentTraceCounter = 0;
DriverCodecDiagnostics::DriverCodecDiagnostics(CodecDiagnostics& driver_diagnostics,
inspect::Node root)
: driver_diagnostics_(driver_diagnostics),
root_(std::move(root)),
creation_time_(
root_.CreateUint(kCreationTime, static_cast<uint64_t>(zx_clock_get_monotonic()))),
utilizing_hardware_(root_.CreateUint(kCurrentlyUtilizingHardware, 0)),
allocation_(root_.CreateDouble(kAllocation, 0.0)),
total_allocated_time_(root_.CreateUint(kTotalAllocatedTime, 0)) {}
DriverCodecDiagnostics::~DriverCodecDiagnostics() {
// Inform the driver diagnostics that the codec implementation is being destroyed
if (currently_utilizing_hardware_) {
driver_diagnostics_.get().DecrementCurrentlyDecoding();
}
driver_diagnostics_.get().RemoveCodec();
}
// Update the hardware utilization status. This function should be called whenever a variable that
// could effect value of VideoDecoder::IsUtilizingHardware() changes even if the value of
// VideoDecoder::IsUtilizingHardware() has not changed from the previous call to this function. The
// reason is so that this function can take into account the passage of time and update durations
// stored by this class accordingly. This will also effect the allocation which is calculated and
// published by this function.
void DriverCodecDiagnostics::UpdateHardwareUtilizationStatus(zx::time now,
bool is_utilizing_hardware) {
// Get the total time from the last time we checked
zx::duration total_time = now - last_checked_time_;
// If we are allocated then add the time our allocation
if (is_utilizing_hardware) {
total_allocated_time_.Add(total_time.to_nsecs());
}
zx::duration active_time = is_utilizing_hardware ? total_time : zx::nsec(0);
bool coalesced = false;
if (!time_periods_.empty()) {
auto& last_time_period = time_periods_.back();
auto start_time = time_periods_.back().end_time - time_periods_.back().total_time;
if (now - start_time < kBucketDuration) {
coalesced = true;
last_time_period.end_time = now;
last_time_period.total_time += total_time;
last_time_period.active_time += active_time;
}
}
if (!coalesced) {
time_periods_.emplace_back(now, total_time, active_time);
}
while (!time_periods_.empty() && (now - time_periods_.front().end_time > kMemoryDuration)) {
time_periods_.pop_front();
}
zx::duration total_time_accumulate(0);
zx::duration active_time_accumulate(0);
for (const auto& current_period : time_periods_) {
active_time_accumulate += current_period.active_time;
total_time_accumulate += current_period.total_time;
}
double utilization = 0.0;
if (total_time_accumulate != zx::nsec(0)) {
utilization = 100.0 * (static_cast<double>(active_time_accumulate.to_nsecs()) /
static_cast<double>(total_time_accumulate.to_nsecs()));
}
allocation_.Set(utilization);
utilizing_hardware_.Set(is_utilizing_hardware);
TRACE_COUNTER("media", "Decoder Utilization", trace_counter_id_, "utilization", utilization);
// See if there was a change in value of currently_utilizing_hardware_ and if so
// let the DriverDiagnostics class know that our hardware status has changed.
if (!currently_utilizing_hardware_ && is_utilizing_hardware) {
driver_diagnostics_.get().IncrementCurrentlyDecoding();
} else if (currently_utilizing_hardware_ && !is_utilizing_hardware) {
driver_diagnostics_.get().DecrementCurrentlyDecoding();
}
last_checked_time_ = now;
currently_utilizing_hardware_ = is_utilizing_hardware;
}
CodecDiagnostics::CodecDiagnostics(std::string_view driver_name, async_dispatcher_t* dispatcher)
: inspector_(dispatcher, {}),
root_(inspector_.root().CreateChild(driver_name)),
bind_time_(root_.CreateUint(kBindTime, 0)),
num_of_active_codecs_(root_.CreateUint(kNumOfActiveCodecs, 0)),
currently_decoding_(root_.CreateBool(kCurrentlyDecoding, false)) {}
zx::vmo CodecDiagnostics::DuplicateVmo() const { return inspector_.inspector().DuplicateVmo(); }
void CodecDiagnostics::SetBindTime() {
zx_time_t current_time = zx_clock_get_monotonic();
bind_time_.Set(static_cast<int64_t>(current_time));
}
void CodecDiagnostics::IncrementCurrentlyDecoding() {
num_of_currently_decoding_ += 1;
currently_decoding_.Set(true);
}
void CodecDiagnostics::DecrementCurrentlyDecoding() {
if (num_of_currently_decoding_ > 0) {
num_of_currently_decoding_ -= 1;
}
currently_decoding_.Set(num_of_currently_decoding_ != 0);
}
DriverCodecDiagnostics CodecDiagnostics::CreateDriverCodec(std::string_view codec_name) {
const std::string& codec_prefix = std::string(codec_name) + "-";
inspect::Node new_decoder_node = root_.CreateChild(root_.UniqueName(codec_prefix));
num_of_active_codecs_.Add(1);
return DriverCodecDiagnostics(*this, std::move(new_decoder_node));
}
ComponentCodecDiagnostics CodecDiagnostics::CreateComponentCodec(std::string_view codec_name) {
inspect::Node new_decoder_node = root_.CreateChild(codec_name);
num_of_active_codecs_.Add(1);
return ComponentCodecDiagnostics(*this, std::move(new_decoder_node));
}
void CodecDiagnostics::RemoveCodec() { num_of_active_codecs_.Subtract(1); }