1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121
|
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/exo/frame_timing_history.h"
#include "base/logging.h"
#include "base/metrics/histogram_macros.h"
namespace exo {
namespace {
constexpr size_t kRollingHistorySize = 60u;
constexpr double kFrameTransferDurationEstimationPercentile = 90.0;
// Reports metrics when the number of data points reaches this threshold.
constexpr int32_t kReportMetricsThreshold = 100;
} // namespace
FrameTimingHistory::FrameTimingHistory()
: frame_transfer_duration_history_(kRollingHistorySize) {}
FrameTimingHistory::~FrameTimingHistory() = default;
base::TimeDelta FrameTimingHistory::GetFrameTransferDurationEstimate() const {
return frame_transfer_duration_history_.Percentile(
kFrameTransferDurationEstimationPercentile);
}
void FrameTimingHistory::FrameSubmitted(uint32_t frame_token,
base::TimeTicks submitted_time) {
DCHECK(pending_submitted_time_.find(frame_token) ==
pending_submitted_time_.end());
pending_submitted_time_[frame_token] = submitted_time;
RecordFrameResponseToRemote(/*did_not_produce=*/false);
RecordFrameHandled(/*discarded=*/false);
consecutive_did_not_produce_count_ = 0;
}
void FrameTimingHistory::FrameDidNotProduce() {
RecordFrameResponseToRemote(/*did_not_produce=*/true);
consecutive_did_not_produce_count_++;
}
void FrameTimingHistory::FrameReceivedAtRemoteSide(
uint32_t frame_token,
base::TimeTicks received_time) {
auto iter = pending_submitted_time_.find(frame_token);
DCHECK(iter != pending_submitted_time_.end())
<< "Frame submitted time information is missing. Frame Token: "
<< frame_token;
DCHECK_GE(received_time, iter->second);
frame_transfer_duration_history_.InsertSample(received_time - iter->second);
pending_submitted_time_.erase(iter);
// FrameSubmitted() / FrameReceivedAtRemoteSide() are supposed to match, so
// that the map won't grow indefinitely.
DCHECK_LE(pending_submitted_time_.size(), 60u);
}
void FrameTimingHistory::FrameDiscarded() {
RecordFrameHandled(/*discarded=*/true);
}
void FrameTimingHistory::MayRecordDidNotProduceToFrameArrvial(bool valid) {
if (last_did_not_produce_time_.is_null()) {
return;
}
base::TimeDelta duration =
valid ? (base::TimeTicks::Now() - last_did_not_produce_time_)
: base::TimeDelta();
UMA_HISTOGRAM_CUSTOM_MICROSECONDS_TIMES(
"Graphics.Exo.Smoothness.DidNotProduceToFrameArrival", duration,
base::Microseconds(1), base::Milliseconds(50), 50);
last_did_not_produce_time_ = {};
}
void FrameTimingHistory::RecordFrameResponseToRemote(bool did_not_produce) {
last_did_not_produce_time_ =
did_not_produce ? base::TimeTicks::Now() : base::TimeTicks();
frame_response_count_++;
if (did_not_produce) {
frame_response_did_not_produce_++;
}
if (frame_response_count_ >= kReportMetricsThreshold) {
UMA_HISTOGRAM_PERCENTAGE(
"Graphics.Exo.Smoothness.PercentDidNotProduceFrame",
frame_response_did_not_produce_ * 100 / frame_response_count_);
frame_response_count_ = 0;
frame_response_did_not_produce_ = 0;
}
}
void FrameTimingHistory::RecordFrameHandled(bool discarded) {
frame_handling_count_++;
if (discarded) {
frame_handling_discarded_++;
}
if (frame_handling_count_ >= kReportMetricsThreshold) {
UMA_HISTOGRAM_PERCENTAGE(
"Graphics.Exo.Smoothness.PercentFrameDiscarded",
frame_handling_discarded_ * 100 / frame_handling_count_);
frame_handling_count_ = 0;
frame_handling_discarded_ = 0;
}
}
} // namespace exo
|