File: average_lag_tracking_manager.cc

package info (click to toggle)
chromium 138.0.7204.183-1
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 6,071,908 kB
  • sloc: cpp: 34,937,088; ansic: 7,176,967; javascript: 4,110,704; python: 1,419,953; asm: 946,768; xml: 739,971; pascal: 187,324; sh: 89,623; perl: 88,663; objc: 79,944; sql: 50,304; cs: 41,786; fortran: 24,137; makefile: 21,806; php: 13,980; tcl: 13,166; yacc: 8,925; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (129 lines) | stat: -rw-r--r-- 4,920 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
// 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);

  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