summaryrefslogtreecommitdiffstats
path: root/tools/deep_memory_profiler
diff options
context:
space:
mode:
authorjunjianx@chromium.org <junjianx@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-08-16 02:56:09 +0000
committerjunjianx@chromium.org <junjianx@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-08-16 02:56:09 +0000
commit485fd579f74a6f24bdde004dc871df86d17137e8 (patch)
tree4b213ee19c2c94ab77808ec20f5cf6c953151b2f /tools/deep_memory_profiler
parent13cac682638080201b5754833bcbcdb7ecf032ed (diff)
downloadchromium_src-485fd579f74a6f24bdde004dc871df86d17137e8.zip
chromium_src-485fd579f74a6f24bdde004dc871df86d17137e8.tar.gz
chromium_src-485fd579f74a6f24bdde004dc871df86d17137e8.tar.bz2
Add line selecting feature for dmprof graph visualizer, and separate profiler class to new file
BUG=259206 NOTRY=True Review URL: https://chromiumcodereview.appspot.com/23216003 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@217916 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'tools/deep_memory_profiler')
-rw-r--r--tools/deep_memory_profiler/visualizer/main.html2
-rw-r--r--tools/deep_memory_profiler/visualizer/main.js155
-rw-r--r--tools/deep_memory_profiler/visualizer/profiler.js110
-rw-r--r--tools/deep_memory_profiler/visualizer/utility.js27
4 files changed, 187 insertions, 107 deletions
diff --git a/tools/deep_memory_profiler/visualizer/main.html b/tools/deep_memory_profiler/visualizer/main.html
index fdd7874..75df003 100644
--- a/tools/deep_memory_profiler/visualizer/main.html
+++ b/tools/deep_memory_profiler/visualizer/main.html
@@ -9,6 +9,8 @@ found in the LICENSE file.
<script src="../../../third_party/flot/jquery.min.js"></script>
<script src="../../../third_party/flot/jquery.flot.min.js"></script>
<script src="../../../third_party/flot/jquery.flot.stack.min.js"></script>
+<script src="utility.js"></script>
+<script src="profiler.js"></script>
<script src="main.js"></script>
<body>
diff --git a/tools/deep_memory_profiler/visualizer/main.js b/tools/deep_memory_profiler/visualizer/main.js
index 8c4dff8..1d96213 100644
--- a/tools/deep_memory_profiler/visualizer/main.js
+++ b/tools/deep_memory_profiler/visualizer/main.js
@@ -3,111 +3,6 @@
// found in the LICENSE file.
/**
- * This class provides data access interface for dump file profiler
- * @constructor
- */
-var Profiler = function(jsonData) {
- this._jsonData = jsonData;
-};
-
-/**
- * Get units of a snapshot in a world.
- * Exception will be thrown when no world of given name exists.
- * @param {string} worldName
- * @param {number} snapshotIndex
- * @return {Object.<string, number>}
- */
-Profiler.prototype.getUnits = function(worldName, snapshotIndex) {
- var snapshot = this._jsonData.snapshots[snapshotIndex];
- if (!snapshot.worlds[worldName])
- throw 'no world ' + worldName + ' in snapshot ' + index;
-
- // Return units.
- var world = snapshot.worlds[worldName];
- var units = {};
- for (var unitName in world.units)
- units[unitName] = world.units[unitName][0];
- return units;
-};
-
-/**
- * Get first-level breakdowns of a snapshot in a world.
- * Exception will be thrown when no world of given name exists.
- * @param {string} worldName
- * @param {number} snapshotIndex
- * @return {Object.<string, Object>}
- */
-Profiler.prototype.getBreakdowns = function(worldName, snapshotIndex) {
- var snapshot = this._jsonData.snapshots[snapshotIndex];
- if (!snapshot.worlds[worldName])
- throw 'no world ' + worldName + ' in snapshot ' + index;
-
- // Return breakdowns.
- // TODO(junjianx): handle breakdown with arbitrary-level structure.
- return snapshot.worlds[worldName].breakdown;
-};
-
-/**
- * Get categories from fixed hard-coded worlds and breakdowns temporarily.
- * TODO(junjianx): remove the hard-code and support general cases.
- * @return {Array.<Object>}
- */
-Profiler.prototype.getCategories = function() {
- var categories = [];
- var snapshotNum = this._jsonData.snapshots.length;
-
- for (var snapshotIndex = 0; snapshotIndex < snapshotNum; ++snapshotIndex) {
- // Initial categories object for one snapshot.
- categories.push({});
-
- // Handle breakdowns in malloc world.
- var mallocBreakdown = this.getBreakdowns('malloc', snapshotIndex);
- var mallocUnits = this.getUnits('malloc', snapshotIndex);
- if (!mallocBreakdown['component'])
- throw 'no breakdown ' + 'component' + ' in snapshot ' + snapshotIndex;
-
- var componentBreakdown = mallocBreakdown['component'];
- var componentMemory = 0;
- Object.keys(componentBreakdown).forEach(function(breakdownName) {
- var breakdown = componentBreakdown[breakdownName];
- var memory = breakdown.units.reduce(function(previous, current) {
- return previous + mallocUnits[current];
- }, 0);
- componentMemory += memory;
-
- if (componentBreakdown['hidden'] === true)
- return;
- else
- categories[snapshotIndex][breakdownName] = memory;
- });
-
- // Handle breakdowns in vm world.
- var vmBreakdown = this.getBreakdowns('vm', snapshotIndex);
- var vmUnits = this.getUnits('vm', snapshotIndex);
- if (!vmBreakdown['map'])
- throw 'no breakdown ' + 'map' + ' in snapshot ' + snapshotIndex;
-
- var mapBreakdown = vmBreakdown['map'];
-
- Object.keys(mapBreakdown).forEach(function(breakdownName) {
- var breakdown = mapBreakdown[breakdownName];
- var memory = breakdown.units.reduce(function(previous, current) {
- return previous + vmUnits[current];
- }, 0);
-
- if (vmBreakdown['hidden'] === true)
- return;
- else if (breakdownName === 'mmap-tcmalloc')
- categories[snapshotIndex]['tc-unused'] = memory - componentMemory;
- else
- categories[snapshotIndex][breakdownName] = memory;
- });
- }
-
- return categories;
-};
-
-/**
* Generate lines for flot plotting.
* @param {Array.<Object>} categories
* @return {Array.<Object>}
@@ -148,13 +43,59 @@ $(function() {
var profiler = new Profiler(jsonData);
var categories = profiler.getCategories();
var lines = generateLines(categories);
+ var placeholder = '#plot';
+
+ // Bind click event so that user can select breakdown by clicking stack
+ // area. It firstly checks x range which clicked point is in, and all lines
+ // share same x values, so it is checked only once at first. Secondly, it
+ // checked y range by accumulated y values because this is a stack graph.
+ $(placeholder).bind('plotclick', function(event, pos, item) {
+ // If only <=1 line exists or axis area clicked, return.
+ var right = binarySearch.call(lines[0].data.map(function(point) {
+ return point[0];
+ }), pos.x);
+ if (lines.length <= 1 || right === lines.length || right === 0)
+ return;
+
+ // Calculate interpolate y value of every line.
+ for (var i = 0; i < lines.length; ++i) {
+ var line = lines[i].data;
+ // [left, right] is the range including clicked point.
+ var left = right - 1;
+ var leftPoint = {
+ x: line[left][0],
+ y: (leftPoint ? leftPoint.y : 0) + line[left][1]
+ };
+ var rightPoint = {
+ x: line[right][0],
+ y: (rightPoint ? rightPoint.y : 0) + line[right][1]
+ };
+
+ // Calculate slope of the linear equation.
+ var slope = (rightPoint.y - leftPoint.y) / (rightPoint.x - leftPoint.x);
+ var interpolateY = slope * (pos.x - rightPoint.x) + rightPoint.y;
+ if (interpolateY >= pos.y)
+ break;
+ }
+
+ // If pos.y is higher than all lines, return.
+ if (i === lines.length)
+ return;
+
+ // TODO(junjianx): temporary log for checking selected object.
+ console.log('line ' + i + ' is selected.');
+ });
// Plot stack graph.
- $.plot('#plot', lines, {
+ $.plot(placeholder, lines, {
series: {
stack: true,
lines: { show: true, fill: true }
+ },
+ grid: {
+ hoverable: true,
+ clickable: true
}
});
});
-}); \ No newline at end of file
+});
diff --git a/tools/deep_memory_profiler/visualizer/profiler.js b/tools/deep_memory_profiler/visualizer/profiler.js
new file mode 100644
index 0000000..672c8f0
--- /dev/null
+++ b/tools/deep_memory_profiler/visualizer/profiler.js
@@ -0,0 +1,110 @@
+// Copyright 2013 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.
+
+/**
+ * This class provides data access interface for dump file profiler
+ * @constructor
+ */
+var Profiler = function(jsonData) {
+ this._jsonData = jsonData;
+};
+
+/**
+ * Get units of a snapshot in a world.
+ * Exception will be thrown when no world of given name exists.
+ * @param {string} worldName
+ * @param {number} snapshotIndex
+ * @return {Object.<string, number>}
+ * @private
+ */
+Profiler.prototype.getUnits_ = function(worldName, snapshotIndex) {
+ var snapshot = this._jsonData.snapshots[snapshotIndex];
+ if (!snapshot.worlds[worldName])
+ throw 'no world ' + worldName + ' in snapshot ' + index;
+
+ // Return units.
+ var world = snapshot.worlds[worldName];
+ var units = {};
+ for (var unitName in world.units)
+ units[unitName] = world.units[unitName][0];
+ return units;
+};
+
+/**
+ * Get first-level breakdowns of a snapshot in a world.
+ * Exception will be thrown when no world of given name exists.
+ * @param {string} worldName
+ * @param {number} snapshotIndex
+ * @return {Object.<string, Object>}
+ * @private
+ */
+Profiler.prototype.getBreakdowns_ = function(worldName, snapshotIndex) {
+ var snapshot = this._jsonData.snapshots[snapshotIndex];
+ if (!snapshot.worlds[worldName])
+ throw 'no world ' + worldName + ' in snapshot ' + index;
+
+ // Return breakdowns.
+ // TODO(junjianx): handle breakdown with arbitrary-level structure.
+ return snapshot.worlds[worldName].breakdown;
+};
+
+/**
+ * Get categories from fixed hard-coded worlds and breakdowns temporarily.
+ * TODO(junjianx): remove the hard-code and support general cases.
+ * @return {Array.<Object>}
+ */
+Profiler.prototype.getCategories = function() {
+ var categories = [];
+ var snapshotNum = this._jsonData.snapshots.length;
+
+ for (var snapshotIndex = 0; snapshotIndex < snapshotNum; ++snapshotIndex) {
+ // Initial categories object for one snapshot.
+ categories.push({});
+
+ // Handle breakdowns in malloc world.
+ var mallocBreakdown = this.getBreakdowns_('malloc', snapshotIndex);
+ var mallocUnits = this.getUnits_('malloc', snapshotIndex);
+ if (!mallocBreakdown['component'])
+ throw 'no breakdown ' + 'component' + ' in snapshot ' + snapshotIndex;
+
+ var componentBreakdown = mallocBreakdown['component'];
+ var componentMemory = 0;
+ Object.keys(componentBreakdown).forEach(function(breakdownName) {
+ var breakdown = componentBreakdown[breakdownName];
+ var memory = breakdown.units.reduce(function(previous, current) {
+ return previous + mallocUnits[current];
+ }, 0);
+ componentMemory += memory;
+
+ if (componentBreakdown['hidden'] === true)
+ return;
+ else
+ categories[snapshotIndex][breakdownName] = memory;
+ });
+
+ // Handle breakdowns in vm world.
+ var vmBreakdown = this.getBreakdowns_('vm', snapshotIndex);
+ var vmUnits = this.getUnits_('vm', snapshotIndex);
+ if (!vmBreakdown['map'])
+ throw 'no breakdown ' + 'map' + ' in snapshot ' + snapshotIndex;
+
+ var mapBreakdown = vmBreakdown['map'];
+
+ Object.keys(mapBreakdown).forEach(function(breakdownName) {
+ var breakdown = mapBreakdown[breakdownName];
+ var memory = breakdown.units.reduce(function(previous, current) {
+ return previous + vmUnits[current];
+ }, 0);
+
+ if (vmBreakdown['hidden'] === true)
+ return;
+ else if (breakdownName === 'mmap-tcmalloc')
+ categories[snapshotIndex]['tc-unused'] = memory - componentMemory;
+ else
+ categories[snapshotIndex][breakdownName] = memory;
+ });
+ }
+
+ return categories;
+};
diff --git a/tools/deep_memory_profiler/visualizer/utility.js b/tools/deep_memory_profiler/visualizer/utility.js
new file mode 100644
index 0000000..f595fd0
--- /dev/null
+++ b/tools/deep_memory_profiler/visualizer/utility.js
@@ -0,0 +1,27 @@
+// Copyright 2013 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.
+
+/**
+ * This function returns the first element index that >= target, when no element
+ * in the array >= target, return array.length.
+ * This function must be called in the shape of binarySearch(array, target).
+ * @param {number} target
+ * @return {number}
+ */
+var binarySearch = function(target) {
+ 'use strict';
+
+ var left = 0;
+ var right = this.length - 1;
+ while (left <= right) {
+ var mid = Math.floor((left + right) / 2);
+ if (this[mid] < target)
+ left = mid + 1;
+ else if (this[mid] > target)
+ right = mid - 1;
+ else
+ return mid;
+ }
+ return left;
+};