Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(617)

Side by Side Diff: chrome/tools/test/reference_build/chrome_linux/resources/inspector/profiler_processor.js

Issue 177049: On Linux, move the passing of filedescriptors to a dedicated socketpair(). (Closed)
Patch Set: Removed *.d files from reference build Created 11 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 };
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698