| Index: tracing/tracing/ui/analysis/memory_dump_heap_details_pane.html
|
| diff --git a/tracing/tracing/ui/analysis/memory_dump_heap_details_pane.html b/tracing/tracing/ui/analysis/memory_dump_heap_details_pane.html
|
| index 6d3ab2f9b9ded76e31520bf3ecccb4e95c8fd3a5..35dce67c760dcad5d4712ddbf9a9ea8314c90967 100644
|
| --- a/tracing/tracing/ui/analysis/memory_dump_heap_details_pane.html
|
| +++ b/tracing/tracing/ui/analysis/memory_dump_heap_details_pane.html
|
| @@ -1,6 +1,6 @@
|
| <!DOCTYPE html>
|
| <!--
|
| -Copyright 2015 The Chromium Authors. All rights reserved.
|
| +Copyright 2016 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.
|
| -->
|
| @@ -9,13 +9,40 @@ found in the LICENSE file.
|
| <link rel="import" href="/tracing/base/iteration_helpers.html">
|
| <link rel="import" href="/tracing/base/multi_dimensional_view.html">
|
| <link rel="import" href="/tracing/ui/analysis/memory_dump_sub_view_util.html">
|
| +<link rel="import" href="/tracing/ui/analysis/rebuildable_behavior.html">
|
| <link rel="import" href="/tracing/ui/analysis/stacked_pane.html">
|
| <link rel="import" href="/tracing/ui/base/dom_helpers.html">
|
| +<link rel="import" href="/tracing/ui/base/drag_handle.html">
|
| <link rel='import' href='/tracing/ui/base/info_bar.html'>
|
| <link rel="import" href="/tracing/ui/base/table.html">
|
| +<link rel="import" href="/tracing/ui/base/tab_view.html">
|
| <link rel="import" href="/tracing/value/numeric.html">
|
| <link rel="import" href="/tracing/value/unit.html">
|
|
|
| +<dom-module id='tr-ui-a-memory-dump-heap-details-path'>
|
| + <template>
|
| + <style>
|
| + :host {
|
| + display: flex;
|
| + flex-direction: column;
|
| + }
|
| + </style>
|
| + <tr-ui-b-table id="table"></tr-ui-b-table>
|
| + </template>
|
| +</dom-module>
|
| +
|
| +<dom-module id='tr-ui-a-memory-dump-heap-details-view'>
|
| + <template>
|
| + <tr-ui-b-tab-view id="tabs"></tr-ui-b-tab-view>
|
| + </template>
|
| +</dom-module>
|
| +
|
| +<dom-module id='tr-ui-a-memory-dump-heap-details-tab'>
|
| + <template>
|
| + <tr-ui-b-table id="table"></tr-ui-b-table>
|
| + </template>
|
| +</dom-module>
|
| +
|
| <dom-module id='tr-ui-a-memory-dump-heap-details-pane'>
|
| <template>
|
| <style>
|
| @@ -62,10 +89,24 @@ found in the LICENSE file.
|
| text-align: center;
|
| }
|
|
|
| - #table {
|
| - display: none; /* Hide until memory allocator dumps are set. */
|
| + #split_view {
|
| + display: none; /* Hide until memory allocator dumps are set. */
|
| flex: 1 0 auto;
|
| align-self: stretch;
|
| + flex-direction: row;
|
| + }
|
| +
|
| + #path {
|
| + width: 50%;
|
| + }
|
| +
|
| + #view {
|
| + flex: 1 1 auto;
|
| + width: 0;
|
| + }
|
| +
|
| + #path, #view {
|
| + overflow-x: auto; /* Show scrollbar if necessary. */
|
| }
|
| </style>
|
| <div id="header">
|
| @@ -78,8 +119,16 @@ found in the LICENSE file.
|
| <div id="contents">
|
| <tr-ui-b-info-bar id="info_bar" class="info-bar-hidden">
|
| </tr-ui-b-info-bar>
|
| +
|
| <div id="info_text">No heap dump selected</div>
|
| - <tr-ui-b-table id="table"></tr-ui-b-table>
|
| +
|
| + <div id="split_view">
|
| + <tr-ui-a-memory-dump-heap-details-path id="path">
|
| + </tr-ui-a-memory-dump-heap-details-path>
|
| + <tr-ui-b-drag-handle id="drag_handle"></tr-ui-b-drag-handle>
|
| + <tr-ui-a-memory-dump-heap-details-view id="view">
|
| + </tr-ui-a-memory-dump-heap-details-view>
|
| + </div>
|
| </div>
|
| </template>
|
| </dom-module>
|
| @@ -96,22 +145,175 @@ tr.exportTo('tr.ui.analysis', function() {
|
| var MultiDimensionalViewBuilder = tr.b.MultiDimensionalViewBuilder;
|
| var TotalState = tr.b.MultiDimensionalViewNode.TotalState;
|
|
|
| + var LATIN_SMALL_LETTER_F_WITH_HOOK = String.fromCharCode(0x0192);
|
| + var CIRCLED_LATIN_CAPITAL_LETTER_T = String.fromCharCode(0x24C9);
|
| +
|
| /** @{enum} */
|
| var RowDimension = {
|
| - ROOT: -1,
|
| - STACK_FRAME: 0,
|
| - OBJECT_TYPE: 1
|
| + ROOT: {},
|
| + STACK_FRAME: {
|
| + label: 'Stack frame',
|
| + symbol: LATIN_SMALL_LETTER_F_WITH_HOOK,
|
| + color: 'heap_dump_stack_frame'
|
| + },
|
| + OBJECT_TYPE: {
|
| + label: 'Object type',
|
| + symbol: CIRCLED_LATIN_CAPITAL_LETTER_T,
|
| + color: 'heap_dump_object_type'
|
| + }
|
| };
|
|
|
| - var LATIN_SMALL_LETTER_F_WITH_HOOK = String.fromCharCode(0x0192);
|
| - var CIRCLED_LATIN_CAPITAL_LETTER_T = String.fromCharCode(0x24C9);
|
|
|
| /** @{constructor} */
|
| - function HeapDumpNodeTitleColumn(title) {
|
| + function HeapDumpTreeNode(stackFrameNodes, dimension, title, heavyView, parentNode) {
|
| + this.dimension = dimension;
|
| + this.title = title;
|
| + this.parentNode = parentNode;
|
| +
|
| + this.heavyView_ = heavyView;
|
| + this.stackFrameNodes_ = stackFrameNodes;
|
| + this.lazyCells_ = undefined;
|
| + this.lazyChildNodes_ = undefined;
|
| + }
|
| +
|
| + HeapDumpTreeNode.prototype = {
|
| + get minDisplayedTotalState_() {
|
| + if (this.heavyView_) {
|
| + // Show lower-bound and exact values in heavy views.
|
| + return TotalState.LOWER_BOUND;
|
| + } else {
|
| + // Show only exact values in tree view.
|
| + return TotalState.EXACT;
|
| + }
|
| + },
|
| +
|
| + get childNodes() {
|
| + if (!this.lazyChildNodes_) {
|
| + this.lazyChildNodes_ = new Map();
|
| + this.addDimensionChildNodes_(RowDimension.STACK_FRAME, 0);
|
| + this.addDimensionChildNodes_(RowDimension.OBJECT_TYPE, 1);
|
| + this.releaseStackFrameNodesIfPossible_();
|
| + }
|
| + return this.lazyChildNodes_;
|
| + },
|
| +
|
| + get cells() {
|
| + if (!this.lazyCells_) {
|
| + this.addCells_();
|
| + this.releaseStackFrameNodesIfPossible_();
|
| + }
|
| + return this.lazyCells_;
|
| + },
|
| +
|
| + releaseStackFrameNodesIfPossible_: function() {
|
| + if (this.lazyCells_ && this.lazyChildNodes_) {
|
| + // Don't unnecessarily hold a reference to the stack frame nodes when
|
| + // we don't need it anymore.
|
| + this.stackFrameNodes_ = undefined;
|
| + }
|
| + },
|
| +
|
| + addDimensionChildNodes_: function(dimension, dimensionIndex) {
|
| + // Sub-row name (list index) -> Timestamp (list index) -> Child
|
| + // MultiDimensionalViewNode.
|
| + var dimensionGroupedChildNodes = tr.b.dictionaryValues(
|
| + tr.b.invertArrayOfDicts(this.stackFrameNodes_,
|
| + function(stackFrameNode) {
|
| + var childDict = {};
|
| + var displayedChildrenTotalSize = 0;
|
| + var displayedChildrenTotalCount = 0;
|
| + var hasDisplayedChildren = false;
|
| + var allDisplayedChildrenHaveDisplayedCounts = true;
|
| + for (var child of stackFrameNode.children[dimensionIndex].values()) {
|
| + if (child.values[0].totalState < this.minDisplayedTotalState_)
|
| + continue;
|
| + if (child.values[1].totalState < this.minDisplayedTotalState_)
|
| + allDisplayedChildrenHaveDisplayedCounts = false;
|
| + childDict[child.title[dimensionIndex]] = child;
|
| + displayedChildrenTotalSize += child.values[0].total;
|
| + displayedChildrenTotalCount += child.values[1].total;
|
| + hasDisplayedChildren = true;
|
| + }
|
| +
|
| + var nodeTotalSize = stackFrameNode.values[0].total;
|
| + var nodeTotalCount = stackFrameNode.values[1].total;
|
| +
|
| + // Add '<other>' node if necessary in tree-view.
|
| + var hasUnclassifiedSizeOrCount =
|
| + displayedChildrenTotalSize < nodeTotalSize ||
|
| + displayedChildrenTotalCount < nodeTotalCount;
|
| + if (!this.heavyView && hasUnclassifiedSizeOrCount &&
|
| + hasDisplayedChildren) {
|
| + var otherTitle = stackFrameNode.title.slice();
|
| + otherTitle[dimensionIndex] = '<other>';
|
| + childDict['<other>'] = {
|
| + title: otherTitle,
|
| + values: [
|
| + {
|
| + self: 0,
|
| + total: nodeTotalSize - displayedChildrenTotalSize,
|
| + totalState: this.minDisplayedTotalState_
|
| + },
|
| + {
|
| + self: 0,
|
| + total: nodeTotalCount - displayedChildrenTotalCount,
|
| + // Don't show allocation count of the '<other>' node if
|
| + // there is a displayed child node that did NOT display
|
| + // allocation count.
|
| + totalState: allDisplayedChildrenHaveDisplayedCounts ?
|
| + this.minDisplayedTotalState_ :
|
| + TotalState.NOT_PROVIDED
|
| + }
|
| + ],
|
| + children: [new Map(), new Map()]
|
| + };
|
| + }
|
| +
|
| + return childDict;
|
| + }, this));
|
| +
|
| + if (dimensionGroupedChildNodes.length === 0)
|
| + return;
|
| +
|
| + // Sub-row name (list index) -> Sub-row.
|
| + this.lazyChildNodes_.set(dimension,
|
| + dimensionGroupedChildNodes.map(function(subRowNodes) {
|
| + var subRowTitle =
|
| + tr.b.findFirstInArray(subRowNodes).title[dimensionIndex];
|
| + return new HeapDumpTreeNode(subRowNodes, dimension, subRowTitle,
|
| + this.heavyView_, this);
|
| + }, this));
|
| + },
|
| +
|
| + addCells_: function() {
|
| + // Transform a chronological list of heap stack frame tree nodes into a
|
| + // dictionary of cells (where each cell contains a chronological list
|
| + // of the values of its numeric).
|
| + this.lazyCells_ = tr.ui.analysis.createCells(this.stackFrameNodes_,
|
| + function(stackFrameNode) {
|
| + var size = stackFrameNode.values[0].total;
|
| + var numerics = {
|
| + 'Size': new ScalarNumeric(sizeInBytes_smallerIsBetter, size)
|
| + };
|
| + var countValue = stackFrameNode.values[1];
|
| + if (countValue.totalState >= this.minDisplayedTotalState_) {
|
| + var count = countValue.total;
|
| + numerics['Count'] = new ScalarNumeric(
|
| + unitlessNumber_smallerIsBetter, count);
|
| + numerics['Average size per allocation'] = new ScalarNumeric(
|
| + sizeInBytes_smallerIsBetter, count === 0 ? 0 : size / count);
|
| + }
|
| + return numerics;
|
| + });
|
| + }
|
| + };
|
| +
|
| + /** @{constructor} */
|
| + function HeapDumpTreeNodeTitleColumn(title) {
|
| tr.ui.analysis.TitleColumn.call(this, title);
|
| }
|
|
|
| - HeapDumpNodeTitleColumn.prototype = {
|
| + HeapDumpTreeNodeTitleColumn.prototype = {
|
| __proto__: tr.ui.analysis.TitleColumn.prototype,
|
|
|
| formatTitle: function(row) {
|
| @@ -210,7 +412,6 @@ tr.exportTo('tr.ui.analysis', function() {
|
| },
|
|
|
| ready: function() {
|
| - this.$.table.selectionMode = tr.ui.b.TableFormat.SelectionMode.ROW;
|
| this.$.info_bar.message = 'Note: Values displayed in the heavy view ' +
|
| 'are lower bounds (except for the root).';
|
|
|
| @@ -234,6 +435,16 @@ tr.exportTo('tr.ui.analysis', function() {
|
| .BOTTOM_UP_HEAVY_VIEW
|
| }
|
| ]));
|
| +
|
| + this.$.drag_handle.target = this.$.path;
|
| + this.$.drag_handle.horizontal = false;
|
| +
|
| + this.$.path.addEventListener('selected-node-changed', (function(event) {
|
| + this.$.view.displayedNode = this.$.path.selectedNode;
|
| + }).bind(this));
|
| + this.$.view.addEventListener('displayed-node-changed', (function(event) {
|
| + this.$.path.selectedNode = this.$.view.displayedNode;
|
| + }).bind(this));
|
| },
|
|
|
| /**
|
| @@ -260,6 +471,8 @@ tr.exportTo('tr.ui.analysis', function() {
|
|
|
| set aggregationMode(aggregationMode) {
|
| this.aggregationMode_ = aggregationMode;
|
| + this.$.path.aggregationMode = aggregationMode;
|
| + this.$.view.aggregationMode = aggregationMode;
|
| this.scheduleRebuild_();
|
| },
|
|
|
| @@ -291,31 +504,36 @@ tr.exportTo('tr.ui.analysis', function() {
|
| this.heapDumps_.length === 0) {
|
| // Show the info text (hide the table and the view mode selector).
|
| this.$.info_text.style.display = 'block';
|
| - this.$.table.style.display = 'none';
|
| + this.$.split_view.style.display = 'none';
|
| this.$.view_mode_container.style.display = 'none';
|
| this.$.info_bar.visible = false;
|
| -
|
| - this.$.table.clear();
|
| - this.$.table.rebuild();
|
| + this.$.path.selectedNode = undefined;
|
| return;
|
| }
|
|
|
| // Show the table and the view mode selector (hide the info text).
|
| this.$.info_text.style.display = 'none';
|
| - this.$.table.style.display = 'block';
|
| + this.$.split_view.style.display = 'flex';
|
| this.$.view_mode_container.style.display = 'block';
|
|
|
| // Show the info bar if in heavy view mode.
|
| this.$.info_bar.visible = this.heavyView;
|
|
|
| - var stackFrameTrees = this.createStackFrameTrees_(this.heapDumps_);
|
| - var rows = this.createRows_(stackFrameTrees);
|
| - var columns = this.createColumns_(rows);
|
| + this.$.path.selectedNode = this.createHeapTree_(this.heapDumps_);
|
| + },
|
|
|
| - this.$.table.tableRows = rows;
|
| - this.$.table.tableColumns = columns;
|
| - this.$.table.rebuild();
|
| - tr.ui.analysis.expandTableRowsRecursively(this.$.table);
|
| + createHeapTree_: function(heapDumps) {
|
| + var definedHeapDump = tr.b.findFirstInArray(heapDumps);
|
| + if (definedHeapDump === undefined)
|
| + return undefined;
|
| +
|
| + var stackFrameTrees = this.createStackFrameTrees_(heapDumps);
|
| +
|
| + // The title of the root node is the name of the allocator.
|
| + var rootRowTitle = definedHeapDump.allocatorName;
|
| +
|
| + return new HeapDumpTreeNode(stackFrameTrees,
|
| + RowDimension.ROOT, rootRowTitle, this.heavyView);
|
| },
|
|
|
| createStackFrameTrees_: function(heapDumps) {
|
| @@ -344,135 +562,232 @@ tr.exportTo('tr.ui.analysis', function() {
|
|
|
| return builder.buildView(this.viewMode);
|
| }, this);
|
| + }
|
| + });
|
| +
|
| + /** @{constructor} */
|
| + function HeapDumpPathNodeTitleColumn(title) {
|
| + tr.ui.analysis.TitleColumn.call(this, title);
|
| + }
|
| +
|
| + HeapDumpPathNodeTitleColumn.prototype = {
|
| + __proto__: tr.ui.analysis.TitleColumn.prototype,
|
| +
|
| + cmp: undefined
|
| + };
|
| +
|
| + Polymer({
|
| + is: 'tr-ui-a-memory-dump-heap-details-path',
|
| + behaviors: [tr.ui.analysis.RebuildableBehavior],
|
| +
|
| + created: function() {
|
| + this.selectedNode_ = undefined;
|
| + this.aggregationMode_ = undefined;
|
| },
|
|
|
| - createRows_: function(stackFrameTrees) {
|
| - var definedHeapDump = tr.b.findFirstInArray(this.heapDumps);
|
| - if (definedHeapDump === undefined)
|
| - return [];
|
| + ready: function() {
|
| + this.$.table.addEventListener('selection-changed', function(event) {
|
| + this.selectedNode_ = this.$.table.selectedTableRow;
|
| + this.dispatchEvent(new tr.b.Event('selected-node-changed'));
|
| + }.bind(this));
|
| + },
|
|
|
| - // The title of the root row is the name of the allocator.
|
| - var rootRowTitle = definedHeapDump.allocatorName;
|
| - return [this.createHeapRowRecursively_(
|
| - stackFrameTrees, RowDimension.ROOT, rootRowTitle)];
|
| + get selectedNode() {
|
| + return this.selectedNode_;
|
| },
|
|
|
| - createHeapRowRecursively_: function(nodes, dimension, title) {
|
| - // Transform a chronological list of stack frame tree nodes into a
|
| - // dictionary of cells (where each cell contains a chronological list
|
| - // of the values of its numeric).
|
| - var cells = tr.ui.analysis.createCells(nodes, function(node) {
|
| - var size = node.values[0].total;
|
| - var row = {
|
| - 'Size': new ScalarNumeric(sizeInBytes_smallerIsBetter, size)
|
| - };
|
| - var countValue = node.values[1];
|
| - if (countValue.totalState >= this.minDisplayedTotalState_) {
|
| - var count = countValue.total;
|
| - row['Count'] = new ScalarNumeric(unitlessNumber_smallerIsBetter,
|
| - count);
|
| - row['Average size per allocation'] = new ScalarNumeric(
|
| - sizeInBytes_smallerIsBetter, count === 0 ? 0 : size / count);
|
| - }
|
| - return row;
|
| - }, this);
|
| + set selectedNode(node) {
|
| + if (this.selectedNode_ === node)
|
| + return;
|
| + this.selectedNode_ = node;
|
| + this.scheduleRebuild_();
|
| + },
|
|
|
| - var row = {
|
| - dimension: dimension,
|
| - title: title,
|
| - contexts: nodes,
|
| - cells: cells
|
| - };
|
| + get aggregationMode() {
|
| + return this.aggregationMode_;
|
| + },
|
|
|
| - // Recursively create sub-rows for children (if applicable).
|
| - var stackFrameSubRows = this.createHeapDimensionSubRowsRecursively_(
|
| - nodes, RowDimension.STACK_FRAME);
|
| - var objectTypeSubRows = this.createHeapDimensionSubRowsRecursively_(
|
| - nodes, RowDimension.OBJECT_TYPE);
|
| - var subRows = stackFrameSubRows.concat(objectTypeSubRows);
|
| - if (subRows.length > 0)
|
| - row.subRows = subRows;
|
| + set aggregationMode(aggregationMode) {
|
| + this.aggregationMode_ = aggregationMode;
|
| + this.scheduleRebuild_();
|
| + },
|
|
|
| - return row;
|
| + onRebuild_: function() {
|
| + if (this.selectedNode_ === undefined) {
|
| + this.$.table.clear();
|
| + return;
|
| + }
|
| +
|
| + this.$.table.selectionMode = tr.ui.b.TableFormat.SelectionMode.ROW;
|
| + var rows = this.createRows_(this.selectedNode_);
|
| + this.$.table.sortable = false;
|
| + this.$.table.tableRows = rows;
|
| + this.$.table.tableColumns = this.createColumns_(rows);
|
| + this.$.table.selectedTableRow = rows[rows.length - 1];
|
| },
|
|
|
| - get minDisplayedTotalState_() {
|
| - if (this.heavyView) {
|
| - // Show lower-bound and exact values in heavy views.
|
| - return TotalState.LOWER_BOUND;
|
| - } else {
|
| - // Show only exact values in tree view.
|
| - return TotalState.EXACT;
|
| + createRows_: function(node) {
|
| + var rows = [];
|
| + while (node) {
|
| + rows.push(node);
|
| + node = node.parentNode;
|
| }
|
| + rows.reverse();
|
| + return rows;
|
| },
|
|
|
| - createHeapDimensionSubRowsRecursively_: function(nodes, dimension) {
|
| - // Sub-row name (list index) -> Timestamp (list index) -> Child
|
| - // MultiDimensionalViewNode.
|
| - var dimensionGroupedChildNodes = tr.b.dictionaryValues(
|
| - tr.b.invertArrayOfDicts(nodes, function(node) {
|
| - var childDict = {};
|
| - var displayedChildrenTotalSize = 0;
|
| - var displayedChildrenTotalCount = 0;
|
| - var hasDisplayedChildren = false;
|
| - var allDisplayedChildrenHaveDisplayedCounts = true;
|
| - for (var child of node.children[dimension].values()) {
|
| - if (child.values[0].totalState < this.minDisplayedTotalState_)
|
| - continue;
|
| - if (child.values[1].totalState < this.minDisplayedTotalState_)
|
| - allDisplayedChildrenHaveDisplayedCounts = false;
|
| - childDict[child.title[dimension]] = child;
|
| - displayedChildrenTotalSize += child.values[0].total;
|
| - displayedChildrenTotalCount += child.values[1].total;
|
| - hasDisplayedChildren = true;
|
| - }
|
| + createColumns_: function(rows) {
|
| + var titleColumn = new HeapDumpTreeNodeTitleColumn('Current path');
|
| + titleColumn.width = '200px';
|
|
|
| - var nodeTotalSize = node.values[0].total;
|
| - var nodeTotalCount = node.values[1].total;
|
| -
|
| - // Add '<other>' node if necessary in tree-view.
|
| - var hasUnclassifiedSizeOrCount =
|
| - displayedChildrenTotalSize < nodeTotalSize ||
|
| - displayedChildrenTotalCount < nodeTotalCount;
|
| - if (!this.heavyView && hasUnclassifiedSizeOrCount &&
|
| - hasDisplayedChildren) {
|
| - var otherTitle = node.title.slice();
|
| - otherTitle[dimension] = '<other>';
|
| - childDict['<other>'] = {
|
| - title: otherTitle,
|
| - values: [
|
| - {
|
| - self: 0,
|
| - total: nodeTotalSize - displayedChildrenTotalSize,
|
| - totalState: this.minDisplayedTotalState_
|
| - },
|
| - {
|
| - self: 0,
|
| - total: nodeTotalCount - displayedChildrenTotalCount,
|
| - // Don't show allocation count of the '<other>' node if
|
| - // there is a displayed child node that did NOT display
|
| - // allocation count.
|
| - totalState: allDisplayedChildrenHaveDisplayedCounts ?
|
| - this.minDisplayedTotalState_ : TotalState.NOT_PROVIDED
|
| - }
|
| - ],
|
| - children: [new Map(), new Map()]
|
| - };
|
| - }
|
| + var numericColumns = tr.ui.analysis.MemoryColumn.fromRows(
|
| + rows, 'cells', this.aggregationMode_, COLUMN_RULES);
|
| + tr.ui.analysis.MemoryColumn.spaceEqually(numericColumns);
|
|
|
| - return childDict;
|
| - }, this));
|
| + var columns = [titleColumn].concat(numericColumns);
|
| + return columns;
|
| + }
|
| + });
|
|
|
| - // Sub-row name (list index) -> Sub-row.
|
| - return dimensionGroupedChildNodes.map(function(subRowNodes) {
|
| - var subRowTitle = tr.b.findFirstInArray(subRowNodes).title[dimension];
|
| - return this.createHeapRowRecursively_(
|
| - subRowNodes, dimension, subRowTitle);
|
| - }, this);
|
| + Polymer({
|
| + is: 'tr-ui-a-memory-dump-heap-details-view',
|
| + behaviors: [tr.ui.analysis.RebuildableBehavior],
|
| +
|
| + created: function() {
|
| + this.displayedNode_ = undefined;
|
| + },
|
| +
|
| + ready: function() {
|
| + this.scheduleRebuild_();
|
| + },
|
| +
|
| + get displayedNode() {
|
| + return this.displayedNode_;
|
| + },
|
| +
|
| + set displayedNode(node) {
|
| + if (this.displayedNode_ === node)
|
| + return;
|
| + this.displayedNode_ = node;
|
| + this.dispatchEvent(new tr.b.Event('displayed-node-changed'));
|
| + this.scheduleRebuild_();
|
| + },
|
| +
|
| + get aggregationMode() {
|
| + return this.aggregationMode_;
|
| + },
|
| +
|
| + set aggregationMode(aggregationMode) {
|
| + this.aggregationMode_ = aggregationMode;
|
| + for (var tab of this.$.tabs.tabs)
|
| + tab.aggregationMode = aggregationMode;
|
| + },
|
| +
|
| + onRebuild_: function() {
|
| + this.$.tabs.clearSubViews();
|
| +
|
| + if (this.displayedNode_ === undefined) {
|
| + this.$.tabs.label = 'No heap node provided.';
|
| + return;
|
| + }
|
| +
|
| + for (var [dimension, children] of this.displayedNode_.childNodes) {
|
| + var tab = document.createElement('tr-ui-a-memory-dump-heap-details-tab');
|
| + tab.aggregationMode = this.aggregationMode_;
|
| + tab.dimension = dimension;
|
| + tab.nodes = children;
|
| + tab.addEventListener('node-entered', function(e) {
|
| + this.displayedNode = e.node;
|
| + }.bind(this))
|
| + this.$.tabs.addSubView(tab);
|
| + }
|
| +
|
| + if (this.$.tabs.tabs.length > 0)
|
| + this.$.tabs.label = 'Break selected node further by:';
|
| + else
|
| + this.$.tabs.label = 'Selected node cannot be broken down any further.';
|
| + }
|
| + });
|
| +
|
| + Polymer({
|
| + is: 'tr-ui-a-memory-dump-heap-details-tab',
|
| + behaviors: [tr.ui.analysis.RebuildableBehavior],
|
| +
|
| + created: function() {
|
| + this.dimension_ = undefined;
|
| + this.nodes_ = undefined;
|
| + },
|
| +
|
| + ready: function() {
|
| + this.$.table.addEventListener('selection-entered', function(e) {
|
| + var event = new tr.b.Event('node-entered');
|
| + event.node = e.row;
|
| + this.dispatchEvent(event);
|
| + }.bind(this));
|
| + },
|
| +
|
| + get dimension() {
|
| + return this.dimension_;
|
| + },
|
| +
|
| + set dimension(dimension) {
|
| + this.dimension_ = dimension;
|
| + this.scheduleRebuild_();
|
| + },
|
| +
|
| + get nodes() {
|
| + return this.nodes_;
|
| + },
|
| +
|
| + set nodes(nodes) {
|
| + this.nodes_ = nodes;
|
| + this.scheduleRebuild_();
|
| + },
|
| +
|
| + get tabLabel() {
|
| + if (this.dimension_ === undefined)
|
| + return '(undefined)'
|
| + return this.dimension_.label;
|
| + },
|
| +
|
| + get tabIcon() {
|
| + if (this.dimension_ === undefined || this.dimension_ === RowDimension.ROOT)
|
| + return undefined;
|
| + return {
|
| + text: this.dimension_.symbol,
|
| + style: 'color: ' + tr.b.ColorScheme.getColorForReservedNameAsString(this.dimension_.color) + ';'
|
| + };
|
| + },
|
| +
|
| + get aggregationMode() {
|
| + return this.aggregationMode_;
|
| + },
|
| +
|
| + set aggregationMode(aggregationMode) {
|
| + this.aggregationMode_ = aggregationMode;
|
| + this.scheduleRebuild_();
|
| + },
|
| +
|
| + onRebuild_: function() {
|
| + if (this.nodes_ === undefined) {
|
| + this.$.table.clear();
|
| + return;
|
| + }
|
| +
|
| + this.$.table.selectionMode = tr.ui.b.TableFormat.SelectionMode.ROW;
|
| + var rows = this.createRows_(this.nodes_);
|
| + var columns = this.createColumns_(rows);
|
| + this.$.table.tableRows = rows;
|
| + this.$.table.tableColumns = columns;
|
| + this.$.table.rebuild();
|
| + },
|
| +
|
| + createRows_: function(nodes) {
|
| + return nodes;
|
| },
|
|
|
| createColumns_: function(rows) {
|
| - var titleColumn = new HeapDumpNodeTitleColumn('Stack frame');
|
| + var titleColumn = new HeapDumpTreeNodeTitleColumn(this.tabLabel);
|
| titleColumn.width = '500px';
|
|
|
| var numericColumns = tr.ui.analysis.MemoryColumn.fromRows(
|
|
|