| OLD | NEW |
| 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 /** | 5 /** |
| 6 * @fileoverview Profiler processor is used to process log file produced | 6 * @fileoverview Profiler processor is used to process log file produced |
| 7 * by V8 and produce an internal profile representation which is used | 7 * by V8 and produce an internal profile representation which is used |
| 8 * for building profile views in 'Profiles' tab. | 8 * for building profile views in 'Profiles' tab. |
| 9 */ | 9 */ |
| 10 goog.provide('devtools.profiler.Processor'); | 10 goog.provide('devtools.profiler.Processor'); |
| 11 | 11 |
| 12 | 12 |
| 13 /** | 13 /** |
| 14 * Creates a Profile View builder object compatible with WebKit Profiler UI. |
| 15 * |
| 16 * @param {number} samplingRate Number of ms between profiler ticks. |
| 17 * @constructor |
| 18 */ |
| 19 devtools.profiler.WebKitViewBuilder = function(samplingRate) { |
| 20 devtools.profiler.ViewBuilder.call(this, samplingRate); |
| 21 }; |
| 22 goog.inherits(devtools.profiler.WebKitViewBuilder, |
| 23 devtools.profiler.ViewBuilder); |
| 24 |
| 25 |
| 26 /** |
| 27 * @override |
| 28 */ |
| 29 devtools.profiler.WebKitViewBuilder.prototype.createViewNode = function( |
| 30 funcName, totalTime, selfTime, head) { |
| 31 return new devtools.profiler.WebKitViewNode( |
| 32 funcName, totalTime, selfTime, head); |
| 33 }; |
| 34 |
| 35 |
| 36 /** |
| 37 * Constructs a Profile View node object for displaying in WebKit Profiler UI. |
| 38 * |
| 39 * @param {string} internalFuncName A fully qualified function name. |
| 40 * @param {number} totalTime Amount of time that application spent in the |
| 41 * corresponding function and its descendants (not that depending on |
| 42 * profile they can be either callees or callers.) |
| 43 * @param {number} selfTime Amount of time that application spent in the |
| 44 * corresponding function only. |
| 45 * @param {devtools.profiler.ProfileView.Node} head Profile view head. |
| 46 * @constructor |
| 47 */ |
| 48 devtools.profiler.WebKitViewNode = function( |
| 49 internalFuncName, totalTime, selfTime, head) { |
| 50 devtools.profiler.ProfileView.Node.call(this, |
| 51 internalFuncName, totalTime, selfTime, head); |
| 52 this.initFuncInfo_(); |
| 53 this.callUID = internalFuncName; |
| 54 }; |
| 55 goog.inherits(devtools.profiler.WebKitViewNode, |
| 56 devtools.profiler.ProfileView.Node); |
| 57 |
| 58 |
| 59 /** |
| 60 * RegEx for stripping V8's prefixes of compiled functions. |
| 61 */ |
| 62 devtools.profiler.WebKitViewNode.FUNC_NAME_STRIP_RE = |
| 63 /^(?:LazyCompile|Function): (.*)$/; |
| 64 |
| 65 |
| 66 /** |
| 67 * RegEx for extracting script source URL and line number. |
| 68 */ |
| 69 devtools.profiler.WebKitViewNode.FUNC_NAME_PARSE_RE = |
| 70 /^([^ ]+) (.*):(\d+)( \{\d+\})?$/; |
| 71 |
| 72 |
| 73 /** |
| 74 * Inits 'functionName', 'url', and 'lineNumber' fields using 'internalFuncName' |
| 75 * field. |
| 76 * @private |
| 77 */ |
| 78 devtools.profiler.WebKitViewNode.prototype.initFuncInfo_ = function() { |
| 79 var nodeAlias = devtools.profiler.WebKitViewNode; |
| 80 this.functionName = this.internalFuncName; |
| 81 |
| 82 var strippedName = nodeAlias.FUNC_NAME_STRIP_RE.exec(this.functionName); |
| 83 if (strippedName) { |
| 84 this.functionName = strippedName[1]; |
| 85 } |
| 86 |
| 87 var parsedName = nodeAlias.FUNC_NAME_PARSE_RE.exec(this.functionName); |
| 88 if (parsedName) { |
| 89 this.functionName = parsedName[1]; |
| 90 if (parsedName[4]) { |
| 91 this.functionName += parsedName[4]; |
| 92 } |
| 93 this.url = parsedName[2]; |
| 94 this.lineNumber = parsedName[3]; |
| 95 } else { |
| 96 this.url = ''; |
| 97 this.lineNumber = 0; |
| 98 } |
| 99 }; |
| 100 |
| 101 |
| 102 /** |
| 14 * Ancestor of a profile object that leaves out only JS-related functions. | 103 * Ancestor of a profile object that leaves out only JS-related functions. |
| 15 * @constructor | 104 * @constructor |
| 16 */ | 105 */ |
| 17 devtools.profiler.JsProfile = function() { | 106 devtools.profiler.JsProfile = function() { |
| 18 devtools.profiler.Profile.call(this); | 107 devtools.profiler.Profile.call(this); |
| 19 }; | 108 }; |
| 20 goog.inherits(devtools.profiler.JsProfile, devtools.profiler.Profile); | 109 goog.inherits(devtools.profiler.JsProfile, devtools.profiler.Profile); |
| 21 | 110 |
| 22 | 111 |
| 23 /** | 112 /** |
| 113 * RegExp that leaves only JS functions. |
| 24 * @type {RegExp} | 114 * @type {RegExp} |
| 25 */ | 115 */ |
| 26 devtools.profiler.JsProfile.JS_FUNC_RE = /^(LazyCompile|Function|Script):/; | 116 devtools.profiler.JsProfile.JS_FUNC_RE = /^(LazyCompile|Function|Script):/; |
| 27 | 117 |
| 118 /** |
| 119 * RegExp that filters out native code (ending with "native src.js:xxx"). |
| 120 * @type {RegExp} |
| 121 */ |
| 122 devtools.profiler.JsProfile.JS_NATIVE_FUNC_RE = /\ native\ \w+\.js:\d+$/; |
| 123 |
| 124 /** |
| 125 * RegExp that filters out native scripts. |
| 126 * @type {RegExp} |
| 127 */ |
| 128 devtools.profiler.JsProfile.JS_NATIVE_SCRIPT_RE = /^Script:\ native/; |
| 129 |
| 130 /** |
| 131 * RegExp that filters out devtools functions. See inject.js and |
| 132 * inject_dispatch.js. |
| 133 * @type {RegExp} |
| 134 */ |
| 135 devtools.profiler.JsProfile.JS_DEVTOOLS_FUNC_RE = |
| 136 /^\w+:\ devtools(\$\$|\.Injected)/; |
| 137 |
| 28 | 138 |
| 29 /** | 139 /** |
| 30 * @override | 140 * @override |
| 31 */ | 141 */ |
| 32 devtools.profiler.JsProfile.prototype.skipThisFunction = function(name) { | 142 devtools.profiler.JsProfile.prototype.skipThisFunction = function(name) { |
| 33 return !devtools.profiler.JsProfile.JS_FUNC_RE.test(name); | 143 return !devtools.profiler.JsProfile.JS_FUNC_RE.test(name) || |
| 144 // To profile V8's natives comment out two lines below and '||' above. |
| 145 devtools.profiler.JsProfile.JS_NATIVE_FUNC_RE.test(name) || |
| 146 devtools.profiler.JsProfile.JS_NATIVE_SCRIPT_RE.test(name) || |
| 147 devtools.profiler.JsProfile.JS_DEVTOOLS_FUNC_RE.test(name); |
| 34 }; | 148 }; |
| 35 | 149 |
| 36 | 150 |
| 37 /** | 151 /** |
| 38 * Profiler processor. Consumes profiler log and builds profile views. | 152 * Profiler processor. Consumes profiler log and builds profile views. |
| 153 * |
| 154 * @param {function(devtools.profiler.ProfileView)} newProfileCallback Callback |
| 155 * that receives a new processed profile. |
| 39 * @constructor | 156 * @constructor |
| 40 */ | 157 */ |
| 41 devtools.profiler.Processor = function() { | 158 devtools.profiler.Processor = function() { |
| 42 /** | 159 devtools.profiler.LogReader.call(this, { |
| 43 * Current profile. | 160 'code-creation': { |
| 161 parsers: [null, this.createAddressParser('code'), parseInt, null], |
| 162 processor: this.processCodeCreation_, backrefs: true, |
| 163 needsProfile: true }, |
| 164 'code-move': { parsers: [this.createAddressParser('code'), |
| 165 this.createAddressParser('code-move-to')], |
| 166 processor: this.processCodeMove_, backrefs: true, |
| 167 needsProfile: true }, |
| 168 'code-delete': { parsers: [this.createAddressParser('code')], |
| 169 processor: this.processCodeDelete_, backrefs: true, |
| 170 needsProfile: true }, |
| 171 'tick': { parsers: [this.createAddressParser('code'), |
| 172 this.createAddressParser('stack'), parseInt, 'var-args'], |
| 173 processor: this.processTick_, backrefs: true, needProfile: true }, |
| 174 'profiler': { parsers: [null, 'var-args'], |
| 175 processor: this.processProfiler_, needsProfile: false }, |
| 176 'heap-sample-begin': { parsers: [null, null, parseInt], |
| 177 processor: this.processHeapSampleBegin_ }, |
| 178 'heap-sample-stats': { parsers: [null, null, parseInt, parseInt], |
| 179 processor: this.processHeapSampleStats_ }, |
| 180 'heap-sample-item': { parsers: [null, parseInt, parseInt], |
| 181 processor: this.processHeapSampleItem_ }, |
| 182 'heap-js-cons-item': { parsers: [null, parseInt, parseInt], |
| 183 processor: this.processHeapJsConsItem_ }, |
| 184 'heap-sample-end': { parsers: [null, null], |
| 185 processor: this.processHeapSampleEnd_ }, |
| 186 // Not used in DevTools Profiler. |
| 187 'shared-library': null, |
| 188 // Obsolete row types. |
| 189 'code-allocate': null, |
| 190 'begin-code-region': null, |
| 191 'end-code-region': null}); |
| 192 |
| 193 |
| 194 /** |
| 195 * Callback that is called when a new profile is encountered in the log. |
| 196 * @type {function()} |
| 197 */ |
| 198 this.startedProfileProcessing_ = null; |
| 199 |
| 200 /** |
| 201 * Callback that is called periodically to display processing status. |
| 202 * @type {function()} |
| 203 */ |
| 204 this.profileProcessingStatus_ = null; |
| 205 |
| 206 /** |
| 207 * Callback that is called when a profile has been processed and is ready |
| 208 * to be shown. |
| 209 * @type {function(devtools.profiler.ProfileView)} |
| 210 */ |
| 211 this.finishedProfileProcessing_ = null; |
| 212 |
| 213 /** |
| 214 * The current profile. |
| 44 * @type {devtools.profiler.JsProfile} | 215 * @type {devtools.profiler.JsProfile} |
| 45 */ | 216 */ |
| 46 this.profile_ = new devtools.profiler.JsProfile(); | 217 this.currentProfile_ = null; |
| 47 | 218 |
| 48 /** | 219 /** |
| 49 * Builder of profile views. | 220 * Builder of profile views. Created during "profiler,begin" event processing. |
| 50 * @type {devtools.profiler.ViewBuilder} | 221 * @type {devtools.profiler.WebKitViewBuilder} |
| 51 */ | 222 */ |
| 52 this.viewBuilder_ = new devtools.profiler.ViewBuilder(1); | 223 this.viewBuilder_ = null; |
| 53 | 224 |
| 54 /** | 225 /** |
| 55 * Next profile id. | 226 * Next profile id. |
| 56 * @type {number} | 227 * @type {number} |
| 57 */ | 228 */ |
| 58 this.profileId_ = 1; | 229 this.profileId_ = 1; |
| 59 }; | 230 |
| 60 | 231 /** |
| 61 | 232 * Counter for processed ticks. |
| 62 /** | 233 * @type {number} |
| 63 * A dispatch table for V8 profiler event log records. | 234 */ |
| 64 * @private | 235 this.ticksCount_ = 0; |
| 65 */ | 236 |
| 66 devtools.profiler.Processor.RecordsDispatch_ = { | 237 /** |
| 67 'code-creation': { parsers: [null, parseInt, parseInt, null], | 238 * The current heap snapshot. |
| 68 processor: 'processCodeCreation_' }, | 239 * @type {string} |
| 69 'code-move': { parsers: [parseInt, parseInt], | 240 */ |
| 70 processor: 'processCodeMove_' }, | 241 this.currentHeapSnapshot_ = null; |
| 71 'code-delete': { parsers: [parseInt], processor: 'processCodeDelete_' }, | 242 |
| 72 'tick': { parsers: [parseInt, parseInt, parseInt, 'var-args'], | 243 /** |
| 73 processor: 'processTick_' }, | 244 * Next heap snapshot id. |
| 74 // Not used in DevTools Profiler. | 245 * @type {number} |
| 75 'profiler': null, | 246 */ |
| 76 'shared-library': null, | 247 this.heapSnapshotId_ = 1; |
| 77 // Obsolete row types. | 248 }; |
| 78 'code-allocate': null, | 249 goog.inherits(devtools.profiler.Processor, devtools.profiler.LogReader); |
| 79 'begin-code-region': null, | 250 |
| 80 'end-code-region': null | 251 |
| 81 }; | 252 /** |
| 82 | 253 * @override |
| 83 | 254 */ |
| 84 /** | 255 devtools.profiler.Processor.prototype.printError = function(str) { |
| 85 * Processes a portion of V8 profiler event log. | 256 debugPrint(str); |
| 257 }; |
| 258 |
| 259 |
| 260 /** |
| 261 * @override |
| 262 */ |
| 263 devtools.profiler.Processor.prototype.skipDispatch = function(dispatch) { |
| 264 return dispatch.needsProfile && this.currentProfile_ == null; |
| 265 }; |
| 266 |
| 267 |
| 268 /** |
| 269 * Sets profile processing callbacks. |
| 86 * | 270 * |
| 87 * @param {string} chunk A portion of log. | 271 * @param {function()} started Started processing callback. |
| 88 */ | 272 * @param {function(devtools.profiler.ProfileView)} finished Finished |
| 89 devtools.profiler.Processor.prototype.processLogChunk = function(chunk) { | 273 * processing callback. |
| 90 this.processLog_(chunk.split('\n')); | 274 */ |
| 91 }; | 275 devtools.profiler.Processor.prototype.setCallbacks = function( |
| 92 | 276 started, processing, finished) { |
| 93 | 277 this.startedProfileProcessing_ = started; |
| 94 /** | 278 this.profileProcessingStatus_ = processing; |
| 95 * Processes a log lines. | 279 this.finishedProfileProcessing_ = finished; |
| 280 }; |
| 281 |
| 282 |
| 283 /** |
| 284 * An address for the fake "(program)" entry. WebKit's visualisation |
| 285 * has assumptions on how the top of the call tree should look like, |
| 286 * and we need to add a fake entry as the topmost function. This |
| 287 * address is chosen because it's the end address of the first memory |
| 288 * page, which is never used for code or data, but only as a guard |
| 289 * page for catching AV errors. |
| 96 * | 290 * |
| 97 * @param {Array<string>} lines Log lines. | 291 * @type {number} |
| 98 * @private | 292 */ |
| 99 */ | 293 devtools.profiler.Processor.PROGRAM_ENTRY = 0xffff; |
| 100 devtools.profiler.Processor.prototype.processLog_ = function(lines) { | 294 /** |
| 101 var csvParser = new devtools.profiler.CsvParser(); | 295 * @type {string} |
| 102 try { | 296 */ |
| 103 for (var i = 0, n = lines.length; i < n; ++i) { | 297 devtools.profiler.Processor.PROGRAM_ENTRY_STR = '0xffff'; |
| 104 var line = lines[i]; | 298 |
| 105 if (!line) { | 299 |
| 106 continue; | 300 /** |
| 301 * Sets new profile callback. |
| 302 * @param {function(devtools.profiler.ProfileView)} callback Callback function. |
| 303 */ |
| 304 devtools.profiler.Processor.prototype.setNewProfileCallback = function( |
| 305 callback) { |
| 306 this.newProfileCallback_ = callback; |
| 307 }; |
| 308 |
| 309 |
| 310 devtools.profiler.Processor.prototype.processProfiler_ = function( |
| 311 state, params) { |
| 312 var processingInterval = null; |
| 313 switch (state) { |
| 314 case 'resume': |
| 315 if (this.currentProfile_ == null) { |
| 316 this.currentProfile_ = new devtools.profiler.JsProfile(); |
| 317 // see the comment for devtools.profiler.Processor.PROGRAM_ENTRY |
| 318 this.currentProfile_.addCode( |
| 319 'Function', '(program)', |
| 320 devtools.profiler.Processor.PROGRAM_ENTRY, 1); |
| 321 if (this.startedProfileProcessing_) { |
| 322 this.startedProfileProcessing_(); |
| 323 } |
| 324 this.ticksCount_ = 0; |
| 325 var self = this; |
| 326 if (this.profileProcessingStatus_) { |
| 327 processingInterval = window.setInterval( |
| 328 function() { self.profileProcessingStatus_(self.ticksCount_); }, |
| 329 1000); |
| 330 } |
| 107 } | 331 } |
| 108 var fields = csvParser.parseLine(line); | 332 break; |
| 109 this.dispatchLogRow_(fields); | 333 case 'pause': |
| 110 } | 334 if (this.currentProfile_ != null) { |
| 111 } catch (e) { | 335 window.clearInterval(processingInterval); |
| 112 debugPrint('line ' + (i + 1) + ': ' + (e.message || e)); | 336 if (this.finishedProfileProcessing_) { |
| 113 throw e; | 337 this.finishedProfileProcessing_(this.createProfileForView()); |
| 338 } |
| 339 this.currentProfile_ = null; |
| 340 } |
| 341 break; |
| 342 case 'begin': |
| 343 var samplingRate = NaN; |
| 344 if (params.length > 0) { |
| 345 samplingRate = parseInt(params[0]); |
| 346 } |
| 347 if (isNaN(samplingRate)) { |
| 348 samplingRate = 1; |
| 349 } |
| 350 this.viewBuilder_ = new devtools.profiler.WebKitViewBuilder(samplingRate); |
| 351 break; |
| 352 // These events are valid but aren't used. |
| 353 case 'compression': |
| 354 case 'end': break; |
| 355 default: |
| 356 throw new Error('unknown profiler state: ' + state); |
| 114 } | 357 } |
| 115 }; | 358 }; |
| 116 | 359 |
| 117 | 360 |
| 118 /** | |
| 119 * Does a dispatch of a log record. | |
| 120 * | |
| 121 * @param {Array<string>} fields Log record. | |
| 122 * @private | |
| 123 */ | |
| 124 devtools.profiler.Processor.prototype.dispatchLogRow_ = function(fields) { | |
| 125 // Obtain the dispatch. | |
| 126 var command = fields[0]; | |
| 127 if (!(command in devtools.profiler.Processor.RecordsDispatch_)) { | |
| 128 throw new Error('unknown command: ' + command); | |
| 129 } | |
| 130 var dispatch = devtools.profiler.Processor.RecordsDispatch_[command]; | |
| 131 | |
| 132 if (dispatch === null) { | |
| 133 return; | |
| 134 } | |
| 135 | |
| 136 // Parse fields. | |
| 137 var parsedFields = []; | |
| 138 for (var i = 0; i < dispatch.parsers.length; ++i) { | |
| 139 var parser = dispatch.parsers[i]; | |
| 140 if (parser === null) { | |
| 141 parsedFields.push(fields[1 + i]); | |
| 142 } else if (typeof parser == 'function') { | |
| 143 parsedFields.push(parser(fields[1 + i])); | |
| 144 } else { | |
| 145 // var-args | |
| 146 parsedFields.push(fields.slice(1 + i)); | |
| 147 break; | |
| 148 } | |
| 149 } | |
| 150 | |
| 151 // Run the processor. | |
| 152 this[dispatch.processor].apply(this, parsedFields); | |
| 153 }; | |
| 154 | |
| 155 | |
| 156 devtools.profiler.Processor.prototype.processCodeCreation_ = function( | 361 devtools.profiler.Processor.prototype.processCodeCreation_ = function( |
| 157 type, start, size, name) { | 362 type, start, size, name) { |
| 158 this.profile_.addCode(type, name, start, size); | 363 this.currentProfile_.addCode(this.expandAlias(type), name, start, size); |
| 159 }; | 364 }; |
| 160 | 365 |
| 161 | 366 |
| 162 devtools.profiler.Processor.prototype.processCodeMove_ = function(from, to) { | 367 devtools.profiler.Processor.prototype.processCodeMove_ = function(from, to) { |
| 163 this.profile_.moveCode(from, to); | 368 this.currentProfile_.moveCode(from, to); |
| 164 }; | 369 }; |
| 165 | 370 |
| 166 | 371 |
| 167 devtools.profiler.Processor.prototype.processCodeDelete_ = function(start) { | 372 devtools.profiler.Processor.prototype.processCodeDelete_ = function(start) { |
| 168 this.profile_.deleteCode(start); | 373 this.currentProfile_.deleteCode(start); |
| 169 }; | 374 }; |
| 170 | 375 |
| 171 | 376 |
| 172 devtools.profiler.Processor.prototype.processTick_ = function( | 377 devtools.profiler.Processor.prototype.processTick_ = function( |
| 173 pc, sp, vmState, stack) { | 378 pc, sp, vmState, stack) { |
| 174 var fullStack = [pc]; | 379 // see the comment for devtools.profiler.Processor.PROGRAM_ENTRY |
| 175 for (var i = 0, n = stack.length; i < n; ++i) { | 380 stack.push(devtools.profiler.Processor.PROGRAM_ENTRY_STR); |
| 176 var frame = stack[i]; | 381 this.currentProfile_.recordTick(this.processStack(pc, stack)); |
| 177 // Leave only numbers starting with 0x. Filter possible 'overflow' string. | 382 this.ticksCount_++; |
| 178 if (frame.charAt(0) == '0') { | 383 }; |
| 179 fullStack.push(parseInt(frame, 16)); | 384 |
| 180 } | 385 |
| 386 devtools.profiler.Processor.prototype.processHeapSampleBegin_ = function( |
| 387 space, state, ticks) { |
| 388 if (space != 'Heap') return; |
| 389 this.currentHeapSnapshot_ = { |
| 390 number: this.heapSnapshotId_++, |
| 391 entries: {}, |
| 392 lowlevels: {}, |
| 393 ticks: ticks |
| 394 }; |
| 395 }; |
| 396 |
| 397 |
| 398 devtools.profiler.Processor.prototype.processHeapSampleStats_ = function( |
| 399 space, state, capacity, used) { |
| 400 if (space != 'Heap') return; |
| 401 this.currentHeapSnapshot_.capacity = capacity; |
| 402 this.currentHeapSnapshot_.used = used; |
| 403 }; |
| 404 |
| 405 |
| 406 devtools.profiler.Processor.prototype.processHeapSampleItem_ = function( |
| 407 item, number, size) { |
| 408 if (!this.currentHeapSnapshot_) return; |
| 409 this.currentHeapSnapshot_.lowlevels[item] = { |
| 410 type: item, count: number, size: size |
| 411 }; |
| 412 }; |
| 413 |
| 414 |
| 415 devtools.profiler.Processor.prototype.processHeapJsConsItem_ = function( |
| 416 item, number, size) { |
| 417 if (!this.currentHeapSnapshot_) return; |
| 418 this.currentHeapSnapshot_.entries[item] = { |
| 419 cons: item, count: number, size: size |
| 420 }; |
| 421 }; |
| 422 |
| 423 |
| 424 devtools.profiler.Processor.prototype.processHeapSampleEnd_ = function( |
| 425 space, state) { |
| 426 if (space != 'Heap') return; |
| 427 var snapshot = this.currentHeapSnapshot_; |
| 428 this.currentHeapSnapshot_ = null; |
| 429 // For some reason, 'used' from 'heap-sample-stats' sometimes differ from |
| 430 // the sum of objects sizes. To avoid discrepancy, we re-calculate 'used'. |
| 431 snapshot.used = 0; |
| 432 for (var item in snapshot.lowlevels) { |
| 433 snapshot.used += snapshot.lowlevels[item].size; |
| 181 } | 434 } |
| 182 this.profile_.recordTick(fullStack); | 435 WebInspector.panels.heap.addSnapshot(snapshot); |
| 183 }; | 436 }; |
| 184 | 437 |
| 185 | 438 |
| 186 /** | 439 /** |
| 187 * Creates a profile for further displaying in ProfileView. | 440 * Creates a profile for further displaying in ProfileView. |
| 188 */ | 441 */ |
| 189 devtools.profiler.Processor.prototype.createProfileForView = function() { | 442 devtools.profiler.Processor.prototype.createProfileForView = function() { |
| 190 var profile = new devtools.profiler.ProfileView(); | 443 var profile = this.viewBuilder_.buildView( |
| 444 this.currentProfile_.getTopDownProfile()); |
| 191 profile.uid = this.profileId_++; | 445 profile.uid = this.profileId_++; |
| 192 profile.title = UserInitiatedProfileName + '.' + profile.uid; | 446 profile.title = UserInitiatedProfileName + '.' + profile.uid; |
| 193 // A trick to cope with ProfileView.bottomUpProfileDataGridTree and | |
| 194 // ProfileView.topDownProfileDataGridTree behavior. | |
| 195 profile.head = profile; | |
| 196 profile.heavyProfile = this.viewBuilder_.buildView( | |
| 197 this.profile_.getBottomUpProfile(), true); | |
| 198 profile.treeProfile = this.viewBuilder_.buildView( | |
| 199 this.profile_.getTopDownProfile()); | |
| 200 return profile; | 447 return profile; |
| 201 }; | 448 }; |
| OLD | NEW |