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

Side by Side Diff: resources/inspector/profiler_processor.js

Issue 853002: Updating the Chromium reference build for Windows. The continuous... (Closed) Base URL: svn://chrome-svn/chrome/trunk/deps/reference_builds/chrome/
Patch Set: Added the symbol files back. Created 10 years, 9 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 | Annotate | Revision Log
« no previous file with comments | « resources/inspector/profile_view.js ('k') | resources/inspector/splaytree.js » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(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 * 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 /**
103 * Ancestor of a profile object that leaves out only JS-related functions.
104 * @constructor
105 */
106 devtools.profiler.JsProfile = function() {
107 devtools.profiler.Profile.call(this);
108 };
109 goog.inherits(devtools.profiler.JsProfile, devtools.profiler.Profile);
110
111
112 /**
113 * RegExp that leaves only JS functions.
114 * @type {RegExp}
115 */
116 devtools.profiler.JsProfile.JS_FUNC_RE = /^(LazyCompile|Function|Script):/;
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 /**
132 * @override
133 */
134 devtools.profiler.JsProfile.prototype.skipThisFunction = function(name) {
135 return !devtools.profiler.JsProfile.JS_FUNC_RE.test(name) ||
136 // To profile V8's natives comment out two lines below and '||' above.
137 devtools.profiler.JsProfile.JS_NATIVE_FUNC_RE.test(name) ||
138 devtools.profiler.JsProfile.JS_NATIVE_SCRIPT_RE.test(name);
139 };
140
141
142 /**
143 * Profiler processor. Consumes profiler log and builds profile views.
144 *
145 * @param {function(devtools.profiler.ProfileView)} newProfileCallback Callback
146 * that receives a new processed profile.
147 * @constructor
148 */
149 devtools.profiler.Processor = function() {
150 devtools.profiler.LogReader.call(this, {
151 'code-creation': {
152 parsers: [null, this.createAddressParser('code'), parseInt, null],
153 processor: this.processCodeCreation_, backrefs: true,
154 needsProfile: true },
155 'code-move': { parsers: [this.createAddressParser('code'),
156 this.createAddressParser('code-move-to')],
157 processor: this.processCodeMove_, backrefs: true,
158 needsProfile: true },
159 'code-delete': { parsers: [this.createAddressParser('code')],
160 processor: this.processCodeDelete_, backrefs: true,
161 needsProfile: true },
162 'tick': { parsers: [this.createAddressParser('code'),
163 this.createAddressParser('stack'), parseInt, 'var-args'],
164 processor: this.processTick_, backrefs: true, needProfile: true },
165 'profiler': { parsers: [null, 'var-args'],
166 processor: this.processProfiler_, needsProfile: false },
167 'heap-sample-begin': { parsers: [null, null, parseInt],
168 processor: this.processHeapSampleBegin_ },
169 'heap-sample-stats': { parsers: [null, null, parseInt, parseInt],
170 processor: this.processHeapSampleStats_ },
171 'heap-sample-item': { parsers: [null, parseInt, parseInt],
172 processor: this.processHeapSampleItem_ },
173 'heap-js-cons-item': { parsers: [null, parseInt, parseInt],
174 processor: this.processHeapJsConsItem_ },
175 'heap-js-ret-item': { parsers: [null, 'var-args'],
176 processor: this.processHeapJsRetItem_ },
177 'heap-sample-end': { parsers: [null, null],
178 processor: this.processHeapSampleEnd_ },
179 // Not used in DevTools Profiler.
180 'shared-library': null,
181 // Obsolete row types.
182 'code-allocate': null,
183 'begin-code-region': null,
184 'end-code-region': null});
185
186
187 /**
188 * Callback that is called when a new profile is encountered in the log.
189 * @type {function()}
190 */
191 this.startedProfileProcessing_ = null;
192
193 /**
194 * Callback that is called periodically to display processing status.
195 * @type {function()}
196 */
197 this.profileProcessingStatus_ = null;
198
199 /**
200 * Callback that is called when a profile has been processed and is ready
201 * to be shown.
202 * @type {function(devtools.profiler.ProfileView)}
203 */
204 this.finishedProfileProcessing_ = null;
205
206 /**
207 * The current profile.
208 * @type {devtools.profiler.JsProfile}
209 */
210 this.currentProfile_ = null;
211
212 /**
213 * Builder of profile views. Created during "profiler,begin" event processing.
214 * @type {devtools.profiler.WebKitViewBuilder}
215 */
216 this.viewBuilder_ = null;
217
218 /**
219 * Next profile id.
220 * @type {number}
221 */
222 this.profileId_ = 1;
223
224 /**
225 * Counter for processed ticks.
226 * @type {number}
227 */
228 this.ticksCount_ = 0;
229
230 /**
231 * The current heap snapshot.
232 * @type {string}
233 */
234 this.currentHeapSnapshot_ = null;
235
236 /**
237 * Next heap snapshot id.
238 * @type {number}
239 */
240 this.heapSnapshotId_ = 1;
241 };
242 goog.inherits(devtools.profiler.Processor, devtools.profiler.LogReader);
243
244
245 /**
246 * @override
247 */
248 devtools.profiler.Processor.prototype.printError = function(str) {
249 debugPrint(str);
250 };
251
252
253 /**
254 * @override
255 */
256 devtools.profiler.Processor.prototype.skipDispatch = function(dispatch) {
257 return dispatch.needsProfile && this.currentProfile_ == null;
258 };
259
260
261 /**
262 * Sets profile processing callbacks.
263 *
264 * @param {function()} started Started processing callback.
265 * @param {function(devtools.profiler.ProfileView)} finished Finished
266 * processing callback.
267 */
268 devtools.profiler.Processor.prototype.setCallbacks = function(
269 started, processing, finished) {
270 this.startedProfileProcessing_ = started;
271 this.profileProcessingStatus_ = processing;
272 this.finishedProfileProcessing_ = finished;
273 };
274
275
276 /**
277 * An address for the fake "(program)" entry. WebKit's visualisation
278 * has assumptions on how the top of the call tree should look like,
279 * and we need to add a fake entry as the topmost function. This
280 * address is chosen because it's the end address of the first memory
281 * page, which is never used for code or data, but only as a guard
282 * page for catching AV errors.
283 *
284 * @type {number}
285 */
286 devtools.profiler.Processor.PROGRAM_ENTRY = 0xffff;
287 /**
288 * @type {string}
289 */
290 devtools.profiler.Processor.PROGRAM_ENTRY_STR = '0xffff';
291
292
293 /**
294 * Sets new profile callback.
295 * @param {function(devtools.profiler.ProfileView)} callback Callback function.
296 */
297 devtools.profiler.Processor.prototype.setNewProfileCallback = function(
298 callback) {
299 this.newProfileCallback_ = callback;
300 };
301
302
303 devtools.profiler.Processor.prototype.processProfiler_ = function(
304 state, params) {
305 var processingInterval = null;
306 switch (state) {
307 case 'resume':
308 if (this.currentProfile_ == null) {
309 this.currentProfile_ = new devtools.profiler.JsProfile();
310 // see the comment for devtools.profiler.Processor.PROGRAM_ENTRY
311 this.currentProfile_.addCode(
312 'Function', '(program)',
313 devtools.profiler.Processor.PROGRAM_ENTRY, 1);
314 if (this.startedProfileProcessing_) {
315 this.startedProfileProcessing_();
316 }
317 this.ticksCount_ = 0;
318 var self = this;
319 if (this.profileProcessingStatus_) {
320 processingInterval = window.setInterval(
321 function() { self.profileProcessingStatus_(self.ticksCount_); },
322 1000);
323 }
324 }
325 break;
326 case 'pause':
327 if (this.currentProfile_ != null) {
328 window.clearInterval(processingInterval);
329 if (this.finishedProfileProcessing_) {
330 this.finishedProfileProcessing_(this.createProfileForView());
331 }
332 this.currentProfile_ = null;
333 }
334 break;
335 case 'begin':
336 var samplingRate = NaN;
337 if (params.length > 0) {
338 samplingRate = parseInt(params[0]);
339 }
340 if (isNaN(samplingRate)) {
341 samplingRate = 1;
342 }
343 this.viewBuilder_ = new devtools.profiler.WebKitViewBuilder(samplingRate);
344 break;
345 // These events are valid but aren't used.
346 case 'compression':
347 case 'end': break;
348 default:
349 throw new Error('unknown profiler state: ' + state);
350 }
351 };
352
353
354 devtools.profiler.Processor.prototype.processCodeCreation_ = function(
355 type, start, size, name) {
356 this.currentProfile_.addCode(this.expandAlias(type), name, start, size);
357 };
358
359
360 devtools.profiler.Processor.prototype.processCodeMove_ = function(from, to) {
361 this.currentProfile_.moveCode(from, to);
362 };
363
364
365 devtools.profiler.Processor.prototype.processCodeDelete_ = function(start) {
366 this.currentProfile_.deleteCode(start);
367 };
368
369
370 devtools.profiler.Processor.prototype.processTick_ = function(
371 pc, sp, vmState, stack) {
372 // see the comment for devtools.profiler.Processor.PROGRAM_ENTRY
373 stack.push(devtools.profiler.Processor.PROGRAM_ENTRY_STR);
374 this.currentProfile_.recordTick(this.processStack(pc, stack));
375 this.ticksCount_++;
376 };
377
378
379 devtools.profiler.Processor.prototype.processHeapSampleBegin_ = function(
380 space, state, ticks) {
381 if (space != 'Heap') return;
382 this.currentHeapSnapshot_ = {
383 number: this.heapSnapshotId_++,
384 entries: {},
385 clusters: {},
386 lowlevels: {},
387 ticks: ticks
388 };
389 };
390
391
392 devtools.profiler.Processor.prototype.processHeapSampleStats_ = function(
393 space, state, capacity, used) {
394 if (space != 'Heap') return;
395 this.currentHeapSnapshot_.capacity = capacity;
396 this.currentHeapSnapshot_.used = used;
397 };
398
399
400 devtools.profiler.Processor.prototype.processHeapSampleItem_ = function(
401 item, number, size) {
402 if (!this.currentHeapSnapshot_) return;
403 this.currentHeapSnapshot_.lowlevels[item] = {
404 type: item, count: number, size: size
405 };
406 };
407
408
409 devtools.profiler.Processor.prototype.processHeapJsConsItem_ = function(
410 item, number, size) {
411 if (!this.currentHeapSnapshot_) return;
412 this.currentHeapSnapshot_.entries[item] = {
413 cons: item, count: number, size: size, retainers: {}
414 };
415 };
416
417
418 devtools.profiler.Processor.prototype.processHeapJsRetItem_ = function(
419 item, retainersArray) {
420 if (!this.currentHeapSnapshot_) return;
421 var rawRetainers = {};
422 for (var i = 0, n = retainersArray.length; i < n; ++i) {
423 var entry = retainersArray[i].split(';');
424 rawRetainers[entry[0]] = parseInt(entry[1], 10);
425 }
426
427 function mergeRetainers(entry) {
428 for (var rawRetainer in rawRetainers) {
429 var consName = rawRetainer.indexOf(':') != -1 ?
430 rawRetainer.split(':')[0] : rawRetainer;
431 if (!(consName in entry.retainers))
432 entry.retainers[consName] = { cons: consName, count: 0, clusters: {} };
433 var retainer = entry.retainers[consName];
434 retainer.count += rawRetainers[rawRetainer];
435 if (consName != rawRetainer)
436 retainer.clusters[rawRetainer] = true;
437 }
438 }
439
440 if (item.indexOf(':') != -1) {
441 // Array, Function, or Object instances cluster case.
442 if (!(item in this.currentHeapSnapshot_.clusters)) {
443 this.currentHeapSnapshot_.clusters[item] = {
444 cons: item, retainers: {}
445 };
446 }
447 mergeRetainers(this.currentHeapSnapshot_.clusters[item]);
448 item = item.split(':')[0];
449 }
450 mergeRetainers(this.currentHeapSnapshot_.entries[item]);
451 };
452
453
454 devtools.profiler.Processor.prototype.processHeapSampleEnd_ = function(
455 space, state) {
456 if (space != 'Heap') return;
457 var snapshot = this.currentHeapSnapshot_;
458 this.currentHeapSnapshot_ = null;
459 // For some reason, 'used' from 'heap-sample-stats' sometimes differ from
460 // the sum of objects sizes. To avoid discrepancy, we re-calculate 'used'.
461 snapshot.used = 0;
462 for (var item in snapshot.lowlevels) {
463 snapshot.used += snapshot.lowlevels[item].size;
464 }
465 WebInspector.panels.profiles.addSnapshot(snapshot);
466 };
467
468
469 /**
470 * Creates a profile for further displaying in ProfileView.
471 */
472 devtools.profiler.Processor.prototype.createProfileForView = function() {
473 var profile = this.viewBuilder_.buildView(
474 this.currentProfile_.getTopDownProfile());
475 profile.uid = this.profileId_++;
476 profile.title = UserInitiatedProfileName + '.' + profile.uid;
477 return profile;
478 };
OLDNEW
« no previous file with comments | « resources/inspector/profile_view.js ('k') | resources/inspector/splaytree.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698