Chromium Code Reviews| 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 |