| <!DOCTYPE html> |
| <!-- |
| Copyright (c) 2015 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. |
| --> |
| |
| <link rel="import" href="/tracing/base/color_scheme.html"> |
| <link rel="import" href="/tracing/base/iteration_helpers.html"> |
| <link rel="import" href="/tracing/model/memory_allocator_dump.html"> |
| <link rel="import" |
| href="/tracing/ui/analysis/memory_dump_allocator_details_pane.html"> |
| <link rel="import" href="/tracing/ui/analysis/memory_dump_sub_view_util.html"> |
| <link rel="import" |
| href="/tracing/ui/analysis/memory_dump_vm_regions_details_pane.html"> |
| <link rel="import" href="/tracing/ui/analysis/stacked_pane.html"> |
| <link rel="import" href="/tracing/ui/base/color_legend.html"> |
| <link rel="import" href="/tracing/ui/base/dom_helpers.html"> |
| <link rel="import" href="/tracing/ui/base/table.html"> |
| <link rel="import" href="/tracing/ui/view_specific_brushing_state.html"> |
| <link rel="import" href="/tracing/value/numeric.html"> |
| <link rel="import" href="/tracing/value/unit.html"> |
| |
| <polymer-element name="tr-ui-a-memory-dump-overview-pane" |
| extends="tr-ui-a-stacked-pane"> |
| <template> |
| <style> |
| :host { |
| display: flex; |
| flex-direction: column; |
| } |
| |
| #label { |
| flex: 0 0 auto; |
| padding: 8px; |
| |
| background-color: #eee; |
| border-bottom: 1px solid #8e8e8e; |
| border-top: 1px solid white; |
| |
| font-size: 15px; |
| font-weight: bold; |
| } |
| |
| #contents { |
| flex: 1 0 auto; |
| align-self: stretch; |
| font-size: 12px; |
| } |
| |
| #info_text { |
| padding: 8px; |
| color: #666; |
| font-style: italic; |
| text-align: center; |
| } |
| |
| #table { |
| display: none; /* Hide until memory dumps are set. */ |
| flex: 1 0 auto; |
| align-self: stretch; |
| } |
| </style> |
| <tr-ui-b-view-specific-brushing-state id="state" |
| view-id="analysis.memory_dump_overview_pane"> |
| </tr-ui-b-view-specific-brushing-state> |
| <div id="label">Overview</div> |
| <div id="contents"> |
| <div id="info_text">No memory memory dumps selected</div> |
| <tr-ui-b-table id="table"></tr-ui-b-table> |
| </div> |
| </template> |
| </polymer-element> |
| <script> |
| 'use strict'; |
| |
| tr.exportTo('tr.ui.analysis', function() { |
| |
| var ColorScheme = tr.b.ColorScheme; |
| var ScalarNumeric = tr.v.ScalarNumeric; |
| var sizeInBytes_smallerIsBetter = |
| tr.v.Unit.byName.sizeInBytes_smallerIsBetter; |
| |
| var PLATFORM_SPECIFIC_TOTAL_NAME_SUFFIX = '_bytes'; |
| |
| var DISPLAYED_SIZE_NUMERIC_NAME = |
| tr.model.MemoryAllocatorDump.DISPLAYED_SIZE_NUMERIC_NAME; |
| var SOME_TIMESTAMPS_INFO_QUANTIFIER = |
| tr.ui.analysis.MemoryColumn.SOME_TIMESTAMPS_INFO_QUANTIFIER; |
| |
| // Unicode symbols used for memory cell info icons and messages. |
| var RIGHTWARDS_ARROW_WITH_HOOK = String.fromCharCode(0x21AA); |
| var RIGHTWARDS_ARROW_FROM_BAR = String.fromCharCode(0x21A6); |
| var GREATER_THAN_OR_EQUAL_TO = String.fromCharCode(0x2265); |
| var UNMARRIED_PARTNERSHIP_SYMBOL = String.fromCharCode(0x26AF); |
| var TRIGRAM_FOR_HEAVEN = String.fromCharCode(0x2630); |
| |
| // TODO(petrcermak): Move this to iteration_helpers.html. |
| function lazyMap(list, fn, opt_this) { |
| opt_this = opt_this || this; |
| var result = undefined; |
| list.forEach(function(item, index) { |
| var value = fn.call(opt_this, item, index); |
| if (value === undefined) |
| return; |
| if (result === undefined) |
| result = new Array(list.length); |
| result[index] = value; |
| }); |
| return result; |
| } |
| |
| /** @constructor */ |
| function ProcessNameColumn() { |
| tr.ui.analysis.TitleColumn.call(this, 'Process'); |
| } |
| |
| ProcessNameColumn.prototype = { |
| __proto__: tr.ui.analysis.TitleColumn.prototype, |
| |
| formatTitle: function(row) { |
| if (row.contexts === undefined) |
| return row.title; // Total row. |
| var titleEl = document.createElement('tr-ui-b-color-legend'); |
| titleEl.label = row.title; |
| return titleEl; |
| } |
| }; |
| |
| /** @constructor */ |
| function UsedMemoryColumn(name, cellPath, aggregationMode) { |
| tr.ui.analysis.NumericMemoryColumn.call( |
| this, name, cellPath, aggregationMode); |
| } |
| |
| UsedMemoryColumn.COLOR = |
| ColorScheme.getColorForReservedNameAsString('used_memory_column'); |
| UsedMemoryColumn.OLDER_COLOR = |
| ColorScheme.getColorForReservedNameAsString('older_used_memory_column'); |
| |
| UsedMemoryColumn.prototype = { |
| __proto__: tr.ui.analysis.NumericMemoryColumn.prototype, |
| |
| get title() { |
| return tr.ui.b.createSpan({ |
| textContent: this.name, |
| color: UsedMemoryColumn.COLOR |
| }); |
| }, |
| |
| color: function(numerics, processMemoryDumps) { |
| return UsedMemoryColumn.COLOR; |
| }, |
| |
| getChildPaneBuilder: function(processMemoryDumps) { |
| if (processMemoryDumps === undefined) |
| return undefined; |
| |
| var vmRegions = lazyMap(processMemoryDumps, function(pmd) { |
| if (pmd === undefined) |
| return undefined; |
| return pmd.mostRecentVmRegions; |
| }); |
| if (vmRegions === undefined) |
| return undefined; |
| |
| return function() { |
| var pane = document.createElement( |
| 'tr-ui-a-memory-dump-vm-regions-details-pane'); |
| pane.vmRegions = vmRegions; |
| pane.aggregationMode = this.aggregationMode; |
| return pane; |
| }.bind(this); |
| } |
| }; |
| |
| /** @constructor */ |
| function PeakMemoryColumn(name, cellPath, aggregationMode) { |
| UsedMemoryColumn.call(this, name, cellPath, aggregationMode); |
| } |
| |
| PeakMemoryColumn.prototype = { |
| __proto__: UsedMemoryColumn.prototype, |
| |
| addInfos: function(numerics, processMemoryDumps, infos) { |
| if (processMemoryDumps === undefined) |
| return; // Total row. |
| |
| var resettableValueCount = 0; |
| var nonResettableValueCount = 0; |
| for (var i = 0; i < numerics.length; i++) { |
| if (numerics[i] === undefined) |
| continue; |
| if (processMemoryDumps[i].arePeakResidentBytesResettable) |
| resettableValueCount++; |
| else |
| nonResettableValueCount++; |
| } |
| |
| if (resettableValueCount > 0 && nonResettableValueCount > 0) { |
| infos.push(tr.ui.analysis.createWarningInfo('Both resettable and ' + |
| 'non-resettable peak RSS values were provided by the process')); |
| } else if (resettableValueCount > 0) { |
| infos.push({ |
| icon: RIGHTWARDS_ARROW_WITH_HOOK, |
| message: 'Peak RSS since previous memory dump.' |
| }); |
| } else { |
| infos.push({ |
| icon: RIGHTWARDS_ARROW_FROM_BAR, |
| message: 'Peak RSS since process startup. Finer grained ' + |
| 'peaks require a Linux kernel version ' + |
| GREATER_THAN_OR_EQUAL_TO + ' 4.0.' |
| }); |
| } |
| } |
| }; |
| |
| /** @constructor */ |
| function ByteStatColumn(name, cellPath, aggregationMode) { |
| UsedMemoryColumn.call(this, name, cellPath, aggregationMode); |
| } |
| |
| ByteStatColumn.prototype = { |
| __proto__: UsedMemoryColumn.prototype, |
| |
| color: function(numerics, processMemoryDumps) { |
| if (processMemoryDumps === undefined) |
| return UsedMemoryColumn.COLOR; // Total row. |
| |
| var allOlderValues = processMemoryDumps.every( |
| function(processMemoryDump) { |
| if (processMemoryDump === undefined) |
| return true; |
| return !processMemoryDump.hasOwnVmRegions; |
| }); |
| |
| // Show the cell in lighter blue if all values were older (i.e. none of |
| // the defined process memory dumps had own VM regions). |
| if (allOlderValues) |
| return UsedMemoryColumn.OLDER_COLOR; |
| else |
| return UsedMemoryColumn.COLOR; |
| }, |
| |
| addInfos: function(numerics, processMemoryDumps, infos) { |
| if (processMemoryDumps === undefined) |
| return; // Total row. |
| |
| var olderValueCount = 0; |
| for (var i = 0; i < numerics.length; i++) { |
| var processMemoryDump = processMemoryDumps[i]; |
| if (processMemoryDump !== undefined && |
| !processMemoryDump.hasOwnVmRegions) { |
| olderValueCount++; |
| } |
| } |
| |
| if (olderValueCount === 0) |
| return; // There are no older values. |
| |
| var infoQuantifier = olderValueCount < numerics.length ? |
| ' ' + SOME_TIMESTAMPS_INFO_QUANTIFIER /* some values are older */ : |
| '' /* all values are older */; |
| |
| // Emit an info if there was at least one older value (i.e. at least one |
| // defined process memory dump did not have own VM regions). |
| infos.push({ |
| message: 'Older value' + infoQuantifier + |
| ' (only heavy (purple) memory dumps contain memory maps).', |
| icon: UNMARRIED_PARTNERSHIP_SYMBOL |
| }); |
| } |
| }; |
| |
| // Rules for constructing and sorting used memory columns. |
| UsedMemoryColumn.RULES = [ |
| { |
| condition: 'Total resident', |
| importance: 10, |
| columnConstructor: UsedMemoryColumn |
| }, |
| { |
| condition: 'Peak total resident', |
| importance: 9, |
| columnConstructor: PeakMemoryColumn |
| }, |
| { |
| condition: 'PSS', |
| importance: 8, |
| columnConstructor: ByteStatColumn |
| }, |
| { |
| condition: 'Private dirty', |
| importance: 7, |
| columnConstructor: ByteStatColumn |
| }, |
| { |
| condition: 'Swapped', |
| importance: 6, |
| columnConstructor: ByteStatColumn |
| }, |
| { |
| // All other columns. |
| importance: 0, |
| columnConstructor: UsedMemoryColumn |
| } |
| ]; |
| |
| // Map from ProcessMemoryDump totals fields to column names. |
| UsedMemoryColumn.TOTALS_MAP = { |
| 'residentBytes': 'Total resident', |
| 'peakResidentBytes': 'Peak total resident' |
| }; |
| |
| // Map from VMRegionByteStats field names to column names. |
| UsedMemoryColumn.BYTE_STAT_MAP = { |
| 'proportionalResident': 'PSS', |
| 'privateDirtyResident': 'Private dirty', |
| 'swapped': 'Swapped' |
| }; |
| |
| /** @constructor */ |
| function AllocatorColumn(name, cellPath, aggregationMode) { |
| tr.ui.analysis.NumericMemoryColumn.call( |
| this, name, cellPath, aggregationMode); |
| } |
| |
| AllocatorColumn.prototype = { |
| __proto__: tr.ui.analysis.NumericMemoryColumn.prototype, |
| |
| get title() { |
| var titleEl = document.createElement('tr-ui-b-color-legend'); |
| titleEl.label = this.name; |
| return titleEl; |
| }, |
| |
| addInfos: function(numerics, processMemoryDumps, infos) { |
| if (processMemoryDumps === undefined) |
| return; |
| |
| var heapDumpCount = 0; |
| for (var i = 0; i < processMemoryDumps.length; i++) { |
| var processMemoryDump = processMemoryDumps[i]; |
| if (processMemoryDump === undefined) |
| continue; |
| var heapDumps = processMemoryDump.heapDumps; |
| if (heapDumps === undefined) |
| continue; |
| if (heapDumps[this.name] !== undefined) |
| heapDumpCount++; |
| } |
| |
| if (heapDumpCount === 0) |
| return; // There are no heap dumps. |
| |
| var infoQuantifier = heapDumpCount < numerics.length ? |
| ' ' + SOME_TIMESTAMPS_INFO_QUANTIFIER : ''; |
| |
| // Emit a heap dump info if at least one of the process memory dumps has |
| // a heap dump associated with this allocator. |
| infos.push({ |
| message: 'Heap dump provided' + infoQuantifier + '.', |
| icon: TRIGRAM_FOR_HEAVEN |
| }); |
| }, |
| |
| getChildPaneBuilder: function(processMemoryDumps) { |
| if (processMemoryDumps === undefined) |
| return undefined; |
| |
| var memoryAllocatorDumps = lazyMap(processMemoryDumps, function(pmd) { |
| if (pmd === undefined) |
| return undefined; |
| return pmd.getMemoryAllocatorDumpByFullName(this.name); |
| }, this); |
| if (memoryAllocatorDumps === undefined) |
| return undefined; |
| |
| var heapDumps = lazyMap(processMemoryDumps, function(pmd) { |
| if (pmd === undefined || pmd.heapDumps === undefined) |
| return undefined; |
| return pmd.heapDumps[this.name]; |
| }, this); |
| |
| return function() { |
| var pane = document.createElement( |
| 'tr-ui-a-memory-dump-allocator-details-pane'); |
| pane.memoryAllocatorDumps = memoryAllocatorDumps; |
| pane.heapDumps = heapDumps; |
| pane.aggregationMode = this.aggregationMode; |
| return pane; |
| }.bind(this); |
| } |
| }; |
| |
| /** @constructor */ |
| function TracingColumn(name, cellPath, aggregationMode) { |
| AllocatorColumn.call(this, name, cellPath, aggregationMode); |
| } |
| |
| TracingColumn.COLOR = |
| ColorScheme.getColorForReservedNameAsString('tracing_memory_column'); |
| |
| TracingColumn.prototype = { |
| __proto__: AllocatorColumn.prototype, |
| |
| get title() { |
| return tr.ui.b.createSpan({ |
| textContent: this.name, |
| color: TracingColumn.COLOR |
| }); |
| }, |
| |
| color: function(numerics, processMemoryDumps) { |
| return TracingColumn.COLOR; |
| } |
| }; |
| |
| // Rules for constructing and sorting allocator columns. |
| AllocatorColumn.RULES = [ |
| { |
| condition: 'tracing', |
| importance: 0, |
| columnConstructor: TracingColumn |
| }, |
| { |
| // All other columns. |
| importance: 1, |
| columnConstructor: AllocatorColumn |
| } |
| ]; |
| |
| Polymer('tr-ui-a-memory-dump-overview-pane', { |
| created: function() { |
| this.processMemoryDumps_ = undefined; |
| this.aggregationMode_ = undefined; |
| }, |
| |
| ready: function() { |
| this.$.table.selectionMode = tr.ui.b.TableFormat.SelectionMode.CELL; |
| this.$.table.addEventListener('selection-changed', |
| function(tableEvent) { |
| tableEvent.stopPropagation(); |
| this.changeChildPane_(); |
| }.bind(this)); |
| }, |
| |
| /** |
| * Sets the process memory dumps and schedules rebuilding the pane. |
| * |
| * The provided value should be a chronological list of dictionaries |
| * mapping process IDs to process memory dumps. Example: |
| * |
| * [ |
| * { |
| * // PMDs at timestamp 1. |
| * 42: tr.model.ProcessMemoryDump {} |
| * }, |
| * { |
| * // PMDs at timestamp 2. |
| * 42: tr.model.ProcessMemoryDump {}, |
| * 89: tr.model.ProcessMemoryDump {} |
| * } |
| * ] |
| */ |
| set processMemoryDumps(processMemoryDumps) { |
| this.processMemoryDumps_ = processMemoryDumps; |
| this.scheduleRebuildPane_(); |
| }, |
| |
| get processMemoryDumps() { |
| return this.processMemoryDumps_; |
| }, |
| |
| set aggregationMode(aggregationMode) { |
| this.aggregationMode_ = aggregationMode; |
| this.scheduleRebuildPane_(); |
| }, |
| |
| get aggregationMode() { |
| return this.aggregationMode_; |
| }, |
| |
| get selectedMemoryCell() { |
| if (this.processMemoryDumps_ === undefined || |
| this.processMemoryDumps_.length === 0) { |
| return undefined; |
| } |
| |
| var selectedTableRow = this.$.table.selectedTableRow; |
| if (!selectedTableRow) |
| return undefined; |
| |
| var selectedColumnIndex = this.$.table.selectedColumnIndex; |
| if (selectedColumnIndex === undefined) |
| return undefined; |
| |
| var selectedColumn = this.$.table.tableColumns[selectedColumnIndex]; |
| var selectedMemoryCell = selectedColumn.cell(selectedTableRow); |
| return selectedMemoryCell; |
| }, |
| |
| changeChildPane_: function() { |
| this.storeSelection_(); |
| this.childPaneBuilder = this.determineChildPaneBuilderFromSelection_(); |
| }, |
| |
| determineChildPaneBuilderFromSelection_: function() { |
| if (this.processMemoryDumps_ === undefined || |
| this.processMemoryDumps_.length === 0) { |
| return undefined; |
| } |
| |
| var selectedTableRow = this.$.table.selectedTableRow; |
| if (!selectedTableRow) |
| return undefined; |
| |
| var selectedColumnIndex = this.$.table.selectedColumnIndex; |
| if (selectedColumnIndex === undefined) |
| return undefined; |
| var selectedColumn = this.$.table.tableColumns[selectedColumnIndex]; |
| |
| return selectedColumn.getChildPaneBuilder(selectedTableRow.contexts); |
| }, |
| |
| rebuildPane_: function() { |
| if (this.processMemoryDumps_ === undefined || |
| this.processMemoryDumps_.length === 0) { |
| // Show the info text (hide the table). |
| this.$.info_text.style.display = 'block'; |
| this.$.table.style.display = 'none'; |
| |
| this.$.table.clear(); |
| this.$.table.rebuild(); |
| return; |
| } |
| |
| // Show the table (hide the info text). |
| this.$.info_text.style.display = 'none'; |
| this.$.table.style.display = 'block'; |
| |
| var rows = this.createRows_(); |
| var columns = this.createColumns_(rows); |
| var footerRows = this.createFooterRows_(rows, columns); |
| |
| this.$.table.tableRows = rows; |
| this.$.table.footerRows = footerRows; |
| this.$.table.tableColumns = columns; |
| this.$.table.rebuild(); |
| |
| this.restoreSelection_(); |
| }, |
| |
| createRows_: function() { |
| // Timestamp (list index) -> Process ID (dict key) -> PMD. |
| var timeToPidToProcessMemoryDump = this.processMemoryDumps_; |
| |
| // Process ID (dict key) -> Timestamp (list index) -> PMD or undefined. |
| var pidToTimeToProcessMemoryDump = tr.b.invertArrayOfDicts( |
| timeToPidToProcessMemoryDump); |
| |
| // Process (list index) -> Component (dict key) -> Cell. |
| return tr.b.dictionaryValues(tr.b.mapItems( |
| pidToTimeToProcessMemoryDump, function(pid, timeToDump) { |
| // Get the process associated with the dumps. We can use any defined |
| // process memory dump in timeToDump since they all have the same pid. |
| var process = tr.b.findFirstInArray(timeToDump).process; |
| |
| // Used memory (total resident, PSS, ...). |
| var usedMemoryCells = tr.ui.analysis.createCells(timeToDump, |
| function(dump) { |
| var sizes = {}; |
| |
| var totals = dump.totals; |
| if (totals !== undefined) { |
| // Common totals. |
| tr.b.iterItems(UsedMemoryColumn.TOTALS_MAP, |
| function(totalName, cellName) { |
| var total = totals[totalName]; |
| if (total === undefined) |
| return; |
| sizes[cellName] = new ScalarNumeric( |
| sizeInBytes_smallerIsBetter, total); |
| }); |
| |
| // Platform-specific totals (e.g. private resident on Mac). |
| var platformSpecific = totals.platformSpecific; |
| if (platformSpecific !== undefined) { |
| tr.b.iterItems(platformSpecific, function(name, size) { |
| // Change raw OS-specific total name to a user-friendly |
| // column title (e.g. 'private_bytes' -> 'Private'). |
| if (name.endsWith(PLATFORM_SPECIFIC_TOTAL_NAME_SUFFIX)) { |
| name = name.substring(0, name.length - |
| PLATFORM_SPECIFIC_TOTAL_NAME_SUFFIX.length); |
| } |
| name = name.replace('_', ' ').trim(); |
| name = name.charAt(0).toUpperCase() + name.slice(1); |
| sizes[name] = new ScalarNumeric( |
| sizeInBytes_smallerIsBetter, size); |
| }); |
| } |
| } |
| |
| // VM regions byte stats. |
| var vmRegions = dump.mostRecentVmRegions; |
| if (vmRegions !== undefined) { |
| tr.b.iterItems(UsedMemoryColumn.BYTE_STAT_MAP, |
| function(byteStatName, cellName) { |
| var byteStat = vmRegions.byteStats[byteStatName]; |
| if (byteStat === undefined) |
| return; |
| sizes[cellName] = new ScalarNumeric( |
| sizeInBytes_smallerIsBetter, byteStat); |
| }); |
| } |
| |
| return sizes; |
| }); |
| |
| // Allocator memory (v8, oilpan, ...). |
| var allocatorCells = tr.ui.analysis.createCells(timeToDump, |
| function(dump) { |
| var memoryAllocatorDumps = dump.memoryAllocatorDumps; |
| if (memoryAllocatorDumps === undefined) |
| return undefined; |
| var sizes = {}; |
| memoryAllocatorDumps.forEach(function(allocatorDump) { |
| var rootDisplayedSizeNumeric = allocatorDump.numerics[ |
| DISPLAYED_SIZE_NUMERIC_NAME]; |
| if (rootDisplayedSizeNumeric !== undefined) |
| sizes[allocatorDump.fullName] = rootDisplayedSizeNumeric; |
| }); |
| return sizes; |
| }); |
| |
| return { |
| title: process.userFriendlyName, |
| contexts: timeToDump, |
| usedMemoryCells: usedMemoryCells, |
| allocatorCells: allocatorCells |
| }; |
| })); |
| }, |
| |
| createFooterRows_: function(rows, columns) { |
| // Add a 'Total' row if there are at least two process memory dumps. |
| if (rows.length <= 1) |
| return []; |
| |
| var totalRow = {title: 'Total'}; |
| tr.ui.analysis.aggregateTableRowCells(totalRow, rows, columns); |
| |
| return [totalRow]; |
| }, |
| |
| createColumns_: function(rows) { |
| var titleColumn = new ProcessNameColumn(); |
| titleColumn.width = '200px'; |
| |
| var usedMemorySizeColumns = tr.ui.analysis.MemoryColumn.fromRows( |
| rows, 'usedMemoryCells', this.aggregationMode_, |
| UsedMemoryColumn.RULES); |
| |
| var allocatorSizeColumns = tr.ui.analysis.MemoryColumn.fromRows( |
| rows, 'allocatorCells', this.aggregationMode_, |
| AllocatorColumn.RULES); |
| |
| var sizeColumns = usedMemorySizeColumns.concat(allocatorSizeColumns); |
| tr.ui.analysis.MemoryColumn.spaceEqually(sizeColumns); |
| |
| var columns = [titleColumn].concat(sizeColumns); |
| return columns; |
| }, |
| |
| storeSelection_: function() { |
| var selectedRowTitle; |
| var selectedRow = this.$.table.selectedTableRow; |
| if (selectedRow !== undefined) |
| selectedRowTitle = selectedRow.title; |
| |
| var selectedColumnName; |
| var selectedColumnIndex = this.$.table.selectedColumnIndex; |
| if (selectedColumnIndex !== undefined) { |
| var selectedColumn = this.$.table.tableColumns[selectedColumnIndex]; |
| selectedColumnName = selectedColumn.name; |
| } |
| |
| this.$.state.set( |
| {rowTitle: selectedRowTitle, columnName: selectedColumnName}); |
| }, |
| |
| restoreSelection_: function() { |
| var settings = this.$.state.get(); |
| if (settings === undefined || settings.rowTitle === undefined || |
| settings.columnName === undefined) |
| return; |
| |
| var selectedColumnName = settings.columnName; |
| var selectedColumnIndex = tr.b.findFirstIndexInArray( |
| this.$.table.tableColumns, function(column) { |
| return column.name === selectedColumnName; |
| }); |
| if (selectedColumnIndex < 0) |
| return; |
| |
| var selectedRowTitle = settings.rowTitle; |
| var selectedRow = tr.b.findFirstInArray(this.$.table.tableRows, |
| function(row) { |
| return row.title === selectedRowTitle; |
| }); |
| if (selectedRow === undefined) |
| return; |
| |
| this.$.table.selectedTableRow = selectedRow; |
| this.$.table.selectedColumnIndex = selectedColumnIndex; |
| } |
| }); |
| |
| return { |
| // All exports are for testing only. |
| ProcessNameColumn: ProcessNameColumn, |
| UsedMemoryColumn: UsedMemoryColumn, |
| PeakMemoryColumn: PeakMemoryColumn, |
| ByteStatColumn: ByteStatColumn, |
| AllocatorColumn: AllocatorColumn, |
| TracingColumn: TracingColumn |
| }; |
| }); |
| </script> |