Add a new experimental version of scroll jank metrics
This CL adds the following new histograms: Event.ScrollJank.DelayedFramesPercentage.FixedWindow3 Event.ScrollJank.DelayedFramesPercentage.PerScroll3 Event.ScrollJank.MissedVsyncsPercentage.FixedWindow3 Event.ScrollJank.MissedVsyncsPercentage.PerScroll3 Event.ScrollJank.MissedVsyncsSum.FixedWindow3 Event.ScrollJank.MissedVsyncsSum.PerScroll3 The above new metrics aim to address the following old metrics' shortcomings and eventually replace them: Event.ScrollJank.DelayedFramesPercentage.FixedWindow Event.ScrollJank.DelayedFramesPercentage.PerScroll Event.ScrollJank.MissedVsyncsPercentage.FixedWindow Event.ScrollJank.MissedVsyncsPercentage.PerScroll Event.ScrollJank.MissedVsyncsSum.FixedWindow(2) Event.ScrollJank.MissedVsyncsSum.PerScroll The metrics currently only differ in that the new metrics correctly calculate the earliest scroll update that was coalesced into a presented scroll update (so they might report slightly higher values than the old metrics). They will diverge more in the future as we address other shortcomings in follow-up CLs. Bug: 402148798 Change-Id: I4d9a0b55278a0b09103edfe24611df327fc4aca0 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6357111 Reviewed-by: Kartar Singh <kartarsingh@google.com> Reviewed-by: Jonathan Ross <jonross@chromium.org> Auto-Submit: Petr Cermak <petrcermak@chromium.org> Commit-Queue: Petr Cermak <petrcermak@chromium.org> Cr-Commit-Position: refs/heads/main@{#1434064}
This commit is contained in:

committed by
Chromium LUCI CQ

parent
74b35d7c08
commit
7bad5feaff
@ -1647,9 +1647,11 @@ void CompositorFrameReporter::ReportScrollJankMetrics() const {
|
||||
// This handles cases when we have multiple scroll events. Events for dropped
|
||||
// frames are reported by the reporter for next presented frame which could
|
||||
// lead to having multiple scroll events.
|
||||
// TODO(crbug.com/402148798): Calculate and use earliest_event instead of
|
||||
// latest_event.
|
||||
// TODO(crbug.com/402148798): Deprecate usage of latest_event.
|
||||
ScrollUpdateEventMetrics* earliest_event = nullptr;
|
||||
base::TimeTicks earliest_event_generation_ts = base::TimeTicks::Max();
|
||||
ScrollUpdateEventMetrics* latest_event = nullptr;
|
||||
base::TimeTicks latest_event_generation_ts = base::TimeTicks::Min();
|
||||
base::TimeTicks last_coalesced_ts = base::TimeTicks::Min();
|
||||
for (auto& event : events_metrics_) {
|
||||
TRACE_EVENT("input", "GestureType", "gesture", event->type());
|
||||
@ -1659,20 +1661,26 @@ void CompositorFrameReporter::ReportScrollJankMetrics() const {
|
||||
}
|
||||
|
||||
total_predicted_delta += scroll_update->predicted_delta();
|
||||
base::TimeTicks generation_ts = scroll_update->GetDispatchStageTimestamp(
|
||||
EventMetrics::DispatchStage::kGenerated);
|
||||
if (!had_gesture_scrolls) {
|
||||
earliest_event = scroll_update;
|
||||
earliest_event_generation_ts = generation_ts;
|
||||
latest_event = scroll_update;
|
||||
latest_event_generation_ts = generation_ts;
|
||||
}
|
||||
had_gesture_scrolls = true;
|
||||
if (latest_event->GetDispatchStageTimestamp(
|
||||
EventMetrics::DispatchStage::kGenerated) <
|
||||
event->GetDispatchStageTimestamp(
|
||||
EventMetrics::DispatchStage::kGenerated)) {
|
||||
if (generation_ts < earliest_event_generation_ts) {
|
||||
earliest_event = scroll_update;
|
||||
earliest_event_generation_ts = generation_ts;
|
||||
} else if (generation_ts > latest_event_generation_ts) {
|
||||
latest_event = scroll_update;
|
||||
latest_event_generation_ts = generation_ts;
|
||||
}
|
||||
last_coalesced_ts =
|
||||
std::max(last_coalesced_ts, scroll_update->last_timestamp());
|
||||
|
||||
switch (event->type()) {
|
||||
switch (scroll_update->type()) {
|
||||
case EventMetrics::EventType::kFirstGestureScrollUpdate:
|
||||
is_scroll_start = true;
|
||||
[[fallthrough]];
|
||||
@ -1719,8 +1727,9 @@ void CompositorFrameReporter::ReportScrollJankMetrics() const {
|
||||
}
|
||||
if (global_trackers_.scroll_jank_dropped_frame_tracker) {
|
||||
global_trackers_.scroll_jank_dropped_frame_tracker
|
||||
->ReportLatestPresentationData(*latest_event, last_coalesced_ts,
|
||||
end_timestamp, args_.interval);
|
||||
->ReportLatestPresentationData(*earliest_event, *latest_event,
|
||||
last_coalesced_ts, end_timestamp,
|
||||
args_.interval);
|
||||
}
|
||||
if (global_trackers_.scroll_jank_ukm_reporter) {
|
||||
global_trackers_.scroll_jank_ukm_reporter
|
||||
|
@ -2715,6 +2715,90 @@ TEST_F(CompositorFrameReportingControllerTest, JankyScrolledFrameArg) {
|
||||
std::vector<std::string>{"1"}));
|
||||
}
|
||||
|
||||
/*
|
||||
Test if the new v3 metric logic identifies scroll jank in a scenario where a
|
||||
frame is dropped.
|
||||
vsync v1 v2 v3
|
||||
| | | | |
|
||||
input GSU1 GSU2 GSU3
|
||||
| | |
|
||||
F1: |---------------|
|
||||
F2: |---------------x (throttled)
|
||||
F3: |--------------|
|
||||
The new v3 metric should identify scroll jank because F2 got dropped even though
|
||||
there was consistent input for a frame to have been generated.
|
||||
*/
|
||||
TEST_F(CompositorFrameReportingControllerTest, JankyThrottledScrolledFrameArg) {
|
||||
base::test::TestTraceProcessor ttp;
|
||||
ttp.StartTrace("input");
|
||||
|
||||
std::unique_ptr<EventMetrics> metrics_1 = CreateScrollUpdateEventMetrics(
|
||||
ui::ScrollInputType::kWheel, /*is_inertial=*/false,
|
||||
ScrollUpdateEventMetrics::ScrollUpdateType::kStarted, std::nullopt);
|
||||
base::TimeTicks event1_generation_ts = metrics_1->GetDispatchStageTimestamp(
|
||||
EventMetrics::DispatchStage::kGenerated);
|
||||
|
||||
std::unique_ptr<EventMetrics> metrics_2 = CreateScrollUpdateEventMetrics(
|
||||
ui::ScrollInputType::kWheel, /*is_inertial=*/false,
|
||||
ScrollUpdateEventMetrics::ScrollUpdateType::kContinued, std::nullopt);
|
||||
base::TimeTicks event2_generation_ts = metrics_2->GetDispatchStageTimestamp(
|
||||
EventMetrics::DispatchStage::kGenerated);
|
||||
|
||||
std::unique_ptr<EventMetrics> metrics_3 = CreateScrollUpdateEventMetrics(
|
||||
ui::ScrollInputType::kWheel, /*is_inertial=*/false,
|
||||
ScrollUpdateEventMetrics::ScrollUpdateType::kContinued, std::nullopt);
|
||||
base::TimeTicks event3_generation_ts = metrics_3->GetDispatchStageTimestamp(
|
||||
EventMetrics::DispatchStage::kGenerated);
|
||||
|
||||
base::TimeDelta vsync_interval = event2_generation_ts - event1_generation_ts;
|
||||
args_.interval = vsync_interval;
|
||||
|
||||
SimulateBeginImplFrame(); // BF1
|
||||
reporting_controller_.OnFinishImplFrame(current_id_);
|
||||
EventMetrics::List metrics_list_1;
|
||||
metrics_list_1.push_back(std::move(metrics_1));
|
||||
SimulateSubmitCompositorFrame({{}, std::move(metrics_list_1)});
|
||||
|
||||
viz::FrameTimingDetails details_1 = {};
|
||||
details_1.presentation_feedback.timestamp =
|
||||
event1_generation_ts + base::Microseconds(200);
|
||||
reporting_controller_.DidPresentCompositorFrame(*current_token_,
|
||||
details_1); // PF1
|
||||
|
||||
SimulateBeginImplFrame(); // BF2
|
||||
reporting_controller_.OnFinishImplFrame(current_id_);
|
||||
AdvanceNowByMs(10);
|
||||
reporting_controller_.DidNotProduceFrame(current_id_,
|
||||
FrameSkippedReason::kDrawThrottled);
|
||||
|
||||
SimulateBeginImplFrame(); // BF3
|
||||
reporting_controller_.OnFinishImplFrame(current_id_);
|
||||
EventMetrics::List metrics_list_3;
|
||||
metrics_list_3.push_back(std::move(metrics_2));
|
||||
metrics_list_3.push_back(std::move(metrics_3));
|
||||
SimulateSubmitCompositorFrame({{}, std::move(metrics_list_3)});
|
||||
|
||||
viz::FrameTimingDetails details_3 = {};
|
||||
details_3.presentation_feedback.timestamp =
|
||||
event3_generation_ts + base::Microseconds(200);
|
||||
reporting_controller_.DidPresentCompositorFrame(*current_token_,
|
||||
details_3); // PF3
|
||||
|
||||
absl::Status status = ttp.StopAndParseTrace();
|
||||
ASSERT_TRUE(status.ok()) << status.message();
|
||||
constexpr char query[] =
|
||||
R"(
|
||||
SELECT COUNT(*) AS cnt
|
||||
FROM slice
|
||||
WHERE name = 'MissedFrame v3'
|
||||
)";
|
||||
auto result = ttp.RunQuery(query);
|
||||
ASSERT_TRUE(result.has_value()) << result.error();
|
||||
EXPECT_THAT(result.value(),
|
||||
::testing::ElementsAre(std::vector<std::string>{"cnt"},
|
||||
std::vector<std::string>{"1"}));
|
||||
}
|
||||
|
||||
// A simple test that ensures the vsync_interval is copied onto the
|
||||
// EventLatency.
|
||||
TEST_F(CompositorFrameReportingControllerTest, VsyncIntervalArg) {
|
||||
|
@ -6,6 +6,7 @@
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "base/check_op.h"
|
||||
#include "base/metrics/histogram_functions.h"
|
||||
#include "base/metrics/histogram_macros.h"
|
||||
#include "base/notreached.h"
|
||||
@ -86,6 +87,8 @@ ScrollJankDroppedFrameTracker::ScrollJankDroppedFrameTracker() {
|
||||
// it to -1 essentially ignores first frame.
|
||||
fixed_window_.num_presented_frames = -1;
|
||||
experimental_vsync_fixed_window_.num_past_vsyncs = -1;
|
||||
fixed_window_v3_.num_presented_frames = -1;
|
||||
fixed_window_v3_.num_past_vsyncs = -1;
|
||||
}
|
||||
|
||||
ScrollJankDroppedFrameTracker::~ScrollJankDroppedFrameTracker() {
|
||||
@ -95,6 +98,7 @@ ScrollJankDroppedFrameTracker::~ScrollJankDroppedFrameTracker() {
|
||||
// scroll.
|
||||
EmitPerScrollHistogramsAndResetCounters();
|
||||
EmitPerScrollVsyncHistogramsAndResetCounters();
|
||||
EmitPerScrollV3HistogramsAndResetCounters();
|
||||
}
|
||||
}
|
||||
|
||||
@ -140,6 +144,30 @@ void ScrollJankDroppedFrameTracker::EmitPerScrollHistogramsAndResetCounters() {
|
||||
per_scroll_->max_missed_vsyncs = 0;
|
||||
}
|
||||
|
||||
void ScrollJankDroppedFrameTracker::
|
||||
EmitPerScrollV3HistogramsAndResetCounters() {
|
||||
// There should be at least one presented frame given the method is only
|
||||
// called after we have a successful presentation.
|
||||
if (per_scroll_v3_->num_presented_frames == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
UMA_HISTOGRAM_PERCENTAGE(kDelayedFramesPerScrollV3Histogram,
|
||||
(100 * per_scroll_v3_->missed_frames) /
|
||||
per_scroll_v3_->num_presented_frames);
|
||||
UMA_HISTOGRAM_CUSTOM_COUNTS(kMissedVsyncsSumPerScrollV3Histogram,
|
||||
per_scroll_v3_->missed_vsyncs, kVsyncCountsMin,
|
||||
kVsyncCountsMax, kVsyncCountsBuckets);
|
||||
UMA_HISTOGRAM_PERCENTAGE(
|
||||
kMissedVsyncsPerScrollV3Histogram,
|
||||
(100 * per_scroll_v3_->missed_vsyncs) / per_scroll_v3_->num_past_vsyncs);
|
||||
|
||||
per_scroll_v3_->missed_frames = 0;
|
||||
per_scroll_v3_->missed_vsyncs = 0;
|
||||
per_scroll_v3_->num_presented_frames = 0;
|
||||
per_scroll_v3_->num_past_vsyncs = 0;
|
||||
}
|
||||
|
||||
void ScrollJankDroppedFrameTracker::
|
||||
EmitPerScrollVsyncHistogramsAndResetCounters() {
|
||||
// There should be at least one presented frame given the method is only
|
||||
@ -187,6 +215,28 @@ void ScrollJankDroppedFrameTracker::EmitPerWindowHistogramsAndResetCounters() {
|
||||
fixed_window_.num_presented_frames = 0;
|
||||
}
|
||||
|
||||
void ScrollJankDroppedFrameTracker::
|
||||
EmitPerWindowV3HistogramsAndResetCounters() {
|
||||
DCHECK_EQ(fixed_window_v3_.num_presented_frames, kHistogramEmitFrequency);
|
||||
|
||||
UMA_HISTOGRAM_PERCENTAGE(
|
||||
kDelayedFramesWindowV3Histogram,
|
||||
(100 * fixed_window_v3_.missed_frames) / kHistogramEmitFrequency);
|
||||
UMA_HISTOGRAM_CUSTOM_COUNTS(kMissedVsyncsSumInWindowV3Histogram,
|
||||
fixed_window_v3_.missed_vsyncs, kVsyncCountsMin,
|
||||
kVsyncCountsMax, kVsyncCountsBuckets);
|
||||
UMA_HISTOGRAM_PERCENTAGE(kMissedVsyncsWindowV3Histogram,
|
||||
(100 * fixed_window_v3_.missed_vsyncs) /
|
||||
fixed_window_v3_.num_past_vsyncs);
|
||||
|
||||
fixed_window_v3_.missed_frames = 0;
|
||||
fixed_window_v3_.missed_vsyncs = 0;
|
||||
// We don't need to reset these to -1 because after the first window we always
|
||||
// have a valid previous frame data to compare the first frame of window.
|
||||
fixed_window_v3_.num_presented_frames = 0;
|
||||
fixed_window_v3_.num_past_vsyncs = 0;
|
||||
}
|
||||
|
||||
// TODO(b/306611560): Cleanup experimental per vsync metric or promote to
|
||||
// default.
|
||||
void ScrollJankDroppedFrameTracker::
|
||||
@ -212,6 +262,7 @@ void ScrollJankDroppedFrameTracker::
|
||||
}
|
||||
|
||||
void ScrollJankDroppedFrameTracker::ReportLatestPresentationData(
|
||||
ScrollUpdateEventMetrics& earliest_event,
|
||||
ScrollUpdateEventMetrics& latest_event,
|
||||
base::TimeTicks last_input_generation_ts,
|
||||
base::TimeTicks presentation_ts,
|
||||
@ -219,6 +270,10 @@ void ScrollJankDroppedFrameTracker::ReportLatestPresentationData(
|
||||
base::TimeTicks first_input_generation_ts =
|
||||
latest_event.GetDispatchStageTimestamp(
|
||||
EventMetrics::DispatchStage::kGenerated);
|
||||
base::TimeTicks first_input_generation_v3_ts =
|
||||
earliest_event.GetDispatchStageTimestamp(
|
||||
EventMetrics::DispatchStage::kGenerated);
|
||||
CHECK_LE(first_input_generation_v3_ts, first_input_generation_ts);
|
||||
if ((last_input_generation_ts < first_input_generation_ts) ||
|
||||
(presentation_ts <= last_input_generation_ts)) {
|
||||
// TODO(crbug.com/40913586): Investigate when these edge cases can be
|
||||
@ -339,17 +394,81 @@ void ScrollJankDroppedFrameTracker::ReportLatestPresentationData(
|
||||
}
|
||||
DCHECK_LT(fixed_window_.num_presented_frames, kHistogramEmitFrequency);
|
||||
|
||||
ReportLatestPresentationDataV3(first_input_generation_v3_ts, presentation_ts,
|
||||
vsync_interval);
|
||||
|
||||
prev_presentation_ts_ = presentation_ts;
|
||||
prev_last_input_generation_ts_ = last_input_generation_ts;
|
||||
}
|
||||
|
||||
void ScrollJankDroppedFrameTracker::ReportLatestPresentationDataV3(
|
||||
base::TimeTicks first_input_generation_v3_ts,
|
||||
base::TimeTicks presentation_ts,
|
||||
base::TimeDelta vsync_interval) {
|
||||
if (!per_scroll_v3_.has_value()) {
|
||||
per_scroll_v3_ = JankDataV3();
|
||||
}
|
||||
|
||||
// The presentation delta is usually 16.6ms for 60 Hz devices,
|
||||
// but sometimes random errors result in a delta of up to 20ms
|
||||
// as observed in traces. This adds an error margin of 1/2 a
|
||||
// vsync before considering the Vsync missed.
|
||||
bool missed_frame = (presentation_ts - prev_presentation_ts_) >
|
||||
(vsync_interval + vsync_interval / 2);
|
||||
bool input_available =
|
||||
(first_input_generation_v3_ts - prev_last_input_generation_ts_) <
|
||||
(vsync_interval + vsync_interval / 2);
|
||||
|
||||
// Sometimes the vsync interval is not accurate and is slightly more
|
||||
// than the actual signal arrival time, adding (vsync_interval / 2)
|
||||
// here insures the result is always ceiled.
|
||||
int curr_frame_total_vsyncs =
|
||||
(presentation_ts - prev_presentation_ts_ + (vsync_interval / 2)) /
|
||||
vsync_interval;
|
||||
int curr_frame_missed_vsyncs = curr_frame_total_vsyncs - 1;
|
||||
|
||||
if (missed_frame && input_available) {
|
||||
++per_scroll_v3_->missed_frames;
|
||||
++fixed_window_v3_.missed_frames;
|
||||
fixed_window_v3_.missed_vsyncs += curr_frame_missed_vsyncs;
|
||||
per_scroll_v3_->missed_vsyncs += curr_frame_missed_vsyncs;
|
||||
|
||||
TRACE_EVENT_INSTANT(
|
||||
"input,input.scrolling", "MissedFrame v3",
|
||||
"per_scroll_v3_->missed_frames", per_scroll_v3_->missed_frames,
|
||||
"per_scroll_v3_->missed_vsyncs", per_scroll_v3_->missed_vsyncs,
|
||||
"vsync_interval", vsync_interval);
|
||||
}
|
||||
|
||||
++fixed_window_v3_.num_presented_frames;
|
||||
++per_scroll_v3_->num_presented_frames;
|
||||
if (fixed_window_v3_.num_past_vsyncs < 0) {
|
||||
// Ignore the VSyncs in the first frame since it's always deemed non-janky.
|
||||
fixed_window_v3_.num_past_vsyncs = 0;
|
||||
// Ignore curr_frame_total_vsyncs in the first frame since it can be
|
||||
// arbitrarily large due to prev_presentation_ts_ being effectively
|
||||
// uninitialized.
|
||||
per_scroll_v3_->num_past_vsyncs = 1;
|
||||
} else {
|
||||
fixed_window_v3_.num_past_vsyncs += curr_frame_total_vsyncs;
|
||||
per_scroll_v3_->num_past_vsyncs += curr_frame_total_vsyncs;
|
||||
}
|
||||
|
||||
if (fixed_window_v3_.num_presented_frames == kHistogramEmitFrequency) {
|
||||
EmitPerWindowV3HistogramsAndResetCounters();
|
||||
}
|
||||
DCHECK_LT(fixed_window_v3_.num_presented_frames, kHistogramEmitFrequency);
|
||||
}
|
||||
|
||||
void ScrollJankDroppedFrameTracker::OnScrollStarted() {
|
||||
if (per_scroll_.has_value()) {
|
||||
EmitPerScrollHistogramsAndResetCounters();
|
||||
EmitPerScrollVsyncHistogramsAndResetCounters();
|
||||
EmitPerScrollV3HistogramsAndResetCounters();
|
||||
} else {
|
||||
per_scroll_ = JankData();
|
||||
experimental_per_scroll_vsync_ = JankData();
|
||||
per_scroll_v3_ = JankDataV3();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -23,6 +23,7 @@ class CC_EXPORT ScrollJankDroppedFrameTracker {
|
||||
ScrollJankDroppedFrameTracker(const ScrollJankDroppedFrameTracker&) = delete;
|
||||
|
||||
void ReportLatestPresentationData(ScrollUpdateEventMetrics& earliest_event,
|
||||
ScrollUpdateEventMetrics& latest_event,
|
||||
base::TimeTicks last_input_generation_ts,
|
||||
base::TimeTicks presentation_ts,
|
||||
base::TimeDelta vsync_interval);
|
||||
@ -36,16 +37,26 @@ class CC_EXPORT ScrollJankDroppedFrameTracker {
|
||||
static constexpr int kHistogramEmitFrequency = 64;
|
||||
static constexpr const char* kDelayedFramesWindowHistogram =
|
||||
"Event.ScrollJank.DelayedFramesPercentage.FixedWindow";
|
||||
static constexpr const char* kDelayedFramesWindowV3Histogram =
|
||||
"Event.ScrollJank.DelayedFramesPercentage.FixedWindow3";
|
||||
static constexpr const char* kMissedVsyncsWindowHistogram =
|
||||
"Event.ScrollJank.MissedVsyncsPercentage.FixedWindow";
|
||||
static constexpr const char* kMissedVsyncsWindowV3Histogram =
|
||||
"Event.ScrollJank.MissedVsyncsPercentage.FixedWindow3";
|
||||
static constexpr const char* kDelayedFramesPerScrollHistogram =
|
||||
"Event.ScrollJank.DelayedFramesPercentage.PerScroll";
|
||||
static constexpr const char* kDelayedFramesPerScrollV3Histogram =
|
||||
"Event.ScrollJank.DelayedFramesPercentage.PerScroll3";
|
||||
static constexpr const char* kMissedVsyncsPerScrollHistogram =
|
||||
"Event.ScrollJank.MissedVsyncsPercentage.PerScroll";
|
||||
static constexpr const char* kMissedVsyncsPerScrollV3Histogram =
|
||||
"Event.ScrollJank.MissedVsyncsPercentage.PerScroll3";
|
||||
static constexpr const char* kMissedVsyncsSumInWindowHistogram =
|
||||
"Event.ScrollJank.MissedVsyncsSum.FixedWindow";
|
||||
static constexpr const char* kMissedVsyncsSumInVsyncWindowHistogram =
|
||||
"Event.ScrollJank.MissedVsyncsSum.FixedWindow2";
|
||||
static constexpr const char* kMissedVsyncsSumInWindowV3Histogram =
|
||||
"Event.ScrollJank.MissedVsyncsSum.FixedWindow3";
|
||||
static constexpr const char* kMissedVsyncsMaxInWindowHistogram =
|
||||
"Event.ScrollJank.MissedVsyncsMax.FixedWindow";
|
||||
static constexpr const char* kMissedVsyncsMaxInVsyncWindowHistogram =
|
||||
@ -54,6 +65,8 @@ class CC_EXPORT ScrollJankDroppedFrameTracker {
|
||||
"Event.ScrollJank.MissedVsyncsMax.PerScroll";
|
||||
static constexpr const char* kMissedVsyncsSumPerScrollHistogram =
|
||||
"Event.ScrollJank.MissedVsyncsSum.PerScroll";
|
||||
static constexpr const char* kMissedVsyncsSumPerScrollV3Histogram =
|
||||
"Event.ScrollJank.MissedVsyncsSum.PerScroll3";
|
||||
static constexpr const char* kMissedVsyncsPerFrameHistogram =
|
||||
"Event.ScrollJank.MissedVsyncs.PerFrame";
|
||||
|
||||
@ -62,6 +75,12 @@ class CC_EXPORT ScrollJankDroppedFrameTracker {
|
||||
void EmitPerScrollHistogramsAndResetCounters();
|
||||
void EmitPerVsyncWindowHistogramsAndResetCounters();
|
||||
void EmitPerScrollVsyncHistogramsAndResetCounters();
|
||||
void EmitPerWindowV3HistogramsAndResetCounters();
|
||||
void EmitPerScrollV3HistogramsAndResetCounters();
|
||||
void ReportLatestPresentationDataV3(
|
||||
base::TimeTicks first_input_generation_v3_ts,
|
||||
base::TimeTicks presentation_ts,
|
||||
base::TimeDelta vsync_interval);
|
||||
|
||||
// We could have two different frames with same presentation time and due to
|
||||
// this just having previous frame's data is not enough for calculating the
|
||||
@ -81,12 +100,25 @@ class CC_EXPORT ScrollJankDroppedFrameTracker {
|
||||
int num_past_vsyncs = 0;
|
||||
};
|
||||
|
||||
struct JankDataV3 {
|
||||
// Number of frames which were deemed janky.
|
||||
int missed_frames = 0;
|
||||
// Number of vsyncs the frames were delayed by. Whenever a frame is missed
|
||||
// it could be delayed >=1 vsyncs, this helps us track how "long" the janks
|
||||
// are.
|
||||
int missed_vsyncs = 0;
|
||||
int num_presented_frames = 0;
|
||||
int num_past_vsyncs = 0;
|
||||
};
|
||||
|
||||
JankData fixed_window_;
|
||||
// TODO(b/306611560): Cleanup experimental per vsync metric or promote to
|
||||
// default.
|
||||
JankData experimental_vsync_fixed_window_;
|
||||
JankDataV3 fixed_window_v3_;
|
||||
std::optional<JankData> per_scroll_;
|
||||
std::optional<JankData> experimental_per_scroll_vsync_;
|
||||
std::optional<JankDataV3> per_scroll_v3_;
|
||||
|
||||
raw_ptr<ScrollJankUkmReporter> scroll_jank_ukm_reporter_ = nullptr;
|
||||
};
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include "cc/metrics/scroll_jank_dropped_frame_tracker.h"
|
||||
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
@ -23,18 +24,31 @@ struct FrameTimestamps {
|
||||
base::TimeTicks first_input_ts;
|
||||
base::TimeTicks last_input_ts;
|
||||
base::TimeTicks presentation_ts;
|
||||
std::optional<base::TimeTicks> earliest_coalesced_input_ts;
|
||||
|
||||
FrameTimestamps(base::TimeTicks first_input,
|
||||
base::TimeTicks last_input,
|
||||
base::TimeTicks presentation)
|
||||
FrameTimestamps(
|
||||
base::TimeTicks first_input,
|
||||
base::TimeTicks last_input,
|
||||
base::TimeTicks presentation,
|
||||
std::optional<base::TimeTicks> earliest_coalesced_input = std::nullopt)
|
||||
: first_input_ts(first_input),
|
||||
last_input_ts(last_input),
|
||||
presentation_ts(presentation) {}
|
||||
presentation_ts(presentation),
|
||||
earliest_coalesced_input_ts(earliest_coalesced_input) {}
|
||||
|
||||
FrameTimestamps(int first_input, int last_input, int presentation)
|
||||
FrameTimestamps(int first_input,
|
||||
int last_input,
|
||||
int presentation,
|
||||
std::optional<int> earliest_coalesced_input = std::nullopt)
|
||||
: first_input_ts(base::TimeTicks() + base::Milliseconds(first_input)),
|
||||
last_input_ts(base::TimeTicks() + base::Milliseconds(last_input)),
|
||||
presentation_ts(base::TimeTicks() + base::Milliseconds(presentation)) {}
|
||||
presentation_ts(base::TimeTicks() + base::Milliseconds(presentation)),
|
||||
earliest_coalesced_input_ts(
|
||||
earliest_coalesced_input.has_value()
|
||||
? std::optional(
|
||||
base::TimeTicks() +
|
||||
base::Milliseconds(earliest_coalesced_input.value()))
|
||||
: std::nullopt) {}
|
||||
};
|
||||
|
||||
constexpr int kHistogramEmitFrequency =
|
||||
@ -42,14 +56,24 @@ constexpr int kHistogramEmitFrequency =
|
||||
constexpr int kFirstWindowSize = kHistogramEmitFrequency + 1;
|
||||
constexpr const char* kDelayedFramesWindowHistogram =
|
||||
ScrollJankDroppedFrameTracker::kDelayedFramesWindowHistogram;
|
||||
constexpr const char* kDelayedFramesWindowV3Histogram =
|
||||
ScrollJankDroppedFrameTracker::kDelayedFramesWindowV3Histogram;
|
||||
constexpr const char* kMissedVsyncsWindowHistogram =
|
||||
ScrollJankDroppedFrameTracker::kMissedVsyncsWindowHistogram;
|
||||
constexpr const char* kMissedVsyncsWindowV3Histogram =
|
||||
ScrollJankDroppedFrameTracker::kMissedVsyncsWindowV3Histogram;
|
||||
constexpr const char* kDelayedFramesPerScrollHistogram =
|
||||
ScrollJankDroppedFrameTracker::kDelayedFramesPerScrollHistogram;
|
||||
constexpr const char* kDelayedFramesPerScrollV3Histogram =
|
||||
ScrollJankDroppedFrameTracker::kDelayedFramesPerScrollV3Histogram;
|
||||
constexpr const char* kMissedVsyncsPerScrollHistogram =
|
||||
ScrollJankDroppedFrameTracker::kMissedVsyncsPerScrollHistogram;
|
||||
constexpr const char* kMissedVsyncsPerScrollV3Histogram =
|
||||
ScrollJankDroppedFrameTracker::kMissedVsyncsPerScrollV3Histogram;
|
||||
constexpr const char* kMissedVsyncsSumInWindowHistogram =
|
||||
ScrollJankDroppedFrameTracker::kMissedVsyncsSumInWindowHistogram;
|
||||
constexpr const char* kMissedVsyncsSumInWindowV3Histogram =
|
||||
ScrollJankDroppedFrameTracker::kMissedVsyncsSumInWindowV3Histogram;
|
||||
constexpr const char* kMissedVsyncsSumInVsyncWindowHistogram =
|
||||
ScrollJankDroppedFrameTracker::kMissedVsyncsSumInVsyncWindowHistogram;
|
||||
constexpr const char* kMissedVsyncsMaxInWindowHistogram =
|
||||
@ -58,6 +82,8 @@ constexpr const char* kMissedVsyncsMaxInVsyncWindowHistogram =
|
||||
ScrollJankDroppedFrameTracker::kMissedVsyncsMaxInVsyncWindowHistogram;
|
||||
constexpr const char* kMissedVsyncsSumPerScrollHistogram =
|
||||
ScrollJankDroppedFrameTracker::kMissedVsyncsSumPerScrollHistogram;
|
||||
constexpr const char* kMissedVsyncsSumPerScrollV3Histogram =
|
||||
ScrollJankDroppedFrameTracker::kMissedVsyncsSumPerScrollV3Histogram;
|
||||
constexpr const char* kMissedVsyncsMaxPerScrollHistogram =
|
||||
ScrollJankDroppedFrameTracker::kMissedVsyncsMaxPerScrollHistogram;
|
||||
constexpr const char* kMissedVsyncsPerFrameHistogram =
|
||||
@ -81,20 +107,11 @@ class ScrollJankDroppedFrameTrackerTest : public testing::Test {
|
||||
prev_frame.first_input_ts += kVsyncInterval;
|
||||
prev_frame.last_input_ts += kVsyncInterval;
|
||||
prev_frame.presentation_ts += kVsyncInterval;
|
||||
|
||||
base::SimpleTestTickClock tick_clock;
|
||||
tick_clock.SetNowTicks(prev_frame.first_input_ts);
|
||||
|
||||
auto event = ScrollUpdateEventMetrics::CreateForTesting(
|
||||
ui::EventType::kGestureScrollUpdate, ui::ScrollInputType::kWheel,
|
||||
/*is_inertial=*/false,
|
||||
ScrollUpdateEventMetrics::ScrollUpdateType::kContinued,
|
||||
/*delta=*/10.0f, prev_frame.first_input_ts, base::TimeTicks(),
|
||||
&tick_clock, /*trace_id=*/std::nullopt);
|
||||
|
||||
scroll_jank_dropped_frame_tracker_->ReportLatestPresentationData(
|
||||
*event.get(), prev_frame.last_input_ts, prev_frame.presentation_ts,
|
||||
kVsyncInterval);
|
||||
if (prev_frame.earliest_coalesced_input_ts) {
|
||||
prev_frame.earliest_coalesced_input_ts =
|
||||
prev_frame.earliest_coalesced_input_ts.value() + kVsyncInterval;
|
||||
}
|
||||
ReportLatestPresentationDataToTracker(prev_frame);
|
||||
}
|
||||
return prev_frame;
|
||||
}
|
||||
@ -108,9 +125,19 @@ class ScrollJankDroppedFrameTrackerTest : public testing::Test {
|
||||
ScrollUpdateEventMetrics::ScrollUpdateType::kContinued,
|
||||
/*delta=*/10.0f, frame.first_input_ts, base::TimeTicks(), &tick_clock,
|
||||
/*trace_id=*/std::nullopt);
|
||||
std::unique_ptr<ScrollUpdateEventMetrics> earliest_coalesced_event;
|
||||
if (frame.earliest_coalesced_input_ts) {
|
||||
earliest_coalesced_event = ScrollUpdateEventMetrics::CreateForTesting(
|
||||
ui::EventType::kGestureScrollUpdate, ui::ScrollInputType::kWheel,
|
||||
/*is_inertial=*/false,
|
||||
ScrollUpdateEventMetrics::ScrollUpdateType::kContinued,
|
||||
/*delta=*/10.0f, frame.earliest_coalesced_input_ts.value(),
|
||||
base::TimeTicks(), &tick_clock,
|
||||
/*trace_id=*/std::nullopt);
|
||||
}
|
||||
scroll_jank_dropped_frame_tracker_->ReportLatestPresentationData(
|
||||
*event.get(), frame.last_input_ts, frame.presentation_ts,
|
||||
kVsyncInterval);
|
||||
earliest_coalesced_event ? *earliest_coalesced_event : *event, *event,
|
||||
frame.last_input_ts, frame.presentation_ts, kVsyncInterval);
|
||||
}
|
||||
|
||||
std::unique_ptr<base::HistogramTester> histogram_tester;
|
||||
@ -127,8 +154,12 @@ TEST_F(ScrollJankDroppedFrameTrackerTest, EmitsHistograms) {
|
||||
ProduceAndReportMockFrames(f1, kHistogramEmitFrequency);
|
||||
|
||||
histogram_tester->ExpectUniqueSample(kDelayedFramesWindowHistogram, 0, 0);
|
||||
histogram_tester->ExpectUniqueSample(kDelayedFramesWindowV3Histogram, 0, 0);
|
||||
histogram_tester->ExpectUniqueSample(kMissedVsyncsSumInWindowHistogram, 0, 0);
|
||||
histogram_tester->ExpectUniqueSample(kMissedVsyncsSumInWindowV3Histogram, 0,
|
||||
0);
|
||||
histogram_tester->ExpectUniqueSample(kMissedVsyncsWindowHistogram, 0, 0);
|
||||
histogram_tester->ExpectUniqueSample(kMissedVsyncsWindowV3Histogram, 0, 0);
|
||||
histogram_tester->ExpectUniqueSample(kMissedVsyncsSumInVsyncWindowHistogram,
|
||||
0, 0);
|
||||
|
||||
@ -136,8 +167,12 @@ TEST_F(ScrollJankDroppedFrameTrackerTest, EmitsHistograms) {
|
||||
last_frame = ProduceAndReportMockFrames(last_frame, 1);
|
||||
|
||||
histogram_tester->ExpectUniqueSample(kDelayedFramesWindowHistogram, 0, 1);
|
||||
histogram_tester->ExpectUniqueSample(kDelayedFramesWindowV3Histogram, 0, 1);
|
||||
histogram_tester->ExpectUniqueSample(kMissedVsyncsSumInWindowHistogram, 0, 1);
|
||||
histogram_tester->ExpectUniqueSample(kMissedVsyncsSumInWindowV3Histogram, 0,
|
||||
1);
|
||||
histogram_tester->ExpectUniqueSample(kMissedVsyncsWindowHistogram, 0, 1);
|
||||
histogram_tester->ExpectUniqueSample(kMissedVsyncsWindowV3Histogram, 0, 1);
|
||||
histogram_tester->ExpectUniqueSample(kMissedVsyncsSumInVsyncWindowHistogram,
|
||||
0, 1);
|
||||
|
||||
@ -145,8 +180,12 @@ TEST_F(ScrollJankDroppedFrameTrackerTest, EmitsHistograms) {
|
||||
ProduceAndReportMockFrames(last_frame, kHistogramEmitFrequency);
|
||||
|
||||
histogram_tester->ExpectUniqueSample(kDelayedFramesWindowHistogram, 0, 2);
|
||||
histogram_tester->ExpectUniqueSample(kDelayedFramesWindowV3Histogram, 0, 2);
|
||||
histogram_tester->ExpectUniqueSample(kMissedVsyncsSumInWindowHistogram, 0, 2);
|
||||
histogram_tester->ExpectUniqueSample(kMissedVsyncsSumInWindowV3Histogram, 0,
|
||||
2);
|
||||
histogram_tester->ExpectUniqueSample(kMissedVsyncsWindowHistogram, 0, 2);
|
||||
histogram_tester->ExpectUniqueSample(kMissedVsyncsWindowV3Histogram, 0, 2);
|
||||
histogram_tester->ExpectUniqueSample(kMissedVsyncsSumInVsyncWindowHistogram,
|
||||
0, 2);
|
||||
}
|
||||
@ -175,8 +214,12 @@ TEST_F(ScrollJankDroppedFrameTrackerTest, FrameProducedEveryVsync) {
|
||||
ProduceAndReportMockFrames(f2, frames_to_emit_histogram);
|
||||
|
||||
histogram_tester->ExpectUniqueSample(kDelayedFramesWindowHistogram, 0, 1);
|
||||
histogram_tester->ExpectUniqueSample(kDelayedFramesWindowV3Histogram, 0, 1);
|
||||
histogram_tester->ExpectUniqueSample(kMissedVsyncsSumInWindowHistogram, 0, 1);
|
||||
histogram_tester->ExpectUniqueSample(kMissedVsyncsSumInWindowV3Histogram, 0,
|
||||
1);
|
||||
histogram_tester->ExpectUniqueSample(kMissedVsyncsWindowHistogram, 0, 1);
|
||||
histogram_tester->ExpectUniqueSample(kMissedVsyncsWindowV3Histogram, 0, 1);
|
||||
histogram_tester->ExpectUniqueSample(kMissedVsyncsSumInVsyncWindowHistogram,
|
||||
0, 1);
|
||||
}
|
||||
@ -206,8 +249,12 @@ TEST_F(ScrollJankDroppedFrameTrackerTest, NoFrameProducedForMissingInput) {
|
||||
ProduceAndReportMockFrames(f2, frames_to_emit_histogram);
|
||||
|
||||
histogram_tester->ExpectUniqueSample(kDelayedFramesWindowHistogram, 0, 1);
|
||||
histogram_tester->ExpectUniqueSample(kDelayedFramesWindowV3Histogram, 0, 1);
|
||||
histogram_tester->ExpectUniqueSample(kMissedVsyncsSumInWindowHistogram, 0, 1);
|
||||
histogram_tester->ExpectUniqueSample(kMissedVsyncsSumInWindowV3Histogram, 0,
|
||||
1);
|
||||
histogram_tester->ExpectUniqueSample(kMissedVsyncsWindowHistogram, 0, 1);
|
||||
histogram_tester->ExpectUniqueSample(kMissedVsyncsWindowV3Histogram, 0, 1);
|
||||
histogram_tester->ExpectUniqueSample(kMissedVsyncsSumInVsyncWindowHistogram,
|
||||
0, 1);
|
||||
}
|
||||
@ -250,23 +297,93 @@ TEST_F(ScrollJankDroppedFrameTrackerTest, MissedVsyncWhenInputWasPresent) {
|
||||
// Frame F2 missed 2 vsyncs, F3 missed 1 vsync.
|
||||
const int expected_max = 2;
|
||||
const int expected_sum = 3;
|
||||
const int expected_missed_vsyncs_percentage =
|
||||
(100 * expected_sum) / kHistogramEmitFrequency;
|
||||
|
||||
histogram_tester->ExpectUniqueSample(kDelayedFramesWindowHistogram,
|
||||
expected_delayed_frames_percentage, 1);
|
||||
histogram_tester->ExpectUniqueSample(kDelayedFramesWindowV3Histogram,
|
||||
expected_delayed_frames_percentage, 1);
|
||||
histogram_tester->ExpectUniqueSample(kMissedVsyncsSumInWindowHistogram,
|
||||
expected_sum, 1);
|
||||
histogram_tester->ExpectUniqueSample(kMissedVsyncsSumInWindowV3Histogram,
|
||||
expected_sum, 1);
|
||||
histogram_tester->ExpectUniqueSample(kMissedVsyncsMaxInWindowHistogram,
|
||||
expected_max, 1);
|
||||
histogram_tester->ExpectUniqueSample(kMissedVsyncsWindowV3Histogram,
|
||||
expected_missed_vsyncs_percentage, 1);
|
||||
|
||||
// The counters were reset for next set of `kHistogramEmitFrequency` frames.
|
||||
ProduceAndReportMockFrames(last_frame_ts, kHistogramEmitFrequency);
|
||||
|
||||
histogram_tester->ExpectBucketCount(kDelayedFramesWindowHistogram, 0, 1);
|
||||
histogram_tester->ExpectBucketCount(kDelayedFramesWindowV3Histogram, 0, 1);
|
||||
histogram_tester->ExpectBucketCount(kMissedVsyncsSumInWindowHistogram, 0, 1);
|
||||
histogram_tester->ExpectBucketCount(kMissedVsyncsSumInWindowV3Histogram, 0,
|
||||
1);
|
||||
histogram_tester->ExpectBucketCount(kMissedVsyncsMaxInWindowHistogram, 0, 1);
|
||||
histogram_tester->ExpectBucketCount(kMissedVsyncsWindowV3Histogram, 0, 1);
|
||||
// Other non-zero buckets for histogram were tested earlier in the code.
|
||||
histogram_tester->ExpectBucketCount(kMissedVsyncsPerFrameHistogram, 0, 127);
|
||||
}
|
||||
|
||||
/*
|
||||
Test that when a coalesced frame took too long to be produced shows up in the
|
||||
new v3 metric (but not in the old metric).
|
||||
vsync v0 v1 v2
|
||||
| | | | | |
|
||||
input I0 I1 I2 I3 I4 I5 I6
|
||||
| | | | | | | |
|
||||
F1: |-----------| {I0, I1}
|
||||
F2: |-----------------------| {I2(coalesced), I3, I4}
|
||||
F3: |-----------------------| {I5, I6}
|
||||
|
||||
Since the old metric doesn't take coalesced events into account, it ignores I2
|
||||
and considers the following instead:
|
||||
|
||||
F2': |-----------------| {I3, I4}
|
||||
*/
|
||||
TEST_F(ScrollJankDroppedFrameTrackerTest,
|
||||
MissedVsyncWhenCoalescedInputWasPresent) {
|
||||
const std::vector<int> inputs = {103, 111, 119, 135, 143, 151, 159};
|
||||
const std::vector<int> presentations = {135, 183, 215};
|
||||
|
||||
FrameTimestamps f1 = {inputs[0], inputs[1], presentations[0]};
|
||||
FrameTimestamps f2 = {inputs[3], inputs[4], presentations[1], inputs[2]};
|
||||
FrameTimestamps f3 = {inputs[5], inputs[6], presentations[2]};
|
||||
|
||||
ReportLatestPresentationDataToTracker(f1);
|
||||
ReportLatestPresentationDataToTracker(f2);
|
||||
ReportLatestPresentationDataToTracker(f3);
|
||||
|
||||
// To trigger per window histogram emission.
|
||||
int frames_to_emit_histogram = kFirstWindowSize - 3;
|
||||
FrameTimestamps last_frame_ts =
|
||||
ProduceAndReportMockFrames(f3, frames_to_emit_histogram);
|
||||
|
||||
// F2 and F3 are janky frames, but only the new v3 metric considers F2 janky
|
||||
// because it takes coalesced events into account.
|
||||
histogram_tester->ExpectUniqueSample(kDelayedFramesWindowHistogram,
|
||||
(1 * 100) / kHistogramEmitFrequency, 1);
|
||||
histogram_tester->ExpectUniqueSample(kDelayedFramesWindowV3Histogram,
|
||||
(2 * 100) / kHistogramEmitFrequency, 1);
|
||||
histogram_tester->ExpectUniqueSample(kMissedVsyncsSumInWindowHistogram, 1, 1);
|
||||
histogram_tester->ExpectUniqueSample(kMissedVsyncsSumInWindowV3Histogram, 3,
|
||||
1);
|
||||
histogram_tester->ExpectUniqueSample(kMissedVsyncsWindowV3Histogram,
|
||||
(3 * 100) / kHistogramEmitFrequency, 1);
|
||||
|
||||
// The counters were reset for next set of `kHistogramEmitFrequency` frames.
|
||||
ProduceAndReportMockFrames(last_frame_ts, kHistogramEmitFrequency);
|
||||
|
||||
histogram_tester->ExpectBucketCount(kDelayedFramesWindowHistogram, 0, 1);
|
||||
histogram_tester->ExpectBucketCount(kDelayedFramesWindowV3Histogram, 0, 1);
|
||||
histogram_tester->ExpectBucketCount(kMissedVsyncsSumInWindowHistogram, 0, 1);
|
||||
histogram_tester->ExpectBucketCount(kMissedVsyncsSumInWindowV3Histogram, 0,
|
||||
1);
|
||||
histogram_tester->ExpectBucketCount(kMissedVsyncsWindowV3Histogram, 0, 1);
|
||||
}
|
||||
|
||||
TEST_F(ScrollJankDroppedFrameTrackerTest, MissedVsyncsPerVsyncWindow) {
|
||||
const std::vector<int> inputs = {103, 111, 119, 127, 135, 143};
|
||||
const std::vector<int> vsyncs = {148, 196, 228};
|
||||
@ -356,14 +473,23 @@ TEST_P(PerScrollTests, MetricsEmittedPerScroll) {
|
||||
// Frame F2 missed 2 vsyncs, F3 missed 1 vsync.
|
||||
const int expected_max = 2;
|
||||
const int expected_sum = 3;
|
||||
const int total_vsyncs = total_frames + expected_sum;
|
||||
const int expected_missed_vsyncs_percentage =
|
||||
(100 * expected_sum) / total_vsyncs;
|
||||
|
||||
// Emits non-bucketed histograms.
|
||||
histogram_tester->ExpectUniqueSample(kMissedVsyncsSumPerScrollHistogram,
|
||||
expected_sum, 1);
|
||||
histogram_tester->ExpectUniqueSample(kMissedVsyncsSumPerScrollV3Histogram,
|
||||
expected_sum, 1);
|
||||
histogram_tester->ExpectUniqueSample(kMissedVsyncsMaxPerScrollHistogram,
|
||||
expected_max, 1);
|
||||
histogram_tester->ExpectUniqueSample(kMissedVsyncsPerScrollV3Histogram,
|
||||
expected_missed_vsyncs_percentage, 1);
|
||||
histogram_tester->ExpectUniqueSample(kDelayedFramesPerScrollHistogram,
|
||||
expected_delayed_frames_percentage, 1);
|
||||
histogram_tester->ExpectUniqueSample(kDelayedFramesPerScrollV3Histogram,
|
||||
expected_delayed_frames_percentage, 1);
|
||||
|
||||
// Emits bucketed histograms.
|
||||
histogram_tester->ExpectUniqueSample(
|
||||
@ -383,8 +509,12 @@ TEST_P(PerScrollTests, MetricsEmittedPerScroll) {
|
||||
|
||||
// The counters should have been reset and there wouldn't be any janky frames.
|
||||
histogram_tester->ExpectBucketCount(kMissedVsyncsSumPerScrollHistogram, 0, 1);
|
||||
histogram_tester->ExpectBucketCount(kMissedVsyncsSumPerScrollV3Histogram, 0,
|
||||
1);
|
||||
histogram_tester->ExpectBucketCount(kMissedVsyncsMaxPerScrollHistogram, 0, 1);
|
||||
histogram_tester->ExpectBucketCount(kMissedVsyncsPerScrollV3Histogram, 0, 1);
|
||||
histogram_tester->ExpectBucketCount(kDelayedFramesPerScrollHistogram, 0, 1);
|
||||
histogram_tester->ExpectBucketCount(kDelayedFramesPerScrollV3Histogram, 0, 1);
|
||||
}
|
||||
|
||||
TEST_P(PerScrollTests, VsyncMetricsEmittedPerScroll) {
|
||||
|
@ -61,7 +61,7 @@ class ScrollJankUkmReporterTest : public testing::Test {
|
||||
/*delta=*/10.0f, first_input_ts, base::TimeTicks(), &tick_clock,
|
||||
/*trace_id=*/std::nullopt);
|
||||
scroll_jank_dropped_frame_tracker_->ReportLatestPresentationData(
|
||||
*event.get(), last_input_ts, presentation_ts, vsync_interval);
|
||||
*event, *event, last_input_ts, presentation_ts, vsync_interval);
|
||||
}
|
||||
|
||||
void ReportFramesToPredictorJankTracker(double delta,
|
||||
|
@ -492,6 +492,71 @@ chromium-metrics-reviews@google.com.
|
||||
</summary>
|
||||
</histogram>
|
||||
|
||||
<histogram name="Event.ScrollJank.DelayedFramesPercentage.FixedWindow3"
|
||||
units="%" expires_after="2026-03-17">
|
||||
<owner>petrcermak@chromium.org</owner>
|
||||
<owner>kartarsingh@google.com</owner>
|
||||
<owner>jonross@chromium.org</owner>
|
||||
<owner>woa-performance-team@google.com</owner>
|
||||
<summary>
|
||||
NOTE: This metric is a new experimental version of
|
||||
Event.ScrollJank.DelayedFramesPercentage.FixedWindow. This new metric aims
|
||||
to address the old metric's shortcomings and eventually replace it. For now,
|
||||
we recommend you still use the old metric
|
||||
(Event.ScrollJank.DelayedFramesPercentage.FixedWindow) for performance
|
||||
analysis.
|
||||
|
||||
The percentage of frames not presented during a scroll or a fling[1],
|
||||
meaning frame production took longer than expected and the frame was
|
||||
skipped.
|
||||
|
||||
This metric is different from traditional graphics smoothness metrics as it
|
||||
considers performance degradation on all threads and processes including
|
||||
Browser and IO, unlike graphics' smoothness metrics which focus on the core
|
||||
graphics pipeline (Renderer/GPU).
|
||||
|
||||
This metric is only recorded when 64 frames are presented, for example if a
|
||||
scroll only has 12 frames, the next scroll has 40 frames and the scroll
|
||||
after has 12 frames, the metric only will be emitted after the 3rd scroll.
|
||||
This means the last incomplete window might not get reported as the browser
|
||||
terminates.
|
||||
|
||||
For more details about this metric, please check
|
||||
http://doc/1Y0u0Tq5eUZff75nYUzQVw6JxmbZAW9m64pJidmnGWsY
|
||||
|
||||
[1]Fling is a finger boosted scroll, meaning the screen is moving after the
|
||||
user has accelerated their finger on the screen and removed it.
|
||||
</summary>
|
||||
</histogram>
|
||||
|
||||
<histogram name="Event.ScrollJank.DelayedFramesPercentage.PerScroll3" units="%"
|
||||
expires_after="2026-03-17">
|
||||
<owner>petrcermak@chromium.org</owner>
|
||||
<owner>kartarsingh@google.com</owner>
|
||||
<owner>jonross@chromium.org</owner>
|
||||
<owner>woa-performance-team@google.com</owner>
|
||||
<summary>
|
||||
NOTE: This metric is a new experimental version of
|
||||
Event.ScrollJank.DelayedFramesPercentage.PerScroll. This new metric aims to
|
||||
address the old metric's shortcomings and eventually replace it. For now, we
|
||||
recommend you still use the old metric
|
||||
(Event.ScrollJank.DelayedFramesPercentage.PerScroll) for performance
|
||||
analysis.
|
||||
|
||||
A frame is deemed janky during a scroll if there was no presented frame in
|
||||
the previous vsync, and the current frame contains input that was not
|
||||
presented during the missed frame. Missed input is determined by comparing
|
||||
the timestamp of the earliest input of the current frame, to that of the
|
||||
last input of the previously presented frame. If the delta of the timestamps
|
||||
is less than a vsync + vsync/2, then the input is considered to have been
|
||||
intended for the missed frame. This metric reports the percentage of delayed
|
||||
frames within a scroll.
|
||||
|
||||
For more details about this metric, please check
|
||||
http://doc/1Y0u0Tq5eUZff75nYUzQVw6JxmbZAW9m64pJidmnGWsY
|
||||
</summary>
|
||||
</histogram>
|
||||
|
||||
<histogram name="Event.ScrollJank.DelayedFramesPercentage.PerScroll{Length}"
|
||||
units="%" expires_after="2025-08-24">
|
||||
<owner>kartarsingh@google.com</owner>
|
||||
@ -559,6 +624,62 @@ chromium-metrics-reviews@google.com.
|
||||
</summary>
|
||||
</histogram>
|
||||
|
||||
<histogram name="Event.ScrollJank.MissedVsyncsPercentage.FixedWindow3"
|
||||
units="%" expires_after="2026-03-17">
|
||||
<owner>petrcermak@chromium.org</owner>
|
||||
<owner>jonross@chromium.org</owner>
|
||||
<owner>woa-performance-team@google.com</owner>
|
||||
<summary>
|
||||
NOTE: This metric is a new experimental version of
|
||||
Event.ScrollJank.MissedVsyncsPercentage.FixedWindow. This new metric aims to
|
||||
address the old metric's shortcomings and eventually replace it. For now, we
|
||||
recommend you still use the old metric
|
||||
(Event.ScrollJank.MissedVsyncsPercentage.FixedWindow) for performance
|
||||
analysis.
|
||||
|
||||
A vsync is deemed janky during a scroll if there was no presented frame in
|
||||
the vsync and the next frame contained late input that was not presented
|
||||
during the janky vsync. Missed input is determined by comparing the
|
||||
timestamp of the earliest input of the current frame, to that of the last
|
||||
input of the previously presented frame. If the delta of the timestamps is
|
||||
less than a vsync + vsync/2, then the input is considered to have been
|
||||
intended for the missed frame. This metric reports the percentage of janky
|
||||
vsyncs within a window of size 64.
|
||||
|
||||
For more details about this metric, please check
|
||||
http://doc/1Y0u0Tq5eUZff75nYUzQVw6JxmbZAW9m64pJidmnGWsY
|
||||
</summary>
|
||||
</histogram>
|
||||
|
||||
<histogram name="Event.ScrollJank.MissedVsyncsPercentage.PerScroll3" units="%"
|
||||
expires_after="2026-03-17">
|
||||
<owner>petrcermak@chromium.org</owner>
|
||||
<owner>kartarsingh@google.com</owner>
|
||||
<owner>jonross@chromium.org</owner>
|
||||
<owner>woa-performance-team@google.com</owner>
|
||||
<summary>
|
||||
NOTE: This metric is a new experimental version of
|
||||
Event.ScrollJank.MissedVsyncsPercentage.PerScroll. This new metric aims to
|
||||
address the old metric's shortcomings and eventually replace it. For now, we
|
||||
recommend you still use the old metric
|
||||
(Event.ScrollJank.MissedVsyncsPercentage.PerScroll) for performance
|
||||
analysis.
|
||||
|
||||
A vsync is deemed janky during a scroll if there was no presented frame in
|
||||
the vsync and the next frame contained late input that was not presented
|
||||
during the janky vsync. Missed input is determined by comparing the
|
||||
timestamp of the earliest input of the current frame, to that of the last
|
||||
input of the previously presented frame. If the delta of the timestamps is
|
||||
less than a vsync + vsync/2, then the input is considered to have been
|
||||
intended for the missed frame. This metric reports percentage of missed
|
||||
vsyncs in a scroll in scroll. Metric emits zeros as well i.e. the case when
|
||||
no frames were delayed.
|
||||
|
||||
For more details about this metric, please check
|
||||
http://doc/1Y0u0Tq5eUZff75nYUzQVw6JxmbZAW9m64pJidmnGWsY
|
||||
</summary>
|
||||
</histogram>
|
||||
|
||||
<histogram name="Event.ScrollJank.MissedVsyncsPercentage.PerScroll{Length}"
|
||||
units="%" expires_after="2025-08-03">
|
||||
<owner>kartarsingh@google.com</owner>
|
||||
@ -584,6 +705,62 @@ chromium-metrics-reviews@google.com.
|
||||
<token key="Length" variants="ScrollLength"/>
|
||||
</histogram>
|
||||
|
||||
<histogram name="Event.ScrollJank.MissedVsyncsSum.FixedWindow3" units="counts"
|
||||
expires_after="2026-03-17">
|
||||
<owner>petrcermak@chromium.org</owner>
|
||||
<owner>kartarsingh@google.com</owner>
|
||||
<owner>jonross@chromium.org</owner>
|
||||
<owner>woa-performance-team@google.com</owner>
|
||||
<summary>
|
||||
NOTE: This metric is a new experimental version of
|
||||
Event.ScrollJank.MissedVsyncsSum.FixedWindow. This new metric aims to
|
||||
address the old metric's shortcomings and eventually replace it. For now, we
|
||||
recommend you still use the old metric
|
||||
(Event.ScrollJank.MissedVsyncsSum.FixedWindow) for performance analysis.
|
||||
|
||||
A vsync is deemed janky during a scroll if there was no presented frame in
|
||||
the vsync and the next frame contained late input that was not presented
|
||||
during the janky vsync. Missed input is determined by comparing the
|
||||
timestamp of the earliest input of the current frame, to that of the last
|
||||
input of the previously presented frame. If the delta of the timestamps is
|
||||
less than a vsync + vsync/2, then the input is considered to have been
|
||||
intended for the missed frame. This metric reports the sum of missed vsyncs
|
||||
in a window of size 64. Metric emits zeros as well i.e. the case when no
|
||||
frames were delayed.
|
||||
|
||||
For more details about this metric, please check
|
||||
http://doc/1Y0u0Tq5eUZff75nYUzQVw6JxmbZAW9m64pJidmnGWsY
|
||||
</summary>
|
||||
</histogram>
|
||||
|
||||
<histogram name="Event.ScrollJank.MissedVsyncsSum.PerScroll3" units="counts"
|
||||
expires_after="2026-03-17">
|
||||
<owner>petrcermak@chromium.org</owner>
|
||||
<owner>kartarsingh@google.com</owner>
|
||||
<owner>jonross@chromium.org</owner>
|
||||
<owner>woa-performance-team@google.com</owner>
|
||||
<summary>
|
||||
NOTE: This metric is a new experimental version of
|
||||
Event.ScrollJank.MissedVsyncsSum.PerScroll. This new metric aims to address
|
||||
the old metric's shortcomings and eventually replace it. For now, we
|
||||
recommend you still use the old metric
|
||||
(Event.ScrollJank.MissedVsyncsSum.PerScroll) for performance analysis.
|
||||
|
||||
A frame is deemed janky during a scroll if there was no presented frame in
|
||||
the previous vsync, and the current frame contains input that was not
|
||||
presented during the missed frame. Missed input is determined by comparing
|
||||
the timestamp of the earliest input of the current frame, to that of the
|
||||
last input of the previously presented frame. If the delta of the timestamps
|
||||
is less than a vsync + vsync/2, then the input is considered to have been
|
||||
intended for the missed frame. This metric reports the sum of missed vsyncs
|
||||
in a scroll. Metric emits zeros as well i.e. the case when no frames were
|
||||
delayed.
|
||||
|
||||
For more details about this metric, please check
|
||||
http://doc/1Y0u0Tq5eUZff75nYUzQVw6JxmbZAW9m64pJidmnGWsY
|
||||
</summary>
|
||||
</histogram>
|
||||
|
||||
<histogram name="Event.ScrollJank.MissedVsyncs{Operator}.FixedWindow"
|
||||
units="counts" expires_after="2025-08-03">
|
||||
<owner>kartarsingh@google.com</owner>
|
||||
|
Reference in New Issue
Block a user