summaryrefslogtreecommitdiffstats
path: root/cc/debug/frame_rate_counter.cc
diff options
context:
space:
mode:
authorjamesr@chromium.org <jamesr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-03-18 06:54:27 +0000
committerjamesr@chromium.org <jamesr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-03-18 06:54:27 +0000
commit6e84de2e71a4d6c9652ba3dd4471ff4f45ac8b27 (patch)
tree2d9eaa933544f87303d9cfb552c72fd96eb2a1a3 /cc/debug/frame_rate_counter.cc
parent0fc818ec6e012243303de3e013037c8c0221c83f (diff)
downloadchromium_src-6e84de2e71a4d6c9652ba3dd4471ff4f45ac8b27.zip
chromium_src-6e84de2e71a4d6c9652ba3dd4471ff4f45ac8b27.tar.gz
chromium_src-6e84de2e71a4d6c9652ba3dd4471ff4f45ac8b27.tar.bz2
Part 2 of cc/ directory shuffles: debug
Continuation of https://src.chromium.org/viewvc/chrome?view=rev&revision=188681 BUG=190824 TBR=enne@chromium.org Review URL: https://codereview.chromium.org/12648008 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@188685 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'cc/debug/frame_rate_counter.cc')
-rw-r--r--cc/debug/frame_rate_counter.cc137
1 files changed, 137 insertions, 0 deletions
diff --git a/cc/debug/frame_rate_counter.cc b/cc/debug/frame_rate_counter.cc
new file mode 100644
index 0000000..3d8b5c8
--- /dev/null
+++ b/cc/debug/frame_rate_counter.cc
@@ -0,0 +1,137 @@
+// Copyright 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "cc/debug/frame_rate_counter.h"
+
+#include <limits>
+
+#include "base/metrics/histogram.h"
+#include "cc/proxy.h"
+
+namespace cc {
+
+// The following constants are measured in seconds.
+
+// Two thresholds (measured in seconds) that describe what is considered to be a
+// "no-op frame" that should not be counted.
+// - if the frame is too fast, then given our compositor implementation, the
+// frame probably was a no-op and did not draw.
+// - if the frame is too slow, then there is probably not animating content, so
+// we should not pollute the average.
+static const double kFrameTooFast = 1.0 / 70.0;
+static const double kFrameTooSlow = 1.0 / 4.0;
+
+// If a frame takes longer than this threshold (measured in seconds) then we
+// (naively) assume that it missed a screen refresh; that is, we dropped a
+// frame.
+// TODO(brianderson): Determine this threshold based on monitor refresh rate,
+// crbug.com/138642.
+static const double kDroppedFrameTime = 1.0 / 50.0;
+
+// static
+scoped_ptr<FrameRateCounter> FrameRateCounter::Create(bool has_impl_thread) {
+ return make_scoped_ptr(new FrameRateCounter(has_impl_thread));
+}
+
+base::TimeDelta FrameRateCounter::RecentFrameInterval(size_t n) const {
+ DCHECK_GT(n, 0u);
+ DCHECK_LT(n, ring_buffer_.BufferSize());
+ return ring_buffer_.ReadBuffer(n) - ring_buffer_.ReadBuffer(n - 1);
+}
+
+FrameRateCounter::FrameRateCounter(bool has_impl_thread)
+ : has_impl_thread_(has_impl_thread), dropped_frame_count_(0) {}
+
+void FrameRateCounter::SaveTimeStamp(base::TimeTicks timestamp) {
+ ring_buffer_.SaveToBuffer(timestamp);
+
+ // Check if frame interval can be computed.
+ if (ring_buffer_.CurrentIndex() < 2)
+ return;
+
+ base::TimeDelta frame_interval_seconds =
+ RecentFrameInterval(ring_buffer_.BufferSize() - 1);
+
+ if (has_impl_thread_ && ring_buffer_.CurrentIndex() > 0) {
+ UMA_HISTOGRAM_CUSTOM_COUNTS("Renderer4.CompositorThreadImplDrawDelay",
+ frame_interval_seconds.InMilliseconds(),
+ 1,
+ 120,
+ 60);
+ }
+
+ if (!IsBadFrameInterval(frame_interval_seconds) &&
+ frame_interval_seconds.InSecondsF() > kDroppedFrameTime)
+ ++dropped_frame_count_;
+}
+
+bool FrameRateCounter::IsBadFrameInterval(
+ base::TimeDelta interval_between_consecutive_frames) const {
+ double delta = interval_between_consecutive_frames.InSecondsF();
+ bool scheduler_allows_double_frames = !has_impl_thread_;
+ bool interval_too_fast =
+ scheduler_allows_double_frames ? delta < kFrameTooFast : delta <= 0.0;
+ bool interval_too_slow = delta > kFrameTooSlow;
+ return interval_too_fast || interval_too_slow;
+}
+
+void FrameRateCounter::GetMinAndMaxFPS(double* min_fps, double* max_fps) const {
+ *min_fps = std::numeric_limits<double>::max();
+ *max_fps = 0.0;
+
+ for (RingBufferType::Iterator it = --ring_buffer_.End(); it; --it) {
+ base::TimeDelta delta = RecentFrameInterval(it.index() + 1);
+
+ if (IsBadFrameInterval(delta))
+ continue;
+
+ DCHECK_GT(delta.InSecondsF(), 0.f);
+ double fps = 1.0 / delta.InSecondsF();
+
+ *min_fps = std::min(fps, *min_fps);
+ *max_fps = std::max(fps, *max_fps);
+ }
+
+ if (*min_fps > *max_fps)
+ *min_fps = *max_fps;
+}
+
+double FrameRateCounter::GetAverageFPS() const {
+ int frame_count = 0;
+ double frame_times_total = 0.0;
+ double average_fps = 0.0;
+
+ // Walk backwards through the samples looking for a run of good frame
+ // timings from which to compute the mean.
+ //
+ // Slow frames occur just because the user is inactive, and should be
+ // ignored. Fast frames are ignored if the scheduler is in single-thread
+ // mode in order to represent the true frame rate in spite of the fact that
+ // the first few swapbuffers happen instantly which skews the statistics
+ // too much for short lived animations.
+ //
+ // isBadFrameInterval encapsulates the frame too slow/frame too fast logic.
+
+ for (RingBufferType::Iterator it = --ring_buffer_.End();
+ it && frame_times_total < 1.0;
+ --it) {
+ base::TimeDelta delta = RecentFrameInterval(it.index() + 1);
+
+ if (!IsBadFrameInterval(delta)) {
+ frame_count++;
+ frame_times_total += delta.InSecondsF();
+ } else if (frame_count) {
+ break;
+ }
+ }
+
+ if (frame_count) {
+ DCHECK_GT(frame_times_total, 0.0);
+ average_fps = frame_count / frame_times_total;
+ }
+
+ return average_fps;
+}
+
+} // namespace cc