Index: resources/inspector/profiler_processor.js |
=================================================================== |
--- resources/inspector/profiler_processor.js (revision 33840) |
+++ resources/inspector/profiler_processor.js (working copy) |
@@ -1,478 +0,0 @@ |
-// Copyright (c) 2009 The Chromium Authors. All rights reserved. |
-// Use of this source code is governed by a BSD-style license that can be |
-// found in the LICENSE file. |
- |
-/** |
- * @fileoverview Profiler processor is used to process log file produced |
- * by V8 and produce an internal profile representation which is used |
- * for building profile views in 'Profiles' tab. |
- */ |
-goog.provide('devtools.profiler.Processor'); |
- |
- |
-/** |
- * Creates a Profile View builder object compatible with WebKit Profiler UI. |
- * |
- * @param {number} samplingRate Number of ms between profiler ticks. |
- * @constructor |
- */ |
-devtools.profiler.WebKitViewBuilder = function(samplingRate) { |
- devtools.profiler.ViewBuilder.call(this, samplingRate); |
-}; |
-goog.inherits(devtools.profiler.WebKitViewBuilder, |
- devtools.profiler.ViewBuilder); |
- |
- |
-/** |
- * @override |
- */ |
-devtools.profiler.WebKitViewBuilder.prototype.createViewNode = function( |
- funcName, totalTime, selfTime, head) { |
- return new devtools.profiler.WebKitViewNode( |
- funcName, totalTime, selfTime, head); |
-}; |
- |
- |
-/** |
- * Constructs a Profile View node object for displaying in WebKit Profiler UI. |
- * |
- * @param {string} internalFuncName A fully qualified function name. |
- * @param {number} totalTime Amount of time that application spent in the |
- * corresponding function and its descendants (not that depending on |
- * profile they can be either callees or callers.) |
- * @param {number} selfTime Amount of time that application spent in the |
- * corresponding function only. |
- * @param {devtools.profiler.ProfileView.Node} head Profile view head. |
- * @constructor |
- */ |
-devtools.profiler.WebKitViewNode = function( |
- internalFuncName, totalTime, selfTime, head) { |
- devtools.profiler.ProfileView.Node.call(this, |
- internalFuncName, totalTime, selfTime, head); |
- this.initFuncInfo_(); |
- this.callUID = internalFuncName; |
-}; |
-goog.inherits(devtools.profiler.WebKitViewNode, |
- devtools.profiler.ProfileView.Node); |
- |
- |
-/** |
- * RegEx for stripping V8's prefixes of compiled functions. |
- */ |
-devtools.profiler.WebKitViewNode.FUNC_NAME_STRIP_RE = |
- /^(?:LazyCompile|Function): (.*)$/; |
- |
- |
-/** |
- * RegEx for extracting script source URL and line number. |
- */ |
-devtools.profiler.WebKitViewNode.FUNC_NAME_PARSE_RE = |
- /^([^ ]+) (.*):(\d+)( \{\d+\})?$/; |
- |
- |
-/** |
- * Inits 'functionName', 'url', and 'lineNumber' fields using 'internalFuncName' |
- * field. |
- * @private |
- */ |
-devtools.profiler.WebKitViewNode.prototype.initFuncInfo_ = function() { |
- var nodeAlias = devtools.profiler.WebKitViewNode; |
- this.functionName = this.internalFuncName; |
- |
- var strippedName = nodeAlias.FUNC_NAME_STRIP_RE.exec(this.functionName); |
- if (strippedName) { |
- this.functionName = strippedName[1]; |
- } |
- |
- var parsedName = nodeAlias.FUNC_NAME_PARSE_RE.exec(this.functionName); |
- if (parsedName) { |
- this.functionName = parsedName[1]; |
- if (parsedName[4]) { |
- this.functionName += parsedName[4]; |
- } |
- this.url = parsedName[2]; |
- this.lineNumber = parsedName[3]; |
- } else { |
- this.url = ''; |
- this.lineNumber = 0; |
- } |
-}; |
- |
- |
-/** |
- * Ancestor of a profile object that leaves out only JS-related functions. |
- * @constructor |
- */ |
-devtools.profiler.JsProfile = function() { |
- devtools.profiler.Profile.call(this); |
-}; |
-goog.inherits(devtools.profiler.JsProfile, devtools.profiler.Profile); |
- |
- |
-/** |
- * RegExp that leaves only JS functions. |
- * @type {RegExp} |
- */ |
-devtools.profiler.JsProfile.JS_FUNC_RE = /^(LazyCompile|Function|Script):/; |
- |
-/** |
- * RegExp that filters out native code (ending with "native src.js:xxx"). |
- * @type {RegExp} |
- */ |
-devtools.profiler.JsProfile.JS_NATIVE_FUNC_RE = /\ native\ \w+\.js:\d+$/; |
- |
-/** |
- * RegExp that filters out native scripts. |
- * @type {RegExp} |
- */ |
-devtools.profiler.JsProfile.JS_NATIVE_SCRIPT_RE = /^Script:\ native/; |
- |
- |
-/** |
- * @override |
- */ |
-devtools.profiler.JsProfile.prototype.skipThisFunction = function(name) { |
- return !devtools.profiler.JsProfile.JS_FUNC_RE.test(name) || |
- // To profile V8's natives comment out two lines below and '||' above. |
- devtools.profiler.JsProfile.JS_NATIVE_FUNC_RE.test(name) || |
- devtools.profiler.JsProfile.JS_NATIVE_SCRIPT_RE.test(name); |
-}; |
- |
- |
-/** |
- * Profiler processor. Consumes profiler log and builds profile views. |
- * |
- * @param {function(devtools.profiler.ProfileView)} newProfileCallback Callback |
- * that receives a new processed profile. |
- * @constructor |
- */ |
-devtools.profiler.Processor = function() { |
- devtools.profiler.LogReader.call(this, { |
- 'code-creation': { |
- parsers: [null, this.createAddressParser('code'), parseInt, null], |
- processor: this.processCodeCreation_, backrefs: true, |
- needsProfile: true }, |
- 'code-move': { parsers: [this.createAddressParser('code'), |
- this.createAddressParser('code-move-to')], |
- processor: this.processCodeMove_, backrefs: true, |
- needsProfile: true }, |
- 'code-delete': { parsers: [this.createAddressParser('code')], |
- processor: this.processCodeDelete_, backrefs: true, |
- needsProfile: true }, |
- 'tick': { parsers: [this.createAddressParser('code'), |
- this.createAddressParser('stack'), parseInt, 'var-args'], |
- processor: this.processTick_, backrefs: true, needProfile: true }, |
- 'profiler': { parsers: [null, 'var-args'], |
- processor: this.processProfiler_, needsProfile: false }, |
- 'heap-sample-begin': { parsers: [null, null, parseInt], |
- processor: this.processHeapSampleBegin_ }, |
- 'heap-sample-stats': { parsers: [null, null, parseInt, parseInt], |
- processor: this.processHeapSampleStats_ }, |
- 'heap-sample-item': { parsers: [null, parseInt, parseInt], |
- processor: this.processHeapSampleItem_ }, |
- 'heap-js-cons-item': { parsers: [null, parseInt, parseInt], |
- processor: this.processHeapJsConsItem_ }, |
- 'heap-js-ret-item': { parsers: [null, 'var-args'], |
- processor: this.processHeapJsRetItem_ }, |
- 'heap-sample-end': { parsers: [null, null], |
- processor: this.processHeapSampleEnd_ }, |
- // Not used in DevTools Profiler. |
- 'shared-library': null, |
- // Obsolete row types. |
- 'code-allocate': null, |
- 'begin-code-region': null, |
- 'end-code-region': null}); |
- |
- |
- /** |
- * Callback that is called when a new profile is encountered in the log. |
- * @type {function()} |
- */ |
- this.startedProfileProcessing_ = null; |
- |
- /** |
- * Callback that is called periodically to display processing status. |
- * @type {function()} |
- */ |
- this.profileProcessingStatus_ = null; |
- |
- /** |
- * Callback that is called when a profile has been processed and is ready |
- * to be shown. |
- * @type {function(devtools.profiler.ProfileView)} |
- */ |
- this.finishedProfileProcessing_ = null; |
- |
- /** |
- * The current profile. |
- * @type {devtools.profiler.JsProfile} |
- */ |
- this.currentProfile_ = null; |
- |
- /** |
- * Builder of profile views. Created during "profiler,begin" event processing. |
- * @type {devtools.profiler.WebKitViewBuilder} |
- */ |
- this.viewBuilder_ = null; |
- |
- /** |
- * Next profile id. |
- * @type {number} |
- */ |
- this.profileId_ = 1; |
- |
- /** |
- * Counter for processed ticks. |
- * @type {number} |
- */ |
- this.ticksCount_ = 0; |
- |
- /** |
- * The current heap snapshot. |
- * @type {string} |
- */ |
- this.currentHeapSnapshot_ = null; |
- |
- /** |
- * Next heap snapshot id. |
- * @type {number} |
- */ |
- this.heapSnapshotId_ = 1; |
-}; |
-goog.inherits(devtools.profiler.Processor, devtools.profiler.LogReader); |
- |
- |
-/** |
- * @override |
- */ |
-devtools.profiler.Processor.prototype.printError = function(str) { |
- debugPrint(str); |
-}; |
- |
- |
-/** |
- * @override |
- */ |
-devtools.profiler.Processor.prototype.skipDispatch = function(dispatch) { |
- return dispatch.needsProfile && this.currentProfile_ == null; |
-}; |
- |
- |
-/** |
- * Sets profile processing callbacks. |
- * |
- * @param {function()} started Started processing callback. |
- * @param {function(devtools.profiler.ProfileView)} finished Finished |
- * processing callback. |
- */ |
-devtools.profiler.Processor.prototype.setCallbacks = function( |
- started, processing, finished) { |
- this.startedProfileProcessing_ = started; |
- this.profileProcessingStatus_ = processing; |
- this.finishedProfileProcessing_ = finished; |
-}; |
- |
- |
-/** |
- * An address for the fake "(program)" entry. WebKit's visualisation |
- * has assumptions on how the top of the call tree should look like, |
- * and we need to add a fake entry as the topmost function. This |
- * address is chosen because it's the end address of the first memory |
- * page, which is never used for code or data, but only as a guard |
- * page for catching AV errors. |
- * |
- * @type {number} |
- */ |
-devtools.profiler.Processor.PROGRAM_ENTRY = 0xffff; |
-/** |
- * @type {string} |
- */ |
-devtools.profiler.Processor.PROGRAM_ENTRY_STR = '0xffff'; |
- |
- |
-/** |
- * Sets new profile callback. |
- * @param {function(devtools.profiler.ProfileView)} callback Callback function. |
- */ |
-devtools.profiler.Processor.prototype.setNewProfileCallback = function( |
- callback) { |
- this.newProfileCallback_ = callback; |
-}; |
- |
- |
-devtools.profiler.Processor.prototype.processProfiler_ = function( |
- state, params) { |
- var processingInterval = null; |
- switch (state) { |
- case 'resume': |
- if (this.currentProfile_ == null) { |
- this.currentProfile_ = new devtools.profiler.JsProfile(); |
- // see the comment for devtools.profiler.Processor.PROGRAM_ENTRY |
- this.currentProfile_.addCode( |
- 'Function', '(program)', |
- devtools.profiler.Processor.PROGRAM_ENTRY, 1); |
- if (this.startedProfileProcessing_) { |
- this.startedProfileProcessing_(); |
- } |
- this.ticksCount_ = 0; |
- var self = this; |
- if (this.profileProcessingStatus_) { |
- processingInterval = window.setInterval( |
- function() { self.profileProcessingStatus_(self.ticksCount_); }, |
- 1000); |
- } |
- } |
- break; |
- case 'pause': |
- if (this.currentProfile_ != null) { |
- window.clearInterval(processingInterval); |
- if (this.finishedProfileProcessing_) { |
- this.finishedProfileProcessing_(this.createProfileForView()); |
- } |
- this.currentProfile_ = null; |
- } |
- break; |
- case 'begin': |
- var samplingRate = NaN; |
- if (params.length > 0) { |
- samplingRate = parseInt(params[0]); |
- } |
- if (isNaN(samplingRate)) { |
- samplingRate = 1; |
- } |
- this.viewBuilder_ = new devtools.profiler.WebKitViewBuilder(samplingRate); |
- break; |
- // These events are valid but aren't used. |
- case 'compression': |
- case 'end': break; |
- default: |
- throw new Error('unknown profiler state: ' + state); |
- } |
-}; |
- |
- |
-devtools.profiler.Processor.prototype.processCodeCreation_ = function( |
- type, start, size, name) { |
- this.currentProfile_.addCode(this.expandAlias(type), name, start, size); |
-}; |
- |
- |
-devtools.profiler.Processor.prototype.processCodeMove_ = function(from, to) { |
- this.currentProfile_.moveCode(from, to); |
-}; |
- |
- |
-devtools.profiler.Processor.prototype.processCodeDelete_ = function(start) { |
- this.currentProfile_.deleteCode(start); |
-}; |
- |
- |
-devtools.profiler.Processor.prototype.processTick_ = function( |
- pc, sp, vmState, stack) { |
- // see the comment for devtools.profiler.Processor.PROGRAM_ENTRY |
- stack.push(devtools.profiler.Processor.PROGRAM_ENTRY_STR); |
- this.currentProfile_.recordTick(this.processStack(pc, stack)); |
- this.ticksCount_++; |
-}; |
- |
- |
-devtools.profiler.Processor.prototype.processHeapSampleBegin_ = function( |
- space, state, ticks) { |
- if (space != 'Heap') return; |
- this.currentHeapSnapshot_ = { |
- number: this.heapSnapshotId_++, |
- entries: {}, |
- clusters: {}, |
- lowlevels: {}, |
- ticks: ticks |
- }; |
-}; |
- |
- |
-devtools.profiler.Processor.prototype.processHeapSampleStats_ = function( |
- space, state, capacity, used) { |
- if (space != 'Heap') return; |
- this.currentHeapSnapshot_.capacity = capacity; |
- this.currentHeapSnapshot_.used = used; |
-}; |
- |
- |
-devtools.profiler.Processor.prototype.processHeapSampleItem_ = function( |
- item, number, size) { |
- if (!this.currentHeapSnapshot_) return; |
- this.currentHeapSnapshot_.lowlevels[item] = { |
- type: item, count: number, size: size |
- }; |
-}; |
- |
- |
-devtools.profiler.Processor.prototype.processHeapJsConsItem_ = function( |
- item, number, size) { |
- if (!this.currentHeapSnapshot_) return; |
- this.currentHeapSnapshot_.entries[item] = { |
- cons: item, count: number, size: size, retainers: {} |
- }; |
-}; |
- |
- |
-devtools.profiler.Processor.prototype.processHeapJsRetItem_ = function( |
- item, retainersArray) { |
- if (!this.currentHeapSnapshot_) return; |
- var rawRetainers = {}; |
- for (var i = 0, n = retainersArray.length; i < n; ++i) { |
- var entry = retainersArray[i].split(';'); |
- rawRetainers[entry[0]] = parseInt(entry[1], 10); |
- } |
- |
- function mergeRetainers(entry) { |
- for (var rawRetainer in rawRetainers) { |
- var consName = rawRetainer.indexOf(':') != -1 ? |
- rawRetainer.split(':')[0] : rawRetainer; |
- if (!(consName in entry.retainers)) |
- entry.retainers[consName] = { cons: consName, count: 0, clusters: {} }; |
- var retainer = entry.retainers[consName]; |
- retainer.count += rawRetainers[rawRetainer]; |
- if (consName != rawRetainer) |
- retainer.clusters[rawRetainer] = true; |
- } |
- } |
- |
- if (item.indexOf(':') != -1) { |
- // Array, Function, or Object instances cluster case. |
- if (!(item in this.currentHeapSnapshot_.clusters)) { |
- this.currentHeapSnapshot_.clusters[item] = { |
- cons: item, retainers: {} |
- }; |
- } |
- mergeRetainers(this.currentHeapSnapshot_.clusters[item]); |
- item = item.split(':')[0]; |
- } |
- mergeRetainers(this.currentHeapSnapshot_.entries[item]); |
-}; |
- |
- |
-devtools.profiler.Processor.prototype.processHeapSampleEnd_ = function( |
- space, state) { |
- if (space != 'Heap') return; |
- var snapshot = this.currentHeapSnapshot_; |
- this.currentHeapSnapshot_ = null; |
- // For some reason, 'used' from 'heap-sample-stats' sometimes differ from |
- // the sum of objects sizes. To avoid discrepancy, we re-calculate 'used'. |
- snapshot.used = 0; |
- for (var item in snapshot.lowlevels) { |
- snapshot.used += snapshot.lowlevels[item].size; |
- } |
- WebInspector.panels.profiles.addSnapshot(snapshot); |
-}; |
- |
- |
-/** |
- * Creates a profile for further displaying in ProfileView. |
- */ |
-devtools.profiler.Processor.prototype.createProfileForView = function() { |
- var profile = this.viewBuilder_.buildView( |
- this.currentProfile_.getTopDownProfile()); |
- profile.uid = this.profileId_++; |
- profile.title = UserInitiatedProfileName + '.' + profile.uid; |
- return profile; |
-}; |