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