[go: nahoru, domu]

blob: e2b3b45dbc3831895012b1f793ef3013e2e8ab71 [file] [log] [blame]
// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "cc/metrics/average_lag_tracking_manager.h"
#include <algorithm>
#include <memory>
#include "components/viz/common/frame_timing_details.h"
#include "components/viz/common/quads/compositor_frame_metadata.h"
namespace cc {
namespace {
void AddEventInfoFromEventMetricsList(
const EventMetrics::List& events_metrics,
std::vector<AverageLagTracker::EventInfo>* event_infos) {
for (const std::unique_ptr<EventMetrics>& event_metrics : events_metrics) {
EventMetrics::EventType type = event_metrics->type();
if (type != EventMetrics::EventType::kFirstGestureScrollUpdate &&
type != EventMetrics::EventType::kGestureScrollUpdate) {
continue;
}
auto* scroll_update_metrics = event_metrics->AsScrollUpdate();
DCHECK(scroll_update_metrics);
event_infos->emplace_back(
scroll_update_metrics->delta(),
scroll_update_metrics->predicted_delta(),
scroll_update_metrics->last_timestamp(),
type == EventMetrics::EventType::kFirstGestureScrollUpdate
? AverageLagTracker::EventType::kScrollbegin
: AverageLagTracker::EventType::kScrollupdate);
}
}
} // namespace
AverageLagTrackingManager::AverageLagTrackingManager() = default;
AverageLagTrackingManager::~AverageLagTrackingManager() {
// The map must contain only frames that haven't been presented (i.e. did not
// get a presentation feedback yet). Thus, at a given point in time, more than
// a handful (actually around 2) of frames without feedback is unexpected.
DCHECK_LE(frame_token_to_info_.size(), 20u);
}
void AverageLagTrackingManager::CollectScrollEventsFromFrame(
uint32_t frame_token,
const EventMetricsSet& events_metrics) {
std::vector<AverageLagTracker::EventInfo> event_infos;
// A scroll event can be handled either on the main or the compositor thread
// (not both). So, both lists of metrics from the main and the compositor
// thread might contain interesting scroll events and we should collect
// information about scroll events from both. We are not worried about
// ordering of the events at this point. If the frame is presented, events
// for the frame will be sorted and fed into `AverageLagTracker` in order.
AddEventInfoFromEventMetricsList(events_metrics.main_event_metrics,
&event_infos);
AddEventInfoFromEventMetricsList(events_metrics.impl_event_metrics,
&event_infos);
if (event_infos.size() > 0)
frame_token_to_info_.emplace_back(frame_token, std::move(event_infos));
}
void AverageLagTrackingManager::DidPresentCompositorFrame(
uint32_t frame_token,
const viz::FrameTimingDetails& frame_details) {
if (frame_details.presentation_feedback.failed()) {
// When presentation fails, remove the current frame from (potentially, the
// middle of) the queue; but, leave earlier frames in the queue as they
// still might end up being presented successfully.
for (auto submitted_frame = frame_token_to_info_.begin();
submitted_frame != frame_token_to_info_.end(); submitted_frame++) {
if (viz::FrameTokenGT(submitted_frame->first, frame_token))
break;
if (submitted_frame->first == frame_token) {
frame_token_to_info_.erase(submitted_frame);
break;
}
}
return;
}
// When presentation succeeds, consider earlier frames as failed and remove
// them from the front of the queue. Then take the list of events for the
// current frame and remove it from the front of the queue, too.
std::vector<AverageLagTracker::EventInfo> infos;
while (!frame_token_to_info_.empty()) {
auto& submitted_frame = frame_token_to_info_.front();
if (viz::FrameTokenGT(submitted_frame.first, frame_token))
break;
if (submitted_frame.first == frame_token)
infos = std::move(submitted_frame.second);
frame_token_to_info_.pop_front();
}
// If there is no event, there is nothing to report.
if (infos.empty())
return;
DCHECK(!frame_details.swap_timings.is_null());
// AverageLagTracker expects events' info to be in ascending order.
std::sort(infos.begin(), infos.end(),
[](const AverageLagTracker::EventInfo& a,
const AverageLagTracker::EventInfo& b) {
return a.event_timestamp < b.event_timestamp;
});
for (AverageLagTracker::EventInfo& info : infos) {
info.finish_timestamp = frame_details.presentation_feedback.timestamp;
lag_tracker_.AddScrollEventInFrame(info);
}
}
void AverageLagTrackingManager::Clear() {
frame_token_to_info_.clear();
}
} // namespace cc