| <!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/memory_dump_test_utils.html"> |
| <link rel="import" href="/tracing/model/vm_region.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/analysis/memory_dump_vm_regions_details_pane.html"> |
| |
| <script> |
| 'use strict'; |
| |
| tr.b.unittest.testSuite(function() { |
| var newAllocatorDump = tr.model.MemoryDumpTestUtils.newAllocatorDump; |
| var VMRegion = tr.model.VMRegion; |
| var VMRegionClassificationNode = tr.model.VMRegionClassificationNode; |
| var TitleColumn = tr.ui.analysis.TitleColumn; |
| var StringMemoryColumn = tr.ui.analysis.StringMemoryColumn; |
| var NumericMemoryColumn = tr.ui.analysis.NumericMemoryColumn; |
| var AggregationMode = tr.ui.analysis.MemoryColumn.AggregationMode; |
| var addGlobalMemoryDump = tr.ui.analysis.addGlobalMemoryDump; |
| var addProcessMemoryDump = tr.ui.analysis.addProcessMemoryDump; |
| var checkSizeNumericFields = tr.ui.analysis.checkSizeNumericFields; |
| var checkStringFields = tr.ui.analysis.checkStringFields; |
| var checkColumns = tr.ui.analysis.checkColumns; |
| var isElementDisplayed = tr.ui.analysis.isElementDisplayed; |
| |
| function createVMRegions() { |
| var model = tr.c.TestUtils.newModel(function(model) { |
| var process = model.getOrCreateProcess(1); |
| |
| // First timestamp. |
| var gmd1 = addGlobalMemoryDump(model, 42); |
| var pmd1 = addProcessMemoryDump(gmd1, process, 42); |
| pmd1.vmRegions = VMRegionClassificationNode.fromRegions([ |
| VMRegion.fromDict({ |
| mappedFile: '/lib/chrome.so', |
| startAddress: 65536, |
| sizeInBytes: 536870912, |
| protectionFlags: VMRegion.PROTECTION_FLAG_READ | |
| VMRegion.PROTECTION_FLAG_EXECUTE, |
| byteStats: { |
| proportionalResident: 8192 |
| } |
| }), |
| VMRegion.fromDict({ |
| mappedFile: '/usr/lib/x86_64-linux-gnu/libX11.so.6.3.0', |
| startAddress: 140296983150592, |
| sizeInBytes: 2097152, |
| protectionFlags: 0, |
| byteStats: { |
| proportionalResident: 0 |
| } |
| }), |
| VMRegion.fromDict({ |
| startAddress: 10995116277760, |
| sizeInBytes: 2147483648, |
| protectionFlags: VMRegion.PROTECTION_FLAG_READ | |
| VMRegion.PROTECTION_FLAG_WRITE, |
| byteStats: { |
| privateDirtyResident: 0, |
| swapped: 0 |
| } |
| }), |
| VMRegion.fromDict({ |
| startAddress: 12094627905536, |
| sizeInBytes: 2147483648, |
| protectionFlags: VMRegion.PROTECTION_FLAG_READ | |
| VMRegion.PROTECTION_FLAG_WRITE, |
| byteStats: { |
| privateDirtyResident: 0, |
| swapped: 0 |
| } |
| }), |
| VMRegion.fromDict({ |
| mappedFile: '/dev/ashmem/dalvik-zygote space', |
| startAddress: 13194139533312, |
| sizeInBytes: 100, |
| protectionFlags: VMRegion.PROTECTION_FLAG_READ | |
| VMRegion.PROTECTION_FLAG_EXECUTE, |
| byteStats: { |
| proportionalResident: 100, |
| privateDirtyResident: 0, |
| swapped: 0 |
| } |
| }), |
| VMRegion.fromDict({ |
| mappedFile: '/dev/ashmem/libc malloc', |
| startAddress: 14293651161088, |
| sizeInBytes: 200, |
| protectionFlags: VMRegion.PROTECTION_FLAG_READ | |
| VMRegion.PROTECTION_FLAG_EXECUTE, |
| byteStats: { |
| proportionalResident: 200, |
| privateDirtyResident: 96, |
| swapped: 0 |
| } |
| }) |
| ]); |
| |
| // This is here so that we could test that tracing is discounted from the |
| // 'Native heap' category. |
| pmd1.memoryAllocatorDumps = [ |
| newAllocatorDump(pmd1, 'tracing', { size: 500, resident_size: 32 }) |
| ]; |
| |
| // Second timestamp. |
| var gmd2 = addGlobalMemoryDump(model, 42); |
| var pmd2 = addProcessMemoryDump(gmd2, process, 42); |
| pmd2.vmRegions = VMRegionClassificationNode.fromRegions([ |
| VMRegion.fromDict({ |
| mappedFile: '/lib/chrome.so', |
| startAddress: 65536, |
| sizeInBytes: 536870912, |
| protectionFlags: VMRegion.PROTECTION_FLAG_READ | |
| VMRegion.PROTECTION_FLAG_EXECUTE, |
| byteStats: { |
| proportionalResident: 9216 |
| } |
| }), |
| VMRegion.fromDict({ |
| mappedFile: '/lib/chrome.so', |
| startAddress: 140296983150592, |
| sizeInBytes: 536870912, |
| protectionFlags: VMRegion.PROTECTION_FLAG_READ | |
| VMRegion.PROTECTION_FLAG_EXECUTE, |
| byteStats: { |
| proportionalResident: 10240 |
| } |
| }), |
| VMRegion.fromDict({ |
| startAddress: 10995116277760, |
| sizeInBytes: 2147483648, |
| protectionFlags: VMRegion.PROTECTION_FLAG_READ | |
| VMRegion.PROTECTION_FLAG_WRITE, |
| byteStats: { |
| privateDirtyResident: 0, |
| swapped: 32 |
| } |
| }), |
| VMRegion.fromDict({ |
| startAddress: 12094627905536, |
| sizeInBytes: 2147483648, |
| protectionFlags: VMRegion.PROTECTION_FLAG_READ | |
| VMRegion.PROTECTION_FLAG_WRITE, |
| byteStats: { |
| privateDirtyResident: 0, |
| swapped: 0 |
| } |
| }), |
| VMRegion.fromDict({ |
| mappedFile: '/dev/ashmem/dalvik-zygote space', |
| startAddress: 13194139533312, |
| sizeInBytes: 100, |
| protectionFlags: VMRegion.PROTECTION_FLAG_READ | |
| VMRegion.PROTECTION_FLAG_EXECUTE, |
| byteStats: { |
| proportionalResident: 0, |
| privateDirtyResident: 100, |
| swapped: 0 |
| } |
| }), |
| VMRegion.fromDict({ |
| mappedFile: '/dev/ashmem/libc malloc', |
| startAddress: 14293651161088, |
| sizeInBytes: 200, |
| protectionFlags: VMRegion.PROTECTION_FLAG_READ | |
| VMRegion.PROTECTION_FLAG_EXECUTE, |
| byteStats: { |
| proportionalResident: 100, |
| privateDirtyResident: 96, |
| swapped: 0 |
| } |
| }), |
| VMRegion.fromDict({ |
| mappedFile: '/usr/share/fonts/DejaVuSansMono.ttf', |
| startAddress: 140121259503616, |
| sizeInBytes: 335872, |
| protectionFlags: VMRegion.PROTECTION_FLAG_READ, |
| byteStats: { |
| proportionalResident: 22528 |
| } |
| }), |
| VMRegion.fromDict({ |
| mappedFile: 'another-map', |
| startAddress: 52583094233905872, |
| sizeInBytes: 1, |
| byteStats: { |
| proportionalResident: 1, |
| privateDirtyResident: 1, |
| swapped: 1 |
| } |
| }) |
| ]); |
| }); |
| |
| return model.processes[1].memoryDumps.map(function(pmd) { |
| return pmd.mostRecentVmRegions; |
| }); |
| } |
| |
| var EXPECTED_COLUMNS = [ |
| { title: 'Mapped file', type: TitleColumn, noAggregation: true }, |
| { title: 'Start address', type: StringMemoryColumn, noAggregation: true }, |
| { title: 'Virtual size', type: NumericMemoryColumn }, |
| { title: 'Protection flags', type: StringMemoryColumn }, |
| { title: 'PSS', type: NumericMemoryColumn }, |
| { title: 'Private dirty', type: NumericMemoryColumn }, |
| { title: 'Swapped', type: NumericMemoryColumn } |
| ]; |
| |
| function checkRow(columns, row, expectedTitle, expectedStartAddress, |
| expectedVirtualSize, expectedProtectionFlags, |
| expectedProportionalResidentValues, expectedPrivateDirtyResidentValues, |
| expectedSwappedValues, expectedSubRowCount, expectedContexts) { |
| assert.equal(columns[0].formatTitle(row), expectedTitle); |
| checkStringFields(row, columns[1], expectedStartAddress); |
| checkSizeNumericFields(row, columns[2], expectedVirtualSize); |
| checkStringFields(row, columns[3], expectedProtectionFlags); |
| checkSizeNumericFields(row, columns[4], expectedProportionalResidentValues); |
| checkSizeNumericFields(row, columns[5], expectedPrivateDirtyResidentValues); |
| checkSizeNumericFields(row, columns[6], expectedSwappedValues); |
| |
| if (expectedSubRowCount === undefined) |
| assert.isUndefined(row.subRows); |
| else |
| assert.lengthOf(row.subRows, expectedSubRowCount); |
| |
| if (typeof expectedContexts === 'function') |
| expectedContexts(row.contexts); |
| else if (expectedContexts !== undefined) |
| assert.deepEqual(tr.b.asArray(row.contexts), expectedContexts); |
| else |
| assert.isUndefined(row.contexts); |
| } |
| |
| function genericMatcher(callback, defined) { |
| return function(actualValues) { |
| assert.lengthOf(actualValues, defined.length); |
| for (var i = 0; i < defined.length; i++) { |
| var actualValue = actualValues[i]; |
| if (defined[i]) |
| callback(actualValue); |
| else |
| assert.isUndefined(actualValue); |
| } |
| } |
| } |
| |
| function vmRegionsMatcher(expectedMappedFile, expectedStartAddress, defined) { |
| return genericMatcher(function(actualRegion) { |
| assert.instanceOf(actualRegion, VMRegion); |
| assert.strictEqual(actualRegion.mappedFile, expectedMappedFile); |
| assert.strictEqual(actualRegion.startAddress, expectedStartAddress); |
| }, defined); |
| } |
| |
| function classificationNodesMatcher(expectedTitle, defined) { |
| return genericMatcher(function(actualNode) { |
| assert.instanceOf(actualNode, VMRegionClassificationNode); |
| assert.strictEqual(actualNode.title, expectedTitle); |
| }, defined); |
| } |
| |
| test('instantiate_empty', function() { |
| tr.ui.analysis.createAndCheckEmptyPanes(this, |
| 'tr-ui-a-memory-dump-vm-regions-details-pane', 'vmRegions', |
| function(viewEl) { |
| // Check that the info text is shown. |
| assert.isTrue(isElementDisplayed(viewEl.$.info_text)); |
| assert.isFalse(isElementDisplayed(viewEl.$.table)); |
| }); |
| }); |
| |
| test('instantiate_single', function() { |
| var vmRegions = createVMRegions().slice(0, 1); |
| |
| var viewEl = document.createElement( |
| 'tr-ui-a-memory-dump-vm-regions-details-pane'); |
| viewEl.vmRegions = vmRegions; |
| viewEl.rebuild(); |
| this.addHTMLOutput(viewEl); |
| |
| // Check that the table is shown. |
| assert.isTrue(isElementDisplayed(viewEl.$.table)); |
| assert.isFalse(isElementDisplayed(viewEl.$.info_text)); |
| |
| var table = viewEl.$.table; |
| var columns = table.tableColumns; |
| checkColumns(columns, EXPECTED_COLUMNS, undefined /* no aggregation */); |
| var rows = table.tableRows; |
| assert.lengthOf(rows, 1); |
| |
| // Check the rows of the table. |
| var totalRow = rows[0]; |
| checkRow(columns, totalRow, 'Total', undefined, [4833935160], undefined, |
| [8460], [64], [0], 3, vmRegions); |
| |
| var androidRow = totalRow.subRows[0]; |
| checkRow(columns, androidRow, 'Android', undefined, [100], undefined, |
| [100], [0], [0], 1, classificationNodesMatcher('Android', [true])); |
| |
| var javaRuntimeRow = androidRow.subRows[0]; |
| checkRow(columns, javaRuntimeRow, 'Java runtime', undefined, [100], |
| undefined, [100], [0], [0], 1, |
| classificationNodesMatcher('Java runtime', [true])); |
| |
| var spacesRow = javaRuntimeRow.subRows[0]; |
| checkRow(columns, spacesRow, 'Spaces', undefined, [100], undefined, [100], |
| [0], [0], 1, classificationNodesMatcher('Spaces', [true])); |
| |
| var nativeHeapRow = totalRow.subRows[1]; |
| checkRow(columns, nativeHeapRow, 'Native heap', undefined, [4294966996], |
| undefined, [168], [64], [0], 4, |
| classificationNodesMatcher('Native heap', [true])); |
| |
| var discountedTracingOverheadRow = nativeHeapRow.subRows[3]; |
| checkRow(columns, discountedTracingOverheadRow, |
| '[discounted tracing overhead]', undefined, [-500], undefined, [-32], |
| [-32], undefined, undefined, |
| vmRegionsMatcher('[discounted tracing overhead]', undefined, [true])); |
| |
| var filesRow = totalRow.subRows[2]; |
| checkRow(columns, filesRow, 'Files', undefined, [538968064], undefined, |
| [8192], undefined, undefined, 1, |
| classificationNodesMatcher('Files', [true])); |
| |
| var soRow = filesRow.subRows[0]; |
| checkRow(columns, soRow, 'so', undefined, [538968064], undefined, |
| [8192], undefined, undefined, 2, |
| classificationNodesMatcher('so', [true])); |
| |
| var mmapChromeRow = soRow.subRows[0]; |
| checkRow(columns, mmapChromeRow, '/lib/chrome.so', ['0000000000010000'], |
| [536870912], ['r-xp'], [8192], undefined, undefined, undefined, |
| vmRegionsMatcher('/lib/chrome.so', 65536, [true])); |
| |
| var mmapLibX11Row = soRow.subRows[1]; |
| checkRow(columns, mmapLibX11Row, |
| '/usr/lib/x86_64-linux-gnu/libX11.so.6.3.0', ['00007f996fd80000'], |
| [2097152], ['---p'], [0], undefined, undefined, undefined, |
| vmRegionsMatcher('/usr/lib/x86_64-linux-gnu/libX11.so.6.3.0', |
| 140296983150592, [true])); |
| }); |
| |
| test('instantiate_multipleDiff', function() { |
| var vmRegions = createVMRegions(); |
| |
| var viewEl = document.createElement( |
| 'tr-ui-a-memory-dump-vm-regions-details-pane'); |
| viewEl.vmRegions = vmRegions; |
| viewEl.aggregationMode = AggregationMode.DIFF; |
| viewEl.rebuild(); |
| this.addHTMLOutput(viewEl); |
| |
| // Check that the table is shown. |
| assert.isTrue(isElementDisplayed(viewEl.$.table)); |
| assert.isFalse(isElementDisplayed(viewEl.$.info_text)); |
| |
| var table = viewEl.$.table; |
| var columns = table.tableColumns; |
| checkColumns(columns, EXPECTED_COLUMNS, AggregationMode.DIFF); |
| var rows = table.tableRows; |
| assert.lengthOf(rows, 1); |
| |
| // Check the rows of the table. |
| var totalRow = rows[0]; |
| checkRow(columns, totalRow, 'Total', undefined, [4833935160, 5369045293], |
| undefined, [8460, 42085], [64, 197], [0, 33], 4, vmRegions); |
| |
| var androidRow = totalRow.subRows[0]; |
| checkRow(columns, androidRow, 'Android', undefined, [100, 100], undefined, |
| [100, 0], [0, 100], [0, 0], 1, |
| classificationNodesMatcher('Android', [true, true])); |
| |
| var javaRuntimeRow = androidRow.subRows[0]; |
| checkRow(columns, javaRuntimeRow, 'Java runtime', undefined, [100, 100], |
| undefined, [100, 0], [0, 100], [0, 0], 1, |
| classificationNodesMatcher('Java runtime', [true, true])); |
| |
| var spacesRow = javaRuntimeRow.subRows[0]; |
| checkRow(columns, spacesRow, 'Spaces', undefined, [100, 100], undefined, |
| [100, 0], [0, 100], [0, 0], 1, |
| classificationNodesMatcher('Spaces', [true, true])); |
| |
| var nativeHeapRow = totalRow.subRows[1]; |
| checkRow(columns, nativeHeapRow, 'Native heap', undefined, |
| [4294966996, 4294967496], undefined, [168, 100], [64, 96], [0, 32], 4, |
| classificationNodesMatcher('Native heap', [true, true])); |
| |
| var discountedTracingOverheadRow = nativeHeapRow.subRows[3]; |
| checkRow(columns, discountedTracingOverheadRow, |
| '[discounted tracing overhead]', undefined, [-500, undefined], |
| undefined, [-32, undefined], [-32, undefined], undefined, undefined, |
| vmRegionsMatcher('[discounted tracing overhead]', undefined, |
| [true, false])); |
| |
| var filesRow = totalRow.subRows[2]; |
| checkRow(columns, filesRow, 'Files', undefined, [538968064, 1074077696], |
| undefined, [8192, 41984], undefined, undefined, 2, |
| classificationNodesMatcher('Files', [true, true])); |
| |
| var soRow = filesRow.subRows[0]; |
| checkRow(columns, soRow, 'so', undefined, [538968064, 1073741824], |
| undefined, [8192, 19456], undefined, undefined, 3, |
| classificationNodesMatcher('so', [true, true])); |
| |
| var mmapChromeRow = soRow.subRows[0]; |
| checkRow(columns, mmapChromeRow, '/lib/chrome.so', ['0000000000010000'], |
| [536870912, 536870912], ['r-xp', 'r-xp'], [8192, 9216], undefined, |
| undefined, undefined, |
| vmRegionsMatcher('/lib/chrome.so', 65536, [true, true])); |
| |
| var mmapLibX11Row = soRow.subRows[1]; |
| checkRow(columns, mmapLibX11Row, |
| '/usr/lib/x86_64-linux-gnu/libX11.so.6.3.0', ['00007f996fd80000'], |
| [2097152, undefined], ['---p', undefined], [0, undefined], undefined, |
| undefined, undefined, |
| vmRegionsMatcher('/usr/lib/x86_64-linux-gnu/libX11.so.6.3.0', |
| 140296983150592, [true, false])); |
| |
| var otherRow = totalRow.subRows[3]; |
| checkRow(columns, otherRow, 'Other', undefined, [undefined, 1], undefined, |
| [undefined, 1], [undefined, 1], [undefined, 1], 1, |
| classificationNodesMatcher('Other', [false, true])); |
| |
| var anotherMapRow = otherRow.subRows[0]; |
| checkRow(columns, anotherMapRow, 'another-map', ['00bad00bad00bad0'], |
| [undefined, 1], undefined, [undefined, 1], [undefined, 1], |
| [undefined, 1], undefined, |
| vmRegionsMatcher('another-map', 52583094233905872, [false, true])); |
| }); |
| |
| test('instantiate_multipleMax', function() { |
| var vmRegions = createVMRegions(); |
| |
| var viewEl = document.createElement( |
| 'tr-ui-a-memory-dump-vm-regions-details-pane'); |
| viewEl.vmRegions = vmRegions; |
| viewEl.aggregationMode = AggregationMode.MAX; |
| viewEl.rebuild(); |
| this.addHTMLOutput(viewEl); |
| |
| // Check that the table is shown. |
| assert.isTrue(isElementDisplayed(viewEl.$.table)); |
| assert.isFalse(isElementDisplayed(viewEl.$.info_text)); |
| |
| // Just check that the aggregation mode was propagated to the columns. |
| var table = viewEl.$.table; |
| var columns = table.tableColumns; |
| checkColumns(columns, EXPECTED_COLUMNS, AggregationMode.MAX); |
| var rows = table.tableRows; |
| assert.lengthOf(rows, 1); |
| }); |
| |
| test('instantiate_multipleWithUndefined', function() { |
| var vmRegions = createVMRegions(); |
| vmRegions.splice(1, 0, undefined); |
| |
| var viewEl = document.createElement( |
| 'tr-ui-a-memory-dump-vm-regions-details-pane'); |
| viewEl.vmRegions = vmRegions; |
| viewEl.aggregationMode = AggregationMode.DIFF; |
| viewEl.rebuild(); |
| this.addHTMLOutput(viewEl); |
| |
| // Check that the table is shown. |
| assert.isTrue(isElementDisplayed(viewEl.$.table)); |
| assert.isFalse(isElementDisplayed(viewEl.$.info_text)); |
| |
| // Just check that the table has the right shape. |
| var table = viewEl.$.table; |
| var columns = table.tableColumns; |
| checkColumns(columns, EXPECTED_COLUMNS, AggregationMode.DIFF); |
| var rows = table.tableRows; |
| assert.lengthOf(rows, 1); |
| }); |
| }); |
| </script> |