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( |