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"; | |
tonyg
2014/02/12 18:01:20
I'd really like to see Telemetry report StatCounte
slamm
2014/02/12 18:37:32
Filed a bug: http://crbug.com/343197
| |
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) { | |
tonyg
2014/02/12 18:01:20
Slamm, we probably need to port this method to Tel
slamm
2014/02/12 18:37:32
This method uses the Chrome Extension API. How wou
| |
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 }); | |
OLD | NEW |