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

cc / metrics / total_frame_counter.cc [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/total_frame_counter.h"

#include <cmath>

#include "base/logging.h"
#include "components/viz/common/frame_sinks/begin_frame_args.h"

namespace cc {

TotalFrameCounter::TotalFrameCounter() = default;

void TotalFrameCounter::OnShow(base::TimeTicks timestamp) {
  DCHECK(last_shown_timestamp_.is_null());
  DCHECK(latest_interval_.is_zero());
  last_shown_timestamp_ = timestamp;
}

void TotalFrameCounter::OnHide(base::TimeTicks timestamp) {
  // It is possible to hide right after being shown before receiving any
  // BeginFrameArgs.
  if (!latest_interval_.is_zero())
    UpdateTotalFramesSinceLastVisible(timestamp);
  last_shown_timestamp_ = base::TimeTicks();
  latest_interval_ = base::TimeDelta();
}

void TotalFrameCounter::OnBeginFrame(const viz::BeginFrameArgs& args) {
  // In tests, it is possible to receive begin-frames when invisible. Ignore
  // these.
  if (last_shown_timestamp_.is_null())
    return;

  if (!latest_interval_.is_zero() && latest_interval_ != args.interval) {
    UpdateTotalFramesSinceLastVisible(args.frame_time);
    last_shown_timestamp_ = args.frame_time;
  }

  latest_interval_ = args.interval;
}

void TotalFrameCounter::Reset() {
  total_frames_ = 0;
  latest_interval_ = {};
  // If the compositor is visible, then update the visible timestamp to current
  // time.
  if (!last_shown_timestamp_.is_null())
    last_shown_timestamp_ = base::TimeTicks::Now();
}

void TotalFrameCounter::UpdateTotalFramesSinceLastVisible(
    base::TimeTicks until) {
  total_frames_ = ComputeTotalVisibleFrames(until);
}

size_t TotalFrameCounter::ComputeTotalVisibleFrames(
    base::TimeTicks until) const {
  DCHECK(!until.is_null());

  if (last_shown_timestamp_.is_null() || latest_interval_.is_zero()) {
    // The compositor may be currently invisible, or has just been made visible
    // but has yet to receive a BeginFrameArgs.
    return total_frames_;
  }

  // We have two sources for timestamps. Show/Hide uses the Renderer time
  // source. While viz::BeginFrameArgs will be either timestamps from the
  // physical GPU, or fallbacks in the GPU/Viz process. This could be the cause
  // of a drift. We don't error on these edgecases, we just return the
  // `total_frames_` which reflects the latest OnBeginFrame.
  if (until < last_shown_timestamp_) {
    return total_frames_;
  }
  auto frames_since =
      std::ceil((until - last_shown_timestamp_) / latest_interval_);
  return total_frames_ + frames_since;
}

}  // namespace cc