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"; | |
|
tonyg
2012/04/13 14:32:21
This extension is very closely coupled with WPR. I
slamm_google
2012/04/13 23:43:36
The extension is what couples WPR and the page cyc
tonyg
2012/04/16 15:34:32
OK, fair enough. I'm just sad to see duplication b
slamm_google
2012/04/16 23:43:07
Perhaps it could be made into a generic WPR extens
James Simonsen
2012/04/17 03:30:19
The only thing I really liked about the old one we
tonyg
2012/04/17 11:04:45
Makes sense. I like the idea of porting those scen
| |
| 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. | |
|
tonyg
2012/04/13 14:32:21
Why bother with this map. Wouldn't it be more clea
slamm_google
2012/04/13 23:43:36
I copied this from the perftracker code. A better
tonyg
2012/04/16 15:34:32
Yeah, I like the idea of dropping the map.
The pe
slamm_google
2012/04/16 23:43:07
The map is gone. The code is much easier to unders
| |
| 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_.clearConnections_; | |
| 149 }; | |
| 150 | |
| 151 this.clearAll_ = function(callback) { | |
| 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, | |
|
tonyg
2012/04/13 14:32:21
Is there a way to tell browsingData to remove ever
slamm_google
2012/04/13 23:43:36
I did not see a way. I even left a few things off
tonyg
2012/04/16 15:34:32
If there's no way to do them all, at least do as m
slamm_google
2012/04/16 23:43:07
I added the full list again and they work fine --
| |
| 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) { | |
| 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) { | |
| 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_); | |
| 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 |