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
  132
  133
  134
  135
  136

cc / metrics / average_lag_tracker.h [blame]

// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CC_METRICS_AVERAGE_LAG_TRACKER_H_
#define CC_METRICS_AVERAGE_LAG_TRACKER_H_

#include <deque>
#include <string>

#include "base/time/time.h"
#include "cc/cc_export.h"

namespace cc {

// A class for reporting AverageLag metrics. See
// https://docs.google.com/document/d/1e8NuzPblIv2B9bz01oSj40rmlse7_PHq5oFS3lqz6N4/
class CC_EXPORT AverageLagTracker {
 public:
  enum class EventType { kScrollbegin, kScrollupdate };

  struct EventInfo {
    EventInfo(float event_scroll_delta,
              float predicted_scroll_delta,
              base::TimeTicks event_timestamp,
              EventType event_type)
        : event_scroll_delta(event_scroll_delta),
          predicted_scroll_delta(predicted_scroll_delta),
          event_timestamp(event_timestamp),
          event_type(event_type) {}
    // Delta reported by the scroll event (begin or update).
    float event_scroll_delta;
    // Delta predicted (when prediction is on, otherwise should be equals to
    // |event_scroll_delta|).
    float predicted_scroll_delta;
    // Timestamp when the scroll event happened.
    base::TimeTicks event_timestamp;
    // Timestamp when the scroll event's frame finished, which is currently
    // when the frame swap completed.
    base::TimeTicks finish_timestamp;
    // Scroll event type (begin or update).
    EventType event_type;
  };

  AverageLagTracker();
  ~AverageLagTracker();

  // Disallow copy and assign.
  AverageLagTracker(const AverageLagTracker&) = delete;
  AverageLagTracker& operator=(AverageLagTracker const&) = delete;

  // Adds a scroll event defined by |event_info|.
  void AddScrollEventInFrame(const EventInfo& event_info);

 protected:
  std::string GetAverageLagMetricName(EventType) const;

 private:
  struct LagAreaInFrame {
    explicit LagAreaInFrame(base::TimeTicks time,
                            float rendered_pos = 0,
                            float rendered_pos_no_prediction = 0)
        : frame_time(time),
          rendered_accumulated_delta(rendered_pos),
          lag_area(0),
          rendered_accumulated_delta_no_prediction(rendered_pos_no_prediction),
          lag_area_no_prediction(0) {}
    base::TimeTicks frame_time;
    // |rendered_accumulated_delta| is the cumulative delta that was swapped for
    // this frame; this is based on the predicted delta, if prediction is
    // enabled.
    float rendered_accumulated_delta;
    // |lag_area| is computed once a future input is processed that occurs after
    // the swap timestamp (so that we can compute how far the rendered delta
    // was from the actual position at the swap time).
    float lag_area;
    // |rendered_accumulated_delta_no_prediction| is the what would have been
    // rendered if prediction was not taken into account, i.e., the actual delta
    // from the input event.
    float rendered_accumulated_delta_no_prediction;
    // |lag_area_no_prediction| is computed the same as |lag_area| but using
    // rendered_accumulated_delta_no_prediction as the rendered delta.
    float lag_area_no_prediction;
  };

  // Processes |event_info| as a ScrollBegin event and add it to the Lag.
  void AddScrollBeginInFrame(const EventInfo& event_info);
  // Processes |event_info| as a ScrollUpdate event and add it to the Lag.
  void AddScrollUpdateInFrame(const EventInfo& event_info);

  // Calculate lag in 1 seconds intervals and report UMA.
  void CalculateAndReportAverageLagUma(bool send_anyway = false);

  // Helper function to calculate lag area between |front_time| to
  // |back_time|.
  float LagBetween(base::TimeTicks front_time,
                   base::TimeTicks back_time,
                   float scroll_delta,
                   base::TimeTicks event_time,
                   float rendered_accumulated_delta);

  float LagForUnfinishedFrame(float rendered_accumulated_delta);

  std::deque<LagAreaInFrame> frame_lag_infos_;

  // Last scroll event's timestamp in the sequence, reset on ScrollBegin.
  base::TimeTicks last_event_timestamp_;
  // Timestamp of the last frame popped from |frame_lag_infos_| queue.
  base::TimeTicks last_finished_frame_time_;

  // Accumulated scroll delta for actual scroll update events. Cumulated from
  // event_scroll_delta. Reset on ScrollBegin.
  float last_event_accumulated_delta_ = 0;
  // Accumulated scroll delta got rendered on gpu swap. Cumulated from
  // predicted_scroll_delta. It always has same value as
  // |last_event_accumulated_delta_| when scroll prediction is disabled.
  float last_rendered_accumulated_delta_ = 0;

  // This keeps track of the last report_time when we report to UMA, so we can
  // calculate the report's duration by current - last. Reset on ScrollBegin.
  base::TimeTicks last_reported_time_;

  // True if the first element of |frame_lag_infos_| is for ScrollBegin.
  // For ScrollBegin, we don't wait for the 1 second interval but record the
  // UMA once the frame is finished.
  bool is_begin_ = false;

  // Accumulated lag area in the 1 second intervals.
  float accumulated_lag_ = 0;
  // Accumulated lag not taking into account the predicted deltas.
  float accumulated_lag_no_prediction_ = 0;
};

}  // namespace cc

#endif  // CC_METRICS_AVERAGE_LAG_TRACKER_H_