OLD | NEW |
(Empty) | |
| 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 |
| 3 // found in the LICENSE file. |
| 4 |
| 5 /** |
| 6 * @fileoverview Profiler processor is used to process log file produced |
| 7 * by V8 and produce an internal profile representation which is used |
| 8 * for building profile views in 'Profiles' tab. |
| 9 */ |
| 10 goog.provide('devtools.profiler.Processor'); |
| 11 |
| 12 |
| 13 /** |
| 14 * Ancestor of a profile object that leaves out only JS-related functions. |
| 15 * @constructor |
| 16 */ |
| 17 devtools.profiler.JsProfile = function() { |
| 18 devtools.profiler.Profile.call(this); |
| 19 }; |
| 20 goog.inherits(devtools.profiler.JsProfile, devtools.profiler.Profile); |
| 21 |
| 22 |
| 23 /** |
| 24 * @type {RegExp} |
| 25 */ |
| 26 devtools.profiler.JsProfile.JS_FUNC_RE = /^(LazyCompile|Function|Script):/; |
| 27 |
| 28 |
| 29 /** |
| 30 * @override |
| 31 */ |
| 32 devtools.profiler.JsProfile.prototype.skipThisFunction = function(name) { |
| 33 return !devtools.profiler.JsProfile.JS_FUNC_RE.test(name); |
| 34 }; |
| 35 |
| 36 |
| 37 /** |
| 38 * Profiler processor. Consumes profiler log and builds profile views. |
| 39 * @constructor |
| 40 */ |
| 41 devtools.profiler.Processor = function() { |
| 42 /** |
| 43 * Current profile. |
| 44 * @type {devtools.profiler.JsProfile} |
| 45 */ |
| 46 this.profile_ = new devtools.profiler.JsProfile(); |
| 47 |
| 48 /** |
| 49 * Builder of profile views. |
| 50 * @type {devtools.profiler.ViewBuilder} |
| 51 */ |
| 52 this.viewBuilder_ = new devtools.profiler.ViewBuilder(1); |
| 53 |
| 54 /** |
| 55 * Next profile id. |
| 56 * @type {number} |
| 57 */ |
| 58 this.profileId_ = 1; |
| 59 }; |
| 60 |
| 61 |
| 62 /** |
| 63 * A dispatch table for V8 profiler event log records. |
| 64 * @private |
| 65 */ |
| 66 devtools.profiler.Processor.RecordsDispatch_ = { |
| 67 'code-creation': { parsers: [null, parseInt, parseInt, null], |
| 68 processor: 'processCodeCreation_' }, |
| 69 'code-move': { parsers: [parseInt, parseInt], |
| 70 processor: 'processCodeMove_' }, |
| 71 'code-delete': { parsers: [parseInt], processor: 'processCodeDelete_' }, |
| 72 'tick': { parsers: [parseInt, parseInt, parseInt, 'var-args'], |
| 73 processor: 'processTick_' }, |
| 74 // Not used in DevTools Profiler. |
| 75 'profiler': null, |
| 76 'shared-library': null, |
| 77 // Obsolete row types. |
| 78 'code-allocate': null, |
| 79 'begin-code-region': null, |
| 80 'end-code-region': null |
| 81 }; |
| 82 |
| 83 |
| 84 /** |
| 85 * Processes a portion of V8 profiler event log. |
| 86 * |
| 87 * @param {string} chunk A portion of log. |
| 88 */ |
| 89 devtools.profiler.Processor.prototype.processLogChunk = function(chunk) { |
| 90 this.processLog_(chunk.split('\n')); |
| 91 }; |
| 92 |
| 93 |
| 94 /** |
| 95 * Processes a log lines. |
| 96 * |
| 97 * @param {Array<string>} lines Log lines. |
| 98 * @private |
| 99 */ |
| 100 devtools.profiler.Processor.prototype.processLog_ = function(lines) { |
| 101 var csvParser = new devtools.profiler.CsvParser(); |
| 102 try { |
| 103 for (var i = 0, n = lines.length; i < n; ++i) { |
| 104 var line = lines[i]; |
| 105 if (!line) { |
| 106 continue; |
| 107 } |
| 108 var fields = csvParser.parseLine(line); |
| 109 this.dispatchLogRow_(fields); |
| 110 } |
| 111 } catch (e) { |
| 112 debugPrint('line ' + (i + 1) + ': ' + (e.message || e)); |
| 113 throw e; |
| 114 } |
| 115 }; |
| 116 |
| 117 |
| 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( |
| 157 type, start, size, name) { |
| 158 this.profile_.addCode(type, name, start, size); |
| 159 }; |
| 160 |
| 161 |
| 162 devtools.profiler.Processor.prototype.processCodeMove_ = function(from, to) { |
| 163 this.profile_.moveCode(from, to); |
| 164 }; |
| 165 |
| 166 |
| 167 devtools.profiler.Processor.prototype.processCodeDelete_ = function(start) { |
| 168 this.profile_.deleteCode(start); |
| 169 }; |
| 170 |
| 171 |
| 172 devtools.profiler.Processor.prototype.processTick_ = function( |
| 173 pc, sp, vmState, stack) { |
| 174 var fullStack = [pc]; |
| 175 for (var i = 0, n = stack.length; i < n; ++i) { |
| 176 var frame = stack[i]; |
| 177 // Leave only numbers starting with 0x. Filter possible 'overflow' string. |
| 178 if (frame.charAt(0) == '0') { |
| 179 fullStack.push(parseInt(frame, 16)); |
| 180 } |
| 181 } |
| 182 this.profile_.recordTick(fullStack); |
| 183 }; |
| 184 |
| 185 |
| 186 /** |
| 187 * Creates a profile for further displaying in ProfileView. |
| 188 */ |
| 189 devtools.profiler.Processor.prototype.createProfileForView = function() { |
| 190 var profile = new devtools.profiler.ProfileView(); |
| 191 profile.uid = this.profileId_++; |
| 192 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; |
| 201 }; |
OLD | NEW |