15ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org// Copyright 2009 the V8 project authors. All rights reserved.
25ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org// Redistribution and use in source and binary forms, with or without
35ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org// modification, are permitted provided that the following conditions are
45ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org// met:
55ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org//
65ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org//     * Redistributions of source code must retain the above copyright
75ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org//       notice, this list of conditions and the following disclaimer.
85ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org//     * Redistributions in binary form must reproduce the above
95ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org//       copyright notice, this list of conditions and the following
105ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org//       disclaimer in the documentation and/or other materials provided
115ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org//       with the distribution.
125ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org//     * Neither the name of Google Inc. nor the names of its
135ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org//       contributors may be used to endorse or promote products derived
145ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org//       from this software without specific prior written permission.
155ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org//
165ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
175ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
185ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
195ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
205ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
215ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
225ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
235ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
245ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
255ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
265ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
275ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org
285ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org
295ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org/**
305ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org * Creates a Profile View builder object.
315ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org *
325ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org * @param {number} samplingRate Number of ms between profiler ticks.
335ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org * @constructor
345ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org */
35496c03a64f12710e837204e261ef155601247895sgjesse@chromium.orgfunction ViewBuilder(samplingRate) {
365ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org  this.samplingRate = samplingRate;
375ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org};
385ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org
395ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org
405ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org/**
415ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org * Builds a profile view for the specified call tree.
425ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org *
43496c03a64f12710e837204e261ef155601247895sgjesse@chromium.org * @param {CallTree} callTree A call tree.
44b3284ad36ee358a35b81379ad1c449e4f8021362kasperl@chromium.org * @param {boolean} opt_bottomUpViewWeights Whether remapping
45b3284ad36ee358a35b81379ad1c449e4f8021362kasperl@chromium.org *     of self weights for a bottom up view is needed.
465ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org */
47496c03a64f12710e837204e261ef155601247895sgjesse@chromium.orgViewBuilder.prototype.buildView = function(
48b3284ad36ee358a35b81379ad1c449e4f8021362kasperl@chromium.org    callTree, opt_bottomUpViewWeights) {
495ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org  var head;
505ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org  var samplingRate = this.samplingRate;
51e2902be65446e26fd63a3b4eab2f14257cf4ebafager@chromium.org  var createViewNode = this.createViewNode;
525ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org  callTree.traverse(function(node, viewParent) {
53b3284ad36ee358a35b81379ad1c449e4f8021362kasperl@chromium.org    var totalWeight = node.totalWeight * samplingRate;
54b3284ad36ee358a35b81379ad1c449e4f8021362kasperl@chromium.org    var selfWeight = node.selfWeight * samplingRate;
55b3284ad36ee358a35b81379ad1c449e4f8021362kasperl@chromium.org    if (opt_bottomUpViewWeights === true) {
56b3284ad36ee358a35b81379ad1c449e4f8021362kasperl@chromium.org      if (viewParent === head) {
57b3284ad36ee358a35b81379ad1c449e4f8021362kasperl@chromium.org        selfWeight = totalWeight;
58b3284ad36ee358a35b81379ad1c449e4f8021362kasperl@chromium.org      } else {
59b3284ad36ee358a35b81379ad1c449e4f8021362kasperl@chromium.org        selfWeight = 0;
60b3284ad36ee358a35b81379ad1c449e4f8021362kasperl@chromium.org      }
61b3284ad36ee358a35b81379ad1c449e4f8021362kasperl@chromium.org    }
62e2902be65446e26fd63a3b4eab2f14257cf4ebafager@chromium.org    var viewNode = createViewNode(node.label, totalWeight, selfWeight, head);
635ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org    if (viewParent) {
645ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org      viewParent.addChild(viewNode);
655ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org    } else {
665ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org      head = viewNode;
675ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org    }
685ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org    return viewNode;
695ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org  });
70e2902be65446e26fd63a3b4eab2f14257cf4ebafager@chromium.org  var view = this.createView(head);
715ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org  return view;
725ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org};
735ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org
745ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org
755ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org/**
76e2902be65446e26fd63a3b4eab2f14257cf4ebafager@chromium.org * Factory method for a profile view.
77e2902be65446e26fd63a3b4eab2f14257cf4ebafager@chromium.org *
78496c03a64f12710e837204e261ef155601247895sgjesse@chromium.org * @param {ProfileView.Node} head View head node.
79496c03a64f12710e837204e261ef155601247895sgjesse@chromium.org * @return {ProfileView} Profile view.
80e2902be65446e26fd63a3b4eab2f14257cf4ebafager@chromium.org */
81496c03a64f12710e837204e261ef155601247895sgjesse@chromium.orgViewBuilder.prototype.createView = function(head) {
82496c03a64f12710e837204e261ef155601247895sgjesse@chromium.org  return new ProfileView(head);
83e2902be65446e26fd63a3b4eab2f14257cf4ebafager@chromium.org};
84e2902be65446e26fd63a3b4eab2f14257cf4ebafager@chromium.org
85e2902be65446e26fd63a3b4eab2f14257cf4ebafager@chromium.org
86e2902be65446e26fd63a3b4eab2f14257cf4ebafager@chromium.org/**
87e2902be65446e26fd63a3b4eab2f14257cf4ebafager@chromium.org * Factory method for a profile view node.
88e2902be65446e26fd63a3b4eab2f14257cf4ebafager@chromium.org *
89e2902be65446e26fd63a3b4eab2f14257cf4ebafager@chromium.org * @param {string} internalFuncName A fully qualified function name.
90e2902be65446e26fd63a3b4eab2f14257cf4ebafager@chromium.org * @param {number} totalTime Amount of time that application spent in the
91e2902be65446e26fd63a3b4eab2f14257cf4ebafager@chromium.org *     corresponding function and its descendants (not that depending on
92e2902be65446e26fd63a3b4eab2f14257cf4ebafager@chromium.org *     profile they can be either callees or callers.)
93e2902be65446e26fd63a3b4eab2f14257cf4ebafager@chromium.org * @param {number} selfTime Amount of time that application spent in the
94e2902be65446e26fd63a3b4eab2f14257cf4ebafager@chromium.org *     corresponding function only.
95496c03a64f12710e837204e261ef155601247895sgjesse@chromium.org * @param {ProfileView.Node} head Profile view head.
96496c03a64f12710e837204e261ef155601247895sgjesse@chromium.org * @return {ProfileView.Node} Profile view node.
97e2902be65446e26fd63a3b4eab2f14257cf4ebafager@chromium.org */
98496c03a64f12710e837204e261ef155601247895sgjesse@chromium.orgViewBuilder.prototype.createViewNode = function(
99e2902be65446e26fd63a3b4eab2f14257cf4ebafager@chromium.org    funcName, totalTime, selfTime, head) {
100496c03a64f12710e837204e261ef155601247895sgjesse@chromium.org  return new ProfileView.Node(
101e2902be65446e26fd63a3b4eab2f14257cf4ebafager@chromium.org      funcName, totalTime, selfTime, head);
102e2902be65446e26fd63a3b4eab2f14257cf4ebafager@chromium.org};
103e2902be65446e26fd63a3b4eab2f14257cf4ebafager@chromium.org
104e2902be65446e26fd63a3b4eab2f14257cf4ebafager@chromium.org
105e2902be65446e26fd63a3b4eab2f14257cf4ebafager@chromium.org/**
1065ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org * Creates a Profile View object. It allows to perform sorting
107e2902be65446e26fd63a3b4eab2f14257cf4ebafager@chromium.org * and filtering actions on the profile.
1085ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org *
109496c03a64f12710e837204e261ef155601247895sgjesse@chromium.org * @param {ProfileView.Node} head Head (root) node.
1105ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org * @constructor
1115ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org */
112496c03a64f12710e837204e261ef155601247895sgjesse@chromium.orgfunction ProfileView(head) {
1135ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org  this.head = head;
1145ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org};
1155ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org
1165ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org
1175ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org/**
1185ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org * Sorts the profile view using the specified sort function.
1195ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org *
120496c03a64f12710e837204e261ef155601247895sgjesse@chromium.org * @param {function(ProfileView.Node,
121496c03a64f12710e837204e261ef155601247895sgjesse@chromium.org *     ProfileView.Node):number} sortFunc A sorting
1225ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org *     functions. Must comply with Array.sort sorting function requirements.
1235ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org */
124496c03a64f12710e837204e261ef155601247895sgjesse@chromium.orgProfileView.prototype.sort = function(sortFunc) {
1255ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org  this.traverse(function (node) {
1265ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org    node.sortChildren(sortFunc);
1275ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org  });
1285ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org};
1295ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org
1305ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org
1315ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org/**
1325ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org * Traverses profile view nodes in preorder.
1335ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org *
134496c03a64f12710e837204e261ef155601247895sgjesse@chromium.org * @param {function(ProfileView.Node)} f Visitor function.
1355ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org */
136496c03a64f12710e837204e261ef155601247895sgjesse@chromium.orgProfileView.prototype.traverse = function(f) {
1375ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org  var nodesToTraverse = new ConsArray();
1385ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org  nodesToTraverse.concat([this.head]);
1395ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org  while (!nodesToTraverse.atEnd()) {
1405ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org    var node = nodesToTraverse.next();
1415ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org    f(node);
1425ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org    nodesToTraverse.concat(node.children);
1435ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org  }
1445ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org};
1455ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org
1465ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org
1475ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org/**
1485ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org * Constructs a Profile View node object. Each node object corresponds to
1495ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org * a function call.
1505ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org *
1515ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org * @param {string} internalFuncName A fully qualified function name.
1525ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org * @param {number} totalTime Amount of time that application spent in the
1535ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org *     corresponding function and its descendants (not that depending on
1545ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org *     profile they can be either callees or callers.)
1555ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org * @param {number} selfTime Amount of time that application spent in the
1565ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org *     corresponding function only.
157496c03a64f12710e837204e261ef155601247895sgjesse@chromium.org * @param {ProfileView.Node} head Profile view head.
1585ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org * @constructor
1595ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org */
160496c03a64f12710e837204e261ef155601247895sgjesse@chromium.orgProfileView.Node = function(
1615ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org    internalFuncName, totalTime, selfTime, head) {
1625ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org  this.internalFuncName = internalFuncName;
1635ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org  this.totalTime = totalTime;
1645ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org  this.selfTime = selfTime;
1655ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org  this.head = head;
1665ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org  this.parent = null;
1675ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org  this.children = [];
1685ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org};
1695ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org
1705ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org
1715ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org/**
1725ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org * Returns a share of the function's total time in its parent's total time.
1735ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org */
174496c03a64f12710e837204e261ef155601247895sgjesse@chromium.orgProfileView.Node.prototype.__defineGetter__(
1755ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org    'parentTotalPercent',
1765ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org    function() { return this.totalTime /
1775ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org      (this.parent ? this.parent.totalTime : this.totalTime) * 100.0; });
1785ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org
1795ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org
1805ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org/**
1815ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org * Adds a child to the node.
1825ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org *
183496c03a64f12710e837204e261ef155601247895sgjesse@chromium.org * @param {ProfileView.Node} node Child node.
1845ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org */
185496c03a64f12710e837204e261ef155601247895sgjesse@chromium.orgProfileView.Node.prototype.addChild = function(node) {
1865ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org  node.parent = this;
1875ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org  this.children.push(node);
1885ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org};
1895ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org
1905ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org
1915ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org/**
1925ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org * Sorts all the node's children recursively.
1935ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org *
194496c03a64f12710e837204e261ef155601247895sgjesse@chromium.org * @param {function(ProfileView.Node,
195496c03a64f12710e837204e261ef155601247895sgjesse@chromium.org *     ProfileView.Node):number} sortFunc A sorting
1965ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org *     functions. Must comply with Array.sort sorting function requirements.
1975ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org */
198496c03a64f12710e837204e261ef155601247895sgjesse@chromium.orgProfileView.Node.prototype.sortChildren = function(
1995ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org    sortFunc) {
2005ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org  this.children.sort(sortFunc);
2015ec4892aef9cca42940d7d92302abf674365f6b7ager@chromium.org};
202