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 // Return a list of values for an attribute (e.g. [x.attr for x in array]). | |
28 Array.attrValues = function(array, attr, default_value) { | |
29 var values = []; | |
30 for (var i = 0, len = array.length; i < len; i++) { | |
31 if (attr in array[i]) { | |
32 values.push(array[i][attr]); | |
33 } else { | |
34 values.push(default_value); | |
35 } | |
36 } | |
37 return values; | |
38 }; | |
39 | |
40 // Returns the sum of all values in the array. | |
41 Array.sum = function(array) { | |
42 var sum = 0; | |
43 for (var i = array.length - 1; i >= 0; i--) { | |
44 sum += array[i]; | |
45 } | |
46 return sum; | |
47 }; | |
48 | |
49 // Map WebTiming properties to Result attribute names. | |
50 window.loggedTimings = { | |
51 fetchStart: 'start_load_time', | |
52 domainLookupEnd: 'dns_time', | |
53 connectEnd: 'connect_time', | |
54 responseStart: 'first_byte_time', | |
55 responseEnd: 'last_byte_time', | |
56 domInteractive: 'doc_load_time', | |
57 domContentLoadedEventEnd: 'dcl_time', | |
58 loadEventEnd: 'total_time', | |
59 }; | |
60 | |
61 function Result() { | |
62 this.url = ""; | |
63 this.paint_time = 0; | |
64 this.read_bytes_kb = 0; | |
65 this.write_bytes_kb = 0; | |
66 this.num_requests = 0; | |
67 this.num_connects = 0; | |
68 this.num_sessions = 0; | |
69 // The values of window.loggedTimings are also added as attributes. | |
70 } | |
71 | |
72 // Collect all the results for a session (i.e. different pages). | |
73 function ResultsCollection() { | |
74 var results_ = []; | |
75 var pages_ = []; | |
76 var pageResults_ = {}; | |
77 | |
78 this.addResult = function(result) { | |
79 results_.push(result); | |
80 var url = result.url; | |
81 if (!(url in pageResults_)) { | |
82 pages_.push(url); | |
83 pageResults_[url] = []; | |
84 } | |
85 pageResults_[url].push(result); | |
86 } | |
87 | |
88 this.getPages = function() { | |
89 return pages_; | |
90 } | |
91 | |
92 this.getResults = function() { | |
93 return results_; | |
94 } | |
95 | |
96 this.getTotalTimes = function() { | |
97 var default_time = 0; | |
98 return Array.attrValues(results_, "total_time", default_time); | |
99 } | |
100 } | |
101 | |
102 // Load a url in the default tab and record the time. | |
103 function PageLoader(url, resultReadyCallback) { | |
104 var me_ = this; | |
105 var url_ = url; | |
106 var resultReadyCallback_ = resultReadyCallback; | |
107 | |
108 // If it record mode, wait a little longer for lazy loaded resources. | |
109 var postLoadGraceMs_ = window.isRecordMode ? 5000 : 0; | |
110 var loadInterval_ = window.loadInterval; | |
111 var checkInterval_ = window.checkInterval; | |
112 var timeout_ = window.timeout; | |
113 var maxLoadChecks_ = window.maxLoadChecks; | |
114 | |
115 var preloadFunc_; | |
116 var timeoutId_; | |
117 var isFinished_; | |
118 var result_; | |
119 | |
120 var initialReadBytes_; | |
121 var initialWriteBytes_; | |
122 var initialRequestCount_; | |
123 var initialConnectCount_; | |
124 | |
125 this.result = function() { return result_; }; | |
126 | |
127 this.run = function() { | |
128 timeoutId_ = null; | |
129 isFinished_ = false; | |
130 result_ = null; | |
131 initialReadBytes_ = chrome.benchmarking.counter(kTcpReadBytes); | |
132 initialWriteBytes_ = chrome.benchmarking.counter(kTcpWriteBytes); | |
133 initialRequestCount_ = chrome.benchmarking.counter(kRequestCount); | |
134 initialConnectCount_ = chrome.benchmarking.counter(kConnectCount); | |
135 | |
136 if (me_.preloadFunc_) { | |
137 me_.preloadFunc_(me_.load_); | |
138 } else { | |
139 me_.load_(); | |
140 } | |
141 }; | |
142 | |
143 this.setClearAll = function() { | |
144 me_.preloadFunc_ = me_.clearAll; | |
145 }; | |
146 | |
147 this.setClearConnections = function() { | |
148 me_.preloadFunc_ = me_.clearClearConnections; | |
149 }; | |
150 | |
151 this.clearAll = function(callback) { | |
James Simonsen
2012/04/05 00:07:22
These two clear* methods should be marked private.
| |
152 chrome.tabs.getSelected(null, function(tab) { | |
153 chrome.tabs.update(tab.id, {"url": kWaitUrl}); | |
154 }); | |
155 var isDone = false; | |
156 chrome.browsingData.remove({}, { | |
157 "appcache": true, | |
158 "cache": true, | |
159 "cookies": true, | |
160 "localStorage": true, | |
161 "pluginData": true, | |
162 "webSQL": true | |
163 }, callback); | |
164 chrome.benchmarking.clearHostResolverCache(); | |
165 chrome.benchmarking.clearPredictorCache(); | |
166 chrome.benchmarking.closeConnections(); | |
167 }; | |
168 | |
169 this.clearConnections = function(callback) { | |
170 chrome.benchmarking.closeConnections(); | |
171 callback(); | |
172 }; | |
173 | |
174 this.load_ = function() { | |
175 console.log("LOAD started: " + url_); | |
176 setTimeout(function() { | |
177 chrome.extension.onRequest.addListener(me_.finishLoad); | |
178 timeoutId_ = setTimeout(function() { | |
179 me_.finishLoad({"loadTimes": null, "timing": null}); | |
180 }, timeout_); | |
181 chrome.tabs.getSelected(null, function(tab) { | |
182 chrome.tabs.update(tab.id, {"url": url_}); | |
183 }); | |
184 }, loadInterval_); | |
185 }; | |
186 | |
187 this.finishLoad = function(msg) { | |
James Simonsen
2012/04/05 00:07:22
Should be marked private.
| |
188 if (!isFinished_) { | |
189 isFinished_ = true; | |
190 clearTimeout(timeoutId_); | |
191 chrome.extension.onRequest.removeListener(me_.finishLoad); | |
192 me_.saveResult(msg.loadTimes, msg.timing); | |
193 } | |
194 }; | |
195 | |
196 this.saveResult = function(loadTimes, timing) { | |
James Simonsen
2012/04/05 00:07:22
private
| |
197 result_ = new Result() | |
198 result_.url = url_; | |
199 if (!loadTimes || !timing) { | |
200 console.log("LOAD INCOMPLETE: " + url_); | |
201 } else { | |
202 console.log("LOAD complete: " + url_); | |
203 var baseTime = timing.navigationStart; | |
204 CHECK(baseTime); | |
205 for (var prop in loggedTimings) { | |
206 if (prop in timing) { | |
207 result_[loggedTimings[prop]] = Math.max(0, timing[prop] - baseTime); | |
208 } | |
209 } | |
210 result_.paint_time = Math.max(0, | |
211 Math.round((1000.0 * loadTimes.firstPaintTime) - baseTime)); | |
212 } | |
213 result_.read_bytes_kb = (chrome.benchmarking.counter(kTcpReadBytes) - | |
214 initialReadBytes_) / 1024; | |
215 result_.write_bytes_kb = (chrome.benchmarking.counter(kTcpWriteBytes) - | |
216 initialWriteBytes_) / 1024; | |
217 result_.num_requests = (chrome.benchmarking.counter(kRequestCount) - | |
218 initialRequestCount_); | |
219 result_.num_connects = (chrome.benchmarking.counter(kConnectCount) - | |
220 initialConnectCount_); | |
221 setTimeout(function() { resultReadyCallback_(me_); }, postLoadGraceMs_); | |
222 }; | |
223 } | |
224 | |
225 // Load page sets and prepare performance results. | |
226 function SessionLoader(resultsReadyCallback) { | |
227 var me_ = this; | |
228 var resultsReadyCallback_ = resultsReadyCallback; | |
229 var pageSets_ = benchmarkConfiguration.pageSets; | |
230 var iterations_ = window.iterations; | |
231 var retries_ = window.retries; | |
232 | |
233 var pageLoaders_ = []; | |
234 var resultsCollection_ = new ResultsCollection(); | |
235 var loaderIndex_ = 0; | |
236 var retryIndex_ = 0; | |
237 var iterationIndex_ = 0; | |
238 | |
239 this.run = function() { | |
240 me_.createLoaders(); | |
241 me_.loadPage(); | |
242 } | |
243 | |
244 this.getResultsCollection = function() { | |
245 return resultsCollection_; | |
246 } | |
247 | |
248 this.createLoaders = function() { | |
249 // Each url becomes one benchmark. | |
250 for (var i = 0; i < pageSets_.length; i++) { | |
251 for (var j = 0; j < pageSets_[i].length; j++) { | |
252 // Remove extra space at the beginning or end of a url. | |
253 var url = pageSets_[i][j].trim(); | |
254 // Alert about and ignore blank page which does not get loaded. | |
255 if (url == "about:blank") { | |
256 alert("blank page loaded!"); | |
257 } else if (!url.match(/https?:\/\//)) { | |
258 // Alert about url that is not in scheme http:// or https://. | |
259 alert("Skipping url without http:// or https://: " + url); | |
260 } else { | |
261 var loader = new PageLoader(url, me_.handleResult) | |
262 if (j == 0) { | |
263 // Clear all browser data for the first page in a sub list. | |
264 loader.setClearAll(); | |
265 } else { | |
266 // Otherwise, only clear the connections. | |
267 loader.setClearConnections(); | |
268 } | |
269 pageLoaders_.push(loader); | |
270 } | |
271 } | |
272 } | |
273 } | |
274 | |
275 this.loadPage = function() { | |
276 console.log("LOAD url " + (loaderIndex_ + 1) + " of " + | |
277 pageLoaders_.length + | |
278 ", iteration " + (iterationIndex_ + 1) + " of " + | |
279 iterations_); | |
280 pageLoaders_[loaderIndex_].run(); | |
281 } | |
282 | |
283 this.handleResult = function(loader) { | |
284 var result = loader.result(); | |
285 resultsCollection_.addResult(result); | |
286 var totalTime = result["total_time"] || 0; | |
287 if (!totalTime && retryIndex_ < retries_) { | |
288 retryIndex_++; | |
289 console.log("LOAD retry, " + retryIndex_); | |
290 } else { | |
291 retryIndex_ = 0; | |
292 console.log("RESULTS url " + (loaderIndex_ + 1) + " of " + | |
293 pageLoaders_.length + | |
294 ", iteration " + (iterationIndex_ + 1) + " of " + | |
295 iterations_ + ": " + result["total_time"]); | |
296 loaderIndex_++; | |
297 if (loaderIndex_ >= pageLoaders_.length) { | |
298 iterationIndex_++; | |
299 if (iterationIndex_ < iterations_) { | |
300 loaderIndex_ = 0; | |
301 } else { | |
302 resultsReadyCallback(me_); | |
James Simonsen
2012/04/05 00:07:22
Needs _.
| |
303 return; | |
304 } | |
305 } | |
306 } | |
307 me_.loadPage(); | |
308 } | |
309 } | |
310 | |
311 function AddBenchmarkCallback(callback) { | |
312 window.benchmarkCallback = callback; | |
313 } | |
314 | |
315 function Run() { | |
316 window.checkInterval = 500; | |
317 window.loadInterval = 1000; | |
318 window.timeout = 20000; // max ms before killing page. | |
319 window.retries = 0; | |
320 window.isRecordMode = benchmarkConfiguration.isRecordMode; | |
321 if (window.isRecordMode) { | |
322 window.iterations = 1; | |
323 window.timeout = 40000; | |
324 window.retries = 2; | |
325 } else { | |
326 window.iterations = benchmarkConfiguration["iterations"] || 3; | |
327 } | |
328 var sessionLoader = new SessionLoader(benchmarkCallback); | |
329 console.log("pageSets: " + JSON.stringify(benchmarkConfiguration.pageSets)); | |
330 sessionLoader.run(); | |
331 } | |
332 | |
333 chrome.extension.onConnect.addListener(function(port) { | |
334 port.onMessage.addListener(function(data) { | |
335 if (data.message == "start") { | |
336 window.benchmarkConfiguration = data.benchmark; | |
337 Run() | |
338 } | |
339 }); | |
340 }); | |
OLD | NEW |