File: average_lag_tracking_manager.cc

package info (click to toggle)
chromium 139.0.7258.127-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 6,122,068 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (131 lines) | stat: -rw-r--r-- 5,042 bytes parent folder | download | duplicates (3)
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
122
123
124
125
126
127
128
129
130
131
// 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);
    if (scroll_update_metrics->scroll_type() !=
        ScrollEventMetrics::ScrollType::kTouchscreen) {
      continue;
    }

    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);
  AddEventInfoFromEventMetricsList(events_metrics.raster_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