Only fsync leveldb's directory when the manifest is being updated.
[chromium-blink-merge.git] / tools / playback_benchmark / playback.js
blob49628512f0eab535738f4491476946499adc417a
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 /**
6 * @fileoverview Playback agent.
7 */
9 var Benchmark = Benchmark || {};
11 /**
12 * Playback agent class.
13 * @param {Object} data Test data.
14 * @constructor
16 Benchmark.Agent = function(data) {
17 this.timeline = data.timeline;
18 this.timelinePosition = 0;
19 this.steps = data.steps;
20 this.stepsPosition = 0;
21 this.randoms = data.randoms;
22 this.randomsPosition = 0;
23 this.ticks = data.ticks;
24 this.ticksPosition = 0;
25 this.delayedScriptElements = {};
26 this.callStackDepth = 0;
27 document.cookie = data.cookie;
28 if (window.innerWidth != data.width || window.innerHeight != data.height) {
29 Benchmark.die('Wrong window size: ' +
30 window.innerWidth + 'x' + window.innerHeight +
31 ' instead of ' + data.width + 'x' + data.height);
33 this.startTime = Benchmark.originals.Date.now();
36 /**
37 * Returns current timeline event.
38 * @return {Object} Event.
40 Benchmark.Agent.prototype.getCurrentEvent = function() {
41 return this.timeline[this.timelinePosition];
44 /**
45 * Returns next recorded event in timeline. If event is the last event in
46 * timeline, posts test results to driver.
47 * @param {Object} event Event that actually happened, should correspond to
48 * the recorded one (used for debug only).
49 * @return {Object} Recorded event from timeline.
51 Benchmark.Agent.prototype.getNextEvent = function(event) {
52 var recordedEvent = this.getCurrentEvent();
53 this.ensureEqual(event, recordedEvent);
54 if (event.type == 'random' || event.type == 'ticks') {
55 recordedEvent.count -= 1;
56 if (recordedEvent.count == 0) {
57 this.timelinePosition += 1;
59 } else {
60 this.timelinePosition += 1;
62 if (this.timelinePosition == this.steps[this.stepsPosition][1]) {
63 var score = Benchmark.originals.Date.now() - this.startTime;
64 Benchmark.reportScore(score);
66 return recordedEvent;
69 /**
70 * Checks if two events can be considered equal. Throws exception if events
71 * differ.
72 * @param {Object} event Event that actually happened.
73 * @param {Object} recordedEvent Event taken from timeline.
75 Benchmark.Agent.prototype.ensureEqual = function(event, recordedEvent) {
76 var equal = false;
77 if (event.type == recordedEvent.type &&
78 event.type in Benchmark.eventPropertiesMap) {
79 equal = true;
80 var properties = Benchmark.eventPropertiesMap[event.type];
81 for (var i = 0; i < properties.length && equal; ++i)
82 if (event[properties[i]] != recordedEvent[properties[i]])
83 equal = false;
85 if (!equal) {
86 Benchmark.die('unexpected event: ' + JSON.stringify(event) +
87 ' instead of ' + JSON.stringify(recordedEvent));
91 /**
92 * Gets next event from timeline and returns its identifier.
93 * @param {Object} event Object with event information.
94 * @return {number} Event identifier.
96 Benchmark.Agent.prototype.createAsyncEvent = function(event) {
97 return this.getNextEvent(event).id;
101 * Stores callback to be invoked according to timeline order.
102 * @param {number} eventId 'Parent' event identifier.
103 * @param {function} callback Callback.
105 Benchmark.Agent.prototype.fireAsyncEvent = function(eventId, callback) {
106 var event = this.timeline[eventId];
107 if (!event.callbackReference) return;
108 this.timeline[event.callbackReference].callback = callback;
109 this.fireSome();
113 * Ensures that things are happening according to recorded timeline.
114 * @param {number} eventId Identifier of cancelled event.
116 Benchmark.Agent.prototype.cancelAsyncEvent = function(eventId) {
117 this.getNextEvent({type: 'cancel', reference: eventId});
121 * Checks if script isn't going to be executed too early and delays script
122 * execution if necessary.
123 * @param {number} scriptId Unique script identifier.
124 * @param {HTMLElement} doc Document element.
125 * @param {boolean} inlined Indicates whether script is a text block in the page
126 * or resides in a separate file.
127 * @param {string} src Script url (if script is not inlined).
129 Benchmark.Agent.prototype.readyToExecuteScript = function(scriptId, doc,
130 inlined, src) {
131 var event = this.getCurrentEvent();
132 if (event.type == 'willExecuteScript' && event.scriptId == scriptId) {
133 this.timelinePosition += 1;
134 return true;
136 var element;
137 var elements = doc.getElementsByTagName('script');
138 for (var i = 0, el; (el = elements[i]) && !element; ++i) {
139 if (inlined) {
140 if (el.src) continue;
141 var text = el.textContent;
142 if (scriptId == text.substring(2, text.indexOf("*/")))
143 element = elements[i];
144 } else {
145 if (!el.src) continue;
146 if (el.src.indexOf(src) != -1 || src.indexOf(el.src) != -1) {
147 element = el;
151 if (!element) {
152 Benchmark.die('script element not found', scriptId, src);
154 for (var el2 = element; el2; el2 = el2.parentElement) {
155 if (el2.onload) {
156 console.log('found', el2);
159 this.delayedScriptElements[scriptId] = element;
160 return false;
164 * Ensures that things are happening according to recorded timeline.
165 * @param {Object} event Object with event information.
167 Benchmark.Agent.prototype.didExecuteScript = function(scriptId ) {
168 this.getNextEvent({type: 'didExecuteScript', scriptId: scriptId});
169 this.fireSome();
173 * Invokes async events' callbacks according to timeline order.
175 Benchmark.Agent.prototype.fireSome = function() {
176 while (this.timelinePosition < this.timeline.length) {
177 var event = this.getCurrentEvent();
178 if (event.type == 'willFire') {
179 if(!event.callback) break;
180 this.timelinePosition += 1;
181 this.callStackDepth += 1;
182 event.callback();
183 this.callStackDepth -= 1;
184 this.getNextEvent({type: 'didFire', reference: event.reference});
185 } else if (event.type == 'willExecuteScript') {
186 if (event.scriptId in this.delayedScriptElements) {
187 var element = this.delayedScriptElements[event.scriptId];
188 var parent = element.parentElement;
189 var cloneElement = element.cloneNode();
190 delete this.delayedScriptElements[event.scriptId];
191 parent.replaceChild(cloneElement, element);
193 break;
194 } else if (this.callStackDepth > 0) {
195 break;
196 } else {
197 Benchmark.die('unexpected event in fireSome:' + JSON.stringify(event));
203 * Returns recorded random.
204 * @return {number} Recorded random.
206 Benchmark.Agent.prototype.random = function() {
207 this.getNextEvent({type: 'random'});
208 return this.randoms[this.randomsPosition++];
212 * Returns recorded ticks.
213 * @return {number} Recorded ticks.
215 Benchmark.Agent.prototype.dateNow = function(event) {
216 this.getNextEvent({type: 'ticks'});
217 return this.ticks[this.ticksPosition++];
221 * Event type -> property list mapping used for matching events.
222 * @const
224 Benchmark.eventPropertiesMap = {
225 'timeout': ['timeout'],
226 'request': ['url'],
227 'addEventListener': ['eventType'],
228 'script load': ['src'],
229 'willExecuteScript': ['scriptId'],
230 'didExecuteScript': ['scriptId'],
231 'willFire': ['reference'],
232 'didFire': ['reference'],
233 'cancel': ['reference'],
234 'random': [],
235 'ticks': []
239 * Agent used by native window functions wrappers.
241 Benchmark.agent = new Benchmark.Agent(Benchmark.data);
244 * Playback flag.
245 * @const
247 Benchmark.playback = true;
249 Benchmark.reportScore = function(score) {
250 Benchmark.score = score;
253 Benchmark.originals.addEventListenerToWindow.call(
254 window, 'message', function(event) {
255 if (Benchmark.score) {
256 event.source.postMessage(Benchmark.score, event.origin);
258 }, false);