Upstream version 5.34.98.0
[platform/framework/web/crosswalk.git] / src / tools / page_cycler / webpagereplay / extension / background.js
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.
4
5 // start.js sends a "start" message to set this.
6 window.benchmarkConfiguration = {};
7
8 // The callback (e.g. report writer) is set via AddBenchmarckCallback.
9 window.benchmarkCallback;
10
11 // Url to load before loading target page.
12 var kWaitUrl = "http://wprwprwpr/web-page-replay-generate-200";
13
14 // Constant StatCounter Names
15 var kTcpReadBytes = "tcp.read_bytes";
16 var kTcpWriteBytes = "tcp.write_bytes";
17 var kRequestCount = "HttpNetworkTransaction.Count";
18 var kConnectCount = "tcp.connect";
19
20 function CHECK(expr, comment) {
21   if (!expr) {
22     console.log(comment);
23     alert(comment);
24   }
25 }
26
27 function Result() {
28   var me_ = this;
29   this.url = "";
30   this.firstPaintTime = 0;
31   this.readBytesKB = 0;
32   this.writeBytesKB = 0;
33   this.numRequests = 0;
34   this.numConnects = 0;
35   this.timing = {};  // window.performance.timing
36   this.getTotalTime = function() {
37     var totalTime = 0
38     if (me_.timing.navigationStart && me_.timing.loadEventEnd) {
39       totalTime = me_.timing.loadEventEnd - me_.timing.navigationStart;
40     }
41     CHECK(totalTime >= 0);
42     return totalTime;
43   }
44 }
45
46 // Collect all the results for a session (i.e. different pages).
47 function ResultsCollection() {
48   var results_ = [];
49   var pages_ = [];
50   var pageResults_ = {};
51
52   this.addResult = function(result) {
53     results_.push(result);
54     var url = result.url;
55     if (!(url in pageResults_)) {
56       pages_.push(url);
57       pageResults_[url] = [];
58     }
59     pageResults_[url].push(result);
60   }
61
62   this.getPages = function() {
63     return pages_;
64   }
65
66   this.getResults = function() {
67     return results_;
68   }
69
70   this.getTotalTimes = function() {
71     return results_.map(function (t) { return t.getTotalTime(); });
72   }
73 }
74
75 // Load a url in the default tab and record the time.
76 function PageLoader(url, resultReadyCallback) {
77   var me_ = this;
78   var url_ = url;
79   var resultReadyCallback_ = resultReadyCallback;
80
81   // If it record mode, wait a little longer for lazy loaded resources.
82   var postLoadGraceMs_ = window.isRecordMode ? 5000 : 0;
83   var loadInterval_ = window.loadInterval;
84   var checkInterval_ = window.checkInterval;
85   var timeout_ = window.timeout;
86   var maxLoadChecks_ = window.maxLoadChecks;
87
88   var preloadFunc_;
89   var timeoutId_;
90   var isFinished_;
91   var result_;
92
93   var initialReadBytes_;
94   var initialWriteBytes_;
95   var initialRequestCount_;
96   var initialConnectCount_;
97
98   this.result = function() { return result_; };
99
100   this.run = function() {
101     timeoutId_ = null;
102     isFinished_ = false;
103     result_ = null;
104     initialReadBytes_ = chrome.benchmarking.counter(kTcpReadBytes);
105     initialWriteBytes_ = chrome.benchmarking.counter(kTcpWriteBytes);
106     initialRequestCount_ = chrome.benchmarking.counter(kRequestCount);
107     initialConnectCount_ = chrome.benchmarking.counter(kConnectCount);
108
109     if (me_.preloadFunc_) {
110       me_.preloadFunc_(me_.load_);
111     } else {
112       me_.load_();
113     }
114   };
115
116   this.setClearAll = function() {
117     me_.preloadFunc_ = me_.clearAll_;
118   };
119
120   this.setClearConnections = function() {
121     me_.preloadFunc_ = me_.clearConnections_;
122   };
123
124   this.clearAll_ = function(callback) {
125     chrome.tabs.getSelected(null, function(tab) {
126         chrome.tabs.update(tab.id, {"url": kWaitUrl}, function() {
127             chrome.benchmarking.clearHostResolverCache();
128             chrome.benchmarking.clearPredictorCache();
129             chrome.benchmarking.closeConnections();
130             var dataToRemove = {
131                 "appcache": true,
132                 "cache": true,
133                 "cookies": true,
134                 "downloads": true,
135                 "fileSystems": true,
136                 "formData": true,
137                 "history": true,
138                 "indexedDB": true,
139                 "localStorage": true,
140                 "passwords": true,
141                 "pluginData": true,
142                 "webSQL": true
143             };
144             // Add any items new to the API.
145             for (var prop in chrome.browsingData) {
146               var dataName = prop.replace("remove", "");
147               if (dataName && dataName != prop) {
148                 dataName = dataName.charAt(0).toLowerCase() +
149                     dataName.substr(1);
150                 if (!dataToRemove.hasOwnProperty(dataName)) {
151                   console.log("New browsingData API item: " + dataName);
152                   dataToRemove[dataName] = true;
153                 }
154               }
155             }
156             chrome.browsingData.remove({}, dataToRemove, callback);
157           });
158       });
159   };
160
161   this.clearConnections_ = function(callback) {
162     chrome.benchmarking.closeConnections();
163     callback();
164   };
165
166   this.load_ = function() {
167     console.log("LOAD started: " + url_);
168     setTimeout(function() {
169       chrome.extension.onRequest.addListener(me_.finishLoad_);
170       timeoutId_ = setTimeout(function() {
171           me_.finishLoad_({"loadTimes": null, "timing": null});
172       }, timeout_);
173       chrome.tabs.getSelected(null, function(tab) {
174           chrome.tabs.update(tab.id, {"url": url_});
175       });
176     }, loadInterval_);
177   };
178
179   this.finishLoad_ = function(msg) {
180     if (!isFinished_) {
181       isFinished_ = true;
182       clearTimeout(timeoutId_);
183       chrome.extension.onRequest.removeListener(me_.finishLoad_);
184       me_.saveResult_(msg.loadTimes, msg.timing);
185     }
186   };
187
188   this.saveResult_ = function(loadTimes, timing) {
189     result_ = new Result()
190     result_.url = url_;
191     if (!loadTimes || !timing) {
192       console.log("LOAD INCOMPLETE: " + url_);
193     } else {
194       console.log("LOAD complete: " + url_);
195       result_.timing = timing;
196       var baseTime = timing.navigationStart;
197       CHECK(baseTime);
198       result_.firstPaintTime = Math.max(0,
199           Math.round((1000.0 * loadTimes.firstPaintTime) - baseTime));
200     }
201     result_.readBytesKB = (chrome.benchmarking.counter(kTcpReadBytes) -
202                            initialReadBytes_) / 1024;
203     result_.writeBytesKB = (chrome.benchmarking.counter(kTcpWriteBytes) -
204                             initialWriteBytes_) / 1024;
205     result_.numRequests = (chrome.benchmarking.counter(kRequestCount) -
206                            initialRequestCount_);
207     result_.numConnects = (chrome.benchmarking.counter(kConnectCount) -
208                            initialConnectCount_);
209     setTimeout(function() { resultReadyCallback_(me_); }, postLoadGraceMs_);
210   };
211 }
212
213 // Load page sets and prepare performance results.
214 function SessionLoader(resultsReadyCallback) {
215   var me_ = this;
216   var resultsReadyCallback_ = resultsReadyCallback;
217   var pageSets_ = benchmarkConfiguration.pageSets;
218   var iterations_ = window.iterations;
219   var retries_ = window.retries;
220
221   var pageLoaders_ = [];
222   var resultsCollection_ = new ResultsCollection();
223   var loaderIndex_ = 0;
224   var retryIndex_ = 0;
225   var iterationIndex_ = 0;
226
227   this.run = function() {
228     me_.createLoaders_();
229     me_.loadPage_();
230   }
231
232   this.getResultsCollection = function() {
233     return resultsCollection_;
234   }
235
236   this.createLoaders_ = function() {
237     // Each url becomes one benchmark.
238     for (var i = 0; i < pageSets_.length; i++) {
239       for (var j = 0; j < pageSets_[i].length; j++) {
240         // Remove extra space at the beginning or end of a url.
241         var url = pageSets_[i][j].trim();
242         // Alert about and ignore blank page which does not get loaded.
243         if (url == "about:blank") {
244           alert("blank page loaded!");
245         } else if (!url.match(/https?:\/\//)) {
246           // Alert about url that is not in scheme http:// or https://.
247           alert("Skipping url without http:// or https://: " + url);
248         } else {
249           var loader = new PageLoader(url, me_.handleResult_)
250           if (j == 0) {
251             // Clear all browser data for the first page in a sub list.
252             loader.setClearAll();
253           } else {
254             // Otherwise, only clear the connections.
255             loader.setClearConnections();
256           }
257           pageLoaders_.push(loader);
258         }
259       }
260     }
261   }
262
263   this.loadPage_ = function() {
264     console.log("LOAD url " + (loaderIndex_ + 1) + " of " +
265                 pageLoaders_.length +
266                 ", iteration " + (iterationIndex_ + 1) + " of " +
267                 iterations_);
268     pageLoaders_[loaderIndex_].run();
269   }
270
271   this.handleResult_ = function(loader) {
272     var result = loader.result();
273     resultsCollection_.addResult(result);
274     var totalTime = result.getTotalTime();
275     if (!totalTime && retryIndex_ < retries_) {
276       retryIndex_++;
277       console.log("LOAD retry, " + retryIndex_);
278     } else {
279       retryIndex_ = 0;
280       console.log("RESULTS url " + (loaderIndex_ + 1) + " of " +
281                   pageLoaders_.length +
282                   ", iteration " + (iterationIndex_ + 1) + " of " +
283                   iterations_ + ": " + totalTime);
284       loaderIndex_++;
285       if (loaderIndex_ >= pageLoaders_.length) {
286         iterationIndex_++;
287         if (iterationIndex_ < iterations_) {
288           loaderIndex_ = 0;
289         } else {
290           resultsReadyCallback_(me_);
291           return;
292         }
293       }
294     }
295     me_.loadPage_();
296   }
297 }
298
299 function AddBenchmarkCallback(callback) {
300   window.benchmarkCallback = callback;
301 }
302
303 function Run() {
304   window.checkInterval = 500;
305   window.loadInterval = 1000;
306   window.timeout = 20000;  // max ms before killing page.
307   window.retries = 0;
308   window.isRecordMode = benchmarkConfiguration.isRecordMode;
309   if (window.isRecordMode) {
310     window.iterations = 1;
311     window.timeout = 40000;
312     window.retries = 2;
313   } else {
314     window.iterations = benchmarkConfiguration["iterations"] || 3;
315   }
316   var sessionLoader = new SessionLoader(benchmarkCallback);
317   console.log("pageSets: " + JSON.stringify(benchmarkConfiguration.pageSets));
318   sessionLoader.run();
319 }
320
321 chrome.runtime.onConnect.addListener(function(port) {
322   port.onMessage.addListener(function(data) {
323     if (data.message == "start") {
324       window.benchmarkConfiguration = data.benchmark;
325       Run()
326     }
327   });
328 });