Separate Simple Backend creation from initialization.
[chromium-blink-merge.git] / tools / perf / perf_tools / smoothness_measurement.js
blob22336feeb4485c3a924c28cba4b7f6303b8ddccf
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 'use strict';
7 /**
8  * @fileoverview This file provides the RenderingStats object, used
9  * to characterize rendering smoothness.
10  */
11 (function() {
12   var getTimeMs = (function() {
13     if (window.performance)
14       return (performance.now       ||
15               performance.mozNow    ||
16               performance.msNow     ||
17               performance.oNow      ||
18               performance.webkitNow).bind(window.performance);
19     else
20       return function() { return new Date().getTime(); };
21   })();
23   var requestAnimationFrame = (function() {
24     return window.requestAnimationFrame       ||
25            window.webkitRequestAnimationFrame ||
26            window.mozRequestAnimationFrame    ||
27            window.oRequestAnimationFrame      ||
28            window.msRequestAnimationFrame     ||
29            function(callback) {
30              window.setTimeout(callback, 1000 / 60);
31            };
32   })().bind(window);
34   /**
35    * Tracks rendering performance using the gpuBenchmarking.renderingStats API.
36    * @constructor
37    */
38   function GpuBenchmarkingRenderingStats() {
39   }
41   GpuBenchmarkingRenderingStats.prototype.start = function() {
42     this.startTime_ = getTimeMs();
43     this.initialStats_ = this.getRenderingStats_();
44   }
46   GpuBenchmarkingRenderingStats.prototype.stop = function() {
47     this.stopTime_ = getTimeMs();
48     this.finalStats_ = this.getRenderingStats_();
49   }
51   GpuBenchmarkingRenderingStats.prototype.getStartValues = function() {
52     if (!this.initialStats_)
53       throw new Error('Start not called.');
55     if (!this.finalStats_)
56       throw new Error('Stop was not called.');
58     return this.initialStats_;
59   }
61   GpuBenchmarkingRenderingStats.prototype.getEndValues = function() {
62     if (!this.initialStats_)
63       throw new Error('Start not called.');
65     if (!this.finalStats_)
66       throw new Error('Stop was not called.');
68     return this.finalStats_;
69   }
71   GpuBenchmarkingRenderingStats.prototype.getDeltas = function() {
72     if (!this.initialStats_)
73       throw new Error('Start not called.');
75     if (!this.finalStats_)
76       throw new Error('Stop was not called.');
78     var stats = {}
79     for (var key in this.finalStats_)
80       stats[key] = this.finalStats_[key] - this.initialStats_[key];
81     return stats;
82   };
84   GpuBenchmarkingRenderingStats.prototype.getRenderingStats_ = function() {
85     var stats = chrome.gpuBenchmarking.renderingStats();
86     stats.totalTimeInSeconds = getTimeMs() / 1000;
87     return stats;
88   };
90   /**
91    * Tracks rendering performance using requestAnimationFrame.
92    * @constructor
93    */
94   function RafRenderingStats() {
95     this.recording_ = false;
96     this.frameTimes_ = [];
97   }
99   RafRenderingStats.prototype.start = function() {
100     if (this.recording_)
101       throw new Error('Already started.');
102     this.recording_ = true;
103     requestAnimationFrame(this.recordFrameTime_.bind(this));
104   }
106   RafRenderingStats.prototype.stop = function() {
107     this.recording_ = false;
108   }
110   RafRenderingStats.prototype.getStartValues = function() {
111     var results = {};
112     results.numAnimationFrames = 0;
113     results.numFramesSentToScreen = 0;
114     results.droppedFrameCount = 0;
115     return results;
116   }
118   RafRenderingStats.prototype.getEndValues = function() {
119     var results = {};
120     results.numAnimationFrames = this.frameTimes_.length - 1;
121     results.numFramesSentToScreen = results.numAnimationFrames;
122     results.droppedFrameCount = this.getDroppedFrameCount_(this.frameTimes_);
123     return results;
124   }
126   RafRenderingStats.prototype.getDeltas = function() {
127     var endValues = this.getEndValues();
128     endValues.totalTimeInSeconds = (
129         this.frameTimes_[this.frameTimes_.length - 1] -
130         this.frameTimes_[0]) / 1000;
131     return endValues;
132   };
134   RafRenderingStats.prototype.recordFrameTime_ = function(timestamp) {
135     if (!this.recording_)
136       return;
138     this.frameTimes_.push(timestamp);
139     requestAnimationFrame(this.recordFrameTime_.bind(this));
140   };
142   RafRenderingStats.prototype.getDroppedFrameCount_ = function(frameTimes) {
143     var droppedFrameCount = 0;
144     for (var i = 1; i < frameTimes.length; i++) {
145       var frameTime = frameTimes[i] - frameTimes[i-1];
146       if (frameTime > 1000 / 55)
147         droppedFrameCount++;
148     }
149     return droppedFrameCount;
150   };
152   function RenderingStats() {
153     if (window.chrome && chrome.gpuBenchmarking &&
154         chrome.gpuBenchmarking.renderingStats) {
155       return new GpuBenchmarkingRenderingStats();
156     }
157     return new RafRenderingStats();
158   }
160   window.__RenderingStats = RenderingStats;
161 })();