Index: webkit/glue/devtools/js/profiler_processor.js |
=================================================================== |
--- webkit/glue/devtools/js/profiler_processor.js (revision 0) |
+++ webkit/glue/devtools/js/profiler_processor.js (revision 0) |
@@ -0,0 +1,201 @@ |
+// 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'); |
+ |
+ |
+/** |
+ * 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); |
+ |
+ |
+/** |
+ * @type {RegExp} |
+ */ |
+devtools.profiler.JsProfile.JS_FUNC_RE = /^(LazyCompile|Function|Script):/; |
+ |
+ |
+/** |
+ * @override |
+ */ |
+devtools.profiler.JsProfile.prototype.skipThisFunction = function(name) { |
+ return !devtools.profiler.JsProfile.JS_FUNC_RE.test(name); |
+}; |
+ |
+ |
+/** |
+ * Profiler processor. Consumes profiler log and builds profile views. |
+ * @constructor |
+ */ |
+devtools.profiler.Processor = function() { |
+ /** |
+ * Current profile. |
+ * @type {devtools.profiler.JsProfile} |
+ */ |
+ this.profile_ = new devtools.profiler.JsProfile(); |
+ |
+ /** |
+ * Builder of profile views. |
+ * @type {devtools.profiler.ViewBuilder} |
+ */ |
+ this.viewBuilder_ = new devtools.profiler.ViewBuilder(1); |
+ |
+ /** |
+ * Next profile id. |
+ * @type {number} |
+ */ |
+ this.profileId_ = 1; |
+}; |
+ |
+ |
+/** |
+ * A dispatch table for V8 profiler event log records. |
+ * @private |
+ */ |
+devtools.profiler.Processor.RecordsDispatch_ = { |
+ 'code-creation': { parsers: [null, parseInt, parseInt, null], |
+ processor: 'processCodeCreation_' }, |
+ 'code-move': { parsers: [parseInt, parseInt], |
+ processor: 'processCodeMove_' }, |
+ 'code-delete': { parsers: [parseInt], processor: 'processCodeDelete_' }, |
+ 'tick': { parsers: [parseInt, parseInt, parseInt, 'var-args'], |
+ processor: 'processTick_' }, |
+ // Not used in DevTools Profiler. |
+ 'profiler': null, |
+ 'shared-library': null, |
+ // Obsolete row types. |
+ 'code-allocate': null, |
+ 'begin-code-region': null, |
+ 'end-code-region': null |
+}; |
+ |
+ |
+/** |
+ * Processes a portion of V8 profiler event log. |
+ * |
+ * @param {string} chunk A portion of log. |
+ */ |
+devtools.profiler.Processor.prototype.processLogChunk = function(chunk) { |
+ this.processLog_(chunk.split('\n')); |
+}; |
+ |
+ |
+/** |
+ * Processes a log lines. |
+ * |
+ * @param {Array<string>} lines Log lines. |
+ * @private |
+ */ |
+devtools.profiler.Processor.prototype.processLog_ = function(lines) { |
+ var csvParser = new devtools.profiler.CsvParser(); |
+ try { |
+ for (var i = 0, n = lines.length; i < n; ++i) { |
+ var line = lines[i]; |
+ if (!line) { |
+ continue; |
+ } |
+ var fields = csvParser.parseLine(line); |
+ this.dispatchLogRow_(fields); |
+ } |
+ } catch (e) { |
+ debugPrint('line ' + (i + 1) + ': ' + (e.message || e)); |
+ throw e; |
+ } |
+}; |
+ |
+ |
+/** |
+ * Does a dispatch of a log record. |
+ * |
+ * @param {Array<string>} fields Log record. |
+ * @private |
+ */ |
+devtools.profiler.Processor.prototype.dispatchLogRow_ = function(fields) { |
+ // Obtain the dispatch. |
+ var command = fields[0]; |
+ if (!(command in devtools.profiler.Processor.RecordsDispatch_)) { |
+ throw new Error('unknown command: ' + command); |
+ } |
+ var dispatch = devtools.profiler.Processor.RecordsDispatch_[command]; |
+ |
+ if (dispatch === null) { |
+ return; |
+ } |
+ |
+ // Parse fields. |
+ var parsedFields = []; |
+ for (var i = 0; i < dispatch.parsers.length; ++i) { |
+ var parser = dispatch.parsers[i]; |
+ if (parser === null) { |
+ parsedFields.push(fields[1 + i]); |
+ } else if (typeof parser == 'function') { |
+ parsedFields.push(parser(fields[1 + i])); |
+ } else { |
+ // var-args |
+ parsedFields.push(fields.slice(1 + i)); |
+ break; |
+ } |
+ } |
+ |
+ // Run the processor. |
+ this[dispatch.processor].apply(this, parsedFields); |
+}; |
+ |
+ |
+devtools.profiler.Processor.prototype.processCodeCreation_ = function( |
+ type, start, size, name) { |
+ this.profile_.addCode(type, name, start, size); |
+}; |
+ |
+ |
+devtools.profiler.Processor.prototype.processCodeMove_ = function(from, to) { |
+ this.profile_.moveCode(from, to); |
+}; |
+ |
+ |
+devtools.profiler.Processor.prototype.processCodeDelete_ = function(start) { |
+ this.profile_.deleteCode(start); |
+}; |
+ |
+ |
+devtools.profiler.Processor.prototype.processTick_ = function( |
+ pc, sp, vmState, stack) { |
+ var fullStack = [pc]; |
+ for (var i = 0, n = stack.length; i < n; ++i) { |
+ var frame = stack[i]; |
+ // Leave only numbers starting with 0x. Filter possible 'overflow' string. |
+ if (frame.charAt(0) == '0') { |
+ fullStack.push(parseInt(frame, 16)); |
+ } |
+ } |
+ this.profile_.recordTick(fullStack); |
+}; |
+ |
+ |
+/** |
+ * Creates a profile for further displaying in ProfileView. |
+ */ |
+devtools.profiler.Processor.prototype.createProfileForView = function() { |
+ var profile = new devtools.profiler.ProfileView(); |
+ profile.uid = this.profileId_++; |
+ profile.title = UserInitiatedProfileName + '.' + profile.uid; |
+ // A trick to cope with ProfileView.bottomUpProfileDataGridTree and |
+ // ProfileView.topDownProfileDataGridTree behavior. |
+ profile.head = profile; |
+ profile.heavyProfile = this.viewBuilder_.buildView( |
+ this.profile_.getBottomUpProfile(), true); |
+ profile.treeProfile = this.viewBuilder_.buildView( |
+ this.profile_.getTopDownProfile()); |
+ return profile; |
+}; |