| <!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/iteration_helpers.html"> |
| <link rel="import" href="/tracing/core/test_utils.html"> |
| <link rel="import" href="/tracing/model/heap_dump.html"> |
| <link rel="import" href="/tracing/model/memory_allocator_dump.html"> |
| <link rel="import" href="/tracing/model/memory_dump_test_utils.html"> |
| <link rel="import" href="/tracing/ui/analysis/memory_dump_overview_pane.html"> |
| <link rel="import" |
| href="/tracing/ui/analysis/memory_dump_sub_view_test_utils.html"> |
| <link rel="import" href="/tracing/ui/analysis/memory_dump_sub_view_util.html"> |
| <link rel="import" href="/tracing/ui/brushing_state_controller.html"> |
| |
| <script> |
| 'use strict'; |
| |
| tr.b.unittest.testSuite(function() { |
| var ScalarNumeric = tr.v.ScalarNumeric; |
| var sizeInBytes_smallerIsBetter = |
| tr.b.Unit.byName.sizeInBytes_smallerIsBetter; |
| var MemoryAllocatorDump = tr.model.MemoryAllocatorDump; |
| var HeapDump = tr.model.HeapDump; |
| var AggregationMode = tr.ui.analysis.MemoryColumn.AggregationMode; |
| var checkSizeNumericFields = tr.ui.analysis.checkSizeNumericFields; |
| var checkColor = tr.ui.analysis.checkColor; |
| var checkColumns = tr.ui.analysis.checkColumns; |
| var checkColumnInfosAndColor = tr.ui.analysis.checkColumnInfosAndColor; |
| var convertToProcessMemoryDumps = tr.ui.analysis.convertToProcessMemoryDumps; |
| var extractProcessMemoryDumps = tr.ui.analysis.extractProcessMemoryDumps; |
| var extractVmRegions = tr.ui.analysis.extractVmRegions; |
| var extractMemoryAllocatorDumps = tr.ui.analysis.extractMemoryAllocatorDumps; |
| var isElementDisplayed = tr.ui.analysis.isElementDisplayed; |
| var addProcessMemoryDump = tr.model.MemoryDumpTestUtils.addProcessMemoryDump; |
| var addGlobalMemoryDump = tr.model.MemoryDumpTestUtils.addGlobalMemoryDump; |
| var ProcessNameColumn = tr.ui.analysis.ProcessNameColumn; |
| var UsedMemoryColumn = tr.ui.analysis.UsedMemoryColumn; |
| var PeakMemoryColumn = tr.ui.analysis.PeakMemoryColumn; |
| var ByteStatColumn = tr.ui.analysis.ByteStatColumn; |
| var AllocatorColumn = tr.ui.analysis.AllocatorColumn; |
| var TracingColumn = tr.ui.analysis.TracingColumn; |
| |
| function spanMatcher(expectedTitle) { |
| return function(actualTitle) { |
| assert.instanceOf(actualTitle, HTMLElement); |
| assert.strictEqual(actualTitle.tagName, 'SPAN'); |
| assert.strictEqual(Polymer.dom(actualTitle).textContent, expectedTitle); |
| }; |
| } |
| |
| function colorLegendMatcher(expectedTitle) { |
| return function(actualTitle) { |
| assert.instanceOf(actualTitle, HTMLElement); |
| assert.strictEqual(actualTitle.tagName, 'TR-UI-B-COLOR-LEGEND'); |
| assert.strictEqual(actualTitle.label, expectedTitle); |
| }; |
| } |
| |
| var EXPECTED_COLUMNS = [ |
| { title: 'Process', type: ProcessNameColumn, noAggregation: true }, |
| { title: spanMatcher('Total resident'), type: UsedMemoryColumn }, |
| { title: spanMatcher('Peak total resident'), type: PeakMemoryColumn }, |
| { title: spanMatcher('PSS'), type: ByteStatColumn }, |
| { title: spanMatcher('Private dirty'), type: ByteStatColumn }, |
| { title: spanMatcher('Swapped'), type: ByteStatColumn }, |
| { title: spanMatcher('Private'), type: UsedMemoryColumn }, |
| { title: colorLegendMatcher('blink'), type: AllocatorColumn }, |
| { title: colorLegendMatcher('gpu'), type: AllocatorColumn }, |
| { title: colorLegendMatcher('malloc'), type: AllocatorColumn }, |
| { title: colorLegendMatcher('oilpan'), type: AllocatorColumn }, |
| { title: colorLegendMatcher('v8'), type: AllocatorColumn }, |
| { title: spanMatcher('tracing'), type: TracingColumn } |
| ]; |
| |
| function checkRow(columns, row, expectedTitle, expectedSizes, |
| expectedContexts) { |
| // Check title. |
| var formattedTitle = columns[0].formatTitle(row); |
| if (typeof expectedTitle === 'function') |
| expectedTitle(formattedTitle); |
| else |
| assert.strictEqual(formattedTitle, expectedTitle); |
| |
| // Check all sizes. The first assert below is a test sanity check. |
| assert.lengthOf(expectedSizes, columns.length - 1 /* all except title */); |
| for (var i = 0; i < expectedSizes.length; i++) |
| checkSizeNumericFields(row, columns[i + 1], expectedSizes[i]); |
| |
| // There should be no row nesting on the overview pane. |
| assert.isUndefined(row.subRows); |
| |
| if (expectedContexts) |
| assert.deepEqual(tr.b.asArray(row.contexts), expectedContexts); |
| else |
| assert.isUndefined(row.contexts); |
| } |
| |
| function checkRows(columns, actualRows, expectedRows) { |
| if (expectedRows === undefined) { |
| assert.isUndefined(actualRows); |
| return; |
| } |
| assert.lengthOf(actualRows, expectedRows.length); |
| for (var i = 0; i < expectedRows.length; i++) { |
| var actualRow = actualRows[i]; |
| var expectedRow = expectedRows[i]; |
| checkRow(columns, actualRow, expectedRow.title, expectedRow.sizes, |
| expectedRow.contexts); |
| } |
| } |
| |
| function checkSpanWithColor(span, expectedText, expectedColorReservedName) { |
| assert.strictEqual(span.tagName, 'SPAN'); |
| assert.strictEqual(Polymer.dom(span).textContent, expectedText); |
| checkColor(span.style.color, expectedColorReservedName); |
| } |
| |
| function checkColorLegend(legend, expectedLabel) { |
| assert.strictEqual(legend.tagName, 'TR-UI-B-COLOR-LEGEND'); |
| assert.strictEqual(legend.label, expectedLabel); |
| } |
| |
| function createAndCheckMemoryDumpOverviewPane( |
| test, processMemoryDumps, expectedRows, expectedFooterRows, |
| aggregationMode) { |
| var viewEl = |
| tr.ui.analysis.createTestPane('tr-ui-a-memory-dump-overview-pane'); |
| viewEl.processMemoryDumps = processMemoryDumps; |
| viewEl.aggregationMode = aggregationMode; |
| viewEl.rebuild(); |
| test.addHTMLOutput(viewEl); |
| |
| // Check that the table is shown. |
| assert.isTrue(isElementDisplayed(viewEl.$.table)); |
| assert.isFalse(isElementDisplayed(viewEl.$.info_text)); |
| |
| assert.isUndefined(viewEl.createChildPane()); |
| |
| var table = viewEl.$.table; |
| var columns = table.tableColumns; |
| checkColumns(columns, EXPECTED_COLUMNS, aggregationMode); |
| var rows = table.tableRows; |
| |
| checkRows(columns, table.tableRows, expectedRows); |
| checkRows(columns, table.footerRows, expectedFooterRows); |
| } |
| |
| var FIELD = 1 << 0; |
| var DUMP = 1 << 1; |
| |
| function checkOverviewColumnInfosAndColor(column, fieldAndDumpMask, |
| dumpCreatedCallback, expectedInfos, expectedColorReservedName) { |
| var fields = fieldAndDumpMask.map(function(mask, index) { |
| return mask & FIELD ? |
| new ScalarNumeric(sizeInBytes_smallerIsBetter, 1024 + 32 * index) : |
| undefined; |
| }); |
| |
| var contexts; |
| if (dumpCreatedCallback === undefined) { |
| contexts = undefined; |
| } else { |
| tr.c.TestUtils.newModel(function(model) { |
| var process = model.getOrCreateProcess(1); |
| fieldAndDumpMask.forEach(function(mask, i) { |
| var timestamp = 10 + i; |
| var gmd = addGlobalMemoryDump(model, {ts: timestamp}); |
| if (mask & DUMP) { |
| var pmd = addProcessMemoryDump(gmd, process, {ts: timestamp}); |
| dumpCreatedCallback(pmd, mask); |
| } |
| }); |
| contexts = model.globalMemoryDumps.map(function(gmd) { |
| return gmd.processMemoryDumps[1]; |
| }); |
| }); |
| } |
| |
| checkColumnInfosAndColor( |
| column, fields, contexts, expectedInfos, expectedColorReservedName); |
| } |
| |
| test('instantiate_empty', function() { |
| tr.ui.analysis.createAndCheckEmptyPanes(this, |
| 'tr-ui-a-memory-dump-overview-pane', 'processMemoryDumps', |
| function(viewEl) { |
| // Check that the info text is shown. |
| assert.isTrue(isElementDisplayed(viewEl.$.info_text)); |
| assert.isFalse(isElementDisplayed(viewEl.$.table)); |
| }); |
| }); |
| |
| test('instantiate_singleGlobalMemoryDump', function() { |
| var processMemoryDumps = convertToProcessMemoryDumps( |
| [tr.ui.analysis.createSingleTestGlobalMemoryDump()]); |
| createAndCheckMemoryDumpOverviewPane(this, |
| processMemoryDumps, |
| [ // Table rows. |
| { |
| title: colorLegendMatcher('Process 1'), |
| sizes: [[29884416], undefined, [9437184], [5767168], undefined, |
| undefined, undefined, undefined, [7340032], undefined, |
| undefined, [2097152]], |
| contexts: extractProcessMemoryDumps(processMemoryDumps, 1) |
| }, |
| { |
| title: colorLegendMatcher('Process 2'), |
| sizes: [[17825792], [39845888], [18350080], [0], [32], [8912896], |
| [7340032], [0], [1048576], [1], [5242880], [1572864]], |
| contexts: extractProcessMemoryDumps(processMemoryDumps, 2) |
| }, |
| { |
| title: colorLegendMatcher('Process 4'), |
| sizes: [undefined, [17825792], undefined, undefined, undefined, |
| undefined, undefined, undefined, undefined, undefined, |
| undefined, undefined], |
| contexts: extractProcessMemoryDumps(processMemoryDumps, 4) |
| } |
| ], |
| [ // Footer rows. |
| { |
| title: 'Total', |
| sizes: [[47710208], [57671680], [27787264], [5767168], [32], |
| [8912896], [7340032], [0], [8388608], [1], [5242880], |
| [3670016]], |
| contexts: undefined |
| } |
| ], |
| undefined /* no aggregation */); |
| }); |
| |
| test('instantiate_multipleGlobalMemoryDumps', function() { |
| var processMemoryDumps = convertToProcessMemoryDumps( |
| tr.ui.analysis.createMultipleTestGlobalMemoryDumps()); |
| createAndCheckMemoryDumpOverviewPane(this, |
| processMemoryDumps, |
| [ // Table rows. |
| { |
| title: colorLegendMatcher('Process 1'), |
| sizes: [[31457280, 29884416, undefined], undefined, |
| [10485760, 9437184, undefined], [8388608, 5767168, undefined], |
| undefined, undefined, undefined, undefined, |
| [undefined, 7340032, undefined], undefined, undefined, |
| [undefined, 2097152, undefined]], |
| contexts: extractProcessMemoryDumps(processMemoryDumps, 1) |
| }, |
| { |
| title: colorLegendMatcher('Process 2'), |
| sizes: [[19398656, 17825792, 15728640], |
| [40370176, 39845888, 40894464], [18350080, 18350080, 18350080], |
| [0, 0, -2621440], [32, 32, 64], [10485760, 8912896, 7340032], |
| [undefined, 7340032, 6291456], [undefined, 0, 1048576], |
| [2097152, 1048576, 786432], [undefined, 1, undefined], |
| [5242880, 5242880, 5767168], [1048576, 1572864, 2097152]], |
| contexts: extractProcessMemoryDumps(processMemoryDumps, 2) |
| }, |
| { |
| title: colorLegendMatcher('Process 3'), |
| sizes: [undefined, undefined, undefined, undefined, undefined, |
| undefined, undefined, undefined, undefined, |
| [2147483648, undefined, 1073741824], |
| [1073741824, undefined, 2147483648], undefined], |
| contexts: extractProcessMemoryDumps(processMemoryDumps, 3) |
| }, |
| { |
| title: colorLegendMatcher('Process 4'), |
| sizes: [undefined, [undefined, 17825792, 17825792], undefined, |
| undefined, undefined, undefined, undefined, undefined, |
| undefined, undefined, undefined, undefined], |
| contexts: extractProcessMemoryDumps(processMemoryDumps, 4) |
| } |
| ], |
| [ // Footer rows. |
| { |
| title: 'Total', |
| sizes: [[50855936, 47710208, 15728640], |
| [40370176, 57671680, 58720256], [28835840, 27787264, 18350080], |
| [8388608, 5767168, -2621440], [32, 32, 64], |
| [10485760, 8912896, 7340032], [undefined, 7340032, 6291456], |
| [undefined, 0, 1048576], [2097152, 8388608, 786432], |
| [2147483648, 1, 1073741824], [1078984704, 5242880, 2153250816], |
| [1048576, 3670016, 2097152]], |
| contexts: undefined |
| } |
| ], |
| AggregationMode.DIFF); |
| }); |
| |
| test('instantiate_singleProcessMemoryDump', function() { |
| var processMemoryDumps = convertToProcessMemoryDumps( |
| [tr.ui.analysis.createSingleTestProcessMemoryDump()]); |
| createAndCheckMemoryDumpOverviewPane(this, |
| processMemoryDumps, |
| [ // Table rows. |
| { |
| title: colorLegendMatcher('Process 2'), |
| sizes: [[17825792], [39845888], [18350080], [0], [32], [8912896], |
| [7340032], [0], [1048576], [1], [5242880], [1572864]], |
| contexts: extractProcessMemoryDumps(processMemoryDumps, 2) |
| } |
| ], |
| [] /* footer rows */, |
| undefined /* no aggregation */); |
| }); |
| |
| test('instantiate_multipleProcessMemoryDumps', function() { |
| var processMemoryDumps = convertToProcessMemoryDumps( |
| tr.ui.analysis.createMultipleTestProcessMemoryDumps()); |
| createAndCheckMemoryDumpOverviewPane(this, |
| processMemoryDumps, |
| [ // Table rows. |
| { |
| title: colorLegendMatcher('Process 2'), |
| sizes: [[19398656, 17825792, 15728640], |
| [40370176, 39845888, 40894464], [18350080, 18350080, 18350080], |
| [0, 0, -2621440], [32, 32, 64], [10485760, 8912896, 7340032], |
| [undefined, 7340032, 6291456], [undefined, 0, 1048576], |
| [2097152, 1048576, 786432], [undefined, 1, undefined], |
| [5242880, 5242880, 5767168], [1048576, 1572864, 2097152]], |
| contexts: extractProcessMemoryDumps(processMemoryDumps, 2) |
| } |
| ], |
| [] /* footer rows */, |
| AggregationMode.MAX); |
| }); |
| |
| test('selection', function() { |
| var processMemoryDumps = convertToProcessMemoryDumps( |
| tr.ui.analysis.createMultipleTestGlobalMemoryDumps()); |
| |
| var viewEl = |
| tr.ui.analysis.createTestPane('tr-ui-a-memory-dump-overview-pane'); |
| viewEl.processMemoryDumps = processMemoryDumps; |
| viewEl.aggregationMode = AggregationMode.DIFF; |
| viewEl.rebuild(); |
| this.addHTMLOutput(viewEl); |
| |
| var table = viewEl.$.table; |
| |
| // Simulate clicking on the 'malloc' cell of the second process. |
| table.selectedTableRow = table.tableRows[1]; |
| table.selectedColumnIndex = 9; |
| assert.lengthOf(viewEl.requestedChildPanes, 2); |
| var lastChildPane = viewEl.requestedChildPanes[1]; |
| assert.equal( |
| lastChildPane.tagName, 'TR-UI-A-MEMORY-DUMP-ALLOCATOR-DETAILS-PANE'); |
| assert.strictEqual(lastChildPane.aggregationMode, AggregationMode.DIFF); |
| assert.deepEqual(lastChildPane.memoryAllocatorDumps, |
| extractMemoryAllocatorDumps(processMemoryDumps, 2, 'malloc')); |
| |
| // Simulate clicking on the 'Oilpan' cell of the second process. |
| table.selectedColumnIndex = 10; |
| assert.lengthOf(viewEl.requestedChildPanes, 3); |
| var lastChildPane = viewEl.requestedChildPanes[2]; |
| assert.isUndefined(viewEl.lastChildPane); |
| }); |
| |
| test('memory', function() { |
| var processMemoryDumps = convertToProcessMemoryDumps( |
| tr.ui.analysis.createMultipleTestGlobalMemoryDumps()); |
| var containerEl = document.createElement('div'); |
| containerEl.brushingStateController = |
| new tr.c.BrushingStateController(undefined); |
| |
| function simulateView(pids, aggregationMode, |
| expectedSelectedCellFieldValues, expectedSelectedRowTitle, |
| expectedSelectedColumnIndex, callback) { |
| var viewEl = |
| tr.ui.analysis.createTestPane('tr-ui-a-memory-dump-overview-pane'); |
| var table = viewEl.$.table; |
| Polymer.dom(containerEl).textContent = ''; |
| Polymer.dom(containerEl).appendChild(viewEl); |
| |
| var displayedProcessMemoryDumps = processMemoryDumps.map( |
| function(memoryDumps) { |
| return tr.b.filterItems(memoryDumps, function(pid, pmd) { |
| return pids.indexOf(pmd.process.pid) !== -1; |
| }); |
| }); |
| viewEl.processMemoryDumps = displayedProcessMemoryDumps; |
| viewEl.aggregationMode = aggregationMode; |
| viewEl.rebuild(); |
| |
| if (expectedSelectedCellFieldValues === undefined) { |
| assert.isUndefined(viewEl.childPaneBuilder); |
| } else { |
| checkSizeNumericFields(table.selectedTableRow, |
| table.tableColumns[table.selectedColumnIndex], |
| expectedSelectedCellFieldValues); |
| } |
| |
| assert.strictEqual( |
| table.selectedColumnIndex, expectedSelectedColumnIndex); |
| if (expectedSelectedRowTitle === undefined) |
| assert.isUndefined(table.selectedTableRow); |
| else |
| assert.equal(table.selectedTableRow.title, expectedSelectedRowTitle); |
| |
| callback(viewEl, viewEl.$.table); |
| } |
| |
| simulateView( |
| [1, 2, 3, 4], // All processes. |
| AggregationMode.DIFF, |
| undefined, undefined, undefined, // No cell should be selected. |
| function(view, table) { |
| assert.isUndefined(view.createChildPane()); |
| |
| // Select the 'PSS' column of the second process. |
| table.selectedTableRow = table.tableRows[1]; |
| table.selectedColumnIndex = 3; |
| }); |
| |
| simulateView( |
| [2, 3], |
| AggregationMode.MAX, |
| [18350080, 18350080, 18350080], 'Process 2', 3, /* PSS */ |
| function(view, table) { |
| var childPane = view.createChildPane(); |
| assert.equal( |
| childPane.tagName, 'TR-UI-A-MEMORY-DUMP-VM-REGIONS-DETAILS-PANE'); |
| assert.deepEqual(tr.b.asArray(childPane.vmRegions), |
| extractVmRegions(processMemoryDumps, 2)); |
| assert.strictEqual(childPane.aggregationMode, AggregationMode.MAX); |
| }); |
| |
| simulateView( |
| [3], |
| undefined, /* No aggregation */ |
| undefined, undefined, undefined, // No cell selected. |
| function(view, table) { |
| assert.isUndefined(view.createChildPane()); |
| }); |
| |
| simulateView( |
| [1, 2, 3, 4], |
| AggregationMode.DIFF, |
| [18350080, 18350080, 18350080], 'Process 2', 3, /* PSS */ |
| function(view, table) { |
| var childPane = view.createChildPane(); |
| assert.equal( |
| childPane.tagName, 'TR-UI-A-MEMORY-DUMP-VM-REGIONS-DETAILS-PANE'); |
| assert.deepEqual(tr.b.asArray(childPane.vmRegions), |
| extractVmRegions(processMemoryDumps, 2)); |
| assert.strictEqual(childPane.aggregationMode, AggregationMode.DIFF); |
| |
| // Select the 'v8' column of the first process (empty cell). |
| table.selectedTableRow = table.tableRows[0]; |
| table.selectedColumnIndex = 10; |
| }); |
| |
| simulateView( |
| [1], |
| undefined, /* No aggregation */ |
| undefined, undefined, undefined, // No cell should selected. |
| function(view, table) { |
| assert.isUndefined(view.createChildPane()); |
| |
| // Select 'Total resident' column of the first process. |
| table.selectedTableRow = table.tableRows[0]; |
| table.selectedColumnIndex = 1; |
| }); |
| |
| simulateView( |
| [1, 2, 3, 4], |
| AggregationMode.MAX, |
| [31457280, 29884416, undefined], 'Process 1', 1, /* Total resident */ |
| function(view, table) { |
| var childPane = view.createChildPane(); |
| assert.equal( |
| childPane.tagName, 'TR-UI-A-MEMORY-DUMP-VM-REGIONS-DETAILS-PANE'); |
| assert.deepEqual(tr.b.asArray(childPane.vmRegions), |
| extractVmRegions(processMemoryDumps, 1)); |
| assert.strictEqual(childPane.aggregationMode, AggregationMode.MAX); |
| }); |
| }); |
| |
| test('processNameColumn_formatTitle', function() { |
| var c = new ProcessNameColumn(); |
| |
| // With context (total row). |
| assert.strictEqual(c.formatTitle({ |
| title: 'Total', |
| usedMemoryCells: {} |
| }), 'Total'); |
| |
| // Without context (process row). |
| var title = c.formatTitle({ |
| title: 'Process 1', |
| usedMemoryCells: {}, |
| contexts: [tr.ui.analysis.createSingleTestProcessMemoryDump()] |
| }); |
| checkColorLegend(title, 'Process 1'); |
| }); |
| |
| test('usedMemoryColumn', function() { |
| var c = new UsedMemoryColumn('Private', 'bytes', tr.b.identity, |
| AggregationMode.DIFF); |
| checkSpanWithColor(c.title, 'Private', |
| 'used_memory_column' /* blue (column title) */); |
| checkColor(c.color(undefined /* contexts */), |
| 'used_memory_column' /* blue (column cells) */); |
| }); |
| |
| test('peakMemoryColumn', function() { |
| var c = new PeakMemoryColumn('Peak', 'bytes', tr.b.identity, |
| AggregationMode.MAX); |
| checkSpanWithColor(c.title, 'Peak', |
| 'used_memory_column' /* blue (column title) */); |
| checkColor(c.color(undefined) /* contexts */, |
| 'used_memory_column' /* blue (column cells) */); |
| |
| var RESETTABLE_PEAK = 1 << 2; |
| var NON_RESETTABLE_PEAK = 1 << 3; |
| function checkPeakColumnInfosAndColor(fieldAndDumpMask, expectedInfos) { |
| checkOverviewColumnInfosAndColor(c, |
| fieldAndDumpMask, |
| function(pmd, mask) { |
| if (mask & RESETTABLE_PEAK) { |
| assert.strictEqual( |
| mask & NON_RESETTABLE_PEAK, 0); // Test sanity check. |
| pmd.arePeakResidentBytesResettable = true; |
| } else if (mask & NON_RESETTABLE_PEAK) { |
| pmd.arePeakResidentBytesResettable = false; |
| } |
| }, |
| expectedInfos, |
| 'used_memory_column'); |
| } |
| |
| // No context. |
| checkOverviewColumnInfosAndColor(c, |
| [FIELD], |
| undefined /* no context */, |
| [] /* no infos */, |
| 'used_memory_column' /* blue color */); |
| checkOverviewColumnInfosAndColor(c, |
| [FIELD, FIELD, 0, FIELD], |
| undefined /* no context */, |
| [] /* no infos */, |
| 'used_memory_column' /* blue color */); |
| |
| // All resettable. |
| var EXPECTED_RESETTABLE_INFO = { |
| icon: '\u21AA', |
| message: 'Peak RSS since previous memory dump.' |
| }; |
| checkPeakColumnInfosAndColor([ |
| FIELD | DUMP | RESETTABLE_PEAK |
| ], [EXPECTED_RESETTABLE_INFO]); |
| checkPeakColumnInfosAndColor([ |
| FIELD | DUMP | RESETTABLE_PEAK, |
| DUMP /* ignored because there's no field */, |
| 0, |
| FIELD | DUMP | RESETTABLE_PEAK |
| ], [EXPECTED_RESETTABLE_INFO]); |
| |
| // All non-resettable. |
| var EXPECTED_NON_RESETTABLE_INFO = { |
| icon: '\u21A6', |
| message: 'Peak RSS since process startup. Finer grained peaks require ' + |
| 'a Linux kernel version \u2265 4.0.' |
| }; |
| checkPeakColumnInfosAndColor([ |
| FIELD | DUMP | NON_RESETTABLE_PEAK |
| ], [EXPECTED_NON_RESETTABLE_INFO]); |
| checkPeakColumnInfosAndColor([ |
| 0, |
| DUMP | RESETTABLE_PEAK /* ignored because there's no field */, |
| FIELD | DUMP | NON_RESETTABLE_PEAK, |
| FIELD | DUMP | NON_RESETTABLE_PEAK |
| ], [EXPECTED_NON_RESETTABLE_INFO]); |
| |
| // Combination (warning). |
| var EXPECTED_COMBINATION_INFO = { |
| icon: '\u26A0', |
| message: 'Both resettable and non-resettable peak RSS values were ' + |
| 'provided by the process', |
| color: 'red' |
| }; |
| checkPeakColumnInfosAndColor([ |
| FIELD | DUMP | NON_RESETTABLE_PEAK, |
| 0, |
| FIELD | DUMP | RESETTABLE_PEAK, |
| 0 |
| ], [EXPECTED_COMBINATION_INFO]); |
| }); |
| |
| test('byteStatColumn', function() { |
| var c = new ByteStatColumn('Stat', 'bytes', tr.b.identity, |
| AggregationMode.DIFF); |
| checkSpanWithColor(c.title, 'Stat', |
| 'used_memory_column' /* blue (column title) */); |
| |
| var HAS_OWN_VM_REGIONS = 1 << 2; |
| function checkByteStatColumnInfosAndColor( |
| fieldAndDumpMask, expectedInfos, expectedIsOlderColor) { |
| checkOverviewColumnInfosAndColor(c, |
| fieldAndDumpMask, |
| function(pmd, mask) { |
| if (mask & HAS_OWN_VM_REGIONS) |
| pmd.vmRegions = []; |
| }, |
| expectedInfos, |
| expectedIsOlderColor ? |
| 'older_used_memory_column' /* light blue */ : |
| 'used_memory_column' /* blue color */); |
| } |
| |
| var EXPECTED_ALL_OLDER_VALUES = { |
| icon: '\u26AF', |
| message: 'Older value (only heavy (purple) memory dumps contain ' + |
| 'memory maps).' |
| }; |
| var EXPECTED_SOME_OLDER_VALUES = { |
| icon: '\u26AF', |
| message: 'Older value at some selected timestamps (only heavy ' + |
| '(purple) memory dumps contain memory maps).' |
| }; |
| |
| // No context. |
| checkOverviewColumnInfosAndColor(c, |
| [FIELD], |
| undefined /* no context */, |
| [] /* no infos */, |
| 'used_memory_column' /* blue color */); |
| checkOverviewColumnInfosAndColor(c, |
| [FIELD, FIELD, 0, FIELD], |
| undefined /* no context */, |
| [] /* no infos */, |
| 'used_memory_column' /* blue color */); |
| |
| // All process memory dumps have own VM regions. |
| checkByteStatColumnInfosAndColor([ |
| FIELD | DUMP | HAS_OWN_VM_REGIONS |
| ], [] /* no infos */, false /* blue color */); |
| checkByteStatColumnInfosAndColor([ |
| FIELD | DUMP | HAS_OWN_VM_REGIONS, |
| FIELD | DUMP | HAS_OWN_VM_REGIONS, |
| 0, |
| FIELD | DUMP | HAS_OWN_VM_REGIONS |
| ], [] /* no infos */, false /* blue color */); |
| |
| // No process memory dumps have own VM regions. |
| checkByteStatColumnInfosAndColor([ |
| FIELD | DUMP |
| ], [EXPECTED_ALL_OLDER_VALUES], true /* light blue */); |
| checkByteStatColumnInfosAndColor([ |
| FIELD | DUMP, |
| FIELD | DUMP |
| ], [EXPECTED_ALL_OLDER_VALUES], true /* light blue */); |
| |
| // Some process memory dumps don't have own VM regions. |
| checkByteStatColumnInfosAndColor([ |
| FIELD | DUMP, |
| 0, |
| FIELD | DUMP |
| ], [EXPECTED_SOME_OLDER_VALUES], true /* light blue */); |
| checkByteStatColumnInfosAndColor([ |
| FIELD | DUMP | HAS_OWN_VM_REGIONS, |
| FIELD | DUMP, |
| FIELD | DUMP | HAS_OWN_VM_REGIONS |
| ], [EXPECTED_SOME_OLDER_VALUES], false /* blue */); |
| }); |
| |
| test('allocatorColumn', function() { |
| var c = new AllocatorColumn('Allocator', 'bytes', tr.b.identity, |
| AggregationMode.MAX); |
| checkColorLegend(c.title, 'Allocator'); |
| checkColor(c.color(undefined /* contexts */), |
| undefined /* no color (column cells) */); |
| |
| var HAS_HEAP_DUMPS = 1 << 2; |
| var HAS_ALLOCATOR_HEAP_DUMP = 1 << 3; |
| var MISSING_SIZE = 1 << 4; |
| function checkAllocatorColumnInfosAndColor(fieldAndDumpMask, |
| expectedInfos) { |
| checkOverviewColumnInfosAndColor(c, |
| fieldAndDumpMask, |
| function(pmd, mask) { |
| if (mask & HAS_HEAP_DUMPS) |
| pmd.heapDumps = {}; |
| if (mask & HAS_ALLOCATOR_HEAP_DUMP) |
| pmd.heapDumps['Allocator'] = new HeapDump(pmd, 'Allocator'); |
| var mad = new MemoryAllocatorDump(pmd, 'Allocator'); |
| if (!(mask & MISSING_SIZE)) { |
| mad.addNumeric('size', |
| new ScalarNumeric(sizeInBytes_smallerIsBetter, 7)); |
| } |
| pmd.memoryAllocatorDumps = [mad]; |
| }, |
| expectedInfos, |
| undefined /* no color */); |
| } |
| |
| // No context. |
| checkOverviewColumnInfosAndColor(c, |
| [FIELD], |
| undefined /* no context */, |
| [] /* no infos */, |
| undefined /* no color */); |
| checkOverviewColumnInfosAndColor(c, |
| [FIELD, FIELD, 0, FIELD], |
| undefined /* no context */, |
| [] /* no infos */, |
| undefined /* no color */); |
| |
| // No infos. |
| checkAllocatorColumnInfosAndColor([ |
| FIELD | DUMP |
| ], [] /* no infos */); |
| checkAllocatorColumnInfosAndColor([ |
| FIELD | DUMP, |
| FIELD | DUMP | HAS_HEAP_DUMPS, |
| 0, |
| FIELD | DUMP |
| ], [] /* infos */); |
| |
| var EXPECTED_ALL_HAVE_ALLOCATOR_HEAP_DUMP = { |
| icon: '\u2630', |
| message: 'Heap dump provided.' |
| }; |
| var EXPECTED_SOME_HAVE_ALLOCATOR_HEAP_DUMP = { |
| icon: '\u2630', |
| message: 'Heap dump provided at some selected timestamps.' |
| }; |
| |
| // All process memory dumps have heap dumps. |
| checkAllocatorColumnInfosAndColor([ |
| FIELD | DUMP | HAS_HEAP_DUMPS | HAS_ALLOCATOR_HEAP_DUMP |
| ], [EXPECTED_ALL_HAVE_ALLOCATOR_HEAP_DUMP]); |
| checkAllocatorColumnInfosAndColor([ |
| FIELD | DUMP | HAS_HEAP_DUMPS | HAS_ALLOCATOR_HEAP_DUMP, |
| FIELD | DUMP | HAS_HEAP_DUMPS | HAS_ALLOCATOR_HEAP_DUMP, |
| FIELD | DUMP | HAS_HEAP_DUMPS | HAS_ALLOCATOR_HEAP_DUMP |
| ], [EXPECTED_ALL_HAVE_ALLOCATOR_HEAP_DUMP]); |
| |
| // Some process memory dumps have heap dumps. |
| checkAllocatorColumnInfosAndColor([ |
| 0, |
| FIELD | DUMP | HAS_HEAP_DUMPS | HAS_ALLOCATOR_HEAP_DUMP |
| ], [EXPECTED_SOME_HAVE_ALLOCATOR_HEAP_DUMP]); |
| checkAllocatorColumnInfosAndColor([ |
| FIELD | DUMP | HAS_HEAP_DUMPS | HAS_ALLOCATOR_HEAP_DUMP, |
| FIELD | DUMP | HAS_HEAP_DUMPS, |
| FIELD | DUMP | HAS_HEAP_DUMPS | HAS_ALLOCATOR_HEAP_DUMP |
| ], [EXPECTED_SOME_HAVE_ALLOCATOR_HEAP_DUMP]); |
| |
| var EXPECTED_ALL_MISSING_SIZE = { |
| icon: '\u26A0', |
| message: 'Size was not provided.', |
| color: 'red' |
| }; |
| var EXPECTED_SOME_MISSING_SIZE = { |
| icon: '\u26A0', |
| message: 'Size was not provided at some selected timestamps.', |
| color: 'red' |
| }; |
| |
| // All process memory dumps are missing allocator size. |
| checkAllocatorColumnInfosAndColor([ |
| FIELD | DUMP | MISSING_SIZE |
| ], [EXPECTED_ALL_MISSING_SIZE]); |
| checkAllocatorColumnInfosAndColor([ |
| FIELD | DUMP | MISSING_SIZE, |
| FIELD | DUMP | MISSING_SIZE, |
| FIELD | DUMP | MISSING_SIZE |
| ], [EXPECTED_ALL_MISSING_SIZE]); |
| |
| // Some process memory dumps use Android memtrack PSS fallback. |
| checkAllocatorColumnInfosAndColor([ |
| 0, |
| FIELD | DUMP | MISSING_SIZE |
| ], [EXPECTED_SOME_MISSING_SIZE]); |
| checkAllocatorColumnInfosAndColor([ |
| FIELD | DUMP | MISSING_SIZE, |
| FIELD | DUMP, |
| FIELD | DUMP | MISSING_SIZE |
| ], [EXPECTED_SOME_MISSING_SIZE]); |
| |
| // Combination of heap dump and memtrack fallback infos. |
| checkAllocatorColumnInfosAndColor([ |
| FIELD | DUMP | MISSING_SIZE | HAS_HEAP_DUMPS | |
| HAS_ALLOCATOR_HEAP_DUMP |
| ], [ |
| EXPECTED_ALL_HAVE_ALLOCATOR_HEAP_DUMP, |
| EXPECTED_ALL_MISSING_SIZE |
| ]); |
| checkAllocatorColumnInfosAndColor([ |
| FIELD | DUMP | HAS_HEAP_DUMPS | HAS_ALLOCATOR_HEAP_DUMP, |
| FIELD | DUMP, |
| FIELD | DUMP | MISSING_SIZE |
| ], [ |
| EXPECTED_SOME_HAVE_ALLOCATOR_HEAP_DUMP, |
| EXPECTED_SOME_MISSING_SIZE |
| ]); |
| }); |
| |
| test('tracingColumn', function() { |
| var c = new TracingColumn('Tracing', 'bytes', tr.b.identity, |
| AggregationMode.DIFF); |
| checkSpanWithColor(c.title, 'Tracing', |
| 'tracing_memory_column' /* expected column title gray color */); |
| checkColor(c.color(undefined /* contexts */), |
| 'tracing_memory_column' /* expected column cells gray color */); |
| }); |
| }); |
| </script> |